@logbrew/react-native 0.1.21 → 0.1.23

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.
@@ -165,6 +165,7 @@ public final class NativeCrashRecord: NSObject, @unchecked Sendable {
165
165
  private let artifactIdentity: NativeArtifactIdentity?
166
166
  private let context: TelemetryContext?
167
167
  private let correlationState: NativeCrashContextState?
168
+ private let impact: IssueImpactEvidence?
168
169
  private let breadcrumbs: [IssueBreadcrumb]?
169
170
  private let breadcrumbsTruncated: Bool?
170
171
  private let breadcrumbState: NativeCrashContextState?
@@ -182,6 +183,7 @@ public final class NativeCrashRecord: NSObject, @unchecked Sendable {
182
183
  artifactIdentity: NativeArtifactIdentity?,
183
184
  context: TelemetryContext?,
184
185
  correlationState: NativeCrashContextState? = nil,
186
+ impact: IssueImpactEvidence? = nil,
185
187
  breadcrumbs: [IssueBreadcrumb]? = nil,
186
188
  breadcrumbsTruncated: Bool? = nil,
187
189
  breadcrumbState: NativeCrashContextState? = nil,
@@ -198,6 +200,7 @@ public final class NativeCrashRecord: NSObject, @unchecked Sendable {
198
200
  self.artifactIdentity = artifactIdentity
199
201
  self.context = context
200
202
  self.correlationState = correlationState
203
+ self.impact = impact
201
204
  self.breadcrumbs = breadcrumbs
202
205
  self.breadcrumbsTruncated = breadcrumbsTruncated
203
206
  self.breadcrumbState = breadcrumbState
@@ -259,6 +262,7 @@ public final class NativeCrashRecord: NSObject, @unchecked Sendable {
259
262
  exceptionChain: nativeCrashExceptionChain(for: issueException),
260
263
  breadcrumbs: breadcrumbs,
261
264
  breadcrumbsTruncated: breadcrumbsTruncated,
265
+ evidence: impact.map { IssueDiagnosticEvidence(impact: $0) },
262
266
  metadata: metadata,
263
267
  context: context,
264
268
  nativeStackFrames: nativeStackFrames,
@@ -301,7 +305,7 @@ public final class NativeCrashRecord: NSObject, @unchecked Sendable {
301
305
  else {
302
306
  return false
303
307
  }
304
- let legacyFields = ["exception", "exceptionChain", "breadcrumbs", "breadcrumbsTruncated", "context"]
308
+ let legacyFields = ["exception", "exceptionChain", "evidence", "breadcrumbs", "breadcrumbsTruncated", "context"]
305
309
  for legacyField in legacyFields where actual[legacyField] == nil {
306
310
  expected.removeValue(forKey: legacyField)
307
311
  }
@@ -10,7 +10,7 @@
10
10
  "swift/logbrew-swift/Sources/LogBrew/DurableDeliveryStore.swift": "7c292dda68efc3de790daf44733b25e4392226793343c21ba5df4f51fc1b402b",
11
11
  "swift/logbrew-swift/Sources/LogBrew/DurableDeliveryStoreRecovery.swift": "79fee27975b6571954bf0b3692a50e60bbbcf53b5ab47f653a474db5c56d68ba",
12
12
  "swift/logbrew-swift/Sources/LogBrew/EventEncoding.swift": "b88b6b2d17f7d0cee9ac1a1f34ef35b192cd33d213ef3c9e1c2d21cbcc304a97",
13
- "swift/logbrew-swift/Sources/LogBrew/IssueDiagnosticEvidence.swift": "e471f27fadaefe06971c1a98892aeb0774e840a2ce0cbb243ae9aabfa41b1c47",
13
+ "swift/logbrew-swift/Sources/LogBrew/IssueDiagnosticEvidence.swift": "1042b5a6283cf440529572844e5ad1f3078f4ba715133932ea305e075614a53c",
14
14
  "swift/logbrew-swift/Sources/LogBrew/IssueDiagnostics.swift": "bbdfe6169961ff27b8f2cee63c7dcdeacf2e5cee6a3ca17f6a26b933f0adfc39",
15
15
  "swift/logbrew-swift/Sources/LogBrew/IssueExceptionChain.swift": "10f81cbce95b47da0a44ef9e515b150e60d71dfcc8b04be24b037b1222a373a5",
16
16
  "swift/logbrew-swift/Sources/LogBrew/LifecycleTrace.swift": "738cd3f129fac821a892404d1d42ee92bd806b6583d3dbb5379e88b14ab23c16",
@@ -29,13 +29,13 @@
29
29
  "swift/logbrew-swift/Sources/LogBrew/URLSessionTracer.swift": "0cdf08f92d6111c0dc2883b87837b81f69b5c2f9a8e5501780a114c23a741af7",
30
30
  "swift/logbrew-swift/Sources/LogBrew/Validation.swift": "07ff5c2daeb829b1df4f50edb0b79727f9a81b1c9b5cde5f995f5ad6ce660aa7",
31
31
  "swift/logbrew-swift/Sources/LogBrewCrash/CrashEngine.swift": "a94dfce653e3e7f381be42b6d2c4540f0be77e83777ecc53e06682cd2e569c5a",
32
- "swift/logbrew-swift/Sources/LogBrewCrash/CrashReportSanitizer.swift": "ccd0ef83f14096816765278e007f5e4ba0a40286ce00d708b38ca0b94959171e",
32
+ "swift/logbrew-swift/Sources/LogBrewCrash/CrashReportSanitizer.swift": "a56a2f6c6c7f1db900804a37df51aebba7b83dce14fa7816de5753c33409e4a5",
33
33
  "swift/logbrew-swift/Sources/LogBrewCrash/CrashStorageDirectory.swift": "7cd566703cbf704dc99155451ee93dcace12c35c805abc09a6dcf23975cf43f9",
34
34
  "swift/logbrew-swift/Sources/LogBrewCrash/NativeArtifactIdentity.swift": "3d785ad717dcf7302451531c18b5e1183983270a6cd78dd543a407e3facc6ae0",
35
- "swift/logbrew-swift/Sources/LogBrewCrash/NativeCrashCapture.swift": "c2f5d0e9a8953cb988633ebf60a06f3b7ddaa0c9828f99372969fdfb60b99bc4",
36
- "swift/logbrew-swift/Sources/LogBrewCrash/NativeCrashCorrelation.swift": "eef19c6e561bc03bb4c09736722afe57f63d557f9279b26353679bd53362c25d",
35
+ "swift/logbrew-swift/Sources/LogBrewCrash/NativeCrashCapture.swift": "0b773a63987b6c694b044e56c0f81878f4f5e71eae3fdd126744cba3cf15aac1",
36
+ "swift/logbrew-swift/Sources/LogBrewCrash/NativeCrashCorrelation.swift": "e5a7c25448c83ca2ae149c650ecfc72c5193741291a6ff9623eabadad8a9c440",
37
37
  "swift/logbrew-swift/Sources/LogBrewCrash/NativeCrashExceptionEvidence.swift": "ce191e46298d91d87b379528d610caa88b924b15a8dd912b4a164b51eb172a7a",
38
- "swift/logbrew-swift/Sources/LogBrewCrash/NativeCrashPublic.swift": "2d0f2e7cdce09dc09906cede5d83928e8bd0e70a8522ff55c999d19366d84730",
38
+ "swift/logbrew-swift/Sources/LogBrewCrash/NativeCrashPublic.swift": "70aa9700efd26d03b9656f1df96876de0b9eb769c03512ec53f667696773954f",
39
39
  "swift/logbrew-swift/Sources/LogBrewCrash/NativeCrashReplay.swift": "3eb3d93b32cf14de416f56fa30d6d65e6f268b5ec9d1a67081d7525c4efd4f80",
40
40
  "swift/logbrew-swift/Sources/LogBrewCrash/NativeHangIncidentStore.swift": "5a8150083f16d6b495c9c63434809dc5f11f13ebb23211f57151bad62040781b",
41
41
  "swift/logbrew-swift/Sources/LogBrewCrash/NativeHangWatchdog.swift": "37b25904cd6576e20c40500be2c153156403b57ad7b4186a1b6b35b414145ecb",
@@ -5,7 +5,9 @@
5
5
  #import "LBRNPrivateStorage.h"
6
6
 
7
7
  #import <CommonCrypto/CommonDigest.h>
8
+ #import <Security/SecRandom.h>
8
9
  #import <TargetConditionals.h>
10
+ #import <math.h>
9
11
 
10
12
  #ifdef RCT_NEW_ARCH_ENABLED
11
13
  #import <LogBrewReactNativeSpec/LogBrewReactNativeSpec.h>
@@ -130,6 +132,23 @@ RCT_EXPORT_MODULE(LogBrewFatalStore)
130
132
  return self;
131
133
  }
132
134
 
135
+ RCT_EXPORT_BLOCKING_SYNCHRONOUS_METHOD(secureRandomHex:(double)length)
136
+ {
137
+ if (!isfinite(length) || length < 1 || length > 64 || floor(length) != length) {
138
+ return @"";
139
+ }
140
+ uint8_t bytes[64];
141
+ NSUInteger byteCount = (NSUInteger)length;
142
+ if (SecRandomCopyBytes(kSecRandomDefault, byteCount, bytes) != errSecSuccess) {
143
+ return @"";
144
+ }
145
+ NSMutableString *output = [NSMutableString stringWithCapacity:byteCount * 2];
146
+ for (NSUInteger index = 0; index < byteCount; index += 1) {
147
+ [output appendFormat:@"%02x", bytes[index]];
148
+ }
149
+ return output;
150
+ }
151
+
133
152
  - (nullable LBRNEventRecordStore *)eventStoreForQueueKey:(NSString *)queueKey
134
153
  {
135
154
  NSString *queueHash = LBRNQueueHash(queueKey);
package/lifecycle.js CHANGED
@@ -1,121 +1,7 @@
1
- import { SdkError } from "@logbrew/sdk";
2
- import {
3
- createReactNativeSpanAttributes,
4
- createReactNativeTraceContext,
5
- getActiveLogBrewTrace,
6
- getReactNativeContext
7
- } from "./index.js";
1
+ import runtime from "./lifecycle.cjs";
8
2
 
9
- export function createReactNativeLifecycleSpanEvent({
10
- durationMs, fromState, id, idFactory = defaultLifecycleSpanEventId, metadata = {}, name,
11
- now = () => new Date().toISOString(), platform, appState, screen, sessionId, state, status = "ok",
12
- timestamp, toState, trace
13
- } = {}) {
14
- const safeFromState = normalizeLifecycleState(fromState);
15
- const safeToState = normalizeLifecycleState(toState ?? state);
16
- const transition = [safeFromState, safeToState].filter(Boolean).join("->");
17
- const spanName = name ?? `app_state:${transition || safeToState || safeFromState || "change"}`;
18
- const activeTrace = trace ?? getActiveLogBrewTrace() ?? createReactNativeTraceContext();
19
- return {
20
- id: id ?? idFactory({ fromState: safeFromState, screen, toState: safeToState }),
21
- timestamp: timestamp ?? now(),
22
- attributes: createReactNativeSpanAttributes({
23
- name: spanName,
24
- status,
25
- durationMs,
26
- trace: activeTrace,
27
- metadata: {
28
- ...getReactNativeContext({ platform, appState }),
29
- source: "react-native.lifecycle",
30
- appState: safeToState,
31
- durationMs,
32
- fromAppState: safeFromState,
33
- screen,
34
- sessionId,
35
- toAppState: safeToState,
36
- ...metadata
37
- }
38
- })
39
- };
40
- }
41
-
42
- export function captureReactNativeLifecycleSpan(client, input = {}) {
43
- requireClient(client);
44
- const event = createReactNativeLifecycleSpanEvent(input);
45
- client.span(event.id, event.timestamp, event.attributes);
46
- return event;
47
- }
48
-
49
- export function createAppStateLifecycleSpanListener(client, appState, {
50
- captureInitialState = false, metadata = {}, now = () => new Date().toISOString(), nowMs = () => Date.now(),
51
- onError, platform, screen, sessionId, trace
52
- } = {}) {
53
- requireClient(client);
54
- if (!appState || typeof appState.addEventListener !== "function") {
55
- throw new SdkError("configuration_error", "createAppStateLifecycleSpanListener requires AppState.addEventListener");
56
- }
57
-
58
- let previousState = normalizeLifecycleState(appState.currentState);
59
- let previousChangedAtMs = nowMs();
60
- if (captureInitialState && previousState !== undefined) {
61
- captureReactNativeLifecycleSpan(client, {
62
- appState, metadata, now, platform, screen, sessionId, toState: previousState, trace
63
- });
64
- }
65
-
66
- const subscription = appState.addEventListener("change", (nextState) => {
67
- try {
68
- const safeNextState = normalizeLifecycleState(nextState);
69
- if (safeNextState === undefined) {
70
- return;
71
- }
72
- const changedAtMs = nowMs();
73
- const durationMs = previousState === undefined ? undefined : Math.max(0, changedAtMs - previousChangedAtMs);
74
- captureReactNativeLifecycleSpan(client, {
75
- appState, durationMs, fromState: previousState, metadata, now, platform, screen, sessionId,
76
- timestamp: now(), toState: safeNextState, trace
77
- });
78
- previousState = safeNextState;
79
- previousChangedAtMs = changedAtMs;
80
- } catch (error) {
81
- if (typeof onError === "function") {
82
- onError(error);
83
- } else {
84
- throw error;
85
- }
86
- }
87
- });
88
-
89
- return subscriptionRemover(subscription);
90
- }
91
-
92
- function requireClient(client) {
93
- if (!client) {
94
- throw new SdkError("configuration_error", "LogBrew React Native lifecycle helpers require a client");
95
- }
96
- }
97
-
98
- function defaultLifecycleSpanEventId({ fromState, screen, toState }) {
99
- return `evt_native_lifecycle_${slugify([screen, fromState, toState].filter(Boolean).join("_") || "app_state")}`;
100
- }
101
-
102
- function normalizeLifecycleState(state) {
103
- return typeof state === "string" && state.trim() !== "" ? state.trim() : undefined;
104
- }
105
-
106
- function subscriptionRemover(subscription) {
107
- if (typeof subscription === "function") {
108
- return subscription;
109
- }
110
- if (subscription && typeof subscription.remove === "function") {
111
- return () => subscription.remove();
112
- }
113
- return () => {};
114
- }
115
-
116
- function slugify(value) {
117
- return String(value)
118
- .toLowerCase()
119
- .replace(/[^a-z0-9]+/g, "_")
120
- .replace(/^_+|_+$/g, "") || "event";
121
- }
3
+ export const {
4
+ captureReactNativeLifecycleSpan,
5
+ createAppStateLifecycleSpanListener,
6
+ createReactNativeLifecycleSpanEvent
7
+ } = runtime;
package/native-bridge.js CHANGED
@@ -1,125 +1,10 @@
1
- import { SdkError } from "@logbrew/sdk";
2
- import {
3
- getActiveLogBrewTrace,
4
- getReactNativeTraceMetadata
5
- } from "./index.js";
1
+ import runtime from "./native-bridge.cjs";
6
2
 
7
- const DEFAULT_SCOPE_SOURCE = "react-native.native_bridge";
8
- const RESERVED_TRACE_METADATA_KEYS = new Set([
9
- "parentSpanId",
10
- "spanId",
11
- "traceFlags",
12
- "traceId",
13
- "traceSampled",
14
- "traceparent"
15
- ]);
16
-
17
- export function createLogBrewNativeBridgeScope({
18
- logger,
19
- metadata = {},
20
- screen,
21
- sessionId,
22
- source = DEFAULT_SCOPE_SOURCE,
23
- trace = getActiveLogBrewTrace()
24
- } = {}) {
25
- const traceMetadata = getReactNativeTraceMetadata(trace);
26
- return {
27
- trace: Object.keys(traceMetadata).length === 0 ? undefined : {
28
- parentSpanId: traceMetadata.parentSpanId,
29
- spanId: traceMetadata.spanId,
30
- traceFlags: traceMetadata.traceFlags,
31
- traceId: traceMetadata.traceId,
32
- traceSampled: traceMetadata.traceSampled
33
- },
34
- metadata: compactMetadata({
35
- ...metadata,
36
- logger,
37
- screen,
38
- sessionId,
39
- source
40
- })
41
- };
42
- }
43
-
44
- export function syncLogBrewNativeBridgeScope(nativeBridge, options = {}) {
45
- const payload = createLogBrewNativeBridgeScope(options);
46
- bridgeSync(nativeBridge)(payload);
47
- return payload;
48
- }
49
-
50
- export function clearLogBrewNativeBridgeScope(nativeBridge) {
51
- bridgeClear(nativeBridge)();
52
- }
53
-
54
- export function withLogBrewNativeBridgeScope(nativeBridge, options, callback) {
55
- const resolvedOptions = typeof options === "function" ? {} : options ?? {};
56
- const resolvedCallback = typeof options === "function" ? options : callback;
57
- if (typeof resolvedCallback !== "function") {
58
- throw new SdkError("configuration_error", "withLogBrewNativeBridgeScope requires a callback");
59
- }
60
-
61
- const payload = syncLogBrewNativeBridgeScope(nativeBridge, resolvedOptions);
62
- try {
63
- const result = resolvedCallback(payload);
64
- if (result && typeof result.then === "function") {
65
- return Promise.resolve(result).finally(() => clearLogBrewNativeBridgeScope(nativeBridge));
66
- }
67
- clearLogBrewNativeBridgeScope(nativeBridge);
68
- return result;
69
- } catch (error) {
70
- clearLogBrewNativeBridgeScope(nativeBridge);
71
- throw error;
72
- }
73
- }
74
-
75
- function bridgeSync(nativeBridge) {
76
- if (typeof nativeBridge === "function") {
77
- return nativeBridge;
78
- }
79
- if (nativeBridge && typeof nativeBridge.setLogBrewScope === "function") {
80
- return nativeBridge.setLogBrewScope.bind(nativeBridge);
81
- }
82
- if (nativeBridge && typeof nativeBridge.syncLogBrewScope === "function") {
83
- return nativeBridge.syncLogBrewScope.bind(nativeBridge);
84
- }
85
- throw new SdkError(
86
- "configuration_error",
87
- "LogBrew native bridge scope sync requires a function, setLogBrewScope, or syncLogBrewScope"
88
- );
89
- }
90
-
91
- function bridgeClear(nativeBridge) {
92
- if (nativeBridge && typeof nativeBridge.clearLogBrewScope === "function") {
93
- return nativeBridge.clearLogBrewScope.bind(nativeBridge);
94
- }
95
- if (nativeBridge && typeof nativeBridge.clearLogBrewTraceContext === "function") {
96
- return nativeBridge.clearLogBrewTraceContext.bind(nativeBridge);
97
- }
98
- if (typeof nativeBridge === "function") {
99
- return () => nativeBridge(undefined);
100
- }
101
- return () => {};
102
- }
103
-
104
- function compactMetadata(metadata) {
105
- const compacted = {};
106
- for (const [key, value] of Object.entries(metadata)) {
107
- if (value === undefined) {
108
- continue;
109
- }
110
- if (RESERVED_TRACE_METADATA_KEYS.has(key)) {
111
- continue;
112
- }
113
- if (typeof value === "string" || typeof value === "number" || typeof value === "boolean" || value === null) {
114
- compacted[key] = value;
115
- }
116
- }
117
- return compacted;
118
- }
119
-
120
- export default {
3
+ export const {
121
4
  clearLogBrewNativeBridgeScope,
122
5
  createLogBrewNativeBridgeScope,
123
6
  syncLogBrewNativeBridgeScope,
124
7
  withLogBrewNativeBridgeScope
125
- };
8
+ } = runtime;
9
+
10
+ export default runtime.default;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@logbrew/react-native",
3
- "version": "0.1.21",
3
+ "version": "0.1.23",
4
4
  "description": "React Native offline delivery, Apple native diagnostics, screen, error, trace, action, and network timeline helpers for LogBrew.",
5
5
  "type": "module",
6
6
  "main": "./index.cjs",