rnxsim 0.1.458 → 0.1.460

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.
Files changed (62) hide show
  1. package/cli/bridge-flow-runner.ts +13 -10
  2. package/cli/commands/inspect/actions.ts +20 -127
  3. package/cli/commands/inspect/core.ts +4 -19
  4. package/cli/commands/inspect/keyboard.ts +1 -0
  5. package/cli/commands/inspect/resolve-target.ts +3 -1
  6. package/cli/commands/inspect.ts +2 -0
  7. package/cli/drivers/playwright-sim-host.ts +24 -0
  8. package/dist-lib/agent-daemon-client.cjs +1 -1
  9. package/dist-lib/agent-events.cjs +1 -1
  10. package/dist-lib/agent-identity.cjs +1 -1
  11. package/dist-lib/agent-sessions.cjs +1 -1
  12. package/dist-lib/attached-projects.cjs +1 -1
  13. package/dist-lib/auth/shared-session.cjs +1 -1
  14. package/dist-lib/backend-origin.cjs +1 -1
  15. package/dist-lib/beta.cjs +1 -1
  16. package/dist-lib/beta.mjs +1 -1
  17. package/dist-lib/bridge-constants.cjs +1 -1
  18. package/dist-lib/bridge-contract-input.cjs +24 -3
  19. package/dist-lib/bridge-contract-input.mjs +22 -2
  20. package/dist-lib/bridge-contract.cjs +1 -1
  21. package/dist-lib/bridge-contract.mjs +1 -1
  22. package/dist-lib/capture-contract.cjs +1 -1
  23. package/dist-lib/capture-contract.mjs +1 -1
  24. package/dist-lib/cli-constants.cjs +1 -1
  25. package/dist-lib/cloud-contract.cjs +1 -1
  26. package/dist-lib/cloud-contract.mjs +1 -1
  27. package/dist-lib/cloud.cjs +1 -1
  28. package/dist-lib/cloud.mjs +1 -1
  29. package/dist-lib/config.cjs +1 -1
  30. package/dist-lib/detox/index.cjs +1 -1
  31. package/dist-lib/dev-bundle-resolution.cjs +1 -1
  32. package/dist-lib/home-paths.cjs +1 -1
  33. package/dist-lib/host/bridge-host.cjs +12 -7
  34. package/dist-lib/host/fetch-proxy-handler.cjs +1 -1
  35. package/dist-lib/host/fetch-proxy-overrides.cjs +1 -1
  36. package/dist-lib/host/fetch-proxy-overrides.mjs +1 -1
  37. package/dist-lib/host/replacement-module-handler.cjs +1 -1
  38. package/dist-lib/host/websocket-proxy.cjs +1 -1
  39. package/dist-lib/index.cjs +26 -72
  40. package/dist-lib/jump-to-source-babel.cjs +1 -1
  41. package/dist-lib/jump-to-source-native.cjs +1 -1
  42. package/dist-lib/menu.cjs +1 -1
  43. package/dist-lib/menu.mjs +1 -1
  44. package/dist-lib/metro-fingerprint-registry.cjs +1 -1
  45. package/dist-lib/metro-fingerprint-registry.mjs +1 -1
  46. package/dist-lib/metro-production-bundle.cjs +1 -1
  47. package/dist-lib/metro-production-bundle.mjs +1 -1
  48. package/dist-lib/metro.cjs +1 -1
  49. package/dist-lib/profiles.cjs +1 -1
  50. package/dist-lib/public-brand.cjs +1 -1
  51. package/dist-lib/react-native-host-modules.cjs +1 -1
  52. package/dist-lib/react-native-host-modules.mjs +1 -1
  53. package/dist-lib/render-mode.cjs +1 -1
  54. package/dist-lib/scripts/dev-server-scanner.cjs +1 -1
  55. package/dist-lib/sdk.cjs +26 -72
  56. package/dist-lib/sdk.mjs +26 -72
  57. package/dist-lib/skills.cjs +756 -133
  58. package/dist-lib/vite.cjs +1 -1
  59. package/package.json +1 -1
  60. package/src/bridge-contract-input.ts +22 -2
  61. package/src/host/bridge-host.ts +14 -8
  62. package/src/sim-client.ts +14 -2
