craft-native 0.0.178 → 0.0.179
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/dist/cli.js +1 -1
- package/dist/index.cjs +1 -1
- package/dist/index.js +1 -1
- package/dist/ios/templates/CraftCrashReporter.swift +72 -8
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -3303,7 +3303,7 @@ function pinCraftNativeDependency(packagePath, craftVersion) {
|
|
|
3303
3303
|
`);
|
|
3304
3304
|
}
|
|
3305
3305
|
// package.json
|
|
3306
|
-
var version = "0.0.
|
|
3306
|
+
var version = "0.0.179";
|
|
3307
3307
|
|
|
3308
3308
|
// bin/cli.ts
|
|
3309
3309
|
var spawnedFrom = process6.env[CRAFT_CLI_SPAWN_MARKER];
|
package/dist/index.cjs
CHANGED
package/dist/index.js
CHANGED
|
@@ -189,7 +189,7 @@ private func craftCollectFrames(_ context: UnsafeMutableRawPointer?) -> Int {
|
|
|
189
189
|
let returnAddress = craftStrip(record.1)
|
|
190
190
|
// In a leaf function the caller is only in the link register: the
|
|
191
191
|
// first saved return address then belongs to the caller's caller.
|
|
192
|
-
if first, lr != 0, craftStrip(lr) != returnAddress, count < craftCrashMaxFrames {
|
|
192
|
+
if first, lr != 0, craftStrip(lr) != returnAddress, craftStrip(lr) != frames[0], count < craftCrashMaxFrames {
|
|
193
193
|
frames[count] = craftStrip(lr); count += 1
|
|
194
194
|
}
|
|
195
195
|
first = false
|
|
@@ -478,7 +478,13 @@ final class CraftCrashReporter: NSObject, MXMetricManagerSubscriber {
|
|
|
478
478
|
let frames = addresses.map { frame(for: $0, in: images) }
|
|
479
479
|
let signalName = Self.signalName(signal)
|
|
480
480
|
let type = exceptionName ?? signalName
|
|
481
|
-
|
|
481
|
+
// A runtime's own words when it trapped on purpose (Swift's "Fatal
|
|
482
|
+
// error: …", an assertion); an abort's first annotation otherwise.
|
|
483
|
+
// Never the simulator's device banner, which some image's
|
|
484
|
+
// __crash_info carries on every simulator process.
|
|
485
|
+
let deliberate = messages.first(where: { $0.localizedCaseInsensitiveContains("fatal error") || $0.contains("Assertion failed") || $0.contains("Precondition failed") })
|
|
486
|
+
let annotation = signal == SIGABRT ? messages.first(where: { !$0.hasPrefix("CoreSimulator") }) : nil
|
|
487
|
+
var message: String = deliberate ?? annotation ?? ""
|
|
482
488
|
if message.isEmpty {
|
|
483
489
|
message = Self.signalDescription(signal, code: code, address: faultAddress)
|
|
484
490
|
}
|
|
@@ -497,7 +503,8 @@ final class CraftCrashReporter: NSObject, MXMetricManagerSubscriber {
|
|
|
497
503
|
event["timestamp"] = Self.iso(crashedAt)
|
|
498
504
|
event["exception"] = exception
|
|
499
505
|
event["breadcrumbs"] = Array(previousCrumbs.suffix(50))
|
|
500
|
-
|
|
506
|
+
let mechanism: String = exception["mechanism"] as? String ?? "signal"
|
|
507
|
+
event["tags"] = ["mechanism": mechanism]
|
|
501
508
|
if let version = previousSession["version"] as? String, let build = previousSession["build"] as? String {
|
|
502
509
|
var contexts = event["contexts"] as? [String: Any] ?? [:]
|
|
503
510
|
var app = contexts["app"] as? [String: Any] ?? [:]
|
|
@@ -645,7 +652,8 @@ final class CraftCrashReporter: NSObject, MXMetricManagerSubscriber {
|
|
|
645
652
|
if let last = self.lastJavaScriptError, last.key == key, Date().timeIntervalSince(last.at) < 5 { return }
|
|
646
653
|
self.lastJavaScriptError = (key, Date())
|
|
647
654
|
var event = self.baseEvent(release: self.release, sessionId: self.sessionId, sessionStart: Self.iso(self.sessionStart))
|
|
648
|
-
|
|
655
|
+
let type: String = name.flatMap { $0.isEmpty ? nil : $0 } ?? "Error"
|
|
656
|
+
event["type"] = type
|
|
649
657
|
event["message"] = message
|
|
650
658
|
if !stack.isEmpty, stack != "undefined" { event["stack"] = stack }
|
|
651
659
|
event["level"] = "error"
|
|
@@ -757,6 +765,11 @@ final class CraftCrashReporter: NSObject, MXMetricManagerSubscriber {
|
|
|
757
765
|
|
|
758
766
|
private func baseEvent(release: String, sessionId: String?, sessionStart: String?) -> [String: Any] {
|
|
759
767
|
let device = UIDevice.current
|
|
768
|
+
let info = Bundle.main.infoDictionary
|
|
769
|
+
let appName: String = info?["CFBundleDisplayName"] as? String ?? info?["CFBundleName"] as? String ?? ""
|
|
770
|
+
// Typed, not inline: against `Any`, `Locale.current.identifier` picks
|
|
771
|
+
// iOS 16's `identifier(_:)` method and stores a function.
|
|
772
|
+
let locale: String = Locale.current.identifier
|
|
760
773
|
var event: [String: Any] = [
|
|
761
774
|
"platform": "ios",
|
|
762
775
|
"release": release,
|
|
@@ -768,7 +781,7 @@ final class CraftCrashReporter: NSObject, MXMetricManagerSubscriber {
|
|
|
768
781
|
"contexts": [
|
|
769
782
|
"app": [
|
|
770
783
|
"id": Bundle.main.bundleIdentifier ?? "",
|
|
771
|
-
"name":
|
|
784
|
+
"name": appName,
|
|
772
785
|
"version": appVersion,
|
|
773
786
|
"build": appBuild,
|
|
774
787
|
],
|
|
@@ -776,7 +789,7 @@ final class CraftCrashReporter: NSObject, MXMetricManagerSubscriber {
|
|
|
776
789
|
"model": Self.deviceModel(),
|
|
777
790
|
"family": device.model,
|
|
778
791
|
"simulator": Self.isSimulator,
|
|
779
|
-
"locale":
|
|
792
|
+
"locale": locale,
|
|
780
793
|
],
|
|
781
794
|
"os": ["name": "iOS", "version": device.systemVersion],
|
|
782
795
|
],
|
|
@@ -789,8 +802,16 @@ final class CraftCrashReporter: NSObject, MXMetricManagerSubscriber {
|
|
|
789
802
|
private var craftVersion: String { "{{CRAFT_VERSION}}" }
|
|
790
803
|
|
|
791
804
|
private func enqueue(_ endpoint: String, _ body: [String: Any]) {
|
|
792
|
-
|
|
793
|
-
|
|
805
|
+
// Through jsonSafe first: a `[String: Any]` built in Swift can hold an
|
|
806
|
+
// Optional (a `??` inferred against `Any`), and a page's event can hold
|
|
807
|
+
// anything at all. Either made the whole event invalid JSON, and it was
|
|
808
|
+
// dropped without a word.
|
|
809
|
+
let item: [String: Any] = ["endpoint": endpoint, "body": Self.jsonSafe(body)]
|
|
810
|
+
guard let outbox, JSONSerialization.isValidJSONObject(item),
|
|
811
|
+
let data = try? JSONSerialization.data(withJSONObject: item) else {
|
|
812
|
+
CraftNativeConsole.write("error", category: "crash-reporter", message: "dropped an \(endpoint) event that is not JSON")
|
|
813
|
+
return
|
|
814
|
+
}
|
|
794
815
|
let name = String(format: "%013.0f-%@.json", Date().timeIntervalSince1970 * 1000, UUID().uuidString)
|
|
795
816
|
try? data.write(to: outbox.appendingPathComponent(name), options: .atomic)
|
|
796
817
|
flush()
|
|
@@ -893,6 +914,49 @@ final class CraftCrashReporter: NSObject, MXMetricManagerSubscriber {
|
|
|
893
914
|
|
|
894
915
|
// MARK: Helpers
|
|
895
916
|
|
|
917
|
+
/// `value` as something JSONSerialization accepts: Optionals unwrapped
|
|
918
|
+
/// (nil is null), integers of every width as numbers, dates as ISO
|
|
919
|
+
/// strings, and anything else as its description.
|
|
920
|
+
static func jsonSafe(_ value: Any) -> Any {
|
|
921
|
+
let mirror = Mirror(reflecting: value)
|
|
922
|
+
if mirror.displayStyle == .optional {
|
|
923
|
+
guard let wrapped = mirror.children.first?.value else { return NSNull() }
|
|
924
|
+
return jsonSafe(wrapped)
|
|
925
|
+
}
|
|
926
|
+
switch value {
|
|
927
|
+
case let dictionary as [String: Any]:
|
|
928
|
+
return dictionary.mapValues { jsonSafe($0) }
|
|
929
|
+
case let dictionary as NSDictionary:
|
|
930
|
+
var out: [String: Any] = [:]
|
|
931
|
+
for (key, item) in dictionary { out[String(describing: key)] = jsonSafe(item) }
|
|
932
|
+
return out
|
|
933
|
+
case let array as [Any]:
|
|
934
|
+
return array.map { jsonSafe($0) }
|
|
935
|
+
case is String, is NSString, is NSNull:
|
|
936
|
+
return value
|
|
937
|
+
case let flag as Bool:
|
|
938
|
+
return flag
|
|
939
|
+
case let number as NSNumber:
|
|
940
|
+
return number
|
|
941
|
+
case let number as UInt64:
|
|
942
|
+
return NSNumber(value: number)
|
|
943
|
+
case let number as Int64:
|
|
944
|
+
return NSNumber(value: number)
|
|
945
|
+
case let number as UInt32:
|
|
946
|
+
return NSNumber(value: number)
|
|
947
|
+
case let number as Int32:
|
|
948
|
+
return NSNumber(value: number)
|
|
949
|
+
case let number as Double:
|
|
950
|
+
return number.isFinite ? NSNumber(value: number) : NSNull()
|
|
951
|
+
case let date as Date:
|
|
952
|
+
return iso(date)
|
|
953
|
+
case let url as URL:
|
|
954
|
+
return url.absoluteString
|
|
955
|
+
default:
|
|
956
|
+
return String(describing: value)
|
|
957
|
+
}
|
|
958
|
+
}
|
|
959
|
+
|
|
896
960
|
private func write(_ object: [String: Any], to name: String) {
|
|
897
961
|
if let data = try? JSONSerialization.data(withJSONObject: object) {
|
|
898
962
|
try? data.write(to: directory.appendingPathComponent(name), options: .atomic)
|