rnxsim 0.1.516 → 0.1.518

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 (56) hide show
  1. package/detox/index.ts +56 -31
  2. package/dist-lib/agent-daemon-client.cjs +1 -1
  3. package/dist-lib/agent-events.cjs +1 -1
  4. package/dist-lib/agent-identity.cjs +1 -1
  5. package/dist-lib/agent-sessions.cjs +1 -1
  6. package/dist-lib/attached-projects.cjs +1 -1
  7. package/dist-lib/auth/shared-session.cjs +1 -1
  8. package/dist-lib/backend-origin.cjs +1 -1
  9. package/dist-lib/beta.cjs +1 -1
  10. package/dist-lib/beta.mjs +1 -1
  11. package/dist-lib/bridge-constants.cjs +1 -1
  12. package/dist-lib/bridge-contract-input.cjs +1 -1
  13. package/dist-lib/bridge-contract-input.mjs +1 -1
  14. package/dist-lib/bridge-contract.cjs +1 -1
  15. package/dist-lib/bridge-contract.mjs +1 -1
  16. package/dist-lib/capture-contract.cjs +1 -1
  17. package/dist-lib/capture-contract.mjs +1 -1
  18. package/dist-lib/cli-constants.cjs +1 -1
  19. package/dist-lib/cloud-contract.cjs +29 -1
  20. package/dist-lib/cloud-contract.mjs +23 -1
  21. package/dist-lib/cloud.cjs +114 -16
  22. package/dist-lib/cloud.mjs +111 -16
  23. package/dist-lib/config.cjs +1 -1
  24. package/dist-lib/detox/index.cjs +30 -14
  25. package/dist-lib/dev-bundle-resolution.cjs +1 -1
  26. package/dist-lib/home-paths.cjs +1 -1
  27. package/dist-lib/host/bridge-host.cjs +1 -1
  28. package/dist-lib/host/fetch-proxy-handler.cjs +1 -1
  29. package/dist-lib/host/fetch-proxy-overrides.cjs +1 -1
  30. package/dist-lib/host/fetch-proxy-overrides.mjs +1 -1
  31. package/dist-lib/host/replacement-module-handler.cjs +1 -1
  32. package/dist-lib/host/websocket-proxy.cjs +1 -1
  33. package/dist-lib/index.cjs +1 -1
  34. package/dist-lib/jump-to-source-babel.cjs +1 -1
  35. package/dist-lib/jump-to-source-native.cjs +1 -1
  36. package/dist-lib/menu.cjs +1 -1
  37. package/dist-lib/menu.mjs +1 -1
  38. package/dist-lib/metro-fingerprint-registry.cjs +1 -1
  39. package/dist-lib/metro-fingerprint-registry.mjs +1 -1
  40. package/dist-lib/metro-production-bundle.cjs +1 -1
  41. package/dist-lib/metro-production-bundle.mjs +1 -1
  42. package/dist-lib/metro.cjs +1 -1
  43. package/dist-lib/profiles.cjs +1 -1
  44. package/dist-lib/public-brand.cjs +1 -1
  45. package/dist-lib/react-native-host-modules.cjs +1 -1
  46. package/dist-lib/react-native-host-modules.mjs +1 -1
  47. package/dist-lib/render-mode.cjs +1 -1
  48. package/dist-lib/scripts/dev-server-scanner.cjs +1 -1
  49. package/dist-lib/sdk.cjs +1 -1
  50. package/dist-lib/sdk.mjs +1 -1
  51. package/dist-lib/skills.cjs +1 -1
  52. package/dist-lib/swift.cjs +1 -1
  53. package/dist-lib/vite.cjs +1 -1
  54. package/package.json +1 -1
  55. package/src/cloud-contract.ts +37 -1
  56. package/src/cloud.ts +178 -21