package/dist-lib/vite.cjs CHANGED
@@ -1,4 +1,4 @@
1
- /*! rnx v0.1.458 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
1
+ /*! rnx v0.1.460 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
2
2
  let __sootsim_import_meta_url = ''; try { __sootsim_import_meta_url = require('url').pathToFileURL(__filename).href; } catch {}
3
3
  "use strict";
4
4
  var __create = Object.create;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "rnxsim",
3
- "version": "0.1.458",
3
+ "version": "0.1.460",
4
4
  "description": "Vite and Metro plugins, testing drivers, and SDK exports for rnx.",
5
5
  "author": "Tamagui LLC",
6
6
  "license": "SEE LICENSE IN LICENSE",
@@ -1,9 +1,8 @@
1
+ import { SIM_LONG_PRESS_MAX_MS } from './bridge-contract'
1
2
  // untrusted JSON -> bridge-contract argument. one owner for that conversion, so
2
3
  // every transport in front of a sim (the RNX Cloud sim service's HTTP and
3
4
  // WebSocket routes) validates its request bodies here rather than growing a
4
5
  // second reader for the same shapes.
5
-
6
- import { SIM_LONG_PRESS_MAX_MS } from './bridge-contract'
7
6
  import type {
8
7
  ResetOptions,
9
8
  SemanticWaitOptions,
@@ -13,6 +12,7 @@ import type {
13
12
  SimStateOptions,
14
13
  } from './bridge-contract'
15
14
  import type { SimPerformStep, SimScreenshotOptions } from './sim-client'
15
+ import type { SootSimReplayTarget } from '@rnx/globals'
16
16
 
17
17
  /** the caller sent a value this bridge argument cannot be read from. */
18
18
  export class BridgeInputError extends Error {
@@ -113,6 +113,7 @@ export function parsePerformStep(value: unknown, index: number): SimPerformStep
113
113
  case 'tap':
114
114
  return {
115
115
  type,
116
+ target: parseTapTarget(step.target),
116
117
  x: numberValue(step.x, `${path}.x`),
117
118
  y: numberValue(step.y, `${path}.y`),
118
119
  }
@@ -388,3 +389,22 @@ export function parseScreenshotOptions(value: unknown): SimScreenshotOptions {
388
389
  }),
389
390
  }
390
391
  }
392
+
393
+ export function parseTapTarget(value: unknown): SootSimReplayTarget | undefined {
394
+ if (value === undefined) return undefined
395
+ const input = recordValue(value, 'tap.target')
396
+ const target: SootSimReplayTarget = {}
397
+ if (input.nodeId !== undefined && input.nodeId !== null) {
398
+ const nodeId = numberValue(input.nodeId, 'tap.target.nodeId')
399
+ if (!Number.isSafeInteger(nodeId))
400
+ validationFailure('tap.target.nodeId', 'must be an integer')
401
+ target.nodeId = nodeId
402
+ }
403
+ for (const key of ['id', 'testID', 'text', 'type'] as const) {
404
+ if (input[key] !== undefined && input[key] !== null)
405
+ target[key] = stringValue(input[key], `tap.target.${key}`)
406
+ }
407
+ if (target.nodeId === undefined && !target.testID && !target.id)
408
+ validationFailure('tap.target', 'requires nodeId, testID or id')
409
+ return target
410
+ }
@@ -223,6 +223,7 @@ interface BridgeForwardedCommand {
223
223
  }
224
224
 
