@coralogix/react-native-plugin 0.1.0

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.
Files changed (40) hide show
  1. package/CHANGELOG.md +17 -0
  2. package/CxSdk.podspec +45 -0
  3. package/LICENSE +201 -0
  4. package/README.md +187 -0
  5. package/android/build.gradle +87 -0
  6. package/android/gradle.properties +5 -0
  7. package/android/src/main/AndroidManifest.xml +2 -0
  8. package/android/src/main/java/com/cxsdk/CxSdkModule.kt +457 -0
  9. package/android/src/main/java/com/cxsdk/CxSdkPackage.kt +16 -0
  10. package/android/src/main/java/com/cxsdk/ICxSdkModule.kt +24 -0
  11. package/index.cjs.js +682 -0
  12. package/index.d.ts +1 -0
  13. package/index.esm.js +678 -0
  14. package/ios/CxSdk-Bridging-Header.h +2 -0
  15. package/ios/CxSdk.mm +81 -0
  16. package/ios/CxSdk.swift +371 -0
  17. package/package.json +34 -0
  18. package/src/CoralogixPropgator.d.ts +2 -0
  19. package/src/consts.d.ts +23 -0
  20. package/src/index.d.ts +10 -0
  21. package/src/instrumentations/error/ErrorInstrumentation.d.ts +18 -0
  22. package/src/instrumentations/error/error.consts.d.ts +7 -0
  23. package/src/instrumentations/error/error.enums.d.ts +4 -0
  24. package/src/instrumentations/mobile-vitals/JsRefreshRateSamplerInstrumentation.d.ts +8 -0
  25. package/src/instrumentations/mobile-vitals/loopDetectorInstrumentation.d.ts +16 -0
  26. package/src/instrumentations/network/FetchInstrumentation.d.ts +5 -0
  27. package/src/instrumentations/network/network.enums.d.ts +10 -0
  28. package/src/logger.d.ts +16 -0
  29. package/src/model/ApplicationContextConfig.d.ts +4 -0
  30. package/src/model/CoralogixDomain.d.ts +10 -0
  31. package/src/model/CoralogixOtelWebOptionsInstrumentations.d.ts +9 -0
  32. package/src/model/CoralogixOtelWebType.d.ts +49 -0
  33. package/src/model/CoralogixRumLabels.d.ts +1 -0
  34. package/src/model/CustomMeasurement.d.ts +4 -0
  35. package/src/model/NetworkRequestDetails.d.ts +14 -0
  36. package/src/model/SendLog.d.ts +10 -0
  37. package/src/model/Types.d.ts +209 -0
  38. package/src/model/UserContextConfig.d.ts +8 -0
  39. package/src/model/ViewContextConfig.d.ts +3 -0
  40. package/src/utils.d.ts +5 -0
