@logbrew/react-native 0.1.26 → 0.1.28

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.
@@ -19,13 +19,13 @@ final class AndroidDiagnosticsRuntime implements Thread.UncaughtExceptionHandler
19
19
  private final AndroidNativeDiagnostics diagnostics;
20
20
  private final Thread.UncaughtExceptionHandler previousHandler;
21
21
  private final AndroidNativeDiagnostics.Configuration configuration;
22
- private final String signalRecordPath;
23
22
 
24
23
  AndroidDiagnosticsRuntime(
25
24
  Context context,
26
25
  File storageRoot,
27
26
  EventRecordStore eventStore,
28
- AndroidNativeDiagnostics.Configuration configuration) {
27
+ AndroidNativeDiagnostics.Configuration configuration,
28
+ Runnable afterPersist) {
29
29
  this.configuration = configuration;
30
30
  previousHandler = Thread.getDefaultUncaughtExceptionHandler();
31
31
  MainThreadScheduler scheduler = new MainThreadScheduler(context);
@@ -37,10 +37,9 @@ final class AndroidDiagnosticsRuntime implements Thread.UncaughtExceptionHandler
37
37
  signalStore,
38
38
  configuration,
39
39
  scheduler,
40
- () -> {},
40
+ afterPersist,
41
41
  this::chain,
42
42
  scheduler.mainThread::getStackTrace);
43
- signalRecordPath = signalStore.path();
44
43
  }
45
44
 
46
45
  synchronized String install() {
@@ -55,7 +54,7 @@ final class AndroidDiagnosticsRuntime implements Thread.UncaughtExceptionHandler
55
54
  if (!diagnostics.signalStore.prepare(new AndroidParentDirectorySync())
56
55
  || !SIGNAL_CAPTURE_AVAILABLE
57
56
  || !nativeInstall(
58
- signalRecordPath,
57
+ diagnostics.signalStore.path(),
59
58
  diagnostics.nextNativeEventId(),
60
59
  configuration.projectId,
61
60
  configuration.release,
@@ -154,7 +153,6 @@ final class AndroidDiagnosticsRuntime implements Thread.UncaughtExceptionHandler
154
153
  thread.setDaemon(true);
155
154
  return thread;
156
155
  });
157
- long intervalMs = Math.max(500, thresholdMs / 2);
158
156
  executor.scheduleWithFixedDelay(
159
157
  () -> {
160
158
  long now = SystemClock.elapsedRealtime();
@@ -169,7 +167,7 @@ final class AndroidDiagnosticsRuntime implements Thread.UncaughtExceptionHandler
169
167
  mainHandler.post(this::heartbeat);
170
168
  },
171
169
  thresholdMs,
172
- intervalMs,
170
+ AndroidNativeDiagnostics.WATCHDOG_POLL_MS,
173
171
  TimeUnit.MILLISECONDS);
174
172
  }
175
173
 
@@ -90,6 +90,7 @@ final class AndroidNativeDiagnostics {
90
90
  }
91
91
 
92
92
  private static final int MAX_FRAMES = 32;
93
+ static final long WATCHDOG_POLL_MS = 500;
93
94
  private static final AtomicLong SEQUENCE = new AtomicLong();
94
95
 
95
96
  final EventRecordStore eventStore;
@@ -7,6 +7,7 @@ import com.facebook.react.bridge.ReadableMapKeySetIterator;
7
7
  import com.facebook.react.bridge.ReadableType;
8
8
  import com.facebook.react.bridge.WritableArray;
9
9
  import com.facebook.react.bridge.WritableMap;
10
+ import com.facebook.react.modules.core.DeviceEventManagerModule;
10
11
  import java.io.File;
11
12
  import java.nio.charset.StandardCharsets;
12
13
  import java.security.MessageDigest;
@@ -137,7 +138,8 @@ final class FatalStoreModuleImpl {
137
138
  try {
138
139
  androidDiagnostics =
139
140
  new AndroidDiagnosticsRuntime(
140
- context, storageRoot, eventStore, configuration.configuration);
141
+ context, storageRoot, eventStore, configuration.configuration,
142
+ this::notifyDiagnosticPersisted);
141
143
  String statusValue = androidDiagnostics.install();
142
144
  return androidDiagnosticsResult(statusValue);
143
145
  } catch (RuntimeException error) {
@@ -146,6 +148,13 @@ final class FatalStoreModuleImpl {
146
148
  }
147
149
  }
