@logbrew/react-native 0.1.17 → 0.1.18
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/LogBrewReactNative.podspec +1 -1
- package/README.md +2 -1
- package/index.cjs +1 -1
- package/index.js +1 -1
- package/ios/AppleDiagnostics/LBRNAppleNativeDiagnostics.swift +1 -1
- package/ios/GeneratedAppleDiagnostics/LogBrewCrash/CrashReportSanitizer.swift +53 -0
- package/ios/GeneratedAppleDiagnostics/LogBrewCrash/NativeCrashExceptionEvidence.swift +0 -29
- package/ios/GeneratedAppleDiagnostics/LogBrewCrash/NativeCrashPublic.swift +12 -67
- package/ios/GeneratedAppleDiagnostics/LogBrewCrash/NativeHangIncidentStore.swift +1 -0
- package/ios/GeneratedAppleDiagnostics/SOURCE-MANIFEST.json +4 -4
- package/package.json +1 -1
|
@@ -33,7 +33,7 @@ Pod::Spec.new do |spec|
|
|
|
33
33
|
"ios/GeneratedAppleDiagnostics/**/*.swift"
|
|
34
34
|
]
|
|
35
35
|
diagnostics.dependency "#{spec.name}/Core"
|
|
36
|
-
diagnostics.dependency "KSCrash/Recording", "2.
|
|
36
|
+
diagnostics.dependency "KSCrash/Recording", "2.6.0"
|
|
37
37
|
diagnostics.pod_target_xcconfig = {
|
|
38
38
|
"DEFINES_MODULE" => "YES",
|
|
39
39
|
"SWIFT_VERSION" => "5.0"
|
package/README.md
CHANGED
|
@@ -335,7 +335,8 @@ the configured project does not replay an earlier project's records with the
|
|
|
335
335
|
new project's key. The raw local KSCrash report can still contain sensitive
|
|
336
336
|
process details, so apply the app's consent and retention policy to it. Hosted
|
|
337
337
|
replay uploads only the bounded crash or hang issue described by the Swift
|
|
338
|
-
`LogBrewCrash` contract
|
|
338
|
+
`LogBrewCrash` contract, including its capture-time service, deployment, OS,
|
|
339
|
+
device-class, and application-version context. Status and error results expose fixed codes and bounded
|
|
339
340
|
counters, not keys, paths, raw reports, or native error text. A custom endpoint
|
|
340
341
|
must be a plain HTTPS path without embedded authentication, a query, or a fragment.
|
|
341
342
|
|
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.
|
|
19
|
+
const DEFAULT_SDK_VERSION = "0.1.18";
|
|
20
20
|
const DEFAULT_ENDPOINT = "https://api.logbrew.co/v1/events";
|
|
21
21
|
const MAX_ACTION_NAME_LENGTH = 64;
|
|
22
22
|
const MAX_PRODUCT_ANALYTICS_SURFACE_LENGTH = 256;
|
package/index.js
CHANGED
|
@@ -16,7 +16,7 @@ import {
|
|
|
16
16
|
} from "./metadata.js";
|
|
17
17
|
|
|
18
18
|
const DEFAULT_SDK_NAME = "logbrew-react-native";
|
|
19
|
-
const DEFAULT_SDK_VERSION = "0.1.
|
|
19
|
+
const DEFAULT_SDK_VERSION = "0.1.18";
|
|
20
20
|
const DEFAULT_ENDPOINT = "https://api.logbrew.co/v1/events";
|
|
21
21
|
const MAX_ACTION_NAME_LENGTH = 64;
|
|
22
22
|
const MAX_PRODUCT_ANALYTICS_SURFACE_LENGTH = 256;
|
|
@@ -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.
|
|
6
|
+
private static let sdkVersion = "0.1.18"
|
|
7
7
|
|
|
8
8
|
private let lock = NSLock()
|
|
9
9
|
private let replayQueue = DispatchQueue(label: "co.logbrew.react-native.apple-diagnostics-replay")
|
|
@@ -28,6 +28,10 @@ struct CrashReportSanitizer {
|
|
|
28
28
|
mechanism: mechanism(error?["type"] as? String),
|
|
29
29
|
nativeStackFrames: nativeStackFrames,
|
|
30
30
|
artifactIdentity: artifactIdentity,
|
|
31
|
+
context: nativeCrashContext(
|
|
32
|
+
system: rawReport["system"] as? [String: Any],
|
|
33
|
+
artifactIdentity: artifactIdentity,
|
|
34
|
+
),
|
|
31
35
|
hangState: nil,
|
|
32
36
|
hangDurationMs: nil,
|
|
33
37
|
source: .engine(reportID: reportID),
|
|
@@ -70,6 +74,55 @@ struct CrashReportSanitizer {
|
|
|
70
74
|
}
|
|
71
75
|
}
|
|
72
76
|
|
|
77
|
+
func nativeCrashContext(
|
|
78
|
+
system: [String: Any]?,
|
|
79
|
+
artifactIdentity: NativeArtifactIdentity?,
|
|
80
|
+
) -> TelemetryContext? {
|
|
81
|
+
let value = { (key: String) in crashContextValue(system?[key]) }
|
|
82
|
+
let operatingSystem = value("system_name").map {
|
|
83
|
+
TelemetryOperatingSystem(name: $0, version: value("system_version"), build: value("os_version"))
|
|
84
|
+
}
|
|
85
|
+
let family = value("model")
|
|
86
|
+
let model = value("machine")
|
|
87
|
+
let architecture = value("cpu_arch")
|
|
88
|
+
let device = family == nil && model == nil && architecture == nil
|
|
89
|
+
? nil
|
|
90
|
+
: TelemetryDevice(family: family, model: model, architecture: architecture)
|
|
91
|
+
let applicationName = value("CFBundleName")
|
|
92
|
+
let applicationVersion = value("CFBundleShortVersionString")
|
|
93
|
+
let applicationBuild = value("CFBundleVersion")
|
|
94
|
+
let application = applicationName == nil && applicationVersion == nil && applicationBuild == nil
|
|
95
|
+
? nil
|
|
96
|
+
: TelemetryApplication(name: applicationName, version: applicationVersion, build: applicationBuild)
|
|
97
|
+
guard artifactIdentity != nil || operatingSystem != nil || device != nil || application != nil else {
|
|
98
|
+
return nil
|
|
99
|
+
}
|
|
100
|
+
return TelemetryContext(resource: TelemetryResource(
|
|
101
|
+
service: artifactIdentity.map { TelemetryNamedVersion(name: $0.service) },
|
|
102
|
+
deployment: artifactIdentity.map {
|
|
103
|
+
TelemetryDeployment(environment: $0.environment, release: $0.release)
|
|
104
|
+
},
|
|
105
|
+
operatingSystem: operatingSystem,
|
|
106
|
+
device: device,
|
|
107
|
+
application: application,
|
|
108
|
+
))
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
private func crashContextValue(_ rawValue: Any?) -> String? {
|
|
112
|
+
guard let value = rawValue as? String else {
|
|
113
|
+
return nil
|
|
114
|
+
}
|
|
115
|
+
let normalized = value.trimmingCharacters(in: .whitespacesAndNewlines)
|
|
116
|
+
guard (1 ... 256).contains(normalized.utf8.count),
|
|
117
|
+
!normalized.unicodeScalars.contains(where: CharacterSet.controlCharacters.contains),
|
|
118
|
+
!normalized.contains("/"),
|
|
119
|
+
!normalized.contains("\\")
|
|
120
|
+
else {
|
|
121
|
+
return nil
|
|
122
|
+
}
|
|
123
|
+
return normalized
|
|
124
|
+
}
|
|
125
|
+
|
|
73
126
|
struct NativeCrashTimestamp: Comparable {
|
|
74
127
|
let normalized: String
|
|
75
128
|
private let wholeSecond: String
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
// Generated by scripts/sync-apple-native-sources.mjs.
|
|
2
2
|
// Edit the canonical Swift source, then regenerate this package boundary.
|
|
3
|
-
import Foundation
|
|
4
3
|
|
|
5
4
|
func nativeCrashExceptionChain(for exception: IssueException) -> IssueExceptionChain {
|
|
6
5
|
IssueExceptionChain(entries: [
|
|
@@ -14,31 +13,3 @@ func nativeCrashExceptionChain(for exception: IssueException) -> IssueExceptionC
|
|
|
14
13
|
),
|
|
15
14
|
])
|
|
16
15
|
}
|
|
17
|
-
|
|
18
|
-
func nativeCrashExceptionChainMatches(
|
|
19
|
-
_ value: Any?,
|
|
20
|
-
expected exception: IssueException,
|
|
21
|
-
) -> Bool {
|
|
22
|
-
guard let value else {
|
|
23
|
-
// Preserve retry identity for an event queued by an older SDK before chains existed.
|
|
24
|
-
return true
|
|
25
|
-
}
|
|
26
|
-
guard let chain = value as? [String: Any] else {
|
|
27
|
-
return false
|
|
28
|
-
}
|
|
29
|
-
guard let mechanism = exception.mechanism else {
|
|
30
|
-
return false
|
|
31
|
-
}
|
|
32
|
-
let expected = [
|
|
33
|
-
"entries": [[
|
|
34
|
-
"id": 0,
|
|
35
|
-
"relationship": "reported",
|
|
36
|
-
"type": exception.type,
|
|
37
|
-
"messageState": "not_captured",
|
|
38
|
-
"mechanism": ["type": mechanism.type, "handled": mechanism.handled],
|
|
39
|
-
"stackFramesState": "not_captured",
|
|
40
|
-
]],
|
|
41
|
-
"truncated": false,
|
|
42
|
-
] as NSDictionary
|
|
43
|
-
return chain as NSDictionary == expected
|
|
44
|
-
}
|
|
@@ -163,6 +163,7 @@ public final class NativeCrashRecord: NSObject, @unchecked Sendable {
|
|
|
163
163
|
|
|
164
164
|
private let nativeStackFrames: [NativeStackFrame]?
|
|
165
165
|
private let artifactIdentity: NativeArtifactIdentity?
|
|
166
|
+
private let context: TelemetryContext?
|
|
166
167
|
private let hangState: NativeHangIncidentState?
|
|
167
168
|
private let hangDurationMs: Double?
|
|
168
169
|
let source: NativeCrashRecordSource
|
|
@@ -175,6 +176,7 @@ public final class NativeCrashRecord: NSObject, @unchecked Sendable {
|
|
|
175
176
|
mechanism: NativeCrashMechanism,
|
|
176
177
|
nativeStackFrames: [NativeStackFrame]?,
|
|
177
178
|
artifactIdentity: NativeArtifactIdentity?,
|
|
179
|
+
context: TelemetryContext?,
|
|
178
180
|
hangState: NativeHangIncidentState?,
|
|
179
181
|
hangDurationMs: Double? = nil,
|
|
180
182
|
source: NativeCrashRecordSource,
|
|
@@ -186,6 +188,7 @@ public final class NativeCrashRecord: NSObject, @unchecked Sendable {
|
|
|
186
188
|
self.mechanism = mechanism
|
|
187
189
|
self.nativeStackFrames = nativeStackFrames
|
|
188
190
|
self.artifactIdentity = artifactIdentity
|
|
191
|
+
self.context = context
|
|
189
192
|
self.hangState = hangState
|
|
190
193
|
self.hangDurationMs = hangDurationMs
|
|
191
194
|
self.source = source
|
|
@@ -237,6 +240,7 @@ public final class NativeCrashRecord: NSObject, @unchecked Sendable {
|
|
|
237
240
|
exception: issueException,
|
|
238
241
|
exceptionChain: nativeCrashExceptionChain(for: issueException),
|
|
239
242
|
metadata: metadata,
|
|
243
|
+
context: context,
|
|
240
244
|
nativeStackFrames: nativeStackFrames,
|
|
241
245
|
)
|
|
242
246
|
}
|
|
@@ -254,57 +258,13 @@ public final class NativeCrashRecord: NSObject, @unchecked Sendable {
|
|
|
254
258
|
guard event["type"] as? String == "issue",
|
|
255
259
|
event["timestamp"] as? String == timestamp,
|
|
256
260
|
let attributes = event["attributes"] as? [String: Any],
|
|
257
|
-
attributes
|
|
258
|
-
attributes["level"] as? String == issueAttributes.level.canonicalValue,
|
|
259
|
-
attributes["message"] == nil,
|
|
260
|
-
exceptionMatches(attributes["exception"]),
|
|
261
|
-
nativeCrashExceptionChainMatches(
|
|
262
|
-
attributes["exceptionChain"],
|
|
263
|
-
expected: issueException,
|
|
264
|
-
),
|
|
265
|
-
attributes["stackFrames"] == nil,
|
|
266
|
-
attributes["breadcrumbs"] == nil,
|
|
267
|
-
attributes["breadcrumbsTruncated"] == nil,
|
|
268
|
-
attributes["context"] == nil,
|
|
269
|
-
let metadata = attributes["metadata"] as? [String: Any],
|
|
270
|
-
metadata as NSDictionary == expectedMetadata,
|
|
271
|
-
nativeStackFramesMatch(attributes["nativeStackFrames"])
|
|
261
|
+
attributesMatch(attributes)
|
|
272
262
|
else {
|
|
273
263
|
return .collision
|
|
274
264
|
}
|
|
275
265
|
return .matching
|
|
276
266
|
}
|
|
277
267
|
|
|
278
|
-
private var expectedMetadata: NSDictionary {
|
|
279
|
-
var metadata: [String: Any] = [
|
|
280
|
-
"crash.mechanism": mechanism.name,
|
|
281
|
-
"crash.replayed": true,
|
|
282
|
-
]
|
|
283
|
-
if let artifactIdentity {
|
|
284
|
-
metadata["projectId"] = artifactIdentity.projectId
|
|
285
|
-
metadata["release"] = artifactIdentity.release
|
|
286
|
-
metadata["environment"] = artifactIdentity.environment
|
|
287
|
-
metadata["service"] = artifactIdentity.service
|
|
288
|
-
}
|
|
289
|
-
if let hangState {
|
|
290
|
-
metadata["crash.handled"] = hangState == .recovered
|
|
291
|
-
}
|
|
292
|
-
if let hangDurationMs {
|
|
293
|
-
metadata["durationMs"] = hangDurationMs
|
|
294
|
-
}
|
|
295
|
-
return metadata as NSDictionary
|
|
296
|
-
}
|
|
297
|
-
|
|
298
|
-
private var expectedException: NSDictionary {
|
|
299
|
-
[
|
|
300
|
-
"type": hangState == nil ? "AppleNativeCrash" : "AppleNativeHang",
|
|
301
|
-
"mechanism": [
|
|
302
|
-
"type": mechanism.name,
|
|
303
|
-
"handled": hangState == .recovered,
|
|
304
|
-
],
|
|
305
|
-
] as NSDictionary
|
|
306
|
-
}
|
|
307
|
-
|
|
308
268
|
private var issueException: IssueException {
|
|
309
269
|
IssueException(
|
|
310
270
|
type: hangState == nil ? "AppleNativeCrash" : "AppleNativeHang",
|
|
@@ -315,31 +275,16 @@ public final class NativeCrashRecord: NSObject, @unchecked Sendable {
|
|
|
315
275
|
)
|
|
316
276
|
}
|
|
317
277
|
|
|
318
|
-
private func
|
|
319
|
-
guard let
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
}
|
|
323
|
-
guard let exception = value as? [String: Any] else {
|
|
324
|
-
return false
|
|
325
|
-
}
|
|
326
|
-
return exception as NSDictionary == expectedException
|
|
327
|
-
}
|
|
328
|
-
|
|
329
|
-
private func nativeStackFramesMatch(_ value: Any?) -> Bool {
|
|
330
|
-
guard let nativeStackFrames else {
|
|
331
|
-
return value == nil
|
|
332
|
-
}
|
|
333
|
-
guard let frames = value as? [[String: Any]], frames.count == nativeStackFrames.count else {
|
|
278
|
+
private func attributesMatch(_ actual: [String: Any]) -> Bool {
|
|
279
|
+
guard let encoded = try? JSONEncoder().encode(issueAttributes),
|
|
280
|
+
var expected = try? JSONSerialization.jsonObject(with: encoded) as? [String: Any]
|
|
281
|
+
else {
|
|
334
282
|
return false
|
|
335
283
|
}
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
"imageUuid": expected.imageUuid,
|
|
339
|
-
"architecture": expected.architecture.rawValue,
|
|
340
|
-
"instructionOffset": expected.instructionOffset,
|
|
341
|
-
] as NSDictionary
|
|
284
|
+
for legacyField in ["exception", "exceptionChain", "context"] where actual[legacyField] == nil {
|
|
285
|
+
expected.removeValue(forKey: legacyField)
|
|
342
286
|
}
|
|
287
|
+
return actual as NSDictionary == expected as NSDictionary
|
|
343
288
|
}
|
|
344
289
|
}
|
|
345
290
|
|
|
@@ -93,6 +93,7 @@ struct NativeHangIncident: Codable, Equatable {
|
|
|
93
93
|
mechanism: .deadlock,
|
|
94
94
|
nativeStackFrames: nativeStackFrames,
|
|
95
95
|
artifactIdentity: artifactIdentity.validatedIdentity(),
|
|
96
|
+
context: nil,
|
|
96
97
|
hangState: state,
|
|
97
98
|
hangDurationMs: durationMs,
|
|
98
99
|
source: .hang(eventID: eventID),
|
|
@@ -29,14 +29,14 @@
|
|
|
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": "7a46035fcaa72dd7504b4e274a92070d73dd1c45fe20e008474340d6d7c44ede",
|
|
32
|
-
"swift/logbrew-swift/Sources/LogBrewCrash/CrashReportSanitizer.swift": "
|
|
32
|
+
"swift/logbrew-swift/Sources/LogBrewCrash/CrashReportSanitizer.swift": "8798c8900ea28a85d6909183dc8435bc08da96573b89310d26ed178217fbc04b",
|
|
33
33
|
"swift/logbrew-swift/Sources/LogBrewCrash/CrashStorageDirectory.swift": "7cd566703cbf704dc99155451ee93dcace12c35c805abc09a6dcf23975cf43f9",
|
|
34
34
|
"swift/logbrew-swift/Sources/LogBrewCrash/NativeArtifactIdentity.swift": "3d785ad717dcf7302451531c18b5e1183983270a6cd78dd543a407e3facc6ae0",
|
|
35
35
|
"swift/logbrew-swift/Sources/LogBrewCrash/NativeCrashCapture.swift": "e9ab5f1850a096f40592a025d16c5ffa2fdff0222004a37056898cf1cb4b0dd9",
|
|
36
|
-
"swift/logbrew-swift/Sources/LogBrewCrash/NativeCrashExceptionEvidence.swift": "
|
|
37
|
-
"swift/logbrew-swift/Sources/LogBrewCrash/NativeCrashPublic.swift": "
|
|
36
|
+
"swift/logbrew-swift/Sources/LogBrewCrash/NativeCrashExceptionEvidence.swift": "ce191e46298d91d87b379528d610caa88b924b15a8dd912b4a164b51eb172a7a",
|
|
37
|
+
"swift/logbrew-swift/Sources/LogBrewCrash/NativeCrashPublic.swift": "7c1d028bea143c6ab34ebddaaaab64aeb69d4d950ec7a42264c567e672991748",
|
|
38
38
|
"swift/logbrew-swift/Sources/LogBrewCrash/NativeCrashReplay.swift": "3eb3d93b32cf14de416f56fa30d6d65e6f268b5ec9d1a67081d7525c4efd4f80",
|
|
39
|
-
"swift/logbrew-swift/Sources/LogBrewCrash/NativeHangIncidentStore.swift": "
|
|
39
|
+
"swift/logbrew-swift/Sources/LogBrewCrash/NativeHangIncidentStore.swift": "5a8150083f16d6b495c9c63434809dc5f11f13ebb23211f57151bad62040781b",
|
|
40
40
|
"swift/logbrew-swift/Sources/LogBrewCrash/NativeHangWatchdog.swift": "37b25904cd6576e20c40500be2c153156403b57ad7b4186a1b6b35b414145ecb",
|
|
41
41
|
"swift/logbrew-swift/Sources/LogBrewCrash/NativeHangWatchdogContracts.swift": "59f51554d86c326122bb2bdce47c5a7e01996bd61f2b371eba23855032487b9f",
|
|
42
42
|
"swift/logbrew-swift/Sources/LogBrewCrash/NativeHangWatchdogSystem.swift": "b87e3db246691d5b0719898cdc02ba068836647b1ac9339a73cf866eabe235ae",
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@logbrew/react-native",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.18",
|
|
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",
|