@ansight/react-native 1.4.0-preview.5 → 1.5.0

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
@@ -1,6 +1,14 @@
1
1
  # @ansight/react-native
2
2
 
3
- React Native bridge for the Ansight mobile SDK.
3
+ Ansight gives coding agents the runtime evidence to verify their own work in
4
+ React Native and Expo development builds. The SDK captures screenshots, visual trees, touches, logs,
5
+ crashes and unhandled errors, HTTP requests, screen views and navigation, lifecycle events, app events, custom metrics, and sampled memory,
6
+ FPS, frame timing, and battery while the app runs, and exposes app state,
7
+ preferences, secure storage, files, SQLite, artifacts, and your own custom
8
+ tools through guarded remote tools on request. Your agent reads all of it
9
+ through the `ansight` CLI. Nothing leaves your machine unless you export or
10
+ share it. See https://www.ansight.ai and the
11
+ [getting started guide](https://www.ansight.ai/docs/getting-started).
4
12
 
5
13
  The package is intentionally thin: pairing, transport, telemetry, screen
6
14
  capture, touch capture, native tool discovery, and native tool execution are
@@ -80,8 +88,8 @@ bundle; its API requires the native Ansight module.
80
88
 
81
89
  This package version expects matching native SDK packages:
82
90
 
83
- - CocoaPods: `Ansight`, `AnsightObjC` version `1.4.0-preview.5`
84
- - Maven: `ai.ansight:ansight-android:1.4.0-preview.5`
91
+ - CocoaPods: `Ansight`, `AnsightObjC` version `1.5.0`
92
+ - Maven: `ai.ansight:ansight-android:1.5.0`
85
93
 
86
94
  ## Quickstart
87
95
 
@@ -144,9 +152,9 @@ where reconnects should only happen after an explicit app action.
144
152
  > max-width settings, and disable `sessionJpegCapture` for performance-focused
145
153
  > runs unless visual evidence is required.
146
154
 
147
- For simulator/emulator sessions, Studio can acknowledge the native
155
+ For simulator/emulator sessions, host can acknowledge the native
148
156
  `device.profile` with host screenshot mode. The native SDK then suspends
149
- periodic in-app JPEG capture for that session so Studio can use a host-side
157
+ periodic in-app JPEG capture for that session so host can use a host-side
150
158
  source such as `simctl` or `adb`.
151
159
 
152
160
  ## Options
@@ -156,7 +164,7 @@ The TypeScript `AnsightOptions` surface mirrors Android `AnsightOptions`, iOS
156
164
 
157
165
  | Option | Purpose |
158
166
  | --- | --- |
159
- | `useNativeAllInOneDefaults` | Applies native iOS/Android all-in-one defaults when true. Defaults to false. This enables the native visual-tree/screenshot tools required by Studio visual tree inspection unless `remoteTools.visualTree` is explicitly false. Configure `toolGuard`, capture options, and `hostConnection` separately. |
167
+ | `useNativeAllInOneDefaults` | Applies native iOS/Android all-in-one defaults when true. Defaults to false. This enables the native visual-tree/screenshot tools required by host visual tree inspection unless `remoteTools.visualTree` is explicitly false. Configure `toolGuard`, capture options, and `hostConnection` separately. |
160
168
  | `clientName` | Default client name for host auto-probe and connections. |
161
169
  | `sampleFrequencyMilliseconds` | Built-in telemetry sampling interval. |
162
170
  | `retentionPeriodSeconds` | Local metric/event retention window. |
@@ -273,7 +281,7 @@ app-side policy for inspection or testing.
273
281
 
274
282
  ## Native Tool Options
275
283
 
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:
284
+ `remoteTools` configures the native tool suites registered by the bridge. `useNativeAllInOneDefaults: true` enables visual tree tools by default so host 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:
277
285
 
278
286
  ```ts
279
287
  await Ansight.initializeAndActivate(
@@ -472,7 +480,7 @@ locale; if the app selects a different language through an i18n library, set
472
480
 
473
481
  ## JavaScript Tools
474
482
 
475
- Custom JavaScript tools can be exposed to Ansight Studio:
483
+ Custom JavaScript tools can be exposed to Ansight host:
476
484
 
477
485
  ```ts
478
486
  const registration = Ansight.registerTool(
@@ -547,7 +555,7 @@ await reportProvider.ready;
547
555
  The first provider installs the `read` policy `artifacts.query` and
548
556
  `artifacts.request` JavaScript tools in the native registry. A provider can
549
557
  return text, base64, byte arrays, `ArrayBuffer`, or `Uint8Array`. Artifact
550
- requests require a live Studio tool call; the bridge forwards the returned
558
+ requests require a live host tool call; the bridge forwards the returned
551
559
  bytes through the native binary-transfer channel. Call
552
560
  `reportProvider.unregister()` during teardown or hot-reload cleanup.
553
561
 
@@ -670,5 +678,9 @@ The current-Expo validation app lives in:
670
678
 
671
679
  It is pinned to Expo SDK 57 and React Native 0.86 with the New Architecture and
672
680
  Hermes enabled. It validates Expo CNG/autolinking, the bundled config plugin,
673
- Android and iOS native builds, and the same live Studio feature surface as the
681
+ Android and iOS native builds, and the same live host feature surface as the
674
682
  baseline harness.
683
+
684
+ ## Purchase diagnostics
685
+
686
+ See [purchase observations, adapters, and remote validation](../../docs/purchases.md) for the base SDK purchase suite.
@@ -67,6 +67,6 @@ repositories {
67
67
  dependencies {
68
68
  implementation("com.facebook.react:react-android")
69
69
  def ansightAndroidVersion =
70
- findProperty("ansightAndroidVersion") ?: "1.4.0-preview.5"
71
- implementation("ai.ansight:ansight-android:1.4.0-preview.5")
70
+ findProperty("ansightAndroidVersion") ?: "1.5.0"
71
+ implementation("ai.ansight:ansight-android:1.5.0")
72
72
  }
@@ -48,6 +48,8 @@ import ai.ansight.tools.filesystem.AndroidFileSystemRoot
48
48
  import ai.ansight.tools.filesystem.AndroidFileSystemToolsOptions
49
49
  import ai.ansight.tools.filesystem.withFileSystemTools
50
50
  import ai.ansight.tools.preferences.AndroidPreferencesToolsOptions
51
+ import ai.ansight.tools.clipboard.ClipboardToolIds
52
+ import ai.ansight.tools.clipboard.withClipboardTools
51
53
  import ai.ansight.tools.preferences.withPreferencesTools
52
54
  import ai.ansight.tools.reflection.AndroidReflectionToolsOptions
53
55
  import ai.ansight.tools.reflection.withReflectionTools
@@ -135,6 +137,13 @@ class AnsightReactNativeModule(
135
137
 
136
138
  override fun onHostDestroy() = Unit
137
139
 
140
+ @ReactMethod
141
+ fun purchaseCommand(json: String, promise: Promise) {
142
+ try { promise.resolve(ai.ansight.runtime.purchases.PurchaseDiagnostics.shared.command(json)) }
143
+ catch (error: ai.ansight.runtime.purchases.PurchaseEnvironmentException) { promise.reject(ai.ansight.runtime.purchases.PurchaseEnvironmentException.ERROR_CODE, error.message, error) }
144
+ catch (error: Exception) { promise.reject("purchases_command_failed", "Purchase command failed.", error) }
145
+ }
146
+
138
147
  @ReactMethod
139
148
  fun addListener(eventName: String) {
140
149
  listenerCount.incrementAndGet()
@@ -894,7 +903,7 @@ class AnsightReactNativeModule(
894
903
  val crash = map.getMapOrNull("crashCapture")
895
904
  AnsightCrashCaptureOptions(
896
905
  enabled = crash.booleanValue("enabled", true),
897
- studioHandoffEnabled = crash.booleanValue("studioHandoffEnabled", true),
906
+ hostHandoffEnabled = crash.booleanValue("hostHandoffEnabled", true),
898
907
  offlineCaptureAttachmentEnabled = crash.booleanValue("offlineCaptureAttachmentEnabled", true),
899
908
  maximumPendingReports = crash.intValue("maximumPendingReports", 8),
900
909
  retentionDays = crash.intValue("retentionDays", 7),
@@ -962,6 +971,11 @@ class AnsightReactNativeModule(
962
971
  ): AnsightOptions {
963
972
  val remoteTools = map.getMapOrNull("remoteTools")
964
973
  val builder = AnsightOptions.createBuilder(this)
974
+ val clipboardIds = setOf(ClipboardToolIds.GetText, ClipboardToolIds.HasText, ClipboardToolIds.SetText, ClipboardToolIds.Clear)
975
+ builder.withTools(initialTools.filterNot { it.definition.id in clipboardIds })
976
+ if (remoteTools.booleanValue("clipboard", true)) {
977
+ builder.withClipboardTools()
978
+ }
965
979
  if (remoteTools.toolSuiteEnabled("visualTree", enableVisualTreeToolsByDefault)) {
966
980
  builder.withVisualTreeTools()
967
981
  }
package/expo-plugin.js CHANGED
@@ -1,9 +1,9 @@
1
1
  "use strict";
2
2
 
3
3
  const DEFAULT_CAMERA_PERMISSION =
4
- "Allow $(PRODUCT_NAME) to use the camera to scan an Ansight Studio enrollment QR code.";
4
+ "Allow $(PRODUCT_NAME) to use the camera to scan an Ansight host enrollment QR code.";
5
5
  const DEFAULT_LOCAL_NETWORK_PERMISSION =
6
- "Allow $(PRODUCT_NAME) to connect to Ansight Studio on your local network during development.";
6
+ "Allow $(PRODUCT_NAME) to connect to Ansight host on your local network during development.";
7
7
 
8
8
  function withAnsightReactNative(config, options = {}) {
9
9
  const { withInfoPlist } = loadExpoConfigPlugins();
package/index.d.ts CHANGED
@@ -1,3 +1,6 @@
1
+ import type { PurchaseDiagnostics } from "./purchases";
2
+ export * from "./purchases";
3
+ export const purchases: PurchaseDiagnostics;
1
4
  export type AnsightLifecycleState = "unknown" | "foreground" | "background";
2
5
  export type AnsightToolPolicy = "read" | "write" | "critical";
3
6
 
@@ -144,6 +147,8 @@ export interface AnsightVisualTreeToolsOptions {
144
147
  }
145
148
 
146
149
  export interface AnsightRemoteToolsOptions {
150
+ /** Include native clipboard tools; defaults to true. */
151
+ clipboard?: boolean;
147
152
  visualTree?: boolean | AnsightVisualTreeToolsOptions;
148
153
  fileSystem?: AnsightFileSystemToolsOptions;
149
154
  database?: AnsightDatabaseToolsOptions;
@@ -217,7 +222,7 @@ export interface AnsightOptions {
217
222
 
218
223
  export interface AnsightCrashCaptureOptions {
219
224
  enabled?: boolean;
220
- studioHandoffEnabled?: boolean;
225
+ hostHandoffEnabled?: boolean;
221
226
  offlineCaptureAttachmentEnabled?: boolean;
222
227
  maximumPendingReports?: number;
223
228
  retentionDays?: number;
@@ -392,6 +397,7 @@ export class AnsightOptionsBuilder {
392
397
  withoutVisualTreeTools(): this;
393
398
  withFileSystemTools(options?: AnsightFileSystemToolsOptions): this;
394
399
  withDatabaseTools(options?: AnsightDatabaseToolsOptions): this;
400
+ withClipboardTools(enabled?: boolean): this;
395
401
  withPreferencesTools(options?: AnsightPreferencesToolsOptions): this;
396
402
  withReflectionTools(options?: AnsightReflectionToolsOptions): this;
397
403
  build(): AnsightOptions;
@@ -617,7 +623,7 @@ export function screenViewed(name: string, details?: Record<string, string>): Pr
617
623
  export function trackRoute(name: string, details?: Record<string, string>): Promise<AnsightDebugSnapshot>;
618
624
  export function setAppLifecycleState(state: AnsightLifecycleState): Promise<AnsightDebugSnapshot>;
619
625
  export function connect(pairingPayload?: string | object | null, options?: AnsightConnectOptions): Promise<AnsightHostConnectionResult>;
620
- /** Scans a one-use Studio invite, registers this installation, and saves automatic reconnect state. */
626
+ /** Scans a one-use host invite, registers this installation, and saves automatic reconnect state. */
621
627
  export function enrollFromQrCode(options?: AnsightScanPairingOptions): Promise<AnsightHostConnectionResult>;
622
628
  export function scanPairingQrCode(options?: AnsightScanPairingOptions): Promise<AnsightHostConnectionResult>;
623
629
  export function openSession(pairingPayload: string | object, options?: AnsightOpenSessionOptions): Promise<AnsightHostConnectionResult>;
@@ -676,6 +682,7 @@ export function installErrorHandlers(options?: { chain?: boolean }): () => void;
676
682
  export function createReactNavigationTracker(navigationRef: unknown, options?: { recordInitial?: boolean }): ReactNavigationTracker;
677
683
 
678
684
  declare const Ansight: {
685
+ purchases: PurchaseDiagnostics;
679
686
  initialize: typeof initialize;
680
687
  initializeAndActivate: typeof initializeAndActivate;
681
688
  activate: typeof activate;
package/index.js CHANGED
@@ -608,6 +608,11 @@ class AnsightOptionsBuilder {
608
608
  return this;
609
609
  }
610
610
 
611
+ withClipboardTools(enabled = true) {
612
+ this._options.remoteTools = { ...this._options.remoteTools, clipboard: enabled };
613
+ return this;
614
+ }
615
+
611
616
  withPreferencesTools(options = {}) {
612
617
  this._options.remoteTools = {
613
618
  ...(this._options.remoteTools || {}),
@@ -2669,3 +2674,6 @@ module.exports.recordNetworkRequest = recordNetworkRequest;
2669
2674
  module.exports.installNetworkCapture = installNetworkCapture;
2670
2675
  module.exports.uninstallNetworkCapture = uninstallNetworkCapture;
2671
2676
  module.exports.sanitizeNetworkRequest = sanitizeNetworkRequest;
2677
+
2678
+ module.exports.purchases = require("./purchases").createPurchaseDiagnostics((json) => nativeModule.purchaseCommand(json));
2679
+ module.exports.createPurchaseDiagnostics = require("./purchases").createPurchaseDiagnostics;
@@ -4,6 +4,15 @@ import React
4
4
 
5
5
  @objc(AnsightReactNative)
6
6
  final class AnsightReactNative: RCTEventEmitter {
7
+ @objc(purchaseCommand:resolver:rejecter:)
8
+ func purchaseCommand(_ json: String, resolver resolve: @escaping RCTPromiseResolveBlock, rejecter reject: @escaping RCTPromiseRejectBlock) {
9
+ Task {
10
+ do { resolve(try await PurchaseDiagnostics.shared.commandAsync(json)) }
11
+ catch PurchaseDiagnosticsError.environmentNotAllowed { reject(PurchaseDiagnosticsError.environmentErrorCode, "Purchase interop is restricted to simulators and emulators.", PurchaseDiagnosticsError.environmentNotAllowed) }
12
+ catch { reject("purchases_command_failed", "Purchase command failed.", error) }
13
+ }
14
+ }
15
+
7
16
  private final class PendingToolCall {
8
17
  let semaphore = DispatchSemaphore(value: 0)
9
18
  var result: AnsightToolExecutionResult?
@@ -1093,7 +1102,7 @@ final class AnsightReactNative: RCTEventEmitter {
1093
1102
  } else if let crash = raw as? NSDictionary {
1094
1103
  options.crashCapture = AnsightCrashCaptureOptions(
1095
1104
  enabled: boolValue(crash, "enabled", defaultValue: true),
1096
- studioHandoffEnabled: boolValue(crash, "studioHandoffEnabled", defaultValue: true),
1105
+ hostHandoffEnabled: boolValue(crash, "hostHandoffEnabled", defaultValue: true),
1097
1106
  offlineCaptureAttachmentEnabled: boolValue(crash, "offlineCaptureAttachmentEnabled", defaultValue: true),
1098
1107
  maximumPendingReports: intValue(crash, "maximumPendingReports", defaultValue: 8),
1099
1108
  retentionDays: intValue(crash, "retentionDays", defaultValue: 7),
@@ -1153,6 +1162,7 @@ final class AnsightReactNative: RCTEventEmitter {
1153
1162
  remoteTools?["visualTree"],
1154
1163
  defaultValue: useNativeAllInOneDefaults
1155
1164
  ),
1165
+ clipboard: boolValue(remoteTools, "clipboard", defaultValue: true),
1156
1166
  database: databaseToolsOptions(remoteTools?["database"] as? NSDictionary),
1157
1167
  fileSystem: fileSystemToolsOptions(remoteTools?["fileSystem"] as? NSDictionary),
1158
1168
  preferences: preferencesToolsOptions(remoteTools?["preferences"] as? NSDictionary),
@@ -3,6 +3,10 @@
3
3
 
4
4
  @interface RCT_EXTERN_MODULE(AnsightReactNative, RCTEventEmitter)
5
5
 
6
+ RCT_EXTERN_METHOD(purchaseCommand:(NSString *)json
7
+ resolver:(RCTPromiseResolveBlock)resolve
8
+ rejecter:(RCTPromiseRejectBlock)reject)
9
+
6
10
  RCT_EXTERN_METHOD(initialize:(NSDictionary *)options
7
11
  resolver:(RCTPromiseResolveBlock)resolve
8
12
  rejecter:(RCTPromiseRejectBlock)reject)
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@ansight/react-native",
3
- "version": "1.4.0-preview.5",
4
- "description": "React Native bridge for the Ansight mobile SDK.",
3
+ "version": "1.5.0",
4
+ "description": "React Native bridge for Ansight: runtime evidence from your app for coding agents. Screenshots, UI trees, logs, network, telemetry, and app state.",
5
5
  "main": "index.js",
6
6
  "types": "index.d.ts",
7
7
  "license": "SEE LICENSE IN LICENSE",
@@ -34,7 +34,9 @@
34
34
  "expo-plugin.js",
35
35
  "tsconfig.json",
36
36
  "AnsightReactNative.podspec",
37
- "react-native.config.js"
37
+ "react-native.config.js",
38
+ "purchases.js",
39
+ "purchases.d.ts"
38
40
  ],
39
41
  "keywords": [
40
42
  "ansight",
package/purchases.d.ts ADDED
@@ -0,0 +1,61 @@
1
+ export interface PurchaseObservation {
2
+ productId: string;
3
+ source: "store" | "app" | "backend";
4
+ transactionRef?: string | null;
5
+ observedAt?: number;
6
+ state?: "unknown" | "pending" | "purchased" | "cancelled" | "expired" | "revoked" | "failed" | "gracePeriod" | "billingRetry";
7
+ verification?: "unknown" | "verified" | "unverified";
8
+ entitled?: boolean | null;
9
+ deliveryCount?: number | null;
10
+ finished?: boolean | null;
11
+ acknowledged?: boolean | null;
12
+ consumed?: boolean | null;
13
+ expiresAt?: number | null;
14
+ gracePeriodExpiresAt?: number | null;
15
+ environment?: "unknown" | "xcode" | "sandbox" | "production";
16
+ productType?: "unknown" | "consumable" | "nonConsumable" | "subscription" | "nonRenewingSubscription";
17
+ }
18
+ export interface PurchaseProduct {
19
+ productId: string;
20
+ available: boolean;
21
+ observedAt?: number;
22
+ displayPrice?: string | null;
23
+ price?: string | null;
24
+ currencyCode?: string | null;
25
+ productType?: PurchaseObservation["productType"];
26
+ }
27
+ export interface PurchaseExpectations {
28
+ transactionRef?: string;
29
+ productId: string;
30
+ expectedEntitled: boolean;
31
+ requireVerified?: boolean;
32
+ requireBackendVerification?: boolean;
33
+ expectedDeliveryCount?: number;
34
+ maxAgeMilliseconds?: number;
35
+ }
36
+ export interface PurchaseSnapshot {
37
+ schema: "ansight.purchases.v1";
38
+ capturedAt: number;
39
+ droppedEvents: number;
40
+ coverage: "observedOnly";
41
+ observations: PurchaseObservation[];
42
+ products: PurchaseProduct[];
43
+ }
44
+ export interface PurchaseValidationReport extends PurchaseSnapshot {
45
+ status: "pass" | "fail" | "inconclusive";
46
+ checks: { source: string; status: "pass" | "fail" | "inconclusive"; reason: string }[];
47
+ }
48
+ export interface PurchaseDiagnostics {
49
+ createTransactionReference(identifier: string): Promise<{ transactionRef: string }>;
50
+ /** Register read-only remote tools after SDK initialization. */
51
+ register(): Promise<{ success: boolean }>;
52
+ record(observation: PurchaseObservation): Promise<{ success: boolean }>;
53
+ recordProduct(product: PurchaseProduct): Promise<{ success: boolean }>;
54
+ /** Clear evidence on account switch. Does not clear store transactions. */
55
+ clear(): Promise<{ success: boolean }>;
56
+ snapshot(productId?: string): Promise<PurchaseSnapshot>;
57
+ validate(expectations: PurchaseExpectations): Promise<PurchaseValidationReport>;
58
+ /** Apple only. Reads StoreKit 2 using known product IDs. */
59
+ refreshStoreKit(productIds: string[]): Promise<PurchaseSnapshot>;
60
+ }
61
+ export function createPurchaseDiagnostics(send: (json: string) => Promise<string>): PurchaseDiagnostics;
package/purchases.js ADDED
@@ -0,0 +1,17 @@
1
+ "use strict";
2
+
3
+ // All observation retention, validation and tools live in the native base SDK.
4
+ function createPurchaseDiagnostics(send) {
5
+ const command = async (action, fields = {}) => JSON.parse(await send(JSON.stringify({ action, ...fields })));
6
+ return {
7
+ createTransactionReference: (identifier) => command("reference", { identifier }),
8
+ register: () => command("register"),
9
+ record: (observation) => command("record", { observation: { observedAt: Date.now(), ...observation } }),
10
+ recordProduct: (product) => command("recordProduct", { product: { observedAt: Date.now(), productType: "unknown", ...product } }),
11
+ clear: () => command("clear"),
12
+ snapshot: (productId) => command("purchases.get_state", { arguments: productId === undefined ? {} : { productId } }),
13
+ validate: (expectations) => command("purchases.validate", { arguments: expectations }),
14
+ refreshStoreKit: (productIds) => command("refreshStoreKit", { productIds }),
15
+ };
16
+ }
17
+ module.exports = { createPurchaseDiagnostics };