@coralogix/react-native-plugin 0.7.1 → 0.7.2

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/CHANGELOG.md CHANGED
@@ -1,3 +1,10 @@
1
+ ## 0.7.2 (2026-07-20)
2
+
3
+ ### 🩹 Fixes
4
+
5
+ - drain every beforeSend delivery during the fatal flush
6
+ - flush crash events before fatal-error handover
7
+
1
8
  ## 0.7.1 (2026-07-09)
2
9
 
3
10
  ### 🩹 Fixes
package/CxSdk.podspec CHANGED
@@ -16,9 +16,9 @@ Pod::Spec.new do |s|
16
16
 
17
17
  s.source_files = "ios/**/*.{h,m,mm,swift}"
18
18
 
19
- s.dependency 'Coralogix','2.10.0'
20
- s.dependency 'CoralogixInternal','2.10.0'
21
- s.dependency 'SessionReplay','2.10.0'
19
+ s.dependency 'Coralogix','2.11.1'
20
+ s.dependency 'CoralogixInternal','2.11.1'
21
+ s.dependency 'SessionReplay','2.11.1'
22
22
 
23
23
  # Use install_modules_dependencies helper to install the dependencies if React Native version >=0.71.0.
24
24
  # See https://github.com/facebook/react-native/blob/febf6b7f33fdb4904669f99d795eba4c0f95d7bf/scripts/cocoapods/new_architecture.rb#L79.
@@ -84,7 +84,7 @@ dependencies {
84
84
  implementation "com.facebook.react:react-android"
85
85
  implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"
86
86
 
87
- implementation "com.coralogix:android-sdk:2.17.1"
87
+ implementation "com.coralogix:android-sdk:2.18.0"
88
88
 
89
89
  testImplementation "org.jetbrains.kotlin:kotlin-test:$kotlin_version"
90
90
  testImplementation "org.mockito:mockito-core:5.12.0"
@@ -193,6 +193,15 @@ class CxSdkModule(reactContext: ReactApplicationContext) :
193
193
  )
194
194
  }
195
195
 
196
+ @ReactMethod
197
+ override fun flushSpans(promise: Promise) {
198
+ // Force-flushes the batch processor and resolves once the export/upload
199
+ // attempt finishes — the same contract as iOS. Called by the JS fatal-error
200
+ // handler before it hands over to the framework's default handler, which
201
+ // terminates the process.
202
+ CoralogixRum.flush { promise.resolve("flushSpans success") }
203
+ }
204
+
196
205
  @ReactMethod
