@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.
package/index.js CHANGED
@@ -10,6 +10,15 @@ const {
10
10
  findNodeHandle,
11
11
  processColor,
12
12
  } = require("react-native");
13
+ const { version: reactVersion } = require("react");
14
+ const {
15
+ createAutomaticSessionProperties,
16
+ mergeSessionProperties,
17
+ } = require("./session-properties");
18
+ const {
19
+ installNetworkCapture: installNetworkCaptureCore,
20
+ sanitizeNetworkRequest,
21
+ } = require("./network");
13
22
 
14
23
  const nativeModule = NativeModules.AnsightReactNative;
15
24
 
@@ -33,6 +42,9 @@ const hostConnectionStatusListeners = new Set();
33
42
  let lastHostConnectionStatusKey = null;
34
43
  const logListeners = new Set();
35
44
  let logEventSubscription = null;
45
+ let networkCaptureSubscription = null;
46
+ let networkCaptureRegistration = null;
47
+ let networkConnectionEventSubscription = null;
36
48
  const REACT_COMPONENT_TREE_TOOL_ID = "react.get_component_tree";
37
49
  const REACT_SHADOW_TREE_TOOL_ID = "react.get_shadow_tree";
38
50
 
@@ -44,7 +56,28 @@ function normalizePairingPayload(payload) {
44
56
  }
45
57
 
46
58
  function normalizeOptions(options = {}) {
47
- return { ...options };
59
+ const normalized = {
60
+ ...options,
61
+ customProperties: mergeSessionProperties(
62
+ automaticSessionProperties(),
63
+ options.customProperties
64
+ ),
65
+ };
66
+ delete normalized.networkCapture;
67
+ return normalized;
68
+ }
69
+
70
+ function automaticSessionProperties() {
71
+ return createAutomaticSessionProperties({
72
+ platform: Platform,
73
+ reactVersion,
74
+ runtimeGlobal: global,
75
+ developmentMode: typeof __DEV__ !== "undefined" && __DEV__,
76
+ });
77
+ }
78
+
79
+ function automaticSessionPropertyValue(group, key) {
80
+ return automaticSessionProperties()[group]?.[key];
48
81
  }
49
82
 