225
225
  export interface BridgeHostOptions {
226
+ /** use 0 for an OS-assigned port; startAsync returns the bound address. */
226
227
  port?: number
227
228
  openUrl?: (url: string, options?: OpenUrlOptions) => Promise<void> | void
228
229
  /** Contrast-specific excludes for the agent host's dev-server scan. passed
@@ -466,7 +467,7 @@ export class SootSimBridgeHost {
466
467
  private static SCAN_FRESH_MS = 2000
467
468
 
468
469
  constructor(opts: BridgeHostOptions = {}) {
469
- this.preferredPort = opts.port || DEFAULT_SOOTSIM_BRIDGE_PORT
470
+ this.preferredPort = opts.port ?? DEFAULT_SOOTSIM_BRIDGE_PORT
470
471
  this.port = this.preferredPort
471
472
  // default off — callers that want the lockfile (rnx serve) opt in.
472
473
  this.shouldWriteLockfile = opts.writeLockfile === true
@@ -537,9 +538,9 @@ export class SootSimBridgeHost {
537
538
  for (let attempt = 0; attempt < this.portFallbackCount; attempt++) {
538
539
  const candidate = this.preferredPort + attempt
539
540
  try {
540
- await this.bindOnce(candidate, options?.silent === true)
541
- this.effectivePort = candidate
542
- this.port = candidate
541
+ const boundPort = await this.bindOnce(candidate, options?.silent === true)
542
+ this.effectivePort = boundPort
543
+ this.port = boundPort
543
544
  this.startedAt = Date.now()
544
545
  if (attempt > 0 && !options?.silent) {
545
546
  process.stderr.write(
@@ -547,7 +548,7 @@ export class SootSimBridgeHost {
547
548
  )
548
549
  }
549
550
  this.afterBind()
550
- return candidate
551
+ return boundPort
551
552
  } catch (err: unknown) {
552
553
  const e = err as NodeJS.ErrnoException
553
554
  if (e?.code !== 'EADDRINUSE') {
@@ -566,8 +567,8 @@ export class SootSimBridgeHost {
566
567
  )
567
568
  }
568
569
 
569
- private bindOnce(port: number, _silent: boolean): Promise<void> {
570
- return new Promise<void>((resolve, reject) => {
570
+ private bindOnce(port: number, _silent: boolean): Promise<number> {
571
+ return new Promise<number>((resolve, reject) => {
571
572
  const server = createServer((req, res) => this.handleHttpRequest(req, res))
572
573
  let settled = false
573
574
 
@@ -589,6 +590,11 @@ export class SootSimBridgeHost {
589
590
  // 127.0.0.1 explicitly to avoid the localhost-vs-::1 DNS coinflip.
590
591
  server.listen(port, '127.0.0.1', () => {
591
592
  if (settled) return
593
+ const address = server.address()
594
+ if (!address || typeof address === 'string') {
595
+ onError(new Error('ws bridge has no bound TCP address'))
596
+ return
597
+ }
592
598
  settled = true
593
599
  server.removeListener('error', onError)
594
600
  server.on('error', (err) => {
@@ -603,7 +609,7 @@ export class SootSimBridgeHost {
603
609
  this.wss?.emit('connection', ws, req)
604
610
  })
605
611
  })
606
- resolve()
612
+ resolve(address.port)
607
613
  })
608
614
  })
609
615
  }
package/src/sim-client.ts CHANGED
@@ -480,11 +480,22 @@ export class SimClient implements WsBridge, InspectBridge {
480
480
  const { text, ...textOpts } = target
481
481
  return this.throwUnlessTapped(await tapByText(this, text, textOpts), text)
482
482
  }
483
- if ('testID' in target && typeof target.testID === 'string') {
483
+ if (
484
+ 'testID' in target &&
485
+ typeof target.testID === 'string' &&
486
+ typeof target.nodeId !== 'number'
487
+ ) {
484
488
  return this.throwUnlessTapped(await tapById(this, target.testID), target.testID)
485
489
  }
486
490
  const coords = this.coordsForTapTarget(target)
487
- const result = await this.send({ type: 'tap', x: coords.x, y: coords.y })
491
+ const result = await this.send({
492
+ type: 'tap',
493
+ x: coords.x,
494
+ y: coords.y,
495
+ ...('nodeId' in target && typeof target.nodeId === 'number'
496
+ ? { target: { nodeId: target.nodeId } }
497
+ : {}),
498
+ })
488
499
  if (!isTapSuccess(result)) {
489
500
  throw new SimTapError(
490
501
  `tap at ${coords.x},${coords.y} missed: ${JSON.stringify(result)}`,
@@ -559,6 +570,7 @@ export class SimClient implements WsBridge, InspectBridge {
559
570
  x: target.x,
560
571
  y: target.y,
561
572
  target: {
573
+ nodeId: target.nodeId,
562
574
  testID: target.testID ?? undefined,
563
575
  text: target.text ?? undefined,
564
576
  type: target.type ?? undefined,