197
206
  override fun sendCxSpanData(results: ReadableArray) {
198
207
  val data = convertStrictReadableArrayToListOfMaps(results)
@@ -19,6 +19,7 @@ interface RUMClient {
19
19
  fun startTimeMeasure(name: String, labels: ReadableMap?)
20
20
  fun endTimeMeasure(name: String)
21
21
  fun reportError(details: ReadableMap)
22
+ fun flushSpans(promise: Promise)
22
23
  fun sendCxSpanData(results: ReadableArray)
23
24
  fun reportMobileVitalsMeasurement(type: String, value: Double, units: String)
24
25
  fun reportMobileVitalsMeasurementSet(type: String, metrics: ReadableArray)
package/index.cjs.js CHANGED
@@ -130,10 +130,17 @@ class CoralogixErrorInstrumentation extends instrumentation.InstrumentationBase
130
130
  const defaultHandler = ErrorUtils.getGlobalHandler();
131
131
  ErrorUtils.setGlobalHandler((error, isFatal) => {
132
132
  this.report(error, isFatal);
133
- if (defaultHandler) {
134
- setTimeout(() => {
135
- defaultHandler(error, isFatal);
136
- }, 2500);
133
+ if (!defaultHandler) {
134
+ return;
135
+ }
136
+ if (isFatal) {
137
+ // In release builds the default handler terminates the app (RCTFatal),
138
+ // killing any crash event still queued in the native batch processor —
139
+ // flush it out first. waitForFatalErrorFlush never rejects and is
140
+ // time-capped, so the handover is guaranteed.
141
+ waitForFatalErrorFlush().catch(() => undefined).finally(() => defaultHandler(error, isFatal));
142
+ } else {
143
+ defaultHandler(error, isFatal);
137
144
  }
138
145
  });
139
146
  this.listenToConsoleError();
@@ -537,7 +544,7 @@ function stopJsRefreshRateSampler() {
537
544
  appStateSub = null;
538
545
  }
539
546
 
540
- var version = "0.7.1";
547
+ var version = "0.7.2";
541
548
  var pkg = {
542
549
  version: version};
543
550
 
@@ -1389,6 +1396,23 @@ const parseErrorStack = error => {
1389
1396
  return null;
1390
1397
  }).filter(frame => frame !== null);
1391
1398
  };
1399
+ const FATAL_FLUSH_MAX_WAIT_MS = 2500;
1400
+ const delay = ms => new Promise(resolve => setTimeout(resolve, ms));
1401
+
1402
+ /**
1403
+ * Best-effort delivery of a crash before a fatal error is handed back to RN's
1404
+ * default handler, which terminates the app in release builds. `flushSpans`
1405
+ * force-flushes the native batch processor; the native SDK uploads crash events
1406
+ * directly (bypassing the beforeSend round trip) and resolves once the upload
1407
+ * attempt finishes, so awaiting it is the full crash-delivery guarantee.
1408
+ * Never rejects; resolves within FATAL_FLUSH_MAX_WAIT_MS.
1409
+ *
1410
+ * @internal Used by the error instrumentation — not part of the public API.
1411
+ */
1412
+ const waitForFatalErrorFlush = async () => {
1413
+ const flush = Promise.resolve(CxSdk.flushSpans()).catch(e => logger.debug('flushSpans failed:', e));
1414
+ await Promise.race([flush, delay(FATAL_FLUSH_MAX_WAIT_MS)]);
1415
+ };
1392
1416
 
1393
1417
  // Create event emitter
1394
1418
  const eventEmitter = new reactNative.NativeEventEmitter(CxSdk);
@@ -1445,3 +1469,4 @@ exports.CxSdk = CxSdk;
1445
1469
  exports.SessionReplay = SessionReplay;
1446
1470
  exports.attachReactNavigationObserver = attachReactNavigationObserver;
1447
1471
  exports.parseErrorStack = parseErrorStack;
1472
+ exports.waitForFatalErrorFlush = waitForFatalErrorFlush;
package/index.esm.js CHANGED
@@ -128,10 +128,17 @@ class CoralogixErrorInstrumentation extends InstrumentationBase {
128
128
  const defaultHandler = ErrorUtils.getGlobalHandler();
129
129
  ErrorUtils.setGlobalHandler((error, isFatal) => {
130
130
  this.report(error, isFatal);
131
- if (defaultHandler) {
132
- setTimeout(() => {
133
- defaultHandler(error, isFatal);
134
- }, 2500);
131
+ if (!defaultHandler) {
132
+ return;
133
+ }
134
+ if (isFatal) {
135
+ // In release builds the default handler terminates the app (RCTFatal),
136
+ // killing any crash event still queued in the native batch processor —
137
+ // flush it out first. waitForFatalErrorFlush never rejects and is
138
+ // time-capped, so the handover is guaranteed.
139
+ waitForFatalErrorFlush().catch(() => undefined).finally(() => defaultHandler(error, isFatal));
140
+ } else {
141
+ defaultHandler(error, isFatal);
135
142
  }
136
143
  });
137
144
  this.listenToConsoleError();
@@ -535,7 +542,7 @@ function stopJsRefreshRateSampler() {
535
542
  appStateSub = null;
536
543
  }
537
544
 
538
- var version = "0.7.1";
545
+ var version = "0.7.2";
539
546
  var pkg = {
540
547
  version: version};
541
548
 
@@ -1387,6 +1394,23 @@ const parseErrorStack = error => {
1387
1394
  return null;
1388
1395
  }).filter(frame => frame !== null);
1389
1396
  };
1397
+ const FATAL_FLUSH_MAX_WAIT_MS = 2500;
1398
+ const delay = ms => new Promise(resolve => setTimeout(resolve, ms));
1399
+
1400
+ /**
1401
+ * Best-effort delivery of a crash before a fatal error is handed back to RN's
1402
+ * default handler, which terminates the app in release builds. `flushSpans`
1403
+ * force-flushes the native batch processor; the native SDK uploads crash events
1404
+ * directly (bypassing the beforeSend round trip) and resolves once the upload
1405
+ * attempt finishes, so awaiting it is the full crash-delivery guarantee.
1406
+ * Never rejects; resolves within FATAL_FLUSH_MAX_WAIT_MS.
1407
+ *
1408
+ * @internal Used by the error instrumentation — not part of the public API.
1409
+ */
1410
+ const waitForFatalErrorFlush = async () => {
1411
+ const flush = Promise.resolve(CxSdk.flushSpans()).catch(e => logger.debug('flushSpans failed:', e));
1412
+ await Promise.race([flush, delay(FATAL_FLUSH_MAX_WAIT_MS)]);
1413
+ };
1390
1414
 
1391
1415
  // Create event emitter
1392
1416
  const eventEmitter = new NativeEventEmitter(CxSdk);
@@ -1433,4 +1457,4 @@ const subscription = eventEmitter.addListener('onBeforeSend', events => {
1433
1457
  }
1434
1458
  });
1435
1459
 
