@logbrew/react-native 0.1.9 → 0.1.11

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.
@@ -9,10 +9,15 @@ import com.facebook.react.bridge.ReadableType;
9
9
  import com.facebook.react.bridge.WritableArray;
10
10
  import com.facebook.react.bridge.WritableMap;
11
11
  import java.io.File;
12
+ import java.nio.charset.StandardCharsets;
13
+ import java.security.MessageDigest;
14
+ import java.security.NoSuchAlgorithmException;
12
15
  import java.util.ArrayList;
13
16
  import java.util.Arrays;
17
+ import java.util.HashMap;
14
18
  import java.util.HashSet;
15
19
  import java.util.List;
20
+ import java.util.Map;
16
21
  import java.util.Set;
17
22
 
18
23
  final class FatalStoreModuleImpl {
@@ -32,9 +37,12 @@ final class FatalStoreModuleImpl {
32
37
  new HashSet<>(Arrays.asList("filename", "line", "column"));
33
38
 
34
39
  private final FatalRecordStore store;
40
+ private final File eventStoreParent;
41
+ private final Map<String, EventRecordStore> eventStores = new HashMap<>();
35
42
 
36
43
  FatalStoreModuleImpl(ReactApplicationContext context) {
37
44
  File root = context.getNoBackupFilesDir();
45
+ eventStoreParent = root;
38
46
  store =
39
47
  root == null
40
48
  ? null
@@ -43,6 +51,66 @@ final class FatalStoreModuleImpl {
43
51
  new AndroidParentDirectorySync());
44
52
  }
45
53
 
54
+ WritableMap loadEventRecords(String queueKey) {
55
+ try {
56
+ EventRecordStore eventStore = eventStore(queueKey);
57
+ return eventStore == null ? status("storage_error") : eventResultMap(eventStore.load());
58
+ } catch (RuntimeException error) {
59
+ return status("storage_error");
60
+ }
61
+ }
62
+
63
+ WritableMap appendEventRecord(String queueKey, String serializedEvent, double eventBytes) {
64
+ try {
65
+ EventRecordStore eventStore = eventStore(queueKey);
66
+ Integer byteCount = integer(eventBytes);
67
+ return eventStore == null || byteCount == null
68
+ ? status("storage_error")
69
+ : eventResultMap(eventStore.append(serializedEvent, byteCount));
70
+ } catch (RuntimeException error) {
71
+ return status("storage_error");
72
+ }
73
+ }
74
+
75
+ WritableMap acknowledgeEventRecords(String queueKey, double count) {
76
+ try {
77
+ EventRecordStore eventStore = eventStore(queueKey);
78
+ Integer recordCount = integer(count);
79
+ return eventStore == null || recordCount == null
80
+ ? status("storage_error")
81
+ : eventResultMap(eventStore.acknowledge(recordCount));
82
+ } catch (RuntimeException error) {
83
+ return status("storage_error");
84
+ }
85
+ }
86
+
87
+ WritableMap purgeEventRecords(String queueKey) {
88
+ try {
89
+ EventRecordStore eventStore = eventStore(queueKey);
90
+ return eventStore == null ? status("storage_error") : eventResultMap(eventStore.purge());
91
+ } catch (RuntimeException error) {
92
+ return status("storage_error");
93
+ }
94
+ }
95
+
96
+ synchronized WritableMap closeEventStore(String queueKey) {
97
+ String queueHash = queueHash(queueKey);
98
+ if (queueHash == null) {
99
+ return status("storage_error");
100
+ }
101
+ EventRecordStore eventStore = eventStores.get(queueHash);
102
+ if (eventStore == null) {
103
+ return status("closed");
104
+ }
105
+ try {
106
+ return eventResultMap(eventStore.close());
107
+ } catch (RuntimeException error) {
108
+ return status("storage_error");
109
+ } finally {
110
+ eventStores.remove(queueHash);
111
+ }
112
+ }
113
+
46
114
  WritableMap writeFatalRecord(ReadableMap input) {
47
115
  if (store == null) {
48
116
  return status("storage_error");
@@ -227,4 +295,65 @@ final class FatalStoreModuleImpl {
227
295
  output.putString("status", value);
228
296
  return output;
229
297
  }
298
+
299
+ private synchronized EventRecordStore eventStore(String queueKey) {
300
+ String queueHash = queueHash(queueKey);
301
+ if (eventStoreParent == null || queueHash == null) {
302
+ return null;
303
+ }
304
+ EventRecordStore existing = eventStores.get(queueHash);
305
+ if (existing != null) {
306
+ return existing;
307
+ }
308
+ EventRecordStore created =
309
+ new EventRecordStore(
310
+ new File(eventStoreParent, "logbrew-events-v1-" + queueHash),
311
+ new AndroidParentDirectorySync());
312
+ eventStores.put(queueHash, created);
313
+ return created;
314
+ }
315
+
316
+ private static String queueHash(String queueKey) {
317
+ if (queueKey == null || queueKey.trim().isEmpty()) {
318
+ return null;
319
+ }
320
+ byte[] keyBytes = queueKey.getBytes(StandardCharsets.UTF_8);
321
+ if (keyBytes.length == 0 || keyBytes.length > 4096) {
322
+ return null;
323
+ }
324
+ try {
325
+ byte[] digest = MessageDigest.getInstance("SHA-256").digest(keyBytes);
326
+ StringBuilder value = new StringBuilder(digest.length * 2);
327
+ for (byte item : digest) {
328
+ value.append(String.format(java.util.Locale.ROOT, "%02x", item & 0xff));
329
+ }
330
+ return value.toString();
331
+ } catch (NoSuchAlgorithmException impossible) {
332
+ return null;
333
+ }
334
+ }
335
+
336
+ private static Integer integer(double value) {
337
+ return Double.isFinite(value)
338
+ && value >= 0
339
+ && value <= Integer.MAX_VALUE
340
+ && value == Math.rint(value)
341
+ ? (int) value
342
+ : null;
343
+ }
344
+
345
+ private static WritableMap eventResultMap(EventRecordStore.Result result) {
346
+ WritableMap output = status(result.status);
347
+ if ("loaded".equals(result.status)) {
348
+ WritableArray records = Arguments.createArray();
349
+ for (EventRecordStore.Record record : result.records) {
350
+ WritableMap value = Arguments.createMap();
351
+ value.putString("serializedEvent", record.serializedEvent);
352
+ value.putInt("eventBytes", record.eventBytes);
353
+ records.pushMap(value);
354
+ }
355
+ output.putArray("records", records);
356
+ }
357
+ return output;
358
+ }
230
359
  }
@@ -36,4 +36,30 @@ final class FatalStoreModule extends NativeLogBrewFatalStoreSpec {
36
36
  public WritableMap discardFatalRecord() {
37
37
  return implementation.discardFatalRecord();
38
38
  }
39
+
40
+ @Override
41
+ public WritableMap loadEventRecords(String queueKey) {
42
+ return implementation.loadEventRecords(queueKey);
43
+ }
44
+
45
+ @Override
46
+ public WritableMap appendEventRecord(
47
+ String queueKey, String serializedEvent, double eventBytes) {
48
+ return implementation.appendEventRecord(queueKey, serializedEvent, eventBytes);
49
+ }
50
+
51
+ @Override
52
+ public WritableMap acknowledgeEventRecords(String queueKey, double count) {
53
+ return implementation.acknowledgeEventRecords(queueKey, count);
54
+ }
55
+
56
+ @Override
57
+ public WritableMap purgeEventRecords(String queueKey) {
58
+ return implementation.purgeEventRecords(queueKey);
59
+ }
60
+
61
+ @Override
62
+ public WritableMap closeEventStore(String queueKey) {
63
+ return implementation.closeEventStore(queueKey);
64
+ }
39
65
  }
@@ -38,4 +38,30 @@ final class FatalStoreModule extends ReactContextBaseJavaModule {
38
38
  public WritableMap discardFatalRecord() {
39
39
  return implementation.discardFatalRecord();
40
40
  }
41
+
42
+ @ReactMethod(isBlockingSynchronousMethod = true)
43
+ public WritableMap loadEventRecords(String queueKey) {
44
+ return implementation.loadEventRecords(queueKey);
45
+ }
46
+
47
+ @ReactMethod(isBlockingSynchronousMethod = true)
48
+ public WritableMap appendEventRecord(
49
+ String queueKey, String serializedEvent, double eventBytes) {
50
+ return implementation.appendEventRecord(queueKey, serializedEvent, eventBytes);
51
+ }
52
+
53
+ @ReactMethod(isBlockingSynchronousMethod = true)
54
+ public WritableMap acknowledgeEventRecords(String queueKey, double count) {
55
+ return implementation.acknowledgeEventRecords(queueKey, count);
56
+ }
57
+
58
+ @ReactMethod(isBlockingSynchronousMethod = true)
59
+ public WritableMap purgeEventRecords(String queueKey) {
60
+ return implementation.purgeEventRecords(queueKey);
61
+ }
62
+
63
+ @ReactMethod(isBlockingSynchronousMethod = true)
64
+ public WritableMap closeEventStore(String queueKey) {
65
+ return implementation.closeEventStore(queueKey);
66
+ }
41
67
  }
package/global-errors.cjs CHANGED
@@ -3,7 +3,8 @@
3
3
  const { createReactNativeErrorEvent } = require("./index.cjs");
4
4
  const { createFatalController } = require("./fatal-replay.cjs");
5
5
  const {
6
- createLogBrewReactNativePromiseRejectionHandlers
6
+ createLogBrewReactNativePromiseRejectionHandlers,
7
+ installLogBrewReactNativePromiseRejectionTracker
7
8
  } = require("./promise-rejections.cjs");
8
9
 
9
10
  const AUTOMATIC_ERROR_MESSAGE = "React Native global JavaScript report";
@@ -412,7 +413,8 @@ function isObjectLike(value) {
412
413
 
413
414
  const defaultExport = {
414
415
  createLogBrewReactNativePromiseRejectionHandlers,
415
- installLogBrewReactNativeGlobalErrorHandler
416
+ installLogBrewReactNativeGlobalErrorHandler,
417
+ installLogBrewReactNativePromiseRejectionTracker
416
418
  };
417
419
 
418
420
  module.exports = { ...defaultExport, default: defaultExport };
@@ -14,6 +14,9 @@ export type ReactNativePromiseRejectionDiagnosticCode =
14
14
  | "promise_rejection_handler_unavailable"
15
15
  | "promise_rejection_id_unavailable"
16
16
  | "promise_rejection_recursive_capture_suppressed"
17
+ | "promise_rejection_tracker_installation_failed"
18
+ | "promise_rejection_tracker_ownership_required"
19
+ | "promise_rejection_tracker_unavailable"
17
20
  | "promise_rejection_tracking_evicted";
18
21
 
19
22
  export type ReactNativePromiseRejectionDiagnostic = Readonly<{
@@ -96,6 +99,54 @@ export type LogBrewReactNativePromiseRejectionHandlers = Readonly<{
96
99
  onUnhandled(runtimeRejectionId: unknown, rejection?: unknown): void;
97
100
  }>;
98
101
 
102
+ export type ReactNativePromiseRejectionTrackerLike = {
103
+ enable(options: Readonly<{
104
+ allRejections: true;
105
+ onHandled(runtimeRejectionId: unknown): void;
106
+ onUnhandled(runtimeRejectionId: unknown, rejection?: unknown): void;
107
+ }>): void;
108
+ };
109
+
110
+ export type InstallLogBrewReactNativePromiseRejectionTrackerOptions = {
111
+ client: Pick<LogBrewClient, "issue">;
112
+ /**
113
+ * Confirms that LogBrew may claim the runtime's single Promise rejection
114
+ * tracker slot. Do not install another tracker owner at the same time.
115
+ */
116
+ takeOwnership: true;
117
+ /**
118
+ * Optional tracker seam. The React Native conditional export discovers the
119
+ * active Hermes tracker when this is omitted.
120
+ */
121
+ tracker?: ReactNativePromiseRejectionTrackerLike;
122
+ maxTrackedRejections?: number;
123
+ onDiagnostic?: (diagnostic: ReactNativePromiseRejectionDiagnostic) => void;
124
+ };
125
+
126
+ export type ReactNativePromiseRejectionTrackerHealth = Readonly<{
127
+ active: boolean;
128
+ available: boolean;
129
+ engine: "custom" | "hermes" | "unavailable";
130
+ lastOutcome:
131
+ | "deactivated"
132
+ | "handler_unavailable"
133
+ | "installation_failed"
134
+ | "installed"
135
+ | "ownership_required"
136
+ | "tracker_unavailable";
137
+ restoration: "deactivate_only";
138
+ }>;
139
+
140
+ export type LogBrewReactNativePromiseRejectionTrackerInstallation = Readonly<{
141
+ /**
142
+ * Stops LogBrew capture through the installed callbacks. Hermes does not
143
+ * expose a previous-owner restoration API, so this cannot restore one.
144
+ */
145
+ deactivate(): boolean;
146
+ health(): ReactNativePromiseRejectionTrackerHealth;
147
+ rejectionHealth(): ReactNativePromiseRejectionHealth;
148
+ }>;
149
+
99
150
  export type ReactNativeFatalRecord = Readonly<{
100
151
  corruptRecords: number;
101
152
  droppedRecords: number;
@@ -175,6 +226,17 @@ export declare function createLogBrewReactNativePromiseRejectionHandlers(
175
226
  options: CreateLogBrewReactNativePromiseRejectionHandlersOptions
176
227
  ): LogBrewReactNativePromiseRejectionHandlers;
177
228
 
229
+ /**
230
+ * Install privacy-safe automatic Promise rejection capture.
231
+ *
232
+ * Installation is opt-in because React Native runtimes expose one tracker slot.
233
+ * The React Native conditional export discovers Hermes without replacing the
234
+ * global Promise. Other runtimes can inject a compatible tracker explicitly.
235
+ */
236
+ export declare function installLogBrewReactNativePromiseRejectionTracker(
237
+ options: InstallLogBrewReactNativePromiseRejectionTrackerOptions
238
+ ): LogBrewReactNativePromiseRejectionTrackerInstallation;
239
+
178
240
  /**
179
241
  * Install reversible automatic capture for React Native global JavaScript errors.
180
242
  *
@@ -190,6 +252,7 @@ export declare function installLogBrewReactNativeGlobalErrorHandler(
190
252
  declare const logBrewReactNativeGlobalErrors: {
191
253
  createLogBrewReactNativePromiseRejectionHandlers: typeof createLogBrewReactNativePromiseRejectionHandlers;
192
254
  installLogBrewReactNativeGlobalErrorHandler: typeof installLogBrewReactNativeGlobalErrorHandler;
255
+ installLogBrewReactNativePromiseRejectionTracker: typeof installLogBrewReactNativePromiseRejectionTracker;
193
256
  };
194
257
 
195
258
  export default logBrewReactNativeGlobalErrors;
@@ -14,6 +14,9 @@ export type ReactNativePromiseRejectionDiagnosticCode =
14
14
  | "promise_rejection_handler_unavailable"
15
15
  | "promise_rejection_id_unavailable"
16
16
  | "promise_rejection_recursive_capture_suppressed"
17
+ | "promise_rejection_tracker_installation_failed"
18
+ | "promise_rejection_tracker_ownership_required"
19
+ | "promise_rejection_tracker_unavailable"
17
20
  | "promise_rejection_tracking_evicted";
18
21
 
19
22
  export type ReactNativePromiseRejectionDiagnostic = Readonly<{
@@ -96,6 +99,54 @@ export type LogBrewReactNativePromiseRejectionHandlers = Readonly<{
96
99
  onUnhandled(runtimeRejectionId: unknown, rejection?: unknown): void;
97
100
  }>;
98
101
 
102
+ export type ReactNativePromiseRejectionTrackerLike = {
103
+ enable(options: Readonly<{
104
+ allRejections: true;
105
+ onHandled(runtimeRejectionId: unknown): void;
106
+ onUnhandled(runtimeRejectionId: unknown, rejection?: unknown): void;
107
+ }>): void;
108
+ };
109
+
110
+ export type InstallLogBrewReactNativePromiseRejectionTrackerOptions = {
111
+ client: Pick<LogBrewClient, "issue">;
112
+ /**
113
+ * Confirms that LogBrew may claim the runtime's single Promise rejection
114
+ * tracker slot. Do not install another tracker owner at the same time.
115
+ */
116
+ takeOwnership: true;
117
+ /**
118
+ * Optional tracker seam. The React Native conditional export discovers the
119
+ * active Hermes tracker when this is omitted.
120
+ */
121
+ tracker?: ReactNativePromiseRejectionTrackerLike;
122
+ maxTrackedRejections?: number;
123
+ onDiagnostic?: (diagnostic: ReactNativePromiseRejectionDiagnostic) => void;
124
+ };
125
+
126
+ export type ReactNativePromiseRejectionTrackerHealth = Readonly<{
127
+ active: boolean;
128
+ available: boolean;
129
+ engine: "custom" | "hermes" | "unavailable";
130
+ lastOutcome:
131
+ | "deactivated"
132
+ | "handler_unavailable"
133
+ | "installation_failed"
134
+ | "installed"
135
+ | "ownership_required"
136
+ | "tracker_unavailable";
137
+ restoration: "deactivate_only";
138
+ }>;
139
+
140
+ export type LogBrewReactNativePromiseRejectionTrackerInstallation = Readonly<{
141
+ /**
142
+ * Stops LogBrew capture through the installed callbacks. Hermes does not
143
+ * expose a previous-owner restoration API, so this cannot restore one.
144
+ */
145
+ deactivate(): boolean;
146
+ health(): ReactNativePromiseRejectionTrackerHealth;
147
+ rejectionHealth(): ReactNativePromiseRejectionHealth;
148
+ }>;
149
+
99
150
  export type ReactNativeFatalRecord = Readonly<{
100
151
  corruptRecords: number;
101
152
  droppedRecords: number;
@@ -175,6 +226,17 @@ export declare function createLogBrewReactNativePromiseRejectionHandlers(
175
226
  options: CreateLogBrewReactNativePromiseRejectionHandlersOptions
176
227
  ): LogBrewReactNativePromiseRejectionHandlers;
177
228
 
229
+ /**
230
+ * Install privacy-safe automatic Promise rejection capture.
231
+ *
232
+ * Installation is opt-in because React Native runtimes expose one tracker slot.
233
+ * The React Native conditional export discovers Hermes without replacing the
234
+ * global Promise. Other runtimes can inject a compatible tracker explicitly.
235
+ */
236
+ export declare function installLogBrewReactNativePromiseRejectionTracker(
237
+ options: InstallLogBrewReactNativePromiseRejectionTrackerOptions
238
+ ): LogBrewReactNativePromiseRejectionTrackerInstallation;
239
+
178
240
  /**
179
241
  * Install reversible automatic capture for React Native global JavaScript errors.
180
242
  *
@@ -190,6 +252,7 @@ export declare function installLogBrewReactNativeGlobalErrorHandler(
190
252
  declare const logBrewReactNativeGlobalErrors: {
191
253
  createLogBrewReactNativePromiseRejectionHandlers: typeof createLogBrewReactNativePromiseRejectionHandlers;
192
254
  installLogBrewReactNativeGlobalErrorHandler: typeof installLogBrewReactNativeGlobalErrorHandler;
255
+ installLogBrewReactNativePromiseRejectionTracker: typeof installLogBrewReactNativePromiseRejectionTracker;
193
256
  };
194
257
 
195
258
  export default logBrewReactNativeGlobalErrors;
package/global-errors.js CHANGED
@@ -2,7 +2,8 @@ import implementation from "./global-errors.cjs";
2
2
 
3
3
  export const {
4
4
  createLogBrewReactNativePromiseRejectionHandlers,
5
- installLogBrewReactNativeGlobalErrorHandler
5
+ installLogBrewReactNativeGlobalErrorHandler,
6
+ installLogBrewReactNativePromiseRejectionTracker
6
7
  } = implementation;
7
8
 
8
9
  export default implementation;
@@ -2,13 +2,16 @@ import { NativeModules, TurboModuleRegistry } from "react-native";
2
2
 
3
3
  import {
4
4
  createLogBrewReactNativePromiseRejectionHandlers,
5
- installLogBrewReactNativeGlobalErrorHandler as installPlatformNeutralHandler
5
+ installLogBrewReactNativeGlobalErrorHandler as installPlatformNeutralHandler,
6
+ installLogBrewReactNativePromiseRejectionTracker as installPlatformNeutralTracker
6
7
  } from "./global-errors.js";
7
8
 
8
9
  export {
9
10
  createLogBrewReactNativePromiseRejectionHandlers
10
11
  };
11
12
 
13
+ const hermesTrackerAdapters = new WeakMap();
14
+
12
15
  function defaultFatalStore() {
13
16
  try {
14
17
  return TurboModuleRegistry?.get?.("LogBrewFatalStore")
@@ -18,6 +21,40 @@ function defaultFatalStore() {
18
21
  }
19
22
  }
20
23
 
24
+ function defaultPromiseRejectionTracker() {
25
+ let hermes;
26
+ let enable;
27
+ let hasPromise;
28
+ try {
29
+ hermes = globalThis?.HermesInternal;
30
+ if (hermes === null
31
+ || (typeof hermes !== "object" && typeof hermes !== "function")) {
32
+ return undefined;
33
+ }
34
+ enable = hermes.enablePromiseRejectionTracker;
35
+ hasPromise = hermes.hasPromise;
36
+ if (typeof enable !== "function"
37
+ || typeof hasPromise !== "function"
38
+ || hasPromise.call(hermes) !== true) {
39
+ return undefined;
40
+ }
41
+ } catch {
42
+ return undefined;
43
+ }
44
+
45
+ const existing = hermesTrackerAdapters.get(hermes);
46
+ if (existing) {
47
+ return existing;
48
+ }
49
+ const adapter = Object.freeze({
50
+ enable(options) {
51
+ return enable.call(hermes, options);
52
+ }
53
+ });
54
+ hermesTrackerAdapters.set(hermes, adapter);
55
+ return adapter;
56
+ }
57
+
21
58
  export function installLogBrewReactNativeGlobalErrorHandler(options = {}) {
22
59
  let forwarded;
23
60
  let hasInjectedStore = false;
@@ -37,9 +74,33 @@ export function installLogBrewReactNativeGlobalErrorHandler(options = {}) {
37
74
  });
38
75
  }
39
76
 
77
+ export function installLogBrewReactNativePromiseRejectionTracker(options = {}) {
78
+ let forwarded;
79
+ let hasInjectedTracker = false;
80
+ try {
81
+ const input = options !== null
82
+ && (typeof options === "object" || typeof options === "function")
83
+ ? options
84
+ : {};
85
+ hasInjectedTracker = Object.prototype.hasOwnProperty.call(input, "tracker");
86
+ forwarded = { ...input };
87
+ } catch {
88
+ forwarded = {};
89
+ }
90
+ const tracker = hasInjectedTracker
91
+ ? forwarded.tracker
92
+ : defaultPromiseRejectionTracker();
93
+ return installPlatformNeutralTracker({
94
+ ...forwarded,
95
+ tracker,
96
+ trackerKind: hasInjectedTracker ? "custom" : tracker ? "hermes" : undefined
97
+ });
98
+ }
99
+
40
100
  const logBrewReactNativeGlobalErrors = {
41
101
  createLogBrewReactNativePromiseRejectionHandlers,
42
- installLogBrewReactNativeGlobalErrorHandler
102
+ installLogBrewReactNativeGlobalErrorHandler,
103
+ installLogBrewReactNativePromiseRejectionTracker
43
104
  };
44
105
 
45
106
  export default logBrewReactNativeGlobalErrors;
package/index.cjs CHANGED
@@ -29,6 +29,7 @@ function createLogBrewReactNativeClient({
29
29
  clientKey,
30
30
  deliveryIntervalMs,
31
31
  deliveryQueueThreshold,
32
+ eventStore,
32
33
  maxBatchBytes,
33
34
  maxBatchEvents,
34
35
  maxQueueBytes,
@@ -48,6 +49,7 @@ function createLogBrewReactNativeClient({
48
49
  automaticDelivery,
49
50
  deliveryIntervalMs,
50
51
  deliveryQueueThreshold,
52
+ eventStore,
51
53
  maxBatchBytes,
52
54
  maxBatchEvents,
53
55
  maxQueueBytes,
package/index.d.cts CHANGED
@@ -4,6 +4,7 @@ import type {
4
4
  DeliveryHealthSnapshot,
5
5
  DroppedEvent,
6
6
  EnvironmentAttributes,
7
+ EventStore,
7
8
  IssueAttributes,
8
9
  LogAttributes,
9
10
  LogBrewClient,
@@ -37,6 +38,8 @@ export type CreateLogBrewReactNativeClientConfig = {
37
38
  clientKey?: string;
38
39
  deliveryIntervalMs?: number;
39
40
  deliveryQueueThreshold?: number;
41
+ /** Advanced synchronous persistence seam. React Native apps normally use the native entry's persistentQueue mode. */
42
+ eventStore?: EventStore;
40
43
  maxBatchBytes?: number;
41
44
  maxBatchEvents?: number;
42
45
  maxQueueBytes?: number;
package/index.d.ts CHANGED
@@ -4,6 +4,7 @@ import type {
4
4
  DeliveryHealthSnapshot,
5
5
  DroppedEvent,
6
6
  EnvironmentAttributes,
7
+ EventStore,
7
8
  IssueAttributes,
8
9
  LogAttributes,
9
10
  LogBrewClient,
@@ -37,6 +38,8 @@ export type CreateLogBrewReactNativeClientConfig = {
37
38
  clientKey?: string;
38
39
  deliveryIntervalMs?: number;
39
40
  deliveryQueueThreshold?: number;
41
+ /** Advanced synchronous persistence seam. React Native apps normally use the native entry's persistentQueue mode. */
42
+ eventStore?: EventStore;
40
43
  maxBatchBytes?: number;
41
44
  maxBatchEvents?: number;
42
45
  maxQueueBytes?: number;
package/index.js CHANGED
@@ -29,6 +29,7 @@ export function createLogBrewReactNativeClient({
29
29
  clientKey,
30
30
  deliveryIntervalMs,
31
31
  deliveryQueueThreshold,
32
+ eventStore,
32
33
  maxBatchBytes,
33
34
  maxBatchEvents,
34
35
  maxQueueBytes,
@@ -48,6 +49,7 @@ export function createLogBrewReactNativeClient({
48
49
  automaticDelivery,
49
50
  deliveryIntervalMs,
50
51
  deliveryQueueThreshold,
52
+ eventStore,
51
53
  maxBatchBytes,
52
54
  maxBatchEvents,
53
55
  maxQueueBytes,
package/index.native.d.ts CHANGED
@@ -1,2 +1,47 @@
1
- export * from "./index";
2
- export { installLogBrewReactNativeGlobalErrorHandler } from "./global-errors";
1
+ import type { EventStore, LogBrewClient } from "@logbrew/sdk";
2
+ import type { CreateLogBrewReactNativeClientConfig } from "./index.js";
3
+
4
+ export * from "./index.js";
5
+ export {
6
+ installLogBrewReactNativeGlobalErrorHandler,
7
+ installLogBrewReactNativePromiseRejectionTracker
8
+ } from "./global-errors";
9
+
10
+ export type ReactNativePersistentQueueMode = "auto" | "required" | "disabled";
11
+
12
+ export type CreateNativeLogBrewReactNativeClientConfig =
13
+ Omit<CreateLogBrewReactNativeClientConfig, "eventStore"> & ({
14
+ /**
15
+ * `auto` uses the linked app-private native queue when available and otherwise uses memory.
16
+ * `required` fails client creation when the native queue is unavailable. `disabled` uses memory.
17
+ */
18
+ persistentQueue?: ReactNativePersistentQueueMode;
19
+ eventStore?: undefined;
20
+ } | {
21
+ /** Advanced app-owned synchronous persistence adapter. Mutually exclusive with persistentQueue. */
22
+ eventStore: EventStore;
23
+ persistentQueue?: never;
24
+ });
25
+
26
+ export declare function createLogBrewReactNativeClient(
27
+ config: CreateNativeLogBrewReactNativeClientConfig
28
+ ): LogBrewClient;
29
+
30
+ export declare function createDefaultLogBrewReactNativeClient(
31
+ config: CreateNativeLogBrewReactNativeClientConfig
32
+ ): LogBrewClient;
33
+
34
+ export declare function purgeLogBrewReactNativePersistentQueue(
35
+ config: { apiKey?: string; clientKey?: string }
36
+ ): void;
37
+
38
+ declare const defaultExport: Omit<
39
+ typeof import("./index.js").default,
40
+ "createLogBrewReactNativeClient" | "createDefaultLogBrewReactNativeClient"
41
+ > & {
42
+ createLogBrewReactNativeClient: typeof createLogBrewReactNativeClient;
43
+ createDefaultLogBrewReactNativeClient: typeof createDefaultLogBrewReactNativeClient;
44
+ purgeLogBrewReactNativePersistentQueue: typeof purgeLogBrewReactNativePersistentQueue;
45
+ };
46
+
47
+ export default defaultExport;