148
150
 
151
+ private void notifyDiagnosticPersisted() {
152
+ try {
153
+ context.getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter.class)
154
+ .emit("logbrewAndroidDiagnosticPersisted", null);
155
+ } catch (RuntimeException ignored) {}
156
+ }
157
+
149
158
  synchronized WritableMap androidDiagnosticsStatus() {
150
159
  if (androidDiagnostics == null || !androidDiagnostics.installed()) {
151
160
  return androidDiagnosticsReceipt("not_installed", 0);
package/index.cjs CHANGED
@@ -16,7 +16,7 @@ const {
16
16
  } = require("./metadata.cjs");
17
17
 
18
18
  const DEFAULT_SDK_NAME = "logbrew-react-native";
19
- const DEFAULT_SDK_VERSION = "0.1.26";
19
+ const DEFAULT_SDK_VERSION = "0.1.28";
20
20
  const DEFAULT_ENDPOINT = "https://api.logbrew.co/v1/events";
21
21
  const NATIVE_RANDOM_HEX = Symbol.for("co.logbrew.react-native.secure-random-hex");
22
22
  const MAX_ACTION_NAME_LENGTH = 64;
package/index.native.js CHANGED
@@ -1,4 +1,4 @@
1
- import { AppState, NativeModules, Platform, TurboModuleRegistry } from "react-native";
1
+ import { AppState, DeviceEventEmitter, NativeModules, Platform, TurboModuleRegistry } from "react-native";
2
2
  import {
3
3
  captureAppStateChange,
4
4
  captureReactNativeAction,
@@ -91,13 +91,28 @@ export function createLogBrewReactNativeClient(config = {}) {
91
91
  if (resolved.durable) {
92
92
  Object.defineProperty(client, DURABLE_QUEUE, { value: true });
93
93
  }
94
- return bindAppleNativeCrashBreadcrumbs(client);
94
+ return bindAndroidNativeDelivery(bindAppleNativeCrashBreadcrumbs(client), resolved.durable);
95
95
  } catch (error) {
96
96
  resolved.abort();
97
97
  throw error;
98
98
  }
99
99
  }
100
100
 
101
+ function bindAndroidNativeDelivery(client, durable) {
102
+ if (!durable || Platform?.OS !== "android" || typeof DeviceEventEmitter?.addListener !== "function") {
103
+ return client;
104
+ }
105
+ const subscription = DeviceEventEmitter.addListener(
106
+ "logbrewAndroidDiagnosticPersisted", () => void client.flush().catch(() => {})
107
+ );
108
+ const shutdown = client.shutdown.bind(client);
109
+ client.shutdown = (...args) => shutdown(...args).then((result) => {
110
+ subscription?.remove?.();
111
+ return result;
112
+ });
113
+ return client;
114
+ }
115
+
101
116
  function bindAppleNativeCrashBreadcrumbs(client) {
102
117
  if (Platform?.OS !== "ios") {
103
118
  return client;
@@ -3,7 +3,7 @@ import Foundation
3
3
  @objc(LBRNAppleNativeDiagnostics)
4
4
  public final class LBRNAppleNativeDiagnostics: NSObject, @unchecked Sendable {
5
5
  private static let shared = LBRNAppleNativeDiagnostics()
6
- private static let sdkVersion = "0.1.26"
6
+ private static let sdkVersion = "0.1.28"
7
7
 
8
8
  private let lock = NSLock()
9
9
  private let replayQueue = DispatchQueue(label: "co.logbrew.react-native.apple-diagnostics-replay")
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@logbrew/react-native",
3
- "version": "0.1.26",
3
+ "version": "0.1.28",
4
4
  "description": "React Native offline delivery, native diagnostics, screen, error, trace, action, and network timeline helpers for LogBrew.",
5
5
  "type": "module",
6
6
  "main": "./index.cjs",