package/detox/index.ts CHANGED
@@ -1772,8 +1772,15 @@ export const device = {
1772
1772
  // once durationMs of lockstep time has elapsed, so held states (a lifted
1773
1773
  // control thumb, a pressed row) are painted mid-hold. an external trigger
1774
1774
  // that holds and releases before returning never paints a frame in
1775
- // between, because no lockstep frame steps while it runs.
1776
- hold?: { durationMs: number; x: number; y: number } | null
1775
+ // between, because no lockstep frame steps while it runs. moves drag the
1776
+ // held pointer to each point once afterMs of lockstep time has elapsed
1777
+ // since the press, and the release lands at the last point reached.
1778
+ hold?: {
1779
+ durationMs: number
1780
+ moves?: Array<{ afterMs: number; x: number; y: number }>
1781
+ x: number
1782
+ y: number
1783
+ } | null
1777
1784
  rootFrame?: { height: number; width: number; x: number; y: number } | null
1778
1785
  settleMs?: number
1779
1786
  trigger?: () => unknown
@@ -1851,6 +1858,7 @@ export const device = {
1851
1858
  bridges?: {
1852
1859
  interact?: {
1853
1860
  touchDown: (x: number, y: number) => Promise<boolean>
1861
+ touchMove: (x: number, y: number) => Promise<boolean>
1854
1862
  touchUp: (x: number, y: number) => Promise<boolean>
1855
1863
  }
1856
1864
  liveComposite?: {
@@ -1982,23 +1990,45 @@ export const device = {
1982
1990
  const frameMs = 1000 / 60
1983
1991
  const controller = await lockstep.begin(60)
1984
1992
  // the hold's pointer goes down before the first stepped frame, so its
1985
- // start is one frame before the first receipt; the release lands on the
1986
- // first stepped frame at or past durationMs from there. the deadline is
1987
- // a frame index: comparing summed virtual timestamps against the
1988
- // duration lets rounding push the release past the frame it belongs to.
1989
- const holdState: { released: boolean; releaseFrameIndex: number | null } = {
1993
+ // start is one frame before the first receipt; each move and the release
1994
+ // land on the first stepped frame at or past their time from there. the
1995
+ // deadlines are frame indexes: comparing summed virtual timestamps
1996
+ // against a duration lets rounding push an event past its frame.
1997
+ const moves = input.hold?.moves ?? []
1998
+ const holdState = {
1999
+ nextMove: 0,
2000
+ pressFrameIndex: null as number | null,
1990
2001
  released: false,
1991
- releaseFrameIndex: null,
2002
+ x: input.hold?.x ?? 0,
2003
+ y: input.hold?.y ?? 0,
1992
2004
  }
1993
- const releaseHoldIfDue = async (receipt: FrameReceipt) => {
2005
+ const holdEventFrameIndex = (afterMs: number) =>
2006
+ (holdState.pressFrameIndex ?? 0) + Math.ceil(afterMs / frameMs)
2007
+ const nextHoldEventFrameIndex = () => {
2008
+ if (!input.hold || holdState.released || holdState.pressFrameIndex === null) {
2009
+ return null
2010
+ }
2011
+ const move = moves[holdState.nextMove]
2012
+ return holdEventFrameIndex(move ? move.afterMs : input.hold.durationMs)
2013
+ }
2014
+ const advanceHold = async (receipt: FrameReceipt) => {
1994
2015
  if (!input.hold || !interact || holdState.released) return
1995
- if (holdState.releaseFrameIndex === null) {
1996
- holdState.releaseFrameIndex =
1997
- receipt.frameIndex - 1 + Math.ceil(input.hold.durationMs / frameMs)
2016
+ if (holdState.pressFrameIndex === null) {
2017
+ holdState.pressFrameIndex = receipt.frameIndex - 1
2018
+ }
2019
+ for (
2020
+ let move = moves[holdState.nextMove];
2021
+ move && receipt.frameIndex >= holdEventFrameIndex(move.afterMs);
2022
+ move = moves[holdState.nextMove]
2023
+ ) {
2024
+ holdState.nextMove++
2025
+ holdState.x = move.x
2026
+ holdState.y = move.y
2027
+ await interact.touchMove(move.x, move.y)
1998
2028
  }
1999
- if (receipt.frameIndex < holdState.releaseFrameIndex) return
2029
+ if (receipt.frameIndex < holdEventFrameIndex(input.hold.durationMs)) return
2000
2030
  holdState.released = true
2001
- await interact.touchUp(input.hold.x, input.hold.y)
2031
+ await interact.touchUp(holdState.x, holdState.y)
2002
2032
  }
2003
2033
  try {
2004
2034
  const baselineBitmap = await captureBitmap()
@@ -2023,7 +2053,7 @@ export const device = {
2023
2053
  for (let frame = 0; frame < detectionFrameLimit; frame++) {
2024
2054
  if (state.cancelled) throw new Error('rnx motion capture was cancelled')
2025
2055
  const receipt = await controller.stepFrame()
2026
- await releaseHoldIfDue(receipt)
2056
+ await advanceHold(receipt)
2027
2057
  const candidateBitmap = await captureBitmap()
2028
2058
  const bounds = boundsFor(candidateBitmap)
2029
2059
  const measurement = measureChange({
@@ -2050,25 +2080,20 @@ export const device = {
2050
2080
  const snapshots: Snapshot[] = []
2051
2081
  for (const stage of input.stages) {
2052
2082
  if (state.cancelled) throw new Error('rnx motion capture was cancelled')
2053
- if (
2054
- input.hold &&
2055
- !holdState.released &&
2056
- holdState.releaseFrameIndex !== null
2083
+ // step through every hold move and the release that fall before
2084
+ // this stage one frame at a time, so the stage paints the pointer
2085
+ // where it belongs rather than a hold the jump skipped past.
2086
+ const stageFrameIndex =
2087
+ visibleStart.frameIndex + Math.ceil(stage.offsetMs / frameMs)
2088
+ for (
2089
+ let eventFrameIndex = nextHoldEventFrameIndex();
2090
+ eventFrameIndex !== null && stageFrameIndex > eventFrameIndex;
2091
+ eventFrameIndex = nextHoldEventFrameIndex()
2057
2092
  ) {
2058
- // step to the release frame first when this stage lies past it,
2059
- // so the stage paints the released state rather than a hold
2060
- // that overran because the jump skipped its deadline.
2061
- const stageFrameIndex =
2062
- visibleStart.frameIndex + Math.ceil(stage.offsetMs / frameMs)
2063
- while (
2064
- !holdState.released &&
2065
- stageFrameIndex > holdState.releaseFrameIndex
2066
- ) {
2067
- await releaseHoldIfDue(await controller.stepFrame())
2068
- }
2093
+ await advanceHold(await controller.stepFrame())
2069
2094
  }
2070
2095
  const receipt = await controller.stepToOffset(visibleStart, stage.offsetMs)
2071
- await releaseHoldIfDue(receipt)
2096
+ await advanceHold(receipt)
2072
2097
  snapshots.push({
2073
2098
  actualMs: receipt.virtualTimestampMs - visibleStart.virtualTimestampMs,
2074
2099
  bitmap: await captureBitmap(),
@@ -1,4 +1,4 @@
1
- /*! rnx v0.1.516 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
1
+ /*! rnx v0.1.518 | (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;
@@ -1,4 +1,4 @@
1
- /*! rnx v0.1.516 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
1
+ /*! rnx v0.1.518 | (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 __defProp = Object.defineProperty;
@@ -1,4 +1,4 @@
1
- /*! rnx v0.1.516 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
1
+ /*! rnx v0.1.518 | (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 __defProp = Object.defineProperty;
@@ -1,4 +1,4 @@
1
- /*! rnx v0.1.516 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
1
+ /*! rnx v0.1.518 | (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;
@@ -1,4 +1,4 @@
1
- /*! rnx v0.1.516 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
1
+ /*! rnx v0.1.518 | (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;
@@ -1,4 +1,4 @@
1
- /*! rnx v0.1.516 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
1
+ /*! rnx v0.1.518 | (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;
@@ -1,4 +1,4 @@
1
- /*! rnx v0.1.516 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
1
+ /*! rnx v0.1.518 | (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 __defProp = Object.defineProperty;
package/dist-lib/beta.cjs CHANGED
@@ -1,4 +1,4 @@
1
- /*! rnx v0.1.516 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
1
+ /*! rnx v0.1.518 | (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 __defProp = Object.defineProperty;
package/dist-lib/beta.mjs CHANGED
@@ -1,4 +1,4 @@
1
- /*! rnx v0.1.516 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
1
+ /*! rnx v0.1.518 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
2
2
 
3
3
  // src/beta.ts
4
4
  var IS_BETA = true;
@@ -1,4 +1,4 @@
1
- /*! rnx v0.1.516 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
1
+ /*! rnx v0.1.518 | (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 __defProp = Object.defineProperty;
@@ -1,4 +1,4 @@
1
- /*! rnx v0.1.516 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
1
+ /*! rnx v0.1.518 | (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 __defProp = Object.defineProperty;
@@ -1,4 +1,4 @@
1
- /*! rnx v0.1.516 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
1
+ /*! rnx v0.1.518 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
2
2
 
3
3
  // src/bridge-contract.ts
4
4
  var SIM_LONG_PRESS_MAX_MS = 5e3;
@@ -1,4 +1,4 @@
1
- /*! rnx v0.1.516 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
1
+ /*! rnx v0.1.518 | (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 __defProp = Object.defineProperty;
@@ -1,4 +1,4 @@
1
- /*! rnx v0.1.516 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
1
+ /*! rnx v0.1.518 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
2
2
 
3
3
  // src/bridge-contract.ts
4
4
  var REFUSED_PERFORM_STEP_TYPES = [
@@ -1,4 +1,4 @@
1
- /*! rnx v0.1.516 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
1
+ /*! rnx v0.1.518 | (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 __defProp = Object.defineProperty;
@@ -1,4 +1,4 @@
1
- /*! rnx v0.1.516 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
1
+ /*! rnx v0.1.518 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
2
2
 
3
3
  // src/capture-contract.ts
4
4
  var RNX_SCREEN_CAPTURE_VERSION = 1;
@@ -1,4 +1,4 @@
1
- /*! rnx v0.1.516 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
1
+ /*! rnx v0.1.518 | (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 __defProp = Object.defineProperty;
@@ -1,4 +1,4 @@
1
- /*! rnx v0.1.516 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
1
+ /*! rnx v0.1.518 | (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 __defProp = Object.defineProperty;
@@ -30,9 +30,15 @@ __export(cloud_contract_exports, {
30
30
  RNX_CLOUD_LABELS_MAX_COUNT: () => RNX_CLOUD_LABELS_MAX_COUNT,
31
31
  RNX_CLOUD_LABEL_MAX_LENGTH: () => RNX_CLOUD_LABEL_MAX_LENGTH,
32
32
  RNX_CLOUD_MAX_ARTIFACT_BYTES: () => RNX_CLOUD_MAX_ARTIFACT_BYTES,
33
+ RNX_CLOUD_SCOPED_TOKEN_DEFAULT_TTL_SECONDS: () => RNX_CLOUD_SCOPED_TOKEN_DEFAULT_TTL_SECONDS,
34
+ RNX_CLOUD_SCOPED_TOKEN_MAX_ORIGINS: () => RNX_CLOUD_SCOPED_TOKEN_MAX_ORIGINS,
35
+ RNX_CLOUD_SCOPED_TOKEN_MAX_TTL_SECONDS: () => RNX_CLOUD_SCOPED_TOKEN_MAX_TTL_SECONDS,
36
+ RNX_CLOUD_SCOPED_TOKEN_MIN_TTL_SECONDS: () => RNX_CLOUD_SCOPED_TOKEN_MIN_TTL_SECONDS,
37
+ RNX_CLOUD_SCOPED_TOKEN_PREFIX: () => RNX_CLOUD_SCOPED_TOKEN_PREFIX,
33
38
  RNX_CLOUD_TEST_FILES_MAX_BYTES: () => RNX_CLOUD_TEST_FILES_MAX_BYTES,
34
39
  RNX_CLOUD_TEST_FILES_MAX_COUNT: () => RNX_CLOUD_TEST_FILES_MAX_COUNT,
35
40
  RNX_CLOUD_TOKEN_SCOPES: () => RNX_CLOUD_TOKEN_SCOPES,
41
+ isRnxCloudCommandScope: () => isRnxCloudCommandScope,
36
42
  isRnxCloudCommandType: () => isRnxCloudCommandType,
37
43
  isRnxCloudSimStatus: () => isRnxCloudSimStatus,
38
44
  isValidRnxCloudLabel: () => isValidRnxCloudLabel,
@@ -48,6 +54,22 @@ var RNX_CLOUD_DESIGN_MAX_STORAGE_ENTRIES = 256;
48
54
  var RNX_CLOUD_DESIGN_MAX_STORAGE_BYTES = 1024 * 1024;
49
55
  var RNX_CLOUD_TEST_FILES_MAX_COUNT = 256;
50
56
  var RNX_CLOUD_TEST_FILES_MAX_BYTES = 5e5;
57
+ var RNX_CLOUD_COMMAND_SCOPE_SET = /* @__PURE__ */ new Set([
58
+ "read",
59
+ "drive",
60
+ "reset",
61
+ "media",
62
+ "debug",
63
+ "watch"
64
+ ]);
65
+ function isRnxCloudCommandScope(value) {
66
+ return RNX_CLOUD_COMMAND_SCOPE_SET.has(value);
67
+ }
68
+ var RNX_CLOUD_SCOPED_TOKEN_PREFIX = "sk_rnx_sim_";
69
+ var RNX_CLOUD_SCOPED_TOKEN_DEFAULT_TTL_SECONDS = 3600;
70
+ var RNX_CLOUD_SCOPED_TOKEN_MIN_TTL_SECONDS = 1;
71
+ var RNX_CLOUD_SCOPED_TOKEN_MAX_TTL_SECONDS = 14400;
72
+ var RNX_CLOUD_SCOPED_TOKEN_MAX_ORIGINS = 16;
51
73
  var RNX_CLOUD_COMMAND_SCOPES = {
52
74
  state: "read",
53
75
  tree: "read",
@@ -152,9 +174,15 @@ function isRnxCloudSimStatus(value) {
152
174
  RNX_CLOUD_LABELS_MAX_COUNT,
153
175
  RNX_CLOUD_LABEL_MAX_LENGTH,
154
176
  RNX_CLOUD_MAX_ARTIFACT_BYTES,
177
+ RNX_CLOUD_SCOPED_TOKEN_DEFAULT_TTL_SECONDS,
178
+ RNX_CLOUD_SCOPED_TOKEN_MAX_ORIGINS,
179
+ RNX_CLOUD_SCOPED_TOKEN_MAX_TTL_SECONDS,
180
+ RNX_CLOUD_SCOPED_TOKEN_MIN_TTL_SECONDS,
181
+ RNX_CLOUD_SCOPED_TOKEN_PREFIX,
155
182
  RNX_CLOUD_TEST_FILES_MAX_BYTES,
156
183
  RNX_CLOUD_TEST_FILES_MAX_COUNT,
157
184
  RNX_CLOUD_TOKEN_SCOPES,
185
+ isRnxCloudCommandScope,
158
186
  isRnxCloudCommandType,
159
187
  isRnxCloudSimStatus,
160
188
  isValidRnxCloudLabel,
@@ -1,4 +1,4 @@
1
- /*! rnx v0.1.516 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
1
+ /*! rnx v0.1.518 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
2
2
 
3
3
  // src/cloud-contract.ts
4
4
  var RNX_CLOUD_MAX_ARTIFACT_BYTES = 20 * 1024 * 1024;
@@ -6,6 +6,22 @@ var RNX_CLOUD_DESIGN_MAX_STORAGE_ENTRIES = 256;
6
6
  var RNX_CLOUD_DESIGN_MAX_STORAGE_BYTES = 1024 * 1024;
7
7
  var RNX_CLOUD_TEST_FILES_MAX_COUNT = 256;
8
8
  var RNX_CLOUD_TEST_FILES_MAX_BYTES = 5e5;
9
+ var RNX_CLOUD_COMMAND_SCOPE_SET = /* @__PURE__ */ new Set([
10
+ "read",
11
+ "drive",
12
+ "reset",
13
+ "media",
14
+ "debug",
15
+ "watch"
16
+ ]);
17
+ function isRnxCloudCommandScope(value) {
18
+ return RNX_CLOUD_COMMAND_SCOPE_SET.has(value);
19
+ }
20
+ var RNX_CLOUD_SCOPED_TOKEN_PREFIX = "sk_rnx_sim_";
21
+ var RNX_CLOUD_SCOPED_TOKEN_DEFAULT_TTL_SECONDS = 3600;
22
+ var RNX_CLOUD_SCOPED_TOKEN_MIN_TTL_SECONDS = 1;
23
+ var RNX_CLOUD_SCOPED_TOKEN_MAX_TTL_SECONDS = 14400;
24
+ var RNX_CLOUD_SCOPED_TOKEN_MAX_ORIGINS = 16;
9
25
  var RNX_CLOUD_COMMAND_SCOPES = {
10
26
  state: "read",
11
27
  tree: "read",
@@ -109,9 +125,15 @@ export {
109
125
  RNX_CLOUD_LABELS_MAX_COUNT,
110
126
  RNX_CLOUD_LABEL_MAX_LENGTH,
111
127
  RNX_CLOUD_MAX_ARTIFACT_BYTES,
128
+ RNX_CLOUD_SCOPED_TOKEN_DEFAULT_TTL_SECONDS,
129
+ RNX_CLOUD_SCOPED_TOKEN_MAX_ORIGINS,
130
+ RNX_CLOUD_SCOPED_TOKEN_MAX_TTL_SECONDS,
131
+ RNX_CLOUD_SCOPED_TOKEN_MIN_TTL_SECONDS,
132
+ RNX_CLOUD_SCOPED_TOKEN_PREFIX,
112
133
  RNX_CLOUD_TEST_FILES_MAX_BYTES,
113
134
  RNX_CLOUD_TEST_FILES_MAX_COUNT,
114
135
  RNX_CLOUD_TOKEN_SCOPES,
136
+ isRnxCloudCommandScope,
115
137
  isRnxCloudCommandType,
116
138
  isRnxCloudSimStatus,
117
139
  isValidRnxCloudLabel,
@@ -1,4 +1,4 @@
1
- /*! rnx v0.1.516 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
1
+ /*! rnx v0.1.518 | (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 __defProp = Object.defineProperty;
@@ -24,8 +24,11 @@ var cloud_exports = {};
24
24
  __export(cloud_exports, {
25
25
  RNX_CLOUD_COMMAND_TYPES: () => RNX_CLOUD_COMMAND_TYPES,
26
26
  RNX_CLOUD_MAX_ARTIFACT_BYTES: () => RNX_CLOUD_MAX_ARTIFACT_BYTES,
27
+ RNX_CLOUD_SCOPED_TOKEN_PREFIX: () => RNX_CLOUD_SCOPED_TOKEN_PREFIX,
27
28
  RemoteSimulator: () => RemoteSimulator,
29
+ connect: () => connect,
28
30
  createRemoteSimulator: () => createRemoteSimulator,
31
+ isRnxCloudCommandScope: () => isRnxCloudCommandScope,
29
32
  isRnxCloudCommandType: () => isRnxCloudCommandType
30
33
  });
31
34
  module.exports = __toCommonJS(cloud_exports);
@@ -99,6 +102,18 @@ function isRnxScreenCapture(value) {
99
102
  // src/cloud-contract.ts
100
103
  var RNX_CLOUD_MAX_ARTIFACT_BYTES = 20 * 1024 * 1024;
101
104
  var RNX_CLOUD_DESIGN_MAX_STORAGE_BYTES = 1024 * 1024;
105
+ var RNX_CLOUD_COMMAND_SCOPE_SET = /* @__PURE__ */ new Set([
106
+ "read",
107
+ "drive",
108
+ "reset",
109
+ "media",
110
+ "debug",
111
+ "watch"
112
+ ]);
113
+ function isRnxCloudCommandScope(value) {
114
+ return RNX_CLOUD_COMMAND_SCOPE_SET.has(value);
115
+ }
116
+ var RNX_CLOUD_SCOPED_TOKEN_PREFIX = "sk_rnx_sim_";
102
117
  var RNX_CLOUD_COMMAND_SCOPES = {
103
118
  state: "read",
104
119
  tree: "read",
@@ -336,7 +351,7 @@ function readBoxCreate(value, expectedBytes, expectedSha256) {
336
351
  simulatorToken: simulator.token
337
352
  };
338
353
  }
339
- function cloudCommand(command) {
354
+ function cloudCommand(command, scopes) {
340
355
  const clean = {};
341
356
  for (const [key, value] of Object.entries(command)) {
342
357
  if (key !== "id" && key !== "simId") clean[key] = value;
@@ -344,7 +359,7 @@ function cloudCommand(command) {
344
359
  if (!isRnxCloudCommandType(command.type)) {
345
360
  throw new Error(`RNX Cloud does not support bridge command type ${command.type}`);
346
361
  }
347
- if (!rnxCloudScopesAllowCommand(RNX_CLOUD_TOKEN_SCOPES, command.type)) {
362
+ if (!rnxCloudScopesAllowCommand(scopes, command.type)) {
348
363
  throw new Error(
349
364
  `RNX Cloud command ${command.type} requires the ${rnxCloudCommandScope(command.type)} scope`
350
365
  );
@@ -391,7 +406,10 @@ var RemoteSimulator = class {
391
406
  }
392
407
  return result;
393
408
  },
394
- reset: () => this.sendCommand({ type: "reset" })
409
+ reset: () => this.sendCommand({ type: "reset" }),
410
+ state: (options) => this.sendCommand(
411
+ options === void 0 ? { type: "state" } : { type: "state", stateOptions: options }
412
+ )
395
413
  };
396
414
  }
397
415
  get simId() {
@@ -400,7 +418,13 @@ var RemoteSimulator = class {
400
418
  get claim() {
401
419
  return this.session.claim;
402
420
  }
421
+ get scopes() {
422
+ return this.session.scopes;
423
+ }
403
424
  get receipt() {
425
+ if (!this.session.claim) {
426
+ throw new Error("this simulator was attached with connect() and holds no claim");
427
+ }
404
428
  return {
405
429
  simId: this.session.simId,
406
430
  artifact: this.session.artifact,
@@ -410,8 +434,10 @@ var RemoteSimulator = class {
410
434
  async sendCommand(command, options) {
411
435
  const body = {
412
436
  id: globalThis.crypto.randomUUID(),
413
- claimId: this.session.claim.id,
414
- command: cloudCommand(command)
437
+ // a scoped token drives without a claim: the service checks the token
438
+ // instead. a full token still joins the claim it names here.
439
+ claimId: this.session.claim?.id ?? "",
440
+ command: cloudCommand(command, this.session.scopes)
415
441
  };
416
442
  let response;
417
443
  try {
@@ -450,6 +476,10 @@ var RemoteSimulator = class {
450
476
  return parsed.result;
451
477
  }
452
478
  async confirm() {
479
+ if (!this.session.claim) {
480
+ throw new Error("this simulator was attached with connect() and holds no claim");
481
+ }
482
+ const claimId = this.session.claim.id;
453
483
  const response = await fetchWithCloudRetry(
454
484
  `${this.session.origin}/v1/sims/${encodeURIComponent(this.session.simId)}/claim`,
455
485
  {
@@ -458,7 +488,7 @@ var RemoteSimulator = class {
458
488
  authorization: `Bearer ${this.session.simulatorToken}`,
459
489
  "content-type": "application/json"
460
490
  },
461
- body: JSON.stringify({ claimId: this.session.claim.id })
491
+ body: JSON.stringify({ claimId })
462
492
  }
463
493
  );
464
494
  const text = await response.text();
@@ -470,20 +500,24 @@ var RemoteSimulator = class {
470
500
  throw new Error("RNX Cloud claim returned unreadable JSON");
471
501
  }
472
502
  const claim = readClaim(isRecord(parsed) ? parsed.claim : null);
473
- if (claim.id !== this.session.claim.id) {
503
+ if (claim.id !== claimId) {
474
504
  throw new Error("RNX Cloud confirmation replaced the initial claim");
475
505
  }
476
506
  this.session = { ...this.session, claim };
477
507
  return claim;
478
508
  }
479
509
  async close() {
480
- const response = await fetchWithCloudRetry(
481
- `${this.session.origin}/v1/boxes/${encodeURIComponent(this.session.boxId)}`,
482
- {
483
- method: "DELETE",
484
- headers: { authorization: `Bearer ${this.session.boxToken}` }
485
- }
486
- );
510
+ const target = this.session.boxId !== null && this.session.boxToken !== null ? {
511
+ url: `${this.session.origin}/v1/boxes/${encodeURIComponent(this.session.boxId)}`,
512
+ authorization: `Bearer ${this.session.boxToken}`
513
+ } : {
514
+ url: `${this.session.origin}/v1/sims/${encodeURIComponent(this.session.simId)}`,
515
+ authorization: `Bearer ${this.session.simulatorToken}`
516
+ };
517
+ const response = await fetchWithCloudRetry(target.url, {
518
+ method: "DELETE",
519
+ headers: { authorization: target.authorization }
520
+ });
487
521
  const text = await response.text();
488
522
  if (!response.ok && response.status !== 404) {
489
523
  throw responseError(response.status, text);
@@ -541,16 +575,80 @@ async function createRemoteSimulator(input) {
541
575
  simId: created.receipt.simulator.simId,
542
576
  simulatorToken: created.simulatorToken,
543
577
  claim: created.receipt.simulator.claim,
544
- artifact: created.receipt.artifact
578
+ artifact: created.receipt.artifact,
579
+ scopes: RNX_CLOUD_TOKEN_SCOPES
545
580
  });
546
581
  await simulator.confirm();
547
582
  return simulator;
548
583
  }
584
+ function readSimArtifact(value) {
585
+ if (!isRecord(value) || typeof value.sha256 !== "string" || !/^[a-f0-9]{64}$/.test(value.sha256) || typeof value.bytes !== "number" || !Number.isInteger(value.bytes) || value.bytes <= 0) {
586
+ throw new Error("RNX Cloud returned an invalid simulator artifact");
587
+ }
588
+ return { id: `sha256:${value.sha256}`, bytes: value.bytes };
589
+ }
590
+ function readConnectClaim(value) {
591
+ if (value === null) return null;
592
+ return readClaim(value);
593
+ }
594
+ function readConnectScopes(value, token) {
595
+ if (!token.startsWith(RNX_CLOUD_SCOPED_TOKEN_PREFIX)) return RNX_CLOUD_TOKEN_SCOPES;
596
+ if (!isRecord(value) || typeof value.id !== "string" || !value.id || !Array.isArray(value.scopes) || value.scopes.length === 0 || !value.scopes.every(
597
+ (scope) => typeof scope === "string" && isRnxCloudCommandScope(scope)
598
+ ) || typeof value.expiresAt !== "number") {
599
+ throw new Error("RNX Cloud returned an invalid scoped token");
600
+ }
601
+ return Object.freeze([...value.scopes]);
602
+ }
603
+ async function connect(input) {
604
+ if (!input.id) throw new Error("RNX Cloud connect needs a simulator id");
605
+ if (!input.token) throw new Error("RNX Cloud connect needs a token");
606
+ const origin = resolveOrigin(input.origin);
607
+ let response;
608
+ try {
609
+ response = await fetchWithCloudRetry(
610
+ `${origin}/v1/sims/${encodeURIComponent(input.id)}`,
611
+ { headers: { authorization: `Bearer ${input.token}` } }
612
+ );
613
+ } catch (error) {
614
+ throw new Error(
615
+ `could not reach RNX Cloud at ${origin}: ${error instanceof Error ? error.message : String(error)}`
616
+ );
617
+ }
618
+ const text = await response.text();
619
+ if (!response.ok) throw responseError(response.status, text);
620
+ let parsed;
621
+ try {
622
+ parsed = JSON.parse(text);
623
+ } catch {
624
+ throw new Error("RNX Cloud connect returned unreadable JSON");
625
+ }
626
+ if (!isRecord(parsed) || !isRecord(parsed.sim)) {
627
+ throw new Error("RNX Cloud connect returned an invalid simulator");
628
+ }
629
+ const sim = parsed.sim;
630
+ if (typeof sim.simId !== "string" || !sim.simId) {
631
+ throw new Error("RNX Cloud connect returned an invalid simulator");
632
+ }
633
+ return new RemoteSimulator({
634
+ origin,
635
+ boxId: null,
636
+ boxToken: null,
637
+ simId: sim.simId,
638
+ simulatorToken: input.token,
639
+ claim: readConnectClaim(sim.claim ?? null),
640
+ artifact: readSimArtifact(sim.artifact),
641
+ scopes: readConnectScopes(isRecord(parsed) ? parsed.token : null, input.token)
642
+ });
643
+ }
549
644
  // Annotate the CommonJS export names for ESM import in node:
550
645
  0 && (module.exports = {
551
646
  RNX_CLOUD_COMMAND_TYPES,
552
647
  RNX_CLOUD_MAX_ARTIFACT_BYTES,
648
+ RNX_CLOUD_SCOPED_TOKEN_PREFIX,
553
649
  RemoteSimulator,
650
+ connect,
554
651
  createRemoteSimulator,
652
+ isRnxCloudCommandScope,
555
653
  isRnxCloudCommandType
556
654
  });