@ansight/react-native 1.3.0-preview.9 → 1.4.0-preview.3

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/README.md CHANGED
@@ -8,6 +8,9 @@ handled by the Ansight iOS and Android SDKs. The JavaScript layer normalizes
8
8
  React Native inputs, forwards runtime calls to the native bridge, and registers
9
9
  JavaScript-backed tools for React component-tree inspection.
10
10
 
11
+ For guarded startup and CLI verification, see the
12
+ [React Native getting-started guide](https://www.ansight.ai/docs/sdk/react-native/setup).
13
+
11
14
  ## Install
12
15
 
13
16
  ### React Native CLI
@@ -36,7 +39,7 @@ npx expo install @ansight/react-native
36
39
 
37
40
  Add the bundled config plugin to the app config. It supplies the iOS camera
38
41
  usage description required by QR enrollment and the local-network description
39
- used when connecting to Ansight Studio:
42
+ used when connecting to the local Ansight host:
40
43
 
41
44
  ```json
42
45
  {
@@ -45,8 +48,8 @@ used when connecting to Ansight Studio:
45
48
  [
46
49
  "@ansight/react-native",
47
50
  {
48
- "cameraPermission": "Allow $(PRODUCT_NAME) to scan an Ansight Studio enrollment QR code.",
49
- "localNetworkPermission": "Allow $(PRODUCT_NAME) to connect to Ansight Studio on your local network."
51
+ "cameraPermission": "Allow $(PRODUCT_NAME) to scan an Ansight enrollment QR code.",
52
+ "localNetworkPermission": "Allow $(PRODUCT_NAME) to connect to the Ansight host on your local network."
50
53
  }
51
54
  ]
52
55
  ]
@@ -77,25 +80,48 @@ bundle; its API requires the native Ansight module.
77
80
 
78
81
  This package version expects matching native SDK packages:
79
82
 
80
- - CocoaPods: `Ansight`, `AnsightObjC` version `1.3.0-preview.9`
81
- - Maven: `ai.ansight:ansight-android:1.3.0-preview.9`
83
+ - CocoaPods: `Ansight`, `AnsightObjC` version `1.4.0-preview.3`
84
+ - Maven: `ai.ansight:ansight-android:1.4.0-preview.3`
82
85
 
83
86
  ## Quickstart
84
87
 
85
88
  ```ts
86
89
  import Ansight from "@ansight/react-native";
87
90
 
88
- await Ansight.initializeAndActivate({
89
- useNativeAllInOneDefaults: __DEV__,
90
- clientName: "My React Native App",
91
- toolGuard: __DEV__ ? "readOnly" : "disabled",
92
- lifecycle: true,
93
- });
91
+ let ansightStarted = false;
92
+
93
+ export async function startAnsight() {
94
+ if (!__DEV__ || ansightStarted) {
95
+ return;
96
+ }
97
+ ansightStarted = true;
98
+
99
+ await Ansight.initializeAndActivate({
100
+ useNativeAllInOneDefaults: true,
101
+ clientName: "React Native App",
102
+ toolGuard: "readOnly",
103
+ });
104
+ }
105
+ ```
106
+
107
+ Call `startAnsight()` once from app bootstrap. Start the local host in one
108
+ terminal and leave it running:
109
+
110
+ ```sh
111
+ ansight host run
112
+ ```
113
+
114
+ Launch the native development build, then verify the connected session and tool
115
+ catalog from another terminal:
116
+
117
+ ```sh
118
+ ansight session list --connected --json
119
+ ansight app tools <session-id> --json
94
120
  ```
95
121
 
96
122
  The native iOS Simulator or Android emulator runtime registers automatically
97
- with a running, signed-in Studio. No pairing file, environment variable, host
98
- address, or build-time Studio probe is required.
123
+ through loopback. No account, pairing file, environment variable, host address,
124
+ or build-time host probe is required.
99
125
 
100
126
  `useNativeAllInOneDefaults` defaults to `false`. It only applies the native
101
127
  iOS/Android all-in-one defaults: 400 ms sampling, 120 second retention, FPS,
@@ -151,6 +177,7 @@ The TypeScript `AnsightOptions` surface mirrors Android `AnsightOptions`, iOS
151
177
  | `secureStorage` | Compatibility alias for native secure-storage allow-list settings. |
152
178
  | `remoteTools` | Native visual tree, file, database, preferences, reflection, and secure-storage tool options. |
153
179
  | `lifecycle` | JS AppState tracking toggle. Defaults to true. |
180
+ | `networkCapture` | Opt-in `fetch` and `XMLHttpRequest` metadata capture. Accepts `true` or sanitization/capture options. |
154
181
 
155
182
  Use `withOpenFileHandleTracking()` and `withJniReferenceCountTracking()` to
156
183
  opt in through the builder. Matching `without...` methods disable the channels
@@ -200,14 +227,50 @@ await Ansight.initializeAndActivate({
200
227
  });
201
228
  ```
202
229
 
203
- The touch mode captures native visual trees at gesture start, every 250 ms
204
- throughout the gesture, and at the final up or cancel. It requires native touch
205
- capture and visual-tree tools/providers to remain enabled.
230
+ The touch mode captures native visual trees only on touch down and touch up.
231
+ Move and cancel events do not trigger capture. Rapid boundaries are coalesced
232
+ and rate-limited to protect screenshot cadence. Native touch capture and
233
+ visual-tree tools/providers must remain enabled.
206
234
 
207
235
  On iOS, `captureGpuBackedSurfaces` defaults to `true` so Metal, SceneKit, and
208
236
  similar GPU-backed views are included. Set it to `false` to use a lower-overhead
209
237
  capture path when those surfaces are not needed.
210
238
 
239
+ ## Network capture
240
+
241
+ Network capture is explicitly enabled by the React Native layer, which
242
+ instruments `fetch` and `XMLHttpRequest`, then sends a typed metadata record
243
+ through the native bridge. It is opt-in:
244
+
245
+ ```ts
246
+ await Ansight.initializeAndActivate(
247
+ Ansight.createOptionsBuilder()
248
+ .withAnsightDefaults()
249
+ .withNetworkCapture({
250
+ maximumBodyBytes: 64 * 1024,
251
+ additionalSensitiveHeaderNames: ["x-tenant-secret"],
252
+ additionalSensitiveQueryParameterNames: ["session"],
253
+ requestSanitizer: request =>
254
+ request.url.includes("/health") ? null : request,
255
+ })
256
+ .withoutNetworkRequestBodies() // optional, independent opt-out
257
+ .build(),
258
+ );
259
+ ```
260
+
261
+ Text request and response bodies are included by default after network capture
262
+ is explicitly enabled, with a 64 KiB default per-body limit. Set a larger
263
+ `maximumBodyBytes` when needed; use the request/response body builder methods to
264
+ opt either side out or back in, and `captureBinaryBodies` to explicitly allow
265
+ Base64 binary content. Standard credentials, cloud signed-URL fields, cookies,
266
+ URL user information, and sensitive text-body assignments are redacted before
267
+ the bridge. Capture hooks detach whenever the native host is disconnected.
268
+
269
+ Use `installNetworkCapture(...)` and `uninstallNetworkCapture()` when capture
270
+ must be controlled independently of initialization. `recordNetworkRequest(...)`
271
+ supports custom HTTP stacks, and `sanitizeNetworkRequest(...)` exposes the same
272
+ app-side policy for inspection or testing.
273
+
211
274
  ## Native Tool Options
212
275
 
213
276
  `remoteTools` configures the native tool suites registered by the bridge. `useNativeAllInOneDefaults: true` enables visual tree tools by default so Studio can pair `ui.get_visual_tree` data with `ui.get_screenshot` frames. Apps that do not use all-in-one defaults can opt in explicitly:
@@ -256,25 +319,19 @@ compatibility alias for `remoteTools.secureStorage`.
256
319
 
257
320
  ## Host Connection
258
321
 
259
- No connection call is needed for a simulator or emulator. On a physical
260
- device, scan the QR displayed by Studio once:
322
+ No connection call is needed for a simulator or emulator. For a physical
323
+ device, run `ansight pairing issue --qr`, then open the SDK scanner from a
324
+ developer-only app surface:
261
325
 
262
326
  ```ts
263
327
  await Ansight.enrollFromQrCode({
264
328
  clientName: "My React Native App",
265
- expectedAppId: "com.example.app",
266
329
  });
267
330
  ```
268
331
 
269
- After physical-device enrollment, `connect(null, options)` and the runtime
270
- connection loop use the remembered registration:
271
-
272
- ```ts
273
- await Ansight.connect(null, { clientName: "My React Native App" });
274
- ```
275
-
276
- When Studio is closed or signed out, automatic attempts remain dormant and
277
- retry later without failing the React Native app.
332
+ The SDK supplies the native app id, stores the installation registration
333
+ privately, and reconnects automatically on later launches. If the host is
334
+ unavailable, retry attempts do not fail the React Native app.
278
335
 
279
336
  If the app already owns a scanner, pass its result through the explicit payload
280
337
  API:
@@ -282,17 +339,17 @@ API:
282
339
  ```ts
283
340
  await Ansight.connect(enrollmentPayload, {
284
341
  clientName: "My React Native App",
285
- expectedAppId: "com.example.app",
286
- hostAddressOverride: "192.168.1.20",
287
342
  });
288
343
 
289
344
  await Ansight.clearCachedSession();
290
345
  await Ansight.disconnect();
291
346
  ```
292
347
 
293
- `openSession(pairingPayload, options)` is the low-level direct session path.
294
- Prefer `connect(...)` for normal Studio sessions because it coordinates saved
295
- config, host auto-probe, status, telemetry, and live tool handling.
348
+ `openSession(enrollmentPayload, options)` is the low-level direct session path.
349
+ Prefer automatic registration for simulators and emulators or
350
+ `enrollFromQrCode(...)` for physical devices. Use `connect(...)` only when the
351
+ app already owns the scanner; it coordinates saved registration, host
352
+ auto-probe, status, telemetry, and live tool handling.
296
353
 
297
354
  ## Runtime API
298
355
 
@@ -302,7 +359,7 @@ The bridge exposes the native SDK runtime surface:
302
359
  | --- | --- |
303
360
  | `initialize`, `initializeAndActivate`, `activate`, `deactivate`, `clear` | Runtime lifecycle. |
304
361
  | `connect`, `disconnect`, `openSession`, `completeSession`, `closeSession` | Host and live-session control. |
305
- | `savePairingConfig`, `clearSavedPairing`, `clearCachedSession` | Pairing persistence. |
362
+ | `clearCachedSession` | Clears remembered app-installation registration state. |
306
363
  | `status`, `snapshot`, `hostConnectionStatus`, `currentOptions` | Diagnostics and state. |
307
364
  | `registerMetricChannel`, `metric`, `recordMetric` | Metric channels and samples. |
308
365
  | `event`, `recordEvent`, `screenViewed`, `trackRoute` | App events and screen views. |
@@ -389,14 +446,27 @@ await Ansight.clearSessionProperties();
389
446
  When connected, property mutations are sent immediately. When disconnected, the
390
447
  latest values are included in the next `session.open`.
391
448
 
449
+ The bridge automatically adds these property groups:
450
+
451
+ | Group | Properties |
452
+ | --- | --- |
453
+ | `reactNative` | Ansight SDK, React Native and React versions; platform and runtime language; JavaScript engine and available Hermes version/bytecode details; legacy/new architecture; bridgeless state; development mode. |
454
+ | `localization` | Canonical locale, language, optional region, IANA time zone when exposed by `Intl`, and UTC offset in minutes. |
455
+
456
+ App-provided values override an automatic value with the same group and key.
457
+ Clearing all properties, or removing one automatic property, restores the
458
+ current bridge-owned value. `localization` reflects the JavaScript runtime
459
+ locale; if the app selects a different language through an i18n library, set
460
+ `localization.locale`, `language`, and `region` explicitly.
461
+
392
462
  ## Tool Guards
393
463
 
394
- | Value | Allowed scopes |
464
+ | Value | Maximum policy |
395
465
  | --- | --- |
396
466
  | `"disabled"` | None |
397
467
  | `"readOnly"` | Read |
398
- | `"readWrite"` | Read, Write |
399
- | `"fullAccess"` | Read, Write, Delete |
468
+ | `"readWrite"` | Write |
469
+ | `"fullAccess"` | Critical |
400
470
 
401
471
  `"full"` is accepted as a compatibility alias for `"fullAccess"`.
402
472
 
@@ -411,7 +481,7 @@ const registration = Ansight.registerTool(
411
481
  name: "State Snapshot",
412
482
  description: "Returns current app state.",
413
483
  category: "app",
414
- scope: "Read",
484
+ policy: "read",
415
485
  keywords: "state snapshot",
416
486
  argumentsSchema: { type: "object", additionalProperties: true },
417
487
  resultSchema: { type: "object", additionalProperties: true },
@@ -474,7 +544,7 @@ const reportProvider = Ansight.registerArtifactProvider({
474
544
  await reportProvider.ready;
475
545
  ```
476
546
 
477
- The first provider installs the read-scoped `artifacts.query` and
547
+ The first provider installs the `read` policy `artifacts.query` and
478
548
  `artifacts.request` JavaScript tools in the native registry. A provider can
479
549
  return text, base64, byte arrays, `ArrayBuffer`, or `Uint8Array`. Artifact
480
550
  requests require a live Studio tool call; the bridge forwards the returned
@@ -67,6 +67,6 @@ repositories {
67
67
  dependencies {
68
68
  implementation("com.facebook.react:react-android")
69
69
  def ansightAndroidVersion =
70
- findProperty("ansightAndroidVersion") ?: "1.3.0-preview.9"
71
- implementation("ai.ansight:ansight-android:1.3.0-preview.9")
70
+ findProperty("ansightAndroidVersion") ?: "1.4.0-preview.3"
71
+ implementation("ai.ansight:ansight-android:1.4.0-preview.3")
72
72
  }
@@ -12,6 +12,7 @@ import ai.ansight.runtime.AnsightHostConnectionOptions
12
12
  import ai.ansight.runtime.AnsightLogCallback
13
13
  import ai.ansight.runtime.AnsightLogLevel
14
14
  import ai.ansight.runtime.AnsightLogger
15
+ import ai.ansight.runtime.AnsightNetworkRequest
15
16
  import ai.ansight.runtime.AnsightOptions
16
17
  import ai.ansight.runtime.AnsightOptionsBuilder
17
18
  import ai.ansight.runtime.AnsightRuntime
@@ -28,6 +29,7 @@ import ai.ansight.runtime.HostConnectionRequestKind
28
29
  import ai.ansight.runtime.HostConnectionCapabilities
29
30
  import ai.ansight.runtime.HostConnectionResult
30
31
  import ai.ansight.runtime.HostConnectionStatus
32
+ import ai.ansight.runtime.HostConnectionStatusSubscription
31
33
  import ai.ansight.runtime.OperationResult
32
34
  import ai.ansight.runtime.OpenSessionResult
33
35
  import ai.ansight.runtime.PairingOpenOptions
@@ -36,9 +38,7 @@ import ai.ansight.runtime.RecordedEvent
36
38
  import ai.ansight.runtime.RecordedMetric
37
39
  import ai.ansight.runtime.ToolDefinition
38
40
  import ai.ansight.runtime.ToolSchema
39
- import ai.ansight.runtime.ToolScope
40
- import ai.ansight.runtime.ToolSecurity
41
- import ai.ansight.runtime.ToolSecurityLevel
41
+ import ai.ansight.runtime.ToolPolicy
42
42
  import ai.ansight.runtime.sendBinaryTransfer
43
43
  import ai.ansight.pairing.AnsightPairing
44
44
  import ai.ansight.tools.database.AndroidDatabaseRoot
@@ -53,6 +53,10 @@ import ai.ansight.tools.reflection.AndroidReflectionToolsOptions
53
53
  import ai.ansight.tools.reflection.withReflectionTools
54
54
  import ai.ansight.tools.securestorage.withSecureStorageTools
55
55
  import ai.ansight.tools.visualtree.withVisualTreeTools
56
+ import ai.ansight.tools.visualtree.AndroidVisualTreeActionRequest
57
+ import ai.ansight.tools.visualtree.AndroidVisualTreeInteractionProvider
58
+ import ai.ansight.tools.visualtree.AndroidVisualTreeProvider
59
+ import ai.ansight.tools.visualtree.AndroidVisualTreeProviderRegistry
56
60
  import android.app.Activity
57
61
  import android.app.Application
58
62
  import android.util.Base64
@@ -104,16 +108,21 @@ class AnsightReactNativeModule(
104
108
  private val logCallback = AnsightLogCallback { level, message, throwable ->
105
109
  emitLogEvent(level, message, throwable)
106
110
  }
111
+ private val hostConnectionStatusSubscription: HostConnectionStatusSubscription
107
112
 
108
113
  init {
109
114
  reactContext.addLifecycleEventListener(this)
110
115
  AnsightLogger.registerCallback(logCallback)
116
+ hostConnectionStatusSubscription = AnsightRuntime.addHostConnectionStatusListener(
117
+ listener = { status, _ -> emitHostConnectionStatusEvent(status) },
118
+ )
111
119
  }
112
120
 
113
121
  override fun getName(): String = "AnsightReactNative"
114
122
 
115
123
  override fun invalidate() {
116
124
  AnsightLogger.removeCallback(logCallback)
125
+ hostConnectionStatusSubscription.remove()
117
126
  reactContext.removeLifecycleEventListener(this)
118
127
  super.invalidate()
119
128
  }
@@ -226,6 +235,17 @@ class AnsightReactNativeModule(
226
235
  }.resolve(promise)
227
236
  }
228
237
 
238
+ @ReactMethod
239
+ fun recordNetworkRequest(input: ReadableMap, promise: Promise) {
240
+ runCatching {
241
+ val request = AnsightNetworkRequest.fromJson(JSONObject(input.toHashMap()))
242
+ ?: return@runCatching operationResultMap(
243
+ OperationResult.failure("Network request must use the ansight.network-request.v1 schema."),
244
+ )
245
+ operationResultMap(AnsightRuntime.recordNetworkRequest(request))
246
+ }.resolve(promise)
247
+ }
248
+
229
249
  @ReactMethod
230
250
  fun recordCrashCandidate(input: ReadableMap, promise: Promise) {
231
251
  runCatching {
@@ -639,6 +659,58 @@ class AnsightReactNativeModule(
639
659
  },
640
660
  replaceExisting = true,
641
661
  )
662
+ if (definition.id == "react.get_component_tree") {
663
+ AndroidVisualTreeProviderRegistry.register(
664
+ object : AndroidVisualTreeProvider, AndroidVisualTreeInteractionProvider {
665
+ override val source = "react"
666
+ override val displayName = "React Native"
667
+
668
+ override fun getVisualTree(
669
+ arguments: Map<String, String>,
670
+ context: AndroidToolExecutionContext,
671
+ ): AndroidToolResult = executeJavaScriptTool(
672
+ "react.get_component_tree",
673
+ arguments,
674
+ context,
675
+ registration.timeoutMilliseconds,
676
+ )
677
+
678
+ override fun inspectNode(
679
+ arguments: Map<String, String>,
680
+ context: AndroidToolExecutionContext,
681
+ ): AndroidToolResult = executeJavaScriptTool(
682
+ "react.get_component",
683
+ arguments,
684
+ context,
685
+ registration.timeoutMilliseconds,
686
+ )
687
+
688
+ override fun performAction(
689
+ request: AndroidVisualTreeActionRequest,
690
+ context: AndroidToolExecutionContext,
691
+ ): AndroidToolResult {
692
+ val prop = when (request.action.lowercase()) {
693
+ "tap" -> "onPress"
694
+ "focus" -> "onFocus"
695
+ "setvalue", "typetext" -> "onChangeText"
696
+ "toggle" -> "onValueChange"
697
+ else -> request.options.optString("prop", request.action)
698
+ }
699
+ return executeJavaScriptTool(
700
+ "react.invoke_component_action",
701
+ buildMap {
702
+ put("nodeId", request.nodeId)
703
+ put("prop", prop)
704
+ request.value?.let { put("value", it.toString()) }
705
+ },
706
+ context,
707
+ registration.timeoutMilliseconds,
708
+ )
709
+ }
710
+ },
711
+ replaceExisting = true,
712
+ )
713
+ }
642
714
  }
643
715
 
644
716
  private fun emitToolCall(
@@ -677,6 +749,16 @@ class AnsightReactNativeModule(
677
749
  }
678
750
  }
679
751
 
752
+ private fun emitHostConnectionStatusEvent(status: HostConnectionStatus) {
753
+ if (listenerCount.get() <= 0) return
754
+ val event = hostConnectionStatusMap(status)
755
+ UiThreadUtil.runOnUiThread {
756
+ reactContext
757
+ .getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter::class.java)
758
+ .emit("AnsightHostConnectionStatus", event)
759
+ }
760
+ }
761
+
680
762
  private fun configureReactNativeMemoryProfiling(map: ReadableMap?) {
681
763
  val options = reactNativeMemoryProfilingOptions(map)
682
764
  currentReactNativeMemoryOptions = options
@@ -1005,14 +1087,14 @@ class AnsightReactNativeModule(
1005
1087
  name = map.stringValue("name") ?: map.stringValue("id") ?: "",
1006
1088
  description = map.stringValue("description") ?: "",
1007
1089
  category = map.stringValue("category") ?: "custom",
1008
- scope = toolScope(map.stringValue("scope")),
1090
+ policy = toolPolicy(map.stringValue("policy")),
1009
1091
  keywords = when {
1010
1092
  map.hasArray("keywords") -> map.getArray("keywords").toStringList().joinToString(" ")
1011
1093
  else -> map.stringValue("keywords") ?: "react native custom tool"
1012
1094
  },
1013
1095
  argumentsSchema = schemaFrom(map.getMapOrNull("argumentsSchema")),
1014
1096
  resultSchema = schemaFrom(map.getMapOrNull("resultSchema")),
1015
- security = toolSecurity(map.getMapOrNull("security")),
1097
+ prerequisiteToolIds = map.getArrayOrNull("prerequisiteToolIds").toStringList(),
1016
1098
  ).validated()
1017
1099
 
1018
1100
  private fun schemaFrom(map: ReadableMap?): ToolSchema {
@@ -1044,21 +1126,6 @@ class AnsightReactNativeModule(
1044
1126
  )
1045
1127
  }
1046
1128
 
1047
- private fun toolSecurity(map: ReadableMap?): ToolSecurity {
1048
- if (map == null) {
1049
- return ToolSecurity.Unspecified
1050
- }
1051
- return ToolSecurity(
1052
- level = when (map.stringValue("level")?.trim()?.lowercase()) {
1053
- "medium", "moderate" -> ToolSecurityLevel.Medium
1054
- "high" -> ToolSecurityLevel.High
1055
- "critical" -> ToolSecurityLevel.Critical
1056
- else -> ToolSecurityLevel.Low
1057
- },
1058
- implications = map.getArrayOrNull("implications").toStringList(),
1059
- )
1060
- }
1061
-
1062
1129
  private fun resultPayload(map: ReadableMap): JSONObject? {
1063
1130
  if (!map.hasKey("result") || map.isNull("result")) {
1064
1131
  return null
@@ -1327,11 +1394,11 @@ private fun toolGuardName(guard: AnsightToolGuard): String =
1327
1394
  AnsightToolGuard.FullAccess -> "fullAccess"
1328
1395
  }
1329
1396
 
1330
- private fun toolScope(raw: String?): ToolScope =
1397
+ private fun toolPolicy(raw: String?): ToolPolicy =
1331
1398
  when (raw?.trim()?.lowercase()) {
1332
- "write" -> ToolScope.Write
1333
- "delete" -> ToolScope.Delete
1334
- else -> ToolScope.Read
1399
+ "write" -> ToolPolicy.Write
1400
+ "critical", "delete" -> ToolPolicy.Critical
1401
+ else -> ToolPolicy.Read
1335
1402
  }
1336
1403
 
1337
1404
  private fun ReadableMap?.hasKey(name: String): Boolean = this?.hasKey(name) == true
package/index.d.ts CHANGED
@@ -1,18 +1,5 @@
1
1
  export type AnsightLifecycleState = "unknown" | "foreground" | "background";
2
- export type AnsightToolScope = "read" | "write" | "delete" | "Read" | "Write" | "Delete";
3
- export type AnsightToolSecurityLevel =
4
- | "unspecified"
5
- | "low"
6
- | "medium"
7
- | "moderate"
8
- | "high"
9
- | "critical"
10
- | "Unspecified"
11
- | "Low"
12
- | "Medium"
13
- | "Moderate"
14
- | "High"
15
- | "Critical";
2
+ export type AnsightToolPolicy = "read" | "write" | "critical";
16
3
 
17
4
  export interface AnsightChannel {
18
5
  id: number;
@@ -48,6 +35,75 @@ export interface AnsightTouchCaptureOptions {
48
35
  moveCaptureFramesPerSecond?: number;
49
36
  }
50
37
 
38
+ export interface AnsightNetworkHeader {
39
+ name: string;
40
+ value: string;
41
+ }
42
+
43
+ export interface AnsightNetworkBody {
44
+ contentType?: string;
45
+ encoding: "utf8" | "base64";
46
+ data: string;
47
+ capturedBytes: number;
48
+ totalBytes?: number;
49
+ truncated: boolean;
50
+ }
51
+
52
+ /** V1 network metadata with optional, bounded bodies. */
53
+ export interface AnsightNetworkRequest {
54
+ schema: "ansight.network-request.v1";
55
+ id: string;
56
+ source: string;
57
+ startedAtUtc: string;
58
+ completedAtUtc: string;
59
+ durationMilliseconds: number;
60
+ method: string;
61
+ url: string;
62
+ protocol?: string;
63
+ requestHeaders: AnsightNetworkHeader[];
64
+ requestBodySizeBytes?: number;
65
+ requestBody?: AnsightNetworkBody;
66
+ statusCode?: number;
67
+ reasonPhrase?: string;
68
+ responseHeaders: AnsightNetworkHeader[];
69
+ responseBodySizeBytes?: number;
70
+ responseBody?: AnsightNetworkBody;
71
+ errorType?: string;
72
+ errorMessage?: string;
73
+ }
74
+
75
+ export type AnsightNetworkRequestInput = Partial<AnsightNetworkRequest> & {
76
+ method: string;
77
+ url: string;
78
+ };
79
+
80
+ export interface AnsightNetworkSanitizationOptions {
81
+ includeRequestHeaders?: boolean;
82
+ includeResponseHeaders?: boolean;
83
+ includeQueryString?: boolean;
84
+ includeBodySizes?: boolean;
85
+ /** Defaults to true. */
86
+ captureRequestBody?: boolean;
87
+ /** Defaults to true. */
88
+ captureResponseBody?: boolean;
89
+ /** Decoded bytes retained per body. Defaults to 64 KiB; larger explicit limits are honored. */
90
+ maximumBodyBytes?: number;
91
+ captureBinaryBodies?: boolean;
92
+ additionalSensitiveHeaderNames?: string[];
93
+ additionalSensitiveQueryParameterNames?: string[];
94
+ urlSanitizer?: (url: string) => string;
95
+ /** Return a replacement request, or null to suppress capture. */
96
+ requestSanitizer?: (
97
+ request: AnsightNetworkRequest,
98
+ ) => AnsightNetworkRequest | null;
99
+ }
100
+
101
+ export interface AnsightNetworkCaptureOptions
102
+ extends AnsightNetworkSanitizationOptions {
103
+ captureFetch?: boolean;
104
+ captureXmlHttpRequest?: boolean;
105
+ }
106
+
51
107
  export interface AnsightNativeToolRoot {
52
108
  alias: string;
53
109
  path: string;
@@ -155,6 +211,8 @@ export interface AnsightOptions {
155
211
  remoteTools?: AnsightRemoteToolsOptions;
156
212
  additionalChannels?: AnsightChannel[];
157
213
  lifecycle?: boolean;
214
+ /** Explicitly opt in to fetch/XMLHttpRequest instrumentation. */
215
+ networkCapture?: boolean | AnsightNetworkCaptureOptions;
158
216
  }
159
217
 
160
218
  export interface AnsightCrashCaptureOptions {
@@ -300,6 +358,12 @@ export class AnsightOptionsBuilder {
300
358
  withCrashCapture(crashCapture?: AnsightCrashCaptureOptions): this;
301
359
  withoutCrashCapture(): this;
302
360
  withLifecycleCapture(lifecycleCapture?: NonNullable<AnsightOptions["lifecycleCapture"]>): this;
361
+ withNetworkCapture(networkCapture?: AnsightNetworkCaptureOptions): this;
362
+ withNetworkRequestBodies(maximumBodyBytes?: number): this;
363
+ withoutNetworkRequestBodies(): this;
364
+ withNetworkResponseBodies(maximumBodyBytes?: number): this;
365
+ withoutNetworkResponseBodies(): this;
366
+ withoutNetworkCapture(): this;
303
367
  withToolGuard(toolGuard: NonNullable<AnsightOptions["toolGuard"]>): this;
304
368
  withToolsDisabled(): this;
305
369
  withReadOnlyToolAccess(): this;
@@ -333,22 +397,16 @@ export class AnsightOptionsBuilder {
333
397
  build(): AnsightOptions;
334
398
  }
335
399
 
336
- export interface AnsightToolSecurity {
337
- level?: AnsightToolSecurityLevel;
338
- summary?: string;
339
- implications?: string[];
340
- }
341
-
342
400
  export interface AnsightToolDefinition {
343
401
  id: string;
344
402
  name: string;
345
403
  description?: string;
346
404
  category?: string;
347
- scope?: AnsightToolScope;
405
+ policy?: AnsightToolPolicy;
348
406
  keywords?: string | string[];
349
407
  argumentsSchema?: object;
350
408
  resultSchema?: object;
351
- security?: AnsightToolSecurity;
409
+ prerequisiteToolIds?: string[];
352
410
  timeoutMilliseconds?: number;
353
411
  }
354
412
 
@@ -403,7 +461,7 @@ export interface AnsightArtifactDefinition {
403
461
  fileName?: string;
404
462
  estimatedSizeBytes?: number | null;
405
463
  argumentsSchema?: object;
406
- security?: AnsightToolSecurity;
464
+ policy?: AnsightToolPolicy;
407
465
  tags?: string[];
408
466
  metadata?: Record<string, string>;
409
467
  }
@@ -543,6 +601,18 @@ export function recordMetric(value: number, channel?: number): Promise<AnsightDe
543
601
  export function event(input: string | { label: string; type?: string; details?: string; channel?: number }): Promise<AnsightDebugSnapshot>;
544
602
  export function recordEvent(input: string | { label: string; type?: string; details?: string; channel?: number }): Promise<AnsightDebugSnapshot>;
545
603
  export function recordCrashCandidate(input?: AnsightCrashCandidate): Promise<{ candidateId?: string }>;
604
+ export function recordNetworkRequest(
605
+ input: AnsightNetworkRequestInput,
606
+ sanitizationOptions?: AnsightNetworkSanitizationOptions,
607
+ ): Promise<AnsightOperationResult>;
608
+ export function sanitizeNetworkRequest(
609
+ input: AnsightNetworkRequestInput,
610
+ sanitizationOptions?: AnsightNetworkSanitizationOptions,
611
+ ): AnsightNetworkRequest | null;
612
+ export function installNetworkCapture(
613
+ options?: AnsightNetworkCaptureOptions,
614
+ ): AnsightSubscription;
615
+ export function uninstallNetworkCapture(): void;
546
616
  export function screenViewed(name: string, details?: Record<string, string>): Promise<AnsightDebugSnapshot>;
547
617
  export function trackRoute(name: string, details?: Record<string, string>): Promise<AnsightDebugSnapshot>;
548
618
  export function setAppLifecycleState(state: AnsightLifecycleState): Promise<AnsightDebugSnapshot>;
@@ -617,6 +687,7 @@ declare const Ansight: {
617
687
  event: typeof event;
618
688
  recordEvent: typeof recordEvent;
619
689
  recordCrashCandidate: typeof recordCrashCandidate;
690
+ recordNetworkRequest: typeof recordNetworkRequest;
620
691
  screenViewed: typeof screenViewed;
621
692
  trackRoute: typeof trackRoute;
622
693
  setAppLifecycleState: typeof setAppLifecycleState;
@@ -671,6 +742,9 @@ declare const Ansight: {
671
742
  installReactTools: typeof installReactTools;
672
743
  uninstallReactTools: typeof uninstallReactTools;
673
744
  installErrorHandlers: typeof installErrorHandlers;
745
+ installNetworkCapture: typeof installNetworkCapture;
746
+ uninstallNetworkCapture: typeof uninstallNetworkCapture;
747
+ sanitizeNetworkRequest: typeof sanitizeNetworkRequest;
674
748
  createReactNavigationTracker: typeof createReactNavigationTracker;
675
749
  platform: "ios" | "android" | string;
676
750
  };