1436
- export { CoralogixCustomSpan, CoralogixCustomTracer, CoralogixDomain, CoralogixGlobalSpan, CoralogixLogSeverity, CoralogixRum, CxSdk, SessionReplay, attachReactNavigationObserver, parseErrorStack };
1460
+ export { CoralogixCustomSpan, CoralogixCustomTracer, CoralogixDomain, CoralogixGlobalSpan, CoralogixLogSeverity, CoralogixRum, CxSdk, SessionReplay, attachReactNavigationObserver, parseErrorStack, waitForFatalErrorFlush };
package/ios/CxSdk.mm CHANGED
@@ -64,6 +64,9 @@ RCT_EXTERN_METHOD(reportNetworkRequest:(NSDictionary *)networkRequestDictionary
64
64
  withResolver:(RCTPromiseResolveBlock)resolve
65
65
  withRejecter:(RCTPromiseRejectBlock)reject)
66
66
 
67
+ RCT_EXTERN_METHOD(flushSpans:(RCTPromiseResolveBlock)resolve
68
+ withRejecter:(RCTPromiseRejectBlock)reject)
69
+
67
70
  RCT_EXTERN_METHOD(sendCxSpanData:(NSArray *)beforeSendResults
68
71
  withResolver:(RCTPromiseResolveBlock)resolve
69
72
  withRejecter:(RCTPromiseRejectBlock)reject)
package/ios/CxSdk.swift CHANGED
@@ -249,6 +249,24 @@ class CxSdk: RCTEventEmitter {
249
249
  resolve("reportError success")
250
250
  }
251
251
 
252
+ @objc(flushSpans:withRejecter:)
253
+ func flushSpans(resolve: @escaping RCTPromiseResolveBlock,
254
+ reject: @escaping RCTPromiseRejectBlock) -> Void {
255
+ // Force-flushes the batch processor and resolves once the export/upload
256
+ // attempt finishes — the same public SDK API the Android bridge calls.
257
+ // Invoked by the JS fatal-error handler before it hands over to RN's default
258
+ // handler, which terminates the process in release builds. `flush` handles
259
+ // its own threading and always invokes completion (immediately when the SDK
260
+ // is not initialized), so callers never hang.
261
+ guard let coralogixRum else {
262
+ resolve("flushSpans success")
263
+ return
264
+ }
265
+ coralogixRum.flush {
266
+ resolve("flushSpans success")
267
+ }
268
+ }
269
+
252
270
  @objc(sendCxSpanData:withResolver:withRejecter:)
253
271
  func sendCxSpanData(beforeSendResults: NSArray,
254
272
  resolve:RCTPromiseResolveBlock,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@coralogix/react-native-plugin",
3
- "version": "0.7.1",
3
+ "version": "0.7.2",
4
4
  "description": "Official Coralogix React Native plugin",
5
5
  "license": "Apache-2.0",
6
6
  "author": "Coralogix",
package/src/index.d.ts CHANGED
@@ -25,6 +25,14 @@ interface CxSdkClient {
25
25
  endTimeMeasure(name: string): void;
26
26
  reportError(details: Record<string, unknown>): void;
27
27
  reportNetworkRequest(details: NetworkRequestDetails): void;
28
+ /**
29
+ * Forces immediate export of natively queued telemetry. iOS drains the batch
30
+ * processor and resolves after the upload attempt; Android resolves
31
+ * immediately WITHOUT flushing (the native SDK exposes no flush API yet), so
32
+ * a resolved promise must not be read as delivery there — see
33
+ * waitForFatalErrorFlush for the Android fallback.
34
+ */
35
+ flushSpans(): Promise<string>;
28
36
  shutdown(): Promise<boolean>;
29
37
  createNewSession(): Promise<boolean>;
30
38
  sendCxSpanData(results: CxSpan[]): void;
@@ -56,6 +64,17 @@ export declare const CxSdk: CxSdkClient;
56
64
  export declare const CoralogixRum: CoralogixOtelWebType;
57
65
  export declare const SessionReplay: SessionReplayType;
58
66
  export declare const parseErrorStack: (error: Error) => CoralogixStackFrame[];
67
+ /**
68
+ * Best-effort delivery of a crash before a fatal error is handed back to RN's
69
+ * default handler, which terminates the app in release builds. `flushSpans`
70
+ * force-flushes the native batch processor; the native SDK uploads crash events
71
+ * directly (bypassing the beforeSend round trip) and resolves once the upload
72
+ * attempt finishes, so awaiting it is the full crash-delivery guarantee.
73
+ * Never rejects; resolves within FATAL_FLUSH_MAX_WAIT_MS.
74
+ *
75
+ * @internal Used by the error instrumentation — not part of the public API.
76
+ */
77
+ export declare const waitForFatalErrorFlush: () => Promise<void>;
59
78
  export { type ApplicationContextConfig } from './model/ApplicationContextConfig';
60
79
  export { type ViewContextConfig } from './model/ViewContextConfig';
61
80
  export { CoralogixDomain } from './model/CoralogixDomain';