@ansight/react-native 1.3.0-preview.1 → 1.3.0-preview.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.
@@ -139,6 +139,7 @@ final class AnsightReactNative: RCTEventEmitter {
139
139
 
140
140
  private let lock = NSLock()
141
141
  private var hasListeners = false
142
+ private var hostConnectionStatusSubscription: HostConnectionStatusSubscription?
142
143
  private var activeCustomToolIds: Set<String> = []
143
144
  private var pendingToolCalls: [String: PendingToolCall] = [:]
144
145
  private var reactNativeMemorySampler: ReactNativeMemorySamplerBox?
@@ -150,10 +151,14 @@ final class AnsightReactNative: RCTEventEmitter {
150
151
  override init() {
151
152
  super.init()
152
153
  AnsightLogger.registerCallback(logCallback)
154
+ hostConnectionStatusSubscription = AnsightRuntime.shared.addHostConnectionStatusListener { [weak self] status, _ in
155
+ self?.emitHostConnectionStatusEvent(status)
156
+ }
153
157
  }
154
158
 
155
159
  deinit {
156
160
  AnsightLogger.removeCallback(logCallback)
161
+ hostConnectionStatusSubscription?.remove()
157
162
  }
158
163
 
159
164
  override static func requiresMainQueueSetup() -> Bool {
@@ -161,7 +166,7 @@ final class AnsightReactNative: RCTEventEmitter {
161
166
  }
162
167
 
163
168
  override func supportedEvents() -> [String]! {
164
- ["AnsightToolCall", "AnsightLog"]
169
+ ["AnsightToolCall", "AnsightLog", "AnsightHostConnectionStatus"]
165
170
  }
166
171
 
167
172
  override func startObserving() {
@@ -292,6 +297,52 @@ final class AnsightReactNative: RCTEventEmitter {
292
297
  }
293
298
  }
294
299
 
300
+ @objc(recordNetworkRequest:resolver:rejecter:)
301
+ func recordNetworkRequest(
302
+ _ input: NSDictionary,
303
+ resolver resolve: @escaping RCTPromiseResolveBlock,
304
+ rejecter reject: RCTPromiseRejectBlock
305
+ ) {
306
+ guard JSONSerialization.isValidJSONObject(input),
307
+ let data = try? JSONSerialization.data(withJSONObject: input),
308
+ let request = try? JSONDecoder().decode(AnsightNetworkRequest.self, from: data),
309
+ request.schema == AnsightNetworkRequest.schemaName
310
+ else {
311
+ resolve(operationResultDictionary(
312
+ .failure("Network request must use the ansight.network-request.v1 schema.")
313
+ ))
314
+ return
315
+ }
316
+ Task {
317
+ resolve(operationResultDictionary(await AnsightRuntime.shared.recordNetworkRequest(request)))
318
+ }
319
+ }
320
+
321
+ @objc(recordCrashCandidate:resolver:rejecter:)
322
+ func recordCrashCandidate(
323
+ _ input: NSDictionary,
324
+ resolver resolve: RCTPromiseResolveBlock,
325
+ rejecter reject: RCTPromiseRejectBlock
326
+ ) {
327
+ let metadata: [String: String]
328
+ if let metadataJson = stringValue(input, "metadata"),
329
+ let data = metadataJson.data(using: .utf8),
330
+ let decoded = try? JSONDecoder().decode([String: String].self, from: data) {
331
+ metadata = decoded
332
+ } else {
333
+ metadata = [:]
334
+ }
335
+ let candidateId = AnsightRuntime.shared.recordCrashCandidate(
336
+ runtime: stringValue(input, "runtime") ?? "react-native-javascript",
337
+ kind: stringValue(input, "kind") ?? "unhandled_javascript_error",
338
+ message: stringValue(input, "message"),
339
+ stack: stringValue(input, "stack"),
340
+ fatal: boolValue(input, "fatal", defaultValue: false),
341
+ metadata: metadata
342
+ )
343
+ resolve(candidateId.map { ["candidateId": $0] } ?? [:])
344
+ }
345
+
295
346
  @objc(screenViewed:details:resolver:rejecter:)
296
347
  func screenViewed(
297
348
  _ name: NSString,
@@ -834,6 +885,17 @@ final class AnsightReactNative: RCTEventEmitter {
834
885
  }
835
886
  }
836
887
 
888
+ private func emitHostConnectionStatusEvent(_ status: HostConnectionStatus) {
889
+ let shouldEmit = lock.withLock { hasListeners }
890
+ guard shouldEmit else { return }
891
+ DispatchQueue.main.async {
892
+ self.sendEvent(
893
+ withName: "AnsightHostConnectionStatus",
894
+ body: self.hostConnectionStatusDictionary(status)
895
+ )
896
+ }
897
+ }
898
+
837
899
  private func configureReactNativeMemoryProfiling(_ dictionary: NSDictionary?) throws {
838
900
  let options = ReactNativeMemoryProfilingOptions(dictionary: dictionary)
839
901
  currentReactNativeMemoryOptions = options
@@ -895,6 +957,13 @@ final class AnsightReactNative: RCTEventEmitter {
895
957
  if hasBool(dictionary, "enableBatteryLevel") {
896
958
  options.enableBatteryLevel = boolValue(dictionary, "enableBatteryLevel", defaultValue: options.enableBatteryLevel)
897
959
  }
960
+ if hasBool(dictionary, "enableOpenFileHandleTracking") {
961
+ options.enableOpenFileHandleTracking = boolValue(
962
+ dictionary,
963
+ "enableOpenFileHandleTracking",
964
+ defaultValue: options.enableOpenFileHandleTracking
965
+ )
966
+ }
898
967
  if let memory = dictionary?["defaultMemoryChannels"] as? NSDictionary {
899
968
  var channels: DefaultMemoryChannels = []
900
969
  if boolValue(memory, "managedHeap", defaultValue: boolValue(memory, "javaHeap", defaultValue: false)) {
@@ -942,9 +1011,14 @@ final class AnsightReactNative: RCTEventEmitter {
942
1011
  "captureGpuBackedSurfaces",
943
1012
  defaultValue: AnsightSessionJpegCaptureOptions.defaultCaptureGpuBackedSurfaces
944
1013
  ),
945
- mode: stringValue(jpeg, "mode") == "screenshotAndVisualTree"
946
- ? .screenshotAndVisualTree
947
- : .screenshotOnly
1014
+ mode: AnsightSessionJpegCaptureMode(
1015
+ rawValue: stringValue(jpeg, "mode") ?? ""
1016
+ ) ?? .screenshotOnly,
1017
+ captureKeyboardPresence: boolValue(
1018
+ jpeg,
1019
+ "captureKeyboardPresence",
1020
+ defaultValue: AnsightSessionJpegCaptureOptions.defaultCaptureKeyboardPresence
1021
+ )
948
1022
  )
949
1023
  }
950
1024
  }
@@ -960,6 +1034,21 @@ final class AnsightReactNative: RCTEventEmitter {
960
1034
  )
961
1035
  }
962
1036
  }
1037
+ if let raw = dictionary?["crashCapture"] {
1038
+ if (raw as? Bool) == false {
1039
+ options.crashCapture.enabled = false
1040
+ } else if let crash = raw as? NSDictionary {
1041
+ options.crashCapture = AnsightCrashCaptureOptions(
1042
+ enabled: boolValue(crash, "enabled", defaultValue: true),
1043
+ studioHandoffEnabled: boolValue(crash, "studioHandoffEnabled", defaultValue: true),
1044
+ offlineCaptureAttachmentEnabled: boolValue(crash, "offlineCaptureAttachmentEnabled", defaultValue: true),
1045
+ maximumPendingReports: intValue(crash, "maximumPendingReports", defaultValue: 8),
1046
+ retentionDays: intValue(crash, "retentionDays", defaultValue: 7),
1047
+ maximumBreadcrumbs: intValue(crash, "maximumBreadcrumbs", defaultValue: 64),
1048
+ maximumTraceBytes: intValue(crash, "maximumTraceBytes", defaultValue: 1_048_576)
1049
+ )
1050
+ }
1051
+ }
963
1052
  if let lifecycle = dictionary?["lifecycleCapture"] as? NSDictionary {
964
1053
  options.lifecycleCapture = AnsightLifecycleCaptureOptions(
965
1054
  enabled: boolValue(lifecycle, "enabled", defaultValue: options.lifecycleCapture.enabled),
@@ -1271,9 +1360,14 @@ final class AnsightReactNative: RCTEventEmitter {
1271
1360
  "captureGpuBackedSurfaces",
1272
1361
  defaultValue: AnsightSessionJpegCaptureOptions.defaultCaptureGpuBackedSurfaces
1273
1362
  ),
1274
- mode: stringValue(dictionary, "mode") == "screenshotAndVisualTree"
1275
- ? .screenshotAndVisualTree
1276
- : .screenshotOnly
1363
+ mode: AnsightSessionJpegCaptureMode(
1364
+ rawValue: stringValue(dictionary, "mode") ?? ""
1365
+ ) ?? .screenshotOnly,
1366
+ captureKeyboardPresence: boolValue(
1367
+ dictionary,
1368
+ "captureKeyboardPresence",
1369
+ defaultValue: AnsightSessionJpegCaptureOptions.defaultCaptureKeyboardPresence
1370
+ )
1277
1371
  )
1278
1372
  }
1279
1373
 
@@ -1283,6 +1377,8 @@ final class AnsightReactNative: RCTEventEmitter {
1283
1377
  "retentionPeriodSeconds": options.retentionPeriodSeconds,
1284
1378
  "enableFramesPerSecond": options.enableFramesPerSecond,
1285
1379
  "enableBatteryLevel": options.enableBatteryLevel,
1380
+ "enableOpenFileHandleTracking": options.enableOpenFileHandleTracking,
1381
+ "enableJniReferenceCountTracking": false,
1286
1382
  "defaultMemoryChannels": [
1287
1383
  "managedHeap": options.defaultMemoryChannels.contains(.managedHeap),
1288
1384
  "javaHeap": options.defaultMemoryChannels.contains(.managedHeap),
@@ -1322,6 +1418,7 @@ final class AnsightReactNative: RCTEventEmitter {
1322
1418
  "quality": capture.quality,
1323
1419
  "maxWidth": capture.maxWidth as Any,
1324
1420
  "captureGpuBackedSurfaces": capture.captureGpuBackedSurfaces,
1421
+ "captureKeyboardPresence": capture.captureKeyboardPresence,
1325
1422
  "mode": capture.mode.rawValue,
1326
1423
  ]
1327
1424
  } else {
@@ -33,6 +33,14 @@ RCT_EXTERN_METHOD(recordEvent:(NSDictionary *)input
33
33
  resolver:(RCTPromiseResolveBlock)resolve
34
34
  rejecter:(RCTPromiseRejectBlock)reject)
35
35
 
36
+ RCT_EXTERN_METHOD(recordNetworkRequest:(NSDictionary *)input
37
+ resolver:(RCTPromiseResolveBlock)resolve
38
+ rejecter:(RCTPromiseRejectBlock)reject)
39
+
40
+ RCT_EXTERN_METHOD(recordCrashCandidate:(NSDictionary *)input
41
+ resolver:(RCTPromiseResolveBlock)resolve
42
+ rejecter:(RCTPromiseRejectBlock)reject)
43
+
36
44
  RCT_EXTERN_METHOD(screenViewed:(NSString *)name
37
45
  details:(NSDictionary *)details
38
46
  resolver:(RCTPromiseResolveBlock)resolve