package/index.cjs.js ADDED
@@ -0,0 +1,682 @@
1
+ 'use strict';
2
+
3
+ var reactNative = require('react-native');
4
+ var instrumentationFetch = require('@opentelemetry/instrumentation-fetch');
5
+ var instrumentation = require('@opentelemetry/instrumentation');
6
+ var sdkTraceWeb = require('@opentelemetry/sdk-trace-web');
7
+
8
+ function _extends() {
9
+ return _extends = Object.assign ? Object.assign.bind() : function (n) {
10
+ for (var e = 1; e < arguments.length; e++) {
11
+ var t = arguments[e];
12
+ for (var r in t) ({}).hasOwnProperty.call(t, r) && (n[r] = t[r]);
13
+ }
14
+ return n;
15
+ }, _extends.apply(null, arguments);
16
+ }
17
+
18
+ let CoralogixLogSeverity = /*#__PURE__*/function (CoralogixLogSeverity) {
19
+ CoralogixLogSeverity[CoralogixLogSeverity["Debug"] = 1] = "Debug";
20
+ CoralogixLogSeverity[CoralogixLogSeverity["Verbose"] = 2] = "Verbose";
21
+ CoralogixLogSeverity[CoralogixLogSeverity["Info"] = 3] = "Info";
22
+ CoralogixLogSeverity[CoralogixLogSeverity["Warn"] = 4] = "Warn";
23
+ CoralogixLogSeverity[CoralogixLogSeverity["Error"] = 5] = "Error";
24
+ CoralogixLogSeverity[CoralogixLogSeverity["Critical"] = 6] = "Critical";
25
+ return CoralogixLogSeverity;
26
+ }({});
27
+
28
+ let ErrorSource = /*#__PURE__*/function (ErrorSource) {
29
+ ErrorSource["CONSOLE"] = "console";
30
+ ErrorSource["GLOBAL"] = "global";
31
+ return ErrorSource;
32
+ }({});
33
+
34
+ const ERROR_INSTRUMENTATION_NAME = 'errors';
35
+ const ERROR_INSTRUMENTATION_VERSION = '1';
36
+
37
+ let defaultConsoleError = (..._params) => {};
38
+ const MESSAGE_LIMIT = 1024;
39
+ const getCircularReplacer = () => {
40
+ const seen = new WeakSet();
41
+ return (_key, value) => {
42
+ if (typeof value === 'object' && value !== null) {
43
+ if (seen.has(value)) {
44
+ return;
45
+ }
46
+ seen.add(value);
47
+ }
48
+ return value;
49
+ };
50
+ };
51
+ class CoralogixErrorInstrumentation extends instrumentation.InstrumentationBase {
52
+ constructor(config) {
53
+ super(ERROR_INSTRUMENTATION_NAME, ERROR_INSTRUMENTATION_VERSION, config);
54
+ this.parseErrorObject = obj => {
55
+ var _obj$message;
56
+ return (_obj$message = obj == null ? void 0 : obj.message) != null ? _obj$message : JSON.stringify(obj, getCircularReplacer());
57
+ };
58
+ }
59
+ init() {}
60
+ listenToConsoleError() {
61
+ const onConsoleError = (...params) => {
62
+ defaultConsoleError.apply(console, params);
63
+ this.report(ErrorSource.CONSOLE, params);
64
+ };
65
+ defaultConsoleError = console.error;
66
+ console.error = onConsoleError;
67
+ }
68
+ report(source, arg) {
69
+ if (Array.isArray(arg)) {
70
+ if (arg.length === 0) {
71
+ return;
72
+ }
73
+ }
74
+ if (arg instanceof Error) {
75
+ this.reportError(arg);
76
+ } else if (typeof arg === 'string') {
77
+ this.reportString(arg);
78
+ } else if (Array.isArray(arg)) {
79
+ // if any arguments are Errors then add the stack trace even though the message is handled differently
80
+ const firstError = arg.find(x => x instanceof Error);
81
+ const message = arg.map(msg => typeof msg === 'string' ? msg : this.parseErrorObject(msg)).join(' ');
82
+ this.reportString(message, firstError);
83
+ } else {
84
+ this.reportString(typeof arg === 'string' ? arg : this.getPossibleEventMessage(arg));
85
+ }
86
+ }
87
+ reportError(err) {
88
+ CoralogixRum.reportError(err, false);
89
+ }
90
+ reportString(message, firstError) {
91
+ const truncatedMessage = (message == null ? void 0 : message.substring(0, MESSAGE_LIMIT)) || '';
92
+ CoralogixRum.reportError({
93
+ name: (firstError == null ? void 0 : firstError.name) || 'CONSOLE',
94
+ message: truncatedMessage,
95
+ stack: firstError == null ? void 0 : firstError.stack
96
+ }, false);
97
+ }
98
+ getPossibleEventMessage(event) {
99
+ const {
100
+ message,
101
+ statusMessage
102
+ } = event || {};
103
+ if (message && typeof message === 'string') {
104
+ return message;
105
+ }
106
+
107
+ // GrpcStatusEvent
108
+ if (statusMessage && typeof statusMessage === 'string') {
109
+ return statusMessage;
110
+ }
111
+ return JSON.stringify(event);
112
+ }
113
+ enable() {
114
+ const defaultHandler = ErrorUtils.getGlobalHandler();
115
+ ErrorUtils.setGlobalHandler((error, isFatal) => {
116
+ this.report(ErrorSource.GLOBAL, error);
117
+ if (defaultHandler) {
118
+ setTimeout(() => {
119
+ defaultHandler(error, isFatal);
120
+ }, 2500);
121
+ }
122
+ });
123
+ this.listenToConsoleError();
124
+ }
125
+ disable() {}
126
+ }
127
+
128
+ const DEFAULT_SAMPLE_DURATION_MS = 5000;
129
+ const DEFAULT_SAMPLE_INTERVAL_MS = 60000;
130
+ let isSampling = false;
131
+ let rafId = null;
132
+ let intervalTimer = null;
133
+ let appState = 'active';
134
+ let appStateSub = null;
135
+ function startJsRefreshRateSampler({
136
+ sampleDurationMs = DEFAULT_SAMPLE_DURATION_MS,
137
+ sampleIntervalMs = DEFAULT_SAMPLE_INTERVAL_MS,
138
+ onSample
139
+ }) {
140
+ var _AppState$currentStat;
141
+ if (isSampling) return;
142
+ isSampling = true;
143
+ let firstTimestamp = null;
144
+ let lastTimestamp = null;
145
+ let frameCount = 0;
146
+ const requestNext = () => {
147
+ rafId = requestAnimationFrame(loop);
148
+ };
149
+ const loop = t => {
150
+ if (appState === 'active') {
151
+ if (firstTimestamp === null) firstTimestamp = t;
152
+ lastTimestamp = t;
153
+ frameCount += 1;
154
+ }
155
+ requestNext();
156
+ };
157
+ const stopRaf = () => {
158
+ if (rafId !== null) {
159
+ cancelAnimationFrame(rafId);
160
+ rafId = null;
161
+ }
162
+ };
163
+ const resetCounters = () => {
164
+ firstTimestamp = null;
165
+ lastTimestamp = null;
166
+ frameCount = 0;
167
+ };
168
+ const getElapsedMs = () => {
169
+ if (firstTimestamp == null || lastTimestamp == null) return 0;
170
+ return Math.max(0, lastTimestamp - firstTimestamp);
171
+ };
172
+ const computeAverageRafRate = () => {
173
+ const elapsedMs = getElapsedMs();
174
+ if (elapsedMs === 0) return 0;
175
+ return (frameCount - 1) * 1000 / elapsedMs;
176
+ };
177
+ const runSample = () => {
178
+ if (!isSampling) return;
179
+ if (appState !== 'active') {
180
+ scheduleNextSample();
181
+ return;
182
+ }
183
+ resetCounters();
184
+ requestNext();
185
+ setTimeout(() => {
186
+ stopRaf();
187
+ const rafRate = computeAverageRafRate();
188
+ onSample(rafRate);
189
+ scheduleNextSample();
190
+ }, sampleDurationMs);
191
+ };
192
+ const scheduleNextSample = () => {
193
+ if (!isSampling) return;
194
+ intervalTimer = setTimeout(runSample, sampleIntervalMs);
195
+ };
196
+ const handleAppStateChange = next => {
197
+ appState = next;
198
+ if (next !== 'active') {
199
+ stopRaf();
200
+ resetCounters();
201
+ }
202
+ };
203
+ appState = (_AppState$currentStat = reactNative.AppState.currentState) != null ? _AppState$currentStat : 'active';
204
+ appStateSub = reactNative.AppState.addEventListener('change', handleAppStateChange);
205
+ runSample();
206
+ }
207
+ function stopJsRefreshRateSampler() {
208
+ var _appStateSub;
209
+ isSampling = false;
210
+ if (intervalTimer) {
211
+ clearTimeout(intervalTimer);
212
+ intervalTimer = null;
213
+ }
214
+ if (rafId !== null) {
215
+ cancelAnimationFrame(rafId);
216
+ rafId = null;
217
+ }
218
+ (_appStateSub = appStateSub) == null || _appStateSub.remove();
219
+ appStateSub = null;
220
+ }
221
+
222
+ var version = "0.1.0";
223
+ var pkg = {
224
+ version: version};
225
+
226
+ class Logger {
227
+ constructor(config = {}) {
228
+ var _config$shouldLog, _config$prefix;
229
+ this._shouldLog = void 0;
230
+ this._prefix = void 0;
231
+ this._shouldLog = (_config$shouldLog = config.shouldLog) != null ? _config$shouldLog : false;
232
+ this._prefix = (_config$prefix = config.prefix) != null ? _config$prefix : '[Coralogix React Native SDK] - ';
233
+ }
234
+ set shouldLog(value) {
235
+ this._shouldLog = value;
236
+ }
237
+ debug(message, ...args) {
238
+ if (this._shouldLog) {
239
+ console.debug(`${this._prefix} ${message}`, ...args);
240
+ }
241
+ }
242
+ info(message, ...args) {
243
+ if (this._shouldLog) {
244
+ console.info(`${this._prefix} ${message}`, ...args);
245
+ }
246
+ }
247
+ warn(message, ...args) {
248
+ if (this._shouldLog) {
249
+ console.warn(`${this._prefix} ${message}`, ...args);
250
+ }
251
+ }
252
+ error(message, ...args) {
253
+ if (this._shouldLog) {
254
+ console.error(`${this._prefix} ${message}`, ...args);
255
+ }
256
+ }
257
+ }
258
+ const logger = new Logger();
259
+
260
+ const propagateTraceHeaderCorsUrls = config => {
261
+ var _traceParentInHeader$;
262
+ const {
263
+ traceParentInHeader
264
+ } = config;
265
+ const propagateCorsUrls = traceParentInHeader == null || (_traceParentInHeader$ = traceParentInHeader.options) == null ? void 0 : _traceParentInHeader$.propagateTraceHeaderCorsUrls;
266
+ if (traceParentInHeader != null && traceParentInHeader.enabled && propagateCorsUrls) {
267
+ config.propagateTraceHeaderCorsUrls = propagateCorsUrls;
268
+ }
269
+ };
270
+
271
+ const CORALOGIX_LOGS_URL_SUFFIX = '/browser/v1beta/logs';
272
+ const CORALOGIX_RECORDING_URL_SUFFIX = '/sessionrecording';
273
+ const OPTIONS_DEFAULTS = {
274
+ ignoreUrls: [new RegExp(CORALOGIX_LOGS_URL_SUFFIX), new RegExp(CORALOGIX_RECORDING_URL_SUFFIX)],
275
+ user_context: {
276
+ user_id: '',
277
+ user_name: ''
278
+ },
279
+ labels: {},
280
+ view_context: {
281
+ view: ''
282
+ }
283
+ };
284
+
285
+ const hrTimeToMilliseconds = ([seconds, nanoseconds]) => seconds * 1000 + Math.round(nanoseconds / 1e6);
286
+ const getUrlFragments = url => {
287
+ if (!url) {
288
+ return '';
289
+ }
290
+ try {
291
+ if (url.startsWith('blob:')) {
292
+ return url;
293
+ }
294
+ return new URL(url).pathname.substring(1) || '/';
295
+ } catch (err) {
296
+ logger.warn('Error parsing URL', err);
297
+ return url;
298
+ }
299
+ };
300
+ function isSamplingOn(threshold) {
301
+ return threshold > 0 && Math.random() * 100 <= threshold;
302
+ }
303
+ function resolveCoralogixOtelWebConfig(config) {
304
+ var _config$sessionSample, _config$view_context;
305
+ const {
306
+ ignoreUrls,
307
+ debug
308
+ } = config;
309
+ const resolvedIgnoreUrls = [];
310
+ ignoreUrls && resolvedIgnoreUrls.push(...ignoreUrls);
311
+ OPTIONS_DEFAULTS.ignoreUrls && resolvedIgnoreUrls.push(...OPTIONS_DEFAULTS.ignoreUrls);
312
+ return _extends({}, OPTIONS_DEFAULTS, config, {
313
+ ignoreUrls: resolvedIgnoreUrls,
314
+ sessionSampleRate: (_config$sessionSample = config.sessionSampleRate) != null ? _config$sessionSample : 100,
315
+ debug,
316
+ view_context: (_config$view_context = config.view_context) != null ? _config$view_context : OPTIONS_DEFAULTS.view_context
317
+ });
318
+ }
319
+
320
+ let OtelNetworkAttrs = /*#__PURE__*/function (OtelNetworkAttrs) {
321
+ OtelNetworkAttrs["METHOD"] = "http.method";
322
+ OtelNetworkAttrs["URL"] = "http.url";
323
+ OtelNetworkAttrs["STATUS_CODE"] = "http.status_code";
324
+ OtelNetworkAttrs["HOST"] = "http.host";
325
+ OtelNetworkAttrs["SCHEME"] = "http.scheme";
326
+ OtelNetworkAttrs["STATUS_TEXT"] = "http.status_text";
327
+ OtelNetworkAttrs["RESPONSE_CONTENT_LENGTH"] = "http.response_content_length";
328
+ OtelNetworkAttrs["OtelNetworkAttrs"] = "OtelNetworkAttrs";
329
+ return OtelNetworkAttrs;
330
+ }({});
331
+
332
+ class CoralogixFetchInstrumentation extends instrumentationFetch.FetchInstrumentation {
333
+ constructor(config) {
334
+ propagateTraceHeaderCorsUrls(config);
335
+ config.applyCustomAttributesOnSpan = (span, request, result) => {
336
+ span.end();
337
+ const readableSpan = span;
338
+ const attrs = readableSpan.attributes;
339
+ const method = attrs[OtelNetworkAttrs.METHOD];
340
+ const url = attrs[OtelNetworkAttrs.URL];
341
+ const statusCode = result.status;
342
+ const statusText = attrs[OtelNetworkAttrs.STATUS_TEXT];
343
+ const responseContentLength = attrs[OtelNetworkAttrs.RESPONSE_CONTENT_LENGTH] || 0;
344
+ const duration = hrTimeToMilliseconds(readableSpan.duration);
345
+ const fragments = getUrlFragments(url);
346
+ const errorMessage = result.message;
347
+ const customTraceId = readableSpan.spanContext().traceId;
348
+ const customSpanId = readableSpan.spanContext().spanId;
349
+ const parsed = new URL(url);
350
+ const host = parsed.host; // e.g. "example.com:443"
351
+ const schema = parsed.protocol.replace(":", ""); // e.g. "https"
352
+
353
+ const details = {
354
+ method,
355
+ statusCode,
356
+ url,
357
+ fragments,
358
+ host,
359
+ schema,
360
+ statusText,
361
+ duration,
362
+ responseContentLength,
363
+ errorMessage,
364
+ customTraceId,
365
+ customSpanId
366
+ };
367
+ CoralogixRum.reportNetworkRequest(details);
368
+ };
369
+ super(config);
370
+ }
371
+ enable() {
372
+ super.enable();
373
+ }
374
+ }
375
+
376
+ let CoralogixDomain = /*#__PURE__*/function (CoralogixDomain) {
377
+ CoralogixDomain["EU1"] = "EU1";
378
+ CoralogixDomain["EU2"] = "EU2";
379
+ CoralogixDomain["US1"] = "US1";
380
+ CoralogixDomain["US2"] = "US2";
381
+ CoralogixDomain["AP1"] = "AP1";
382
+ CoralogixDomain["AP2"] = "AP2";
383
+ CoralogixDomain["AP3"] = "AP3";
384
+ CoralogixDomain["STAGING"] = "staging";
385
+ return CoralogixDomain;
386
+ }({});
387
+
388
+ const LINKING_ERROR = `The package 'cx-plugin' doesn't seem to be linked. Make sure: \n\n` + reactNative.Platform.select({
389
+ ios: "- You have run 'pod install'\n",
390
+ default: ''
391
+ }) + '- You rebuilt the app after installing the package\n' + '- You are not using Expo Go\n';
392
+ let beforeSendCallback;
393
+ let _deregisterInstrumentations;
394
+ const CxSdk = reactNative.NativeModules.CxSdk ? reactNative.NativeModules.CxSdk : createErrorProxy(LINKING_ERROR);
395
+ function createErrorProxy(errorMessage) {
396
+ return new Proxy({}, {
397
+ get() {
398
+ throw new Error(errorMessage);
399
+ }
400
+ });
401
+ }
402
+ let isInited = false;
403
+ let fetchInstrumentation;
404
+ const CoralogixRum = {
405
+ get isInited() {
406
+ return isInited;
407
+ },
408
+ init: function (options) {
409
+ var _resolvedOptions$debu;
410
+ if (isInited) {
411
+ console.warn('[Coralogix React Native SDK] - already initialized');
412
+ return;
413
+ }
414
+ const resolvedOptions = resolveCoralogixOtelWebConfig(options);
415
+ logger.shouldLog = (_resolvedOptions$debu = resolvedOptions.debug) != null ? _resolvedOptions$debu : false;
416
+ if (!isSamplingOn(resolvedOptions.sessionSampleRate)) {
417
+ logger.debug('CoralogixRum: Session tracking is disabled');
418
+ return;
419
+ }
420
+ registerCoralogixInstrumentations(resolvedOptions);
421
+ CxSdk.initialize(_extends({}, resolvedOptions, {
422
+ frameworkVersion: pkg.version
423
+ }));
424
+ isInited = true;
425
+ },
426
+ shutdown: () => {
427
+ if (!isInited) {
428
+ return;
429
+ }
430
+ CxSdk.shutdown();
431
+ if (subscription) {
432
+ subscription.remove();
433
+ }
434
+ isInited = false;
435
+ _deregisterInstrumentations == null || _deregisterInstrumentations();
436
+ _deregisterInstrumentations = undefined;
437
+ cleanupResources();
438
+ },
439
+ setApplicationContext: applicationContext => {
440
+ if (!isInited) {
441
+ logger.debug('CoralogixRum must be initiated before setting application context');
442
+ return;
443
+ }
444
+ CxSdk.setApplicationContext(applicationContext);
445
+ },
446
+ setUserContext: userContext => {
447
+ if (!isInited) {
448
+ logger.debug('CoralogixRum must be initiated before setting user context');
449
+ return;
450
+ }
451
+ CxSdk.setUserContext(userContext);
452
+ },
453
+ setViewContext(viewContext) {
454
+ if (!isInited) {
455
+ logger.debug('CoralogixRum must be initiated before setting view context');
456
+ return;
457
+ }
458
+ CxSdk.setViewContext(viewContext.view);
459
+ },
460
+ getUserContext: async () => {
461
+ if (!isInited) {
462
+ logger.debug('CoralogixRum must be initiated before getting user context');
463
+ return undefined;
464
+ }
465
+ const result = await CxSdk.getUserContext();
466
+ if (!result || typeof result !== 'object') {
467
+ return undefined;
468
+ }
469
+ return {
470
+ user_id: result.user_id || '',
471
+ user_name: result.user_name || '',
472
+ user_email: result.user_email || '',
473
+ user_metadata: result.user_metadata || {}
474
+ };
475
+ },
476
+ setLabels: labels => {
477
+ if (!isInited) {
478
+ logger.debug('CoralogixRum must be initiated before setting labels');
479
+ return;
480
+ }
481
+ CxSdk.setLabels(labels);
482
+ },
483
+ getLabels: async () => {
484
+ if (!isInited) {
485
+ logger.debug('CoralogixRum must be initiated before getting labels');
486
+ return {};
487
+ }
488
+ return await CxSdk.getLabels();
489
+ },
490
+ getSessionId: async () => {
491
+ if (!isInited) {
492
+ logger.debug('CoralogixRum must be initiated before getting session id');
493
+ return '';
494
+ }
495
+ return CxSdk.getSessionId();
496
+ },
497
+ log: (severity, message, data) => {
498
+ if (!isInited) {
499
+ logger.debug('CoralogixRum must be initiated before using log');
500
+ return;
501
+ }
502
+ CxSdk.log(severity, message, data != null ? data : {});
503
+ },
504
+ debug(message, data) {
505
+ this.log(CoralogixLogSeverity.Debug, message, data);
506
+ },
507
+ verbose(message, data) {
508
+ this.log(CoralogixLogSeverity.Verbose, message, data);
509
+ },
510
+ info(message, data) {
511
+ this.log(CoralogixLogSeverity.Info, message, data);
512
+ },
513
+ warn(message, data) {
514
+ this.log(CoralogixLogSeverity.Warn, message, data);
515
+ },
516
+ error(message, data) {
517
+ this.log(CoralogixLogSeverity.Error, message, data);
518
+ },
519
+ critical(message, data) {
520
+ this.log(CoralogixLogSeverity.Critical, message, data);
521
+ },
522
+ reportNetworkRequest: details => {
523
+ CxSdk.reportNetworkRequest(details);
524
+ },
525
+ sendCustomMeasurement: measurement => {
526
+ if (!isInited) {
527
+ logger.debug('CoralogixRum must be initiated before sending custom measurements');
528
+ return;
529
+ }
530
+ CxSdk.sendCustomMeasurement(measurement);
531
+ },
532
+ reportError: (error, isCrash) => {
533
+ if (!isInited) {
534
+ logger.debug('CoralogixRum must be initiated before error reporting');
535
+ return;
536
+ }
537
+ const errorDetails = {
538
+ error_type: error.name,
539
+ error_message: error.message,
540
+ stack_trace: parseErrorStack(error),
541
+ is_crash: isCrash
542
+ };
543
+ CxSdk.reportError(errorDetails);
544
+ }
545
+ };
546
+ function trackMobileVitals(options) {
547
+ startJsRefreshRateSampler(_extends({}, options.jsRefreshRateSampleRate, {
548
+ onSample: jsRefreshRate => {
549
+ CxSdk.reportMobileVitalsMeasurement('js_refresh_rate', Math.round(jsRefreshRate), 'fps');
550
+ }
551
+ }));
552
+
553
+ // startJSLoopDetector({
554
+ // ...options.jsLoopDetection,
555
+ // onFrameDrop: (event) => {
556
+ // CxSdk.reportMobileVitalsMeasurementSet('js_loop', [
557
+ // {
558
+ // name: 'stall',
559
+ // value: event.stall,
560
+ // units: 'ms',
561
+ // },
562
+ // {
563
+ // name: 'delta',
564
+ // value: event.delta,
565
+ // units: 'ms',
566
+ // },
567
+ // ]);
568
+ // },
569
+ // onError: (error) => {
570
+ // logger.debug('[JSLoopDetector] Error:', { error });
571
+ // },
572
+ // });
573
+ }
574
+ function cleanupResources() {
575
+ stopJsRefreshRateSampler();
576
+ // stopJSLoopDetector();
577
+ }
578
+ function registerCoralogixInstrumentations(options) {
579
+ if (options.beforeSend) {
580
+ beforeSendCallback = options.beforeSend;
581
+ }
582
+ const tracerProvider = new sdkTraceWeb.WebTracerProvider();
583
+ const instrumentations = [];
584
+ const instrumentationsOptions = options.instrumentations;
585
+
586
+ // disable network for ios, since swizzle will capture the fetch requests
587
+ const shouldInterceptNetowrk = reactNative.Platform.OS === 'android' && (!instrumentationsOptions || instrumentationsOptions.network !== false);
588
+ const shouldInterceptErrors = !instrumentationsOptions || instrumentationsOptions.errors !== false;
589
+ const shouldInterceptMobileVitals = !instrumentationsOptions || instrumentationsOptions.mobile_vitals !== false;
590
+
591
+ // Fetch instrumentation
592
+ if (shouldInterceptNetowrk) {
593
+ fetchInstrumentation = new CoralogixFetchInstrumentation(options);
594
+ instrumentations.push(fetchInstrumentation);
595
+ }
596
+
597
+ // Errors instrumentation
598
+ if (shouldInterceptErrors) {
599
+ const errorInstrumentation = new CoralogixErrorInstrumentation(options);
600
+ instrumentations.push(errorInstrumentation);
601
+ }
602
+
603
+ // Mobile vitals instrumentation
604
+ if (shouldInterceptMobileVitals) {
605
+ trackMobileVitals(options);
606
+ }
607
+
608
+ // Register Instrumentations
609
+ _deregisterInstrumentations = instrumentation.registerInstrumentations({
610
+ tracerProvider,
611
+ instrumentations
612
+ });
613
+ }
614
+ const parseErrorStack = error => {
615
+ if (!error.stack) {
616
+ return [];
617
+ }
618
+ const stackLines = error.stack.split('\n').slice(1); // Ignore the first line (error message)
619
+ return stackLines.map(line => {
620
+ const match = line.match(/\s*at\s+(.*)\s+\((.*):(\d+):(\d+)\)/) ||
621
+ // Matches function name, file, line, column
622
+ line.match(/\s*at\s+(.*):(\d+):(\d+)/); // Matches anonymous function calls
623
+
624
+ if (match) {
625
+ var _match$, _match$2;
626
+ return {
627
+ functionName: match[1] || '<anonymous>',
628
+ fileName: match[2],
629
+ lineNumber: parseInt((_match$ = match[3]) != null ? _match$ : '-1', 10),
630
+ columnNumber: parseInt((_match$2 = match[4]) != null ? _match$2 : '-1', 10)
631
+ };
632
+ }
633
+ return null;
634
+ }).filter(frame => frame !== null);
635
+ };
636
+
637
+ // Create event emitter
638
+ const eventEmitter = new reactNative.NativeEventEmitter(CxSdk);
639
+
640
+ // Subscribe to beforeSend events
641
+ const subscription = eventEmitter.addListener('onBeforeSend', events => {
642
+ // logger.log("📨 onBeforeSend triggered with events: ", events)
643
+ // events is an array of events [[String: Any]]
644
+ // Skip processing if SDK is not initialized or events is empty
645
+ if (!CoralogixRum.isInited || !events || !Array.isArray(events)) {
646
+ logger.debug('⚠️ Skipping event processing - SDK not initialized or events invalid');
647
+ return;
648
+ }
649
+ logger.debug('🔄 Processing events with beforeSendCallback');
650
+ // Process event with beforeSendCallback if available
651
+ if (beforeSendCallback) {
652
+ try {
653
+ // Process each event in the array
654
+ const results = [];
655
+ for (const fullEvent of events) {
656
+ const event = fullEvent.text.cx_rum;
657
+ const res = beforeSendCallback(event);
658
+ if (!res) {
659
+ continue;
660
+ }
661
+ // Merge the result from each event
662
+ const mergeEvent = _extends({}, fullEvent, {
663
+ text: _extends({}, fullEvent.text, {
664
+ cx_rum: _extends({}, fullEvent.text.cx_rum, res)
665
+ })
666
+ });
667
+ results.push(mergeEvent);
668
+ }
669
+ if (results.length) {
670
+ CxSdk.sendCxSpanData(results);
671
+ }
672
+ } catch (error) {
673
+ logger.debug('❌ Error in beforeSend callback:', error);
674
+ }
675
+ } else {
676
+ logger.debug('⚠️ No beforeSendCallback available');
677
+ }
678
+ });
679
+
680
+ exports.CoralogixDomain = CoralogixDomain;
681
+ exports.CoralogixLogSeverity = CoralogixLogSeverity;
682
+ exports.CoralogixRum = CoralogixRum;
package/index.d.ts ADDED
@@ -0,0 +1 @@
1
+ export * from "./src/index";