50
83
  function cloneOptions(options = {}) {
@@ -61,6 +94,9 @@ function cloneOptions(options = {}) {
61
94
  if (options.touchCapture && typeof options.touchCapture === "object") {
62
95
  clone.touchCapture = { ...options.touchCapture };
63
96
  }
97
+ if (options.crashCapture && typeof options.crashCapture === "object") {
98
+ clone.crashCapture = { ...options.crashCapture };
99
+ }
64
100
  if (options.lifecycleCapture) {
65
101
  clone.lifecycleCapture = { ...options.lifecycleCapture };
66
102
  }
@@ -70,6 +106,17 @@ function cloneOptions(options = {}) {
70
106
  if (options.hostConnection) {
71
107
  clone.hostConnection = { ...options.hostConnection };
72
108
  }
109
+ if (options.networkCapture && typeof options.networkCapture === "object") {
110
+ clone.networkCapture = {
111
+ ...options.networkCapture,
112
+ additionalSensitiveHeaderNames: options.networkCapture.additionalSensitiveHeaderNames
113
+ ? [...options.networkCapture.additionalSensitiveHeaderNames]
114
+ : undefined,
115
+ additionalSensitiveQueryParameterNames: options.networkCapture.additionalSensitiveQueryParameterNames
116
+ ? [...options.networkCapture.additionalSensitiveQueryParameterNames]
117
+ : undefined,
118
+ };
119
+ }
73
120
  if (options.secureStorage) {
74
121
  clone.secureStorage = {
75
122
  ...options.secureStorage,
@@ -157,6 +204,8 @@ class AnsightOptionsBuilder {
157
204
  retentionPeriodSeconds: 120,
158
205
  enableFramesPerSecond: true,
159
206
  enableBatteryLevel: false,
207
+ enableOpenFileHandleTracking: false,
208
+ enableJniReferenceCountTracking: false,
160
209
  sessionJpegCapture: {
161
210
  intervalMilliseconds: 2000,
162
211
  quality: 60,
@@ -209,6 +258,26 @@ class AnsightOptionsBuilder {
209
258
  return this;
210
259
  }
211
260
 
261
+ withOpenFileHandleTracking() {
262
+ this._options.enableOpenFileHandleTracking = true;
263
+ return this;
264
+ }
265
+
266
+ withoutOpenFileHandleTracking() {
267
+ this._options.enableOpenFileHandleTracking = false;
268
+ return this;
269
+ }
270
+
271
+ withJniReferenceCountTracking() {
272
+ this._options.enableJniReferenceCountTracking = true;
273
+ return this;
274
+ }
275
+
276
+ withoutJniReferenceCountTracking() {
277
+ this._options.enableJniReferenceCountTracking = false;
278
+ return this;
279
+ }
280
+
212
281
  withRetentionPeriodSeconds(retentionPeriodSeconds) {
213
282
  this._options.retentionPeriodSeconds = retentionPeriodSeconds;
214
283
  return this;
@@ -269,6 +338,7 @@ class AnsightOptionsBuilder {
269
338
  maxWidth: arguments.length > 2 ? arguments[2] : 480,
270
339
  captureGpuBackedSurfaces: arguments.length > 3 ? arguments[3] : true,
271
340
  mode: arguments.length > 4 ? arguments[4] : "screenshotOnly",
341
+ captureKeyboardPresence: arguments.length > 5 ? arguments[5] : false,
272
342
  };
273
343
  return this;
274
344
  }
@@ -276,6 +346,7 @@ class AnsightOptionsBuilder {
276
346
  intervalMilliseconds: 2000,
277
347
  quality: 60,
278
348
  maxWidth: 480,
349
+ captureKeyboardPresence: false,
279
350
  mode: "screenshotOnly",
280
351
  ...(optionsOrIntervalMilliseconds || {}),
281
352
  };
@@ -297,11 +368,67 @@ class AnsightOptionsBuilder {
297
368
  return this;
298
369
  }
299
370
 
371
+ withCrashCapture(crashCapture = {}) {
372
+ this._options.crashCapture = { ...crashCapture, enabled: true };
373
+ return this;
374
+ }
375
+
376
+ withoutCrashCapture() {
377
+ this._options.crashCapture = false;
378
+ return this;
379
+ }
380
+
300
381
  withLifecycleCapture(lifecycleCapture = {}) {
301
382
  this._options.lifecycleCapture = { ...lifecycleCapture };
302
383
  return this;
303
384
  }
304
385
 
386
+ withNetworkCapture(networkCapture = {}) {
387
+ this._options.networkCapture = { ...networkCapture };
388
+ return this;
389
+ }
390
+
391
+ withNetworkRequestBodies(maximumBodyBytes) {
392
+ if (!this._options.networkCapture || typeof this._options.networkCapture !== "object") return this;
393
+ const current = this._options.networkCapture;
394
+ this._options.networkCapture = {
395
+ ...current,
396
+ captureRequestBody: true,
397
+ ...(maximumBodyBytes == null ? {} : { maximumBodyBytes }),
398
+ };
399
+ return this;
400
+ }
401
+
402
+ withoutNetworkRequestBodies() {
403
+ if (!this._options.networkCapture || typeof this._options.networkCapture !== "object") return this;
404
+ const current = this._options.networkCapture;
405
+ this._options.networkCapture = { ...current, captureRequestBody: false };
406
+ return this;
407
+ }
408
+
409
+ withNetworkResponseBodies(maximumBodyBytes) {
410
+ if (!this._options.networkCapture || typeof this._options.networkCapture !== "object") return this;
411
+ const current = this._options.networkCapture;
412
+ this._options.networkCapture = {
413
+ ...current,
414
+ captureResponseBody: true,
415
+ ...(maximumBodyBytes == null ? {} : { maximumBodyBytes }),
416
+ };
417
+ return this;
418
+ }
419
+
420
+ withoutNetworkResponseBodies() {
421
+ if (!this._options.networkCapture || typeof this._options.networkCapture !== "object") return this;
422
+ const current = this._options.networkCapture;
423
+ this._options.networkCapture = { ...current, captureResponseBody: false };
424
+ return this;
425
+ }
426
+
427
+ withoutNetworkCapture() {
428
+ this._options.networkCapture = false;
429
+ return this;
430
+ }
431
+
305
432
  withToolGuard(toolGuard) {
306
433
  this._options.toolGuard = toolGuard;
307
434
  return this;
@@ -544,6 +671,7 @@ function addHostConnectionStatusListener(listener, options = {}) {
544
671
 
545
672
  async function notifyAfterHostConnectionChange(operation) {
546
673
  const result = await operation();
674
+ await refreshNetworkCaptureConnection();
547
675
  await emitHostConnectionStatusChangedIfNeeded();
548
676
  return result;
549
677
  }
@@ -1391,7 +1519,7 @@ function summarizeProps(props) {
1391
1519
  }
1392
1520
  const keys = Object.keys(props).filter((key) => key !== "children");
1393
1521
  const summary = { keys };
1394
- ["testID", "nativeID", "accessibilityLabel", "role"].forEach((key) => {
1522
+ ["testID", "nativeID", "accessibilityLabel", "accessibilityRole", "role"].forEach((key) => {
1395
1523
  if (props[key] != null && !isSensitiveKey(key)) {
1396
1524
  summary[key] = String(props[key]);
1397
1525
  }
@@ -1403,6 +1531,42 @@ function summarizeProps(props) {
1403
1531
  return summary;
1404
1532
  }
1405
1533
 
1534
+ function reactSemanticRole(type, props, fiberTag) {
1535
+ const declared = props && (props.accessibilityRole || props.role);
1536
+ if (declared) return String(declared).toLowerCase();
1537
+ if (fiberTag === 6 || /text/i.test(type)) return "text";
1538
+ if (/button|pressable|touchable/i.test(type)) return "button";
1539
+ if (/textinput/i.test(type)) return "textbox";
1540
+ if (/switch/i.test(type)) return "switch";
1541
+ if (/scrollview|flatlist|sectionlist/i.test(type)) return "scrollview";
1542
+ return "view";
1543
+ }
1544
+
1545
+ function reactSupportedActions(type, props) {
1546
+ const actions = [];
1547
+ if (props && typeof props.onPress === "function") actions.push("tap");
1548
+ if (props && (typeof props.onChangeText === "function" || /textinput/i.test(type))) {
1549
+ actions.push("typeText", "focus");
1550
+ }
1551
+ if (/scrollview|flatlist|sectionlist/i.test(type) || (props && typeof props.onScroll === "function")) {
1552
+ actions.push("scroll", "swipe");
1553
+ }
1554
+ return actions;
1555
+ }
1556
+
1557
+ function applyReactTargetability(node, fiber, props, type) {
1558
+ const style = StyleSheet && typeof StyleSheet.flatten === "function"
1559
+ ? StyleSheet.flatten(props && props.style)
1560
+ : props && props.style;
1561
+ node.text = node.label || (node.visual && node.visual.text) || null;
1562
+ node.role = reactSemanticRole(type, props, fiber.tag);
1563
+ node.supportedActions = reactSupportedActions(type, props);
1564
+ node.visible = !(style && style.display === "none") && !(props && props.accessibilityElementsHidden);
1565
+ node.enabled = !(props && (props.disabled === true || props.accessibilityState && props.accessibilityState.disabled === true));
1566
+ node.focusable = !!(props && props.focusable) || node.supportedActions.includes("focus");
1567
+ node.interactable = node.visible && node.enabled && node.supportedActions.length > 0;
1568
+ }
1569
+
1406
1570
  function reactColorToArgbHex(value) {
1407
1571
  if (value == null) {
1408
1572
  return undefined;
@@ -1453,6 +1617,28 @@ function createReactVisual(fiber, props, maxStringLength) {
1453
1617
  return visual;
1454
1618
  }
1455
1619
 
1620
+ function createReactZIndex(props) {
1621
+ const style = StyleSheet && typeof StyleSheet.flatten === "function"
1622
+ ? StyleSheet.flatten(props && props.style)
1623
+ : props && props.style;
1624
+ const zIndex = style && style.zIndex != null ? Number(style.zIndex) : NaN;
1625
+ const elevation = style && style.elevation != null ? Number(style.elevation) : NaN;
1626
+ if (Number.isFinite(zIndex) && zIndex !== 0) return zIndex;
1627
+ if (Number.isFinite(elevation) && elevation !== 0) return elevation;
1628
+ return null;
1629
+ }
1630
+
1631
+ function registerReactType(context, typeName) {
1632
+ const normalizedTypeName = String(typeName || "UnknownComponent").trim() || "UnknownComponent";
1633
+ const existingTypeId = context.typeIdsByName.get(normalizedTypeName);
1634
+ if (existingTypeId != null) return existingTypeId;
1635
+
1636
+ const typeId = context.types.length;
1637
+ context.types.push(normalizedTypeName);
1638
+ context.typeIdsByName.set(normalizedTypeName, typeId);
1639
+ return typeId;
1640
+ }
1641
+
1456
1642
  function nativeTagForFiber(fiber) {
1457
1643
  const stateNode = fiber && fiber.stateNode;
1458
1644
  if (!stateNode) {
@@ -1524,17 +1710,17 @@ function serializeFiber(fiber, context, depth) {
1524
1710
 
1525
1711
  const props = fiber.memoizedProps || fiber.pendingProps || {};
1526
1712
  const type = reactFiberTypeName(fiber);
1527
- const kind = reactFiberKind(fiber.tag);
1528
1713
  const node = {
1529
1714
  id: reactFiberId(fiber),
1530
- type,
1531
- kind,
1715
+ typeId: registerReactType(context, type),
1532
1716
  tag: fiber.tag,
1533
1717
  key: fiber.key == null ? null : String(fiber.key),
1534
1718
  depth,
1535
1719
  visual: createReactVisual(fiber, props, context.maxStringLength),
1536
1720
  children: [],
1537
1721
  };
1722
+ const zIndex = createReactZIndex(props);
1723
+ if (zIndex != null) node.z = zIndex;
1538
1724
 
1539
1725
  if (fiber._debugSource) {
1540
1726
  node.source = {
@@ -1546,7 +1732,7 @@ function serializeFiber(fiber, context, depth) {
1546
1732
 
1547
1733
  const owner = fiber._debugOwner && reactFiberTypeName(fiber._debugOwner);
1548
1734
  if (owner) {
1549
- node.owner = owner;
1735
+ node.ownerTypeId = registerReactType(context, owner);
1550
1736
  }
1551
1737
 
1552
1738
  const nativeTag = nativeTagForFiber(fiber);
@@ -1577,6 +1763,8 @@ function serializeFiber(fiber, context, depth) {
1577
1763
  node.state = sanitizeValue(fiber.memoizedState, context);
1578
1764
  }
1579
1765
 
1766
+ applyReactTargetability(node, fiber, props, type);
1767
+
1580
1768
  if (depth < context.maxDepth) {
1581
1769
  let child = fiber.child;
1582
1770
  while (child) {
@@ -1600,16 +1788,18 @@ function isShadowTreeFiber(fiber) {
1600
1788
 
1601
1789
  function createShadowTreeNode(fiber, context, depth) {
1602
1790
  const props = fiber.memoizedProps || fiber.pendingProps || {};
1791
+ const type = reactFiberTypeName(fiber);
1603
1792
  const node = {
1604
1793
  id: reactFiberId(fiber),
1605
- type: reactFiberTypeName(fiber),
1606
- kind: fiber.tag === 3 ? "root" : fiber.tag === 6 ? "text" : "host",
1794
+ typeId: registerReactType(context, type),
1607
1795
  tag: fiber.tag,
1608
1796
  key: fiber.key == null ? null : String(fiber.key),
1609
1797
  depth,
1610
1798
  visual: createReactVisual(fiber, props, context.maxStringLength),
1611
1799
  children: [],
1612
1800
  };
1801
+ const zIndex = createReactZIndex(props);
1802
+ if (zIndex != null) node.z = zIndex;
1613
1803
 
1614
1804
  const nativeTag = nativeTagForFiber(fiber);
1615
1805
  if (nativeTag != null) {
@@ -1635,6 +1825,8 @@ function createShadowTreeNode(fiber, context, depth) {
1635
1825
  }
1636
1826
  }
1637
1827
 
1828
+ applyReactTargetability(node, fiber, props, type);
1829
+
1638
1830
  return node;
1639
1831
  }
1640
1832
 
@@ -1691,19 +1883,21 @@ async function captureReactVisualTree(rawOptions = {}) {
1691
1883
  maxStringLength: rawOptions.maxStringLength || 180,
1692
1884
  maxValueDepth: rawOptions.maxValueDepth || 2,
1693
1885
  nodesWithNativeTags: [],
1886
+ typeIdsByName: new Map(),
1887
+ types: [],
1694
1888
  count: 0,
1695
1889
  truncated: false,
1696
1890
  visited: new Set(),
1697
1891
  };
1698
1892
  const roots = getReactRoots();
1699
- const rootNodes = roots.roots.map((root, index) => {
1893
+ const rootNodes = roots.roots.map((root) => {
1700
1894
  const node = serializeFiber(root.fiber, context, 0);
1701
1895
  if (node) {
1702
1896
  node.rendererId = root.rendererId;
1703
- node.rootIndex = index;
1704
1897
  }
1705
1898
  return node;
1706
1899
  }).filter(Boolean);
1900
+ const rootTypeId = registerReactType(context, "ReactRoots");
1707
1901
 
1708
1902
  if (includeBounds && context.nodesWithNativeTags.length > 0) {
1709
1903
  await Promise.all(context.nodesWithNativeTags.slice(0, 300).map(async (node) => {
@@ -1715,6 +1909,7 @@ async function captureReactVisualTree(rawOptions = {}) {
1715
1909
  }
1716
1910
 
1717
1911
  return {
1912
+ format: "ansight.react.visual-tree.compact.v2",
1718
1913
  platform: Platform.OS,
1719
1914
  source: "react",
1720
1915
  adapter: "react.fiber",
@@ -1724,11 +1919,11 @@ async function captureReactVisualTree(rawOptions = {}) {
1724
1919
  renderers: roots.renderers,
1725
1920
  root: {
1726
1921
  id: "react:roots",
1727
- type: "ReactRoots",
1728
- kind: "container",
1922
+ typeId: rootTypeId,
1923
+ childCount: rootNodes.length,
1729
1924
  children: rootNodes,
1730
1925
  },
1731
- roots: rootNodes,
1926
+ types: context.types,
1732
1927
  nodeCount: context.count,
1733
1928
  truncated: context.truncated,
1734
1929
  unavailableReason: roots.hookAvailable ? undefined : "React DevTools global hook is not available in this runtime.",
@@ -1748,19 +1943,21 @@ async function captureReactShadowTree(rawOptions = {}) {
1748
1943
  maxStringLength: rawOptions.maxStringLength || 180,
1749
1944
  maxValueDepth: rawOptions.maxValueDepth || 2,
1750
1945
  nodesWithNativeTags: [],
1946
+ typeIdsByName: new Map(),
1947
+ types: [],
1751
1948
  count: 0,
1752
1949
  truncated: false,
1753
1950
  visited: new Set(),
1754
1951
  };
1755
1952
  const roots = getReactRoots();
1756
- const rootNodes = roots.roots.flatMap((root, index) => {
1953
+ const rootNodes = roots.roots.flatMap((root) => {
1757
1954
  const nodes = serializeShadowFiber(root.fiber, context, 0);
1758
1955
  nodes.forEach((node) => {
1759
1956
  node.rendererId = root.rendererId;
1760
- node.rootIndex = index;
1761
1957
  });
1762
1958
  return nodes;
1763
1959
  });
1960
+ const rootTypeId = registerReactType(context, "ReactNativeShadowRoots");
1764
1961
 
1765
1962
  if (includeBounds && context.nodesWithNativeTags.length > 0) {
1766
1963
  await Promise.all(context.nodesWithNativeTags.slice(0, 300).map(async (node) => {
@@ -1772,6 +1969,7 @@ async function captureReactShadowTree(rawOptions = {}) {
1772
1969
  }
1773
1970
 
1774
1971
  return {
1972
+ format: "ansight.react.visual-tree.compact.v2",
1775
1973
  platform: Platform.OS,
1776
1974
  source: "react-native",
1777
1975
  adapter: "react-native.host-fiber",
@@ -1781,11 +1979,11 @@ async function captureReactShadowTree(rawOptions = {}) {
1781
1979
  renderers: roots.renderers,
1782
1980
  root: {
1783
1981
  id: "react:shadow-roots",
1784
- type: "ReactNativeShadowRoots",
1785
- kind: "container",
1982
+ typeId: rootTypeId,
1983
+ childCount: rootNodes.length,
1786
1984
  children: rootNodes,
1787
1985
  },
1788
- roots: rootNodes,
1986
+ types: context.types,
1789
1987
  nodeCount: context.count,
1790
1988
  truncated: context.truncated,
1791
1989
  unavailableReason: roots.hookAvailable ? undefined : "React DevTools global hook is not available in this runtime.",
@@ -1801,13 +1999,18 @@ function flattenReactTree(node, output = []) {
1801
1999
  return output;
1802
2000
  }
1803
2001
 
1804
- function nodeSearchText(node) {
2002
+ function createReactNodeSnapshot(node) {
2003
+ const snapshot = { ...node };
2004
+ delete snapshot.children;
2005
+ return snapshot;
2006
+ }
2007
+
2008
+ function nodeSearchText(node, types) {
1805
2009
  return [
1806
2010
  node.id,
1807
- node.type,
1808
- node.kind,
2011
+ types[node.typeId],
1809
2012
  node.label,
1810
- node.owner,
2013
+ types[node.ownerTypeId],
1811
2014
  node.propsSummary && node.propsSummary.testID,
1812
2015
  node.propsSummary && node.propsSummary.nativeID,
1813
2016
  node.propsSummary && node.propsSummary.accessibilityLabel,
@@ -1815,14 +2018,14 @@ function nodeSearchText(node) {
1815
2018
  ].filter(Boolean).join(" ").toLowerCase();
1816
2019
  }
1817
2020
 
1818
- function matchesReactNode(node, args) {
2021
+ function matchesReactNode(node, args, types) {
1819
2022
  const query = args.query ? String(args.query).toLowerCase() : null;
1820
2023
  const type = args.type ? String(args.type).toLowerCase() : null;
1821
2024
  const testID = args.testID ? String(args.testID).toLowerCase() : null;
1822
2025
  const text = args.text ? String(args.text).toLowerCase() : null;
1823
- const searchText = nodeSearchText(node);
2026
+ const searchText = nodeSearchText(node, types);
1824
2027
  return (!query || searchText.includes(query)) &&
1825
- (!type || String(node.type || "").toLowerCase().includes(type)) &&
2028
+ (!type || String(types[node.typeId] || "").toLowerCase().includes(type)) &&
1826
2029
  (!testID || String((node.propsSummary && node.propsSummary.testID) || "").toLowerCase() === testID) &&
1827
2030
  (!text || searchText.includes(text));
1828
2031
  }
@@ -2043,12 +2246,14 @@ function installReactTools(options = {}) {
2043
2246
  });
2044
2247
  const maxResults = parseInteger(args.maxResults, 50, 1, 500);
2045
2248
  const matches = flattenReactTree(tree.root)
2046
- .filter((node) => node.id !== "react:roots" && matchesReactNode(node, args))
2047
- .slice(0, maxResults);
2249
+ .filter((node) => node.id !== "react:roots" && matchesReactNode(node, args, tree.types))
2250
+ .slice(0, maxResults)
2251
+ .map(createReactNodeSnapshot);
2048
2252
  return {
2049
2253
  success: tree.hookAvailable,
2050
2254
  message: `Found ${matches.length} React component(s).`,
2051
2255
  result: {
2256
+ types: tree.types,
2052
2257
  matches,
2053
2258
  count: matches.length,
2054
2259
  truncated: matches.length === maxResults,
@@ -2060,7 +2265,11 @@ function installReactTools(options = {}) {
2060
2265
  const tree = await captureReactVisualTree(reactToolOptions(options, args));
2061
2266
  const node = flattenReactTree(tree.root).find((candidate) => candidate.id === args.nodeId);
2062
2267
  return node
2063
- ? { success: true, message: "React component captured.", result: node }
2268
+ ? {
2269
+ success: true,
2270
+ message: "React component captured.",
2271
+ result: { types: tree.types, node: createReactNodeSnapshot(node) },
2272
+ }
2064
2273
  : { success: false, message: `React component '${args.nodeId}' was not found.`, errorCode: "react_component_not_found" };
2065
2274
  }
2066
2275
 
@@ -2101,7 +2310,7 @@ function installReactTools(options = {}) {
2101
2310
  result: {
2102
2311
  nodeId: args.nodeId,
2103
2312
  prop,
2104
- type: node.type,
2313
+ type: tree.types[node.typeId],
2105
2314
  },
2106
2315
  };
2107
2316
  }
@@ -2137,6 +2346,14 @@ function installErrorHandlers(options = {}) {
2137
2346
 
2138
2347
  if (global.ErrorUtils && global.ErrorUtils.setGlobalHandler) {
2139
2348
  global.ErrorUtils.setGlobalHandler((error, isFatal) => {
2349
+ nativeModule.recordCrashCandidate({
2350
+ runtime: "react-native-javascript",
2351
+ kind: "unhandled_javascript_error",
2352
+ message: error && error.message,
2353
+ stack: error && error.stack,
2354
+ fatal: !!isFatal,
2355
+ metadata: JSON.stringify({ name: error && error.name }),
2356
+ }).catch(() => {});
2140
2357
  nativeModule.recordEvent({
2141
2358
  label: error && error.message ? error.message : "Unhandled JavaScript error",
2142
2359
  type: "Exception",
@@ -2159,6 +2376,13 @@ function installErrorHandlers(options = {}) {
2159
2376
  global.__ansightUnhandledRejectionTrackingInstalled = true;
2160
2377
  global.addEventListener("unhandledrejection", (event) => {
2161
2378
  const reason = event && event.reason;
2379
+ nativeModule.recordCrashCandidate({
2380
+ runtime: "react-native-javascript",
2381
+ kind: "unhandled_promise_rejection",
2382
+ message: reason && reason.message ? reason.message : String(reason),
2383
+ stack: reason && reason.stack,
2384
+ fatal: false,
2385
+ }).catch(() => {});
2162
2386
  nativeModule.recordEvent({
2163
2387
  label: reason && reason.message ? reason.message : "Unhandled JavaScript promise rejection",
2164
2388
  type: "Exception",
@@ -2180,6 +2404,7 @@ function installErrorHandlers(options = {}) {
2180
2404
 
2181
2405
  async function initialize(options = {}) {
2182
2406
  const result = await nativeModule.initialize(normalizeOptions(options));
2407
+ await configureNetworkCapture(options.networkCapture);
2183
2408
  if (options.lifecycle !== false) {
2184
2409
  startAppStateTracking();
2185
2410
  }
@@ -2189,6 +2414,7 @@ async function initialize(options = {}) {
2189
2414
 
2190
2415
  async function initializeAndActivate(options = {}) {
2191
2416
  const result = await nativeModule.initializeAndActivate(normalizeOptions(options));
2417
+ await configureNetworkCapture(options.networkCapture);
2192
2418
  if (options.lifecycle !== false) {
2193
2419
  startAppStateTracking();
2194
2420
  }
@@ -2253,6 +2479,103 @@ function recordEvent(input) {
2253
2479
  return nativeModule.recordEvent(input || {});
2254
2480
  }
2255
2481
 
2482
+ function recordCrashCandidate(input = {}) {
2483
+ const metadata = input.metadata && typeof input.metadata === "object"
2484
+ ? JSON.stringify(input.metadata)
2485
+ : input.metadata;
2486
+ return nativeModule.recordCrashCandidate({
2487
+ ...input,
2488
+ metadata,
2489
+ });
2490
+ }
2491
+
2492
+ function recordNetworkRequest(input, sanitizationOptions = {}) {
2493
+ const sanitized = sanitizeNetworkRequest(input, sanitizationOptions, global);
2494
+ if (!sanitized) {
2495
+ return Promise.resolve({ success: false, message: "Network request capture was suppressed by the sanitizer." });
2496
+ }
2497
+ return nativeModule.recordNetworkRequest(sanitized);
2498
+ }
2499
+
2500
+ function installNetworkCapture(options = {}) {
2501
+ uninstallNetworkCapture();
2502
+ const registration = { options };
2503
+ networkCaptureRegistration = registration;
2504
+ ensureNetworkConnectionEventSubscription();
2505
+ void refreshNetworkCaptureConnection();
2506
+ return {
2507
+ remove() {
2508
+ if (networkCaptureRegistration === registration) {
2509
+ uninstallNetworkCapture();
2510
+ }
2511
+ },
2512
+ };
2513
+ }
2514
+
2515
+ function uninstallNetworkCapture() {
2516
+ networkCaptureRegistration = null;
2517
+ if (networkConnectionEventSubscription) {
2518
+ networkConnectionEventSubscription.remove();
2519
+ networkConnectionEventSubscription = null;
2520
+ }
2521
+ detachNetworkCapture();
2522
+ }
2523
+
2524
+ function detachNetworkCapture() {
2525
+ if (!networkCaptureSubscription) return;
2526
+ networkCaptureSubscription.remove();
2527
+ networkCaptureSubscription = null;
2528
+ }
2529
+
2530
+ async function refreshNetworkCaptureConnection() {
2531
+ const registration = networkCaptureRegistration;
2532
+ if (!registration) {
2533
+ detachNetworkCapture();
2534
+ return;
2535
+ }
2536
+ try {
2537
+ const status = await nativeModule.hostConnectionStatus();
2538
+ if (networkCaptureRegistration !== registration) return;
2539
+ applyNetworkConnectionStatus(status);
2540
+ } catch {
2541
+ if (networkCaptureRegistration === registration) detachNetworkCapture();
2542
+ }
2543
+ }
2544
+
2545
+ function ensureNetworkConnectionEventSubscription() {
2546
+ if (networkConnectionEventSubscription) return;
2547
+ const emitter = new NativeEventEmitter(nativeModule);
2548
+ networkConnectionEventSubscription = emitter.addListener(
2549
+ "AnsightHostConnectionStatus",
2550
+ applyNetworkConnectionStatus,
2551
+ );
2552
+ }
2553
+
2554
+ function applyNetworkConnectionStatus(status) {
2555
+ const registration = networkCaptureRegistration;
2556
+ if (!registration || !status || status.isConnected !== true) {
2557
+ detachNetworkCapture();
2558
+ return;
2559
+ }
2560
+ if (!networkCaptureSubscription) {
2561
+ networkCaptureSubscription = installNetworkCaptureCore({
2562
+ globalObject: global,
2563
+ options: registration.options,
2564
+ sourcePrefix: "react-native",
2565
+ capture: (request) => nativeModule.recordNetworkRequest(request),
2566
+ });
2567
+ }
2568
+ }
2569
+
2570
+ async function configureNetworkCapture(value) {
2571
+ uninstallNetworkCapture();
2572
+ if (!value) return;
2573
+ const registration = { options: typeof value === "object" ? value : {} };
2574
+ networkCaptureRegistration = registration;
2575
+ ensureNetworkConnectionEventSubscription();
2576
+ await refreshNetworkCaptureConnection();
2577
+ }
2578
+
2256
2579
  function screenViewed(name, details) {
2257
2580
  return nativeModule.screenViewed(name, details || {});
2258
2581
  }
@@ -2295,6 +2618,8 @@ const Ansight = {
2295
2618
  recordMetric: (value, channel = 255) => nativeModule.recordMetric(value, channel),
2296
2619
  event: recordEvent,
2297
2620
  recordEvent,
2621
+ recordCrashCandidate,
2622
+ recordNetworkRequest,
2298
2623
  screenViewed,
2299
2624
  trackRoute,
2300
2625
  setAppLifecycleState: (state) => nativeModule.setAppLifecycleState(state),
@@ -2329,12 +2654,21 @@ const Ansight = {
2329
2654
  captureScreenFrame: (options = {}) => nativeModule.captureScreenFrame(options || {}),
2330
2655
  enableTouchCapture: () => nativeModule.enableTouchCapture(),
2331
2656
  disableTouchCapture: () => nativeModule.disableTouchCapture(),
2332
- updateSessionProperties: (properties) => nativeModule.updateSessionProperties(properties || {}),
2333
- clearSessionProperties: () => nativeModule.clearSessionProperties(),
2334
- updateCustomProperties: (properties) => nativeModule.updateSessionProperties(properties || {}),
2657
+ updateSessionProperties: (properties) => nativeModule.updateSessionProperties(
2658
+ mergeSessionProperties(automaticSessionProperties(), properties || {})
2659
+ ),
2660
+ clearSessionProperties: () => nativeModule.updateSessionProperties(automaticSessionProperties()),
2661
+ updateCustomProperties: (properties) => nativeModule.updateSessionProperties(
2662
+ mergeSessionProperties(automaticSessionProperties(), properties || {})
2663
+ ),
2335
2664
  registerCustomProperty: (group, key, value) => nativeModule.registerCustomProperty(group, key, value),
2336
- removeCustomProperty: (group, key) => nativeModule.removeCustomProperty(group, key),
2337
- clearCustomProperties: () => nativeModule.clearSessionProperties(),
2665
+ removeCustomProperty: (group, key) => {
2666
+ const automaticValue = automaticSessionPropertyValue(group, key);
2667
+ return automaticValue == null
2668
+ ? nativeModule.removeCustomProperty(group, key)
2669
+ : nativeModule.registerCustomProperty(group, key, automaticValue);
2670
+ },
2671
+ clearCustomProperties: () => nativeModule.updateSessionProperties(automaticSessionProperties()),
2338
2672
  registerTool,
2339
2673
  unregisterTool,
2340
2674
  registerArtifactProvider,
@@ -2356,6 +2690,9 @@ const Ansight = {
2356
2690
  installReactTools,
2357
2691
  uninstallReactTools,
2358
2692
  installErrorHandlers,
2693
+ installNetworkCapture,
2694
+ uninstallNetworkCapture,
2695
+ sanitizeNetworkRequest,
2359
2696
  createReactNavigationTracker,
2360
2697
  platform: Platform.OS,
2361
2698
  };
@@ -2374,3 +2711,7 @@ module.exports.registerArtifactProviders = registerArtifactProviders;
2374
2711
  module.exports.unregisterArtifactProvider = unregisterArtifactProvider;
2375
2712
  module.exports.listRegisteredArtifactProviders = listRegisteredArtifactProviders;
2376
2713
  module.exports.clearArtifactProviders = clearArtifactProviders;
2714
+ module.exports.recordNetworkRequest = recordNetworkRequest;
2715
+ module.exports.installNetworkCapture = installNetworkCapture;
2716
+ module.exports.uninstallNetworkCapture = uninstallNetworkCapture;
2717
+ module.exports.sanitizeNetworkRequest = sanitizeNetworkRequest;