rnxsim 0.1.431 → 0.1.433
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 +20 -50
- package/cli/auth.ts +33 -3
- package/cli/cloud-client.ts +524 -88
- package/cli/cloud-dispatch.ts +5 -10
- package/cli/cloud-session.ts +5 -5
- package/cli/commands/auth.ts +13 -2
- package/cli/commands/box.ts +189 -20
- package/cli/commands/control.ts +40 -13
- package/cli/commands/device.ts +1 -1
- package/cli/commands/flow.ts +189 -43
- package/cli/commands/inspect/get-layout.ts +1 -1
- package/cli/commands/inspect.ts +8 -1
- package/cli/commands/login.ts +79 -14
- package/cli/commands/maestro-generate.ts +70 -54
- package/cli/commands/maestro.ts +69 -20
- package/cli/commands/platform.ts +30 -32
- package/cli/commands/screenshot.ts +3 -2
- package/cli/commands/upload.ts +28 -10
- package/cli/help-core.ts +11 -1
- package/cli/outbound-endpoints.ts +27 -5
- package/cli/parse-args.ts +17 -0
- package/cli/shell-init.ts +4 -4
- package/cli/ws-bridge.ts +109 -62
- package/dist-lib/agent-daemon-client.cjs +1 -1
- package/dist-lib/agent-events.cjs +1 -1
- package/dist-lib/agent-identity.cjs +1 -1
- package/dist-lib/agent-sessions.cjs +1 -1
- package/dist-lib/attached-projects.cjs +1 -1
- package/dist-lib/auth/shared-session.cjs +17 -4
- package/dist-lib/backend-origin.cjs +1 -1
- package/dist-lib/beta.cjs +1 -1
- package/dist-lib/beta.mjs +1 -1
- package/dist-lib/bridge-constants.cjs +1 -1
- package/dist-lib/bridge-contract-input.cjs +1 -1
- package/dist-lib/bridge-contract-input.mjs +1 -1
- package/dist-lib/bridge-contract.cjs +1 -1
- package/dist-lib/bridge-contract.mjs +1 -1
- package/dist-lib/capture-contract.cjs +1 -1
- package/dist-lib/capture-contract.mjs +1 -1
- package/dist-lib/cli-constants.cjs +1 -1
- package/dist-lib/cloud-contract.cjs +1 -1
- package/dist-lib/cloud-contract.mjs +1 -1
- package/dist-lib/cloud.cjs +108 -93
- package/dist-lib/cloud.mjs +106 -91
- package/dist-lib/config.cjs +1 -1
- package/dist-lib/detox/index.cjs +1 -1
- package/dist-lib/dev-bundle-resolution.cjs +1 -1
- package/dist-lib/home-paths.cjs +1 -1
- package/dist-lib/host/bridge-host.cjs +1 -1
- package/dist-lib/host/fetch-proxy-handler.cjs +1 -1
- package/dist-lib/host/fetch-proxy-overrides.cjs +1 -1
- package/dist-lib/host/fetch-proxy-overrides.mjs +1 -1
- package/dist-lib/host/replacement-module-handler.cjs +1 -1
- package/dist-lib/host/websocket-proxy.cjs +1 -1
- package/dist-lib/index.cjs +58 -139
- package/dist-lib/jump-to-source-babel.cjs +1 -1
- package/dist-lib/menu.cjs +1 -1
- package/dist-lib/menu.mjs +1 -1
- package/dist-lib/metro-fingerprint-registry.cjs +1 -1
- package/dist-lib/metro-fingerprint-registry.mjs +1 -1
- package/dist-lib/metro-production-bundle.cjs +1 -1
- package/dist-lib/metro-production-bundle.mjs +1 -1
- package/dist-lib/metro.cjs +33 -212
- package/dist-lib/profiles.cjs +1 -1
- package/dist-lib/public-brand.cjs +1 -1
- package/dist-lib/react-native-host-modules.cjs +1 -1
- package/dist-lib/react-native-host-modules.mjs +1 -1
- package/dist-lib/render-mode.cjs +1 -1
- package/dist-lib/scripts/dev-server-scanner.cjs +1 -1
- package/dist-lib/sdk.cjs +1 -1
- package/dist-lib/sdk.mjs +1 -1
- package/dist-lib/skills.cjs +436 -351
- package/dist-lib/vite.cjs +1 -1
- package/package.json +2 -1
- package/src/auth/shared-session.ts +31 -0
- package/src/cloud.ts +83 -113
- package/src/metro-plugin.ts +30 -113
- package/src/vite-plugin.ts +11 -2
package/dist-lib/cloud.cjs
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
/*! rnx v0.1.
|
|
1
|
+
/*! rnx v0.1.433 | (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;
|
|
@@ -22,10 +22,10 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
|
|
|
22
22
|
// src/cloud.ts
|
|
23
23
|
var cloud_exports = {};
|
|
24
24
|
__export(cloud_exports, {
|
|
25
|
-
NanoBox: () => NanoBox,
|
|
26
25
|
RNX_CLOUD_COMMAND_TYPES: () => RNX_CLOUD_COMMAND_TYPES,
|
|
27
26
|
RNX_CLOUD_MAX_ARTIFACT_BYTES: () => RNX_CLOUD_MAX_ARTIFACT_BYTES,
|
|
28
|
-
|
|
27
|
+
RemoteSimulator: () => RemoteSimulator,
|
|
28
|
+
createRemoteSimulator: () => createRemoteSimulator,
|
|
29
29
|
isRnxCloudCommandType: () => isRnxCloudCommandType
|
|
30
30
|
});
|
|
31
31
|
module.exports = __toCommonJS(cloud_exports);
|
|
@@ -39,6 +39,63 @@ function isLoopbackHost(hostname) {
|
|
|
39
39
|
return normalized === "localhost" || normalized.endsWith(".localhost") || normalized === "0.0.0.0" || normalized === "::1" || /^127(?:\.\d{1,3}){3}$/.test(normalized);
|
|
40
40
|
}
|
|
41
41
|
|
|
42
|
+
// src/capture-contract.ts
|
|
43
|
+
var RNX_SCREEN_CAPTURE_VERSION = 1;
|
|
44
|
+
function captureRecord(value) {
|
|
45
|
+
return value !== null && typeof value === "object" && !Array.isArray(value);
|
|
46
|
+
}
|
|
47
|
+
function captureInteger(value) {
|
|
48
|
+
return typeof value === "number" && Number.isSafeInteger(value);
|
|
49
|
+
}
|
|
50
|
+
function captureNumber(value) {
|
|
51
|
+
return typeof value === "number" && Number.isFinite(value);
|
|
52
|
+
}
|
|
53
|
+
function captureNullableString(value) {
|
|
54
|
+
return value === null || typeof value === "string";
|
|
55
|
+
}
|
|
56
|
+
function captureRect(value) {
|
|
57
|
+
return captureRecord(value) && captureNumber(value.x) && captureNumber(value.y) && captureNumber(value.width) && captureNumber(value.height);
|
|
58
|
+
}
|
|
59
|
+
function captureOptionalString(value) {
|
|
60
|
+
return value === void 0 || typeof value === "string";
|
|
61
|
+
}
|
|
62
|
+
function captureOptionalNullableString(value) {
|
|
63
|
+
return value === void 0 || captureNullableString(value);
|
|
64
|
+
}
|
|
65
|
+
function captureFontRegistration(value) {
|
|
66
|
+
return captureRecord(value) && typeof value.family === "string" && value.family.length > 0 && captureOptionalString(value.url) && captureOptionalString(value.sourceLabel) && captureOptionalNullableString(value.parsedFamily) && captureOptionalNullableString(value.parsedPostScript) && captureOptionalNullableString(value.fullName);
|
|
67
|
+
}
|
|
68
|
+
function capturePoint(value) {
|
|
69
|
+
return captureRecord(value) && captureNumber(value.x) && captureNumber(value.y);
|
|
70
|
+
}
|
|
71
|
+
function captureNode(value) {
|
|
72
|
+
if (!captureRecord(value) || !captureInteger(value.nodeId) || !(value.parentNodeId === null || captureInteger(value.parentNodeId)) || !Array.isArray(value.childNodeIds) || !value.childNodeIds.every(captureInteger) || !captureInteger(value.paintIndex) || typeof value.type !== "string" || !captureNullableString(value.id) || !captureNullableString(value.testID) || !captureNullableString(value.text) || !captureInteger(value.childCount) || !captureRecord(value.accessibility) || !captureRecord(value.interaction) || !captureRecord(value.layout) || !captureRecord(value.style) || !captureRecord(value.source) || !captureRecord(value.props) || !captureRecord(value.inspection)) {
|
|
73
|
+
return false;
|
|
74
|
+
}
|
|
75
|
+
const accessibility = value.accessibility;
|
|
76
|
+
if (typeof accessibility.accessible !== "boolean" || !captureNullableString(accessibility.label) || !captureNullableString(accessibility.role) || !captureNullableString(accessibility.hint) || !(accessibility.liveRegion === null || accessibility.liveRegion === "none" || accessibility.liveRegion === "polite" || accessibility.liveRegion === "assertive") || !(accessibility.state === null || captureRecord(accessibility.state)) || !(accessibility.value === null || captureRecord(accessibility.value))) {
|
|
77
|
+
return false;
|
|
78
|
+
}
|
|
79
|
+
const interaction = value.interaction;
|
|
80
|
+
if (typeof interaction.pressed !== "boolean" || typeof interaction.pressable !== "boolean" || typeof interaction.textInput !== "boolean" || !(interaction.textSelection === null || captureRecord(interaction.textSelection)) || typeof interaction.secureTextEntry !== "boolean" || !captureNullableString(interaction.placeholder) || !capturePoint(interaction.scrollOffset) || !(interaction.zoomScale === null || captureNumber(interaction.zoomScale)) || typeof interaction.nativePinchEnabled !== "boolean" || !(interaction.contentOffsetProp === null || captureRecord(interaction.contentOffsetProp)) || !(interaction.strokeDashoffsetProp === null || captureNumber(interaction.strokeDashoffsetProp))) {
|
|
81
|
+
return false;
|
|
82
|
+
}
|
|
83
|
+
const layout = value.layout;
|
|
84
|
+
if (!captureRect(layout.local) || !(layout.frame === null || captureRect(layout.frame)) || !capturePoint(layout.absolutePosition) || !(layout.visibleFrame === null || captureRect(layout.visibleFrame))) {
|
|
85
|
+
return false;
|
|
86
|
+
}
|
|
87
|
+
const style = value.style;
|
|
88
|
+
return captureRecord(style.resolved) && captureRecord(style.authored) && captureRecord(style.computed) && captureRecord(style.tokenBindings) && (value.textLines === void 0 || Array.isArray(value.textLines));
|
|
89
|
+
}
|
|
90
|
+
function isRnxScreenCapture(value) {
|
|
91
|
+
if (!captureRecord(value) || value.contractVersion !== RNX_SCREEN_CAPTURE_VERSION || !captureInteger(value.capturedAt) || !captureRecord(value.tree) || !(value.fonts === void 0 || Array.isArray(value.fonts) && value.fonts.length <= 200 && value.fonts.every(captureFontRegistration)) || !(value.visual === void 0 || captureRecord(value.visual))) {
|
|
92
|
+
return false;
|
|
93
|
+
}
|
|
94
|
+
const tree = value.tree;
|
|
95
|
+
const visual = value.visual;
|
|
96
|
+
return captureRecord(tree.viewport) && captureInteger(tree.viewport.width) && tree.viewport.width > 0 && captureInteger(tree.viewport.height) && tree.viewport.height > 0 && captureInteger(tree.rootNodeId) && (tree.commitRevision === void 0 || captureInteger(tree.commitRevision)) && Array.isArray(tree.nodes) && tree.nodes.every(captureNode) && (visual === void 0 || visual.kind === "png" && (visual.producer === "headless-cpu-app-surface" || visual.producer === "browser-compositor-app-surface") && typeof visual.dataUri === "string" && visual.dataUri.startsWith("data:image/png;base64,") && captureInteger(visual.pixelWidth) && visual.pixelWidth > 0 && captureInteger(visual.pixelHeight) && visual.pixelHeight > 0);
|
|
97
|
+
}
|
|
98
|
+
|
|
42
99
|
// src/cloud-contract.ts
|
|
43
100
|
var RNX_CLOUD_MAX_ARTIFACT_BYTES = 20 * 1024 * 1024;
|
|
44
101
|
var RNX_CLOUD_DESIGN_MAX_STORAGE_BYTES = 1024 * 1024;
|
|
@@ -200,13 +257,48 @@ function cloudCommand(command) {
|
|
|
200
257
|
}
|
|
201
258
|
return { ...clean, type: command.type };
|
|
202
259
|
}
|
|
203
|
-
var
|
|
260
|
+
var RemoteSimulator = class {
|
|
204
261
|
session;
|
|
262
|
+
// driving verbs live here so the client reads the way the CLI does. bound to
|
|
263
|
+
// this simulator at construction, and every verb reads the session live, so a
|
|
264
|
+
// confirmed claim reaches commands issued after it.
|
|
265
|
+
rnx;
|
|
205
266
|
constructor(session) {
|
|
206
267
|
this.session = session;
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
268
|
+
this.rnx = {
|
|
269
|
+
command: (command, options) => this.sendCommand(command, options),
|
|
270
|
+
describe: () => this.sendCommand({ type: "tree" }),
|
|
271
|
+
do: (command) => this.sendCommand(command),
|
|
272
|
+
wait: (condition, options) => {
|
|
273
|
+
const timeoutMs = options?.maxMs ?? DEFAULT_WAIT_READY_MS;
|
|
274
|
+
const waitCondition = condition === "ready" ? { type: "ready" } : condition;
|
|
275
|
+
return this.sendCommand(
|
|
276
|
+
{
|
|
277
|
+
type: "waitFor",
|
|
278
|
+
waitForOptions: { condition: waitCondition, timeoutMs }
|
|
279
|
+
},
|
|
280
|
+
{ timeoutMs: timeoutMs + 1e3 }
|
|
281
|
+
);
|
|
282
|
+
},
|
|
283
|
+
screenshot: async (options) => {
|
|
284
|
+
const result = await this.sendCommand({
|
|
285
|
+
type: "screenshot",
|
|
286
|
+
layers: options?.layers ?? "tenant"
|
|
287
|
+
});
|
|
288
|
+
if (typeof result !== "string" || !result.startsWith("data:image/")) {
|
|
289
|
+
throw new Error("RNX Cloud screenshot did not return an image data url");
|
|
290
|
+
}
|
|
291
|
+
return result;
|
|
292
|
+
},
|
|
293
|
+
capture: async () => {
|
|
294
|
+
const result = await this.sendCommand({ type: "capture" });
|
|
295
|
+
if (!isRnxScreenCapture(result)) {
|
|
296
|
+
throw new Error("RNX Cloud capture returned an invalid screen capture");
|
|
297
|
+
}
|
|
298
|
+
return result;
|
|
299
|
+
},
|
|
300
|
+
reset: () => this.sendCommand({ type: "reset" })
|
|
301
|
+
};
|
|
210
302
|
}
|
|
211
303
|
get simId() {
|
|
212
304
|
return this.session.simId;
|
|
@@ -216,17 +308,12 @@ var NanoBox = class _NanoBox {
|
|
|
216
308
|
}
|
|
217
309
|
get receipt() {
|
|
218
310
|
return {
|
|
219
|
-
|
|
220
|
-
size: "nano",
|
|
311
|
+
simId: this.session.simId,
|
|
221
312
|
artifact: this.session.artifact,
|
|
222
|
-
|
|
223
|
-
simId: this.session.simId,
|
|
224
|
-
artifact: this.session.artifact,
|
|
225
|
-
claim: this.session.claim
|
|
226
|
-
}
|
|
313
|
+
claim: this.session.claim
|
|
227
314
|
};
|
|
228
315
|
}
|
|
229
|
-
async
|
|
316
|
+
async sendCommand(command, options) {
|
|
230
317
|
const body = {
|
|
231
318
|
id: globalThis.crypto.randomUUID(),
|
|
232
319
|
claimId: this.session.claim.id,
|
|
@@ -268,35 +355,6 @@ var NanoBox = class _NanoBox {
|
|
|
268
355
|
}
|
|
269
356
|
return parsed.result;
|
|
270
357
|
}
|
|
271
|
-
describe() {
|
|
272
|
-
return this.command({ type: "tree" });
|
|
273
|
-
}
|
|
274
|
-
do(command) {
|
|
275
|
-
return this.command(command);
|
|
276
|
-
}
|
|
277
|
-
wait(condition, options) {
|
|
278
|
-
const timeoutMs = options?.maxMs ?? DEFAULT_WAIT_READY_MS;
|
|
279
|
-
const waitCondition = condition === "ready" ? { type: "ready" } : condition;
|
|
280
|
-
return this.command(
|
|
281
|
-
{
|
|
282
|
-
type: "waitFor",
|
|
283
|
-
waitForOptions: { condition: waitCondition, timeoutMs }
|
|
284
|
-
},
|
|
285
|
-
{ timeoutMs: timeoutMs + 1e3 }
|
|
286
|
-
);
|
|
287
|
-
}
|
|
288
|
-
screenshot(options) {
|
|
289
|
-
return this.command({
|
|
290
|
-
type: "screenshot",
|
|
291
|
-
layers: options?.layers ?? "tenant"
|
|
292
|
-
});
|
|
293
|
-
}
|
|
294
|
-
capture() {
|
|
295
|
-
return this.command({ type: "capture" });
|
|
296
|
-
}
|
|
297
|
-
reset() {
|
|
298
|
-
return this.command({ type: "reset" });
|
|
299
|
-
}
|
|
300
358
|
async confirm() {
|
|
301
359
|
const response = await fetch(
|
|
302
360
|
`${this.session.origin}/v1/sims/${encodeURIComponent(this.session.simId)}/claim`,
|
|
@@ -324,48 +382,6 @@ var NanoBox = class _NanoBox {
|
|
|
324
382
|
this.session = { ...this.session, claim };
|
|
325
383
|
return claim;
|
|
326
384
|
}
|
|
327
|
-
async addSimulator(input = {}) {
|
|
328
|
-
const device = input.device?.trim() || DEFAULT_DEVICE;
|
|
329
|
-
const response = await fetch(
|
|
330
|
-
`${this.session.origin}/v1/boxes/${encodeURIComponent(this.session.boxId)}/simulators`,
|
|
331
|
-
{
|
|
332
|
-
method: "POST",
|
|
333
|
-
headers: {
|
|
334
|
-
authorization: `Bearer ${this.session.boxToken}`,
|
|
335
|
-
"x-rnx-account-authorization": this.session.authorization,
|
|
336
|
-
"content-type": "application/json"
|
|
337
|
-
},
|
|
338
|
-
body: JSON.stringify({
|
|
339
|
-
device,
|
|
340
|
-
...input.storageFrom === void 0 ? {} : { storageFrom: input.storageFrom }
|
|
341
|
-
})
|
|
342
|
-
}
|
|
343
|
-
);
|
|
344
|
-
const text = await response.text();
|
|
345
|
-
if (!response.ok) throw responseError(response.status, text);
|
|
346
|
-
let parsed;
|
|
347
|
-
try {
|
|
348
|
-
parsed = JSON.parse(text);
|
|
349
|
-
} catch {
|
|
350
|
-
throw new Error("RNX Cloud simulator create returned unreadable JSON");
|
|
351
|
-
}
|
|
352
|
-
if (!isRecord(parsed) || parsed.boxId !== this.session.boxId) {
|
|
353
|
-
throw new Error("RNX Cloud simulator create returned an invalid box id");
|
|
354
|
-
}
|
|
355
|
-
const simulator = readSimulatorCreate(
|
|
356
|
-
parsed.simulator,
|
|
357
|
-
this.session.artifact.id,
|
|
358
|
-
this.session.artifact.bytes
|
|
359
|
-
);
|
|
360
|
-
const pooled = new _NanoBox({
|
|
361
|
-
...this.session,
|
|
362
|
-
simId: simulator.simId,
|
|
363
|
-
simulatorToken: simulator.token,
|
|
364
|
-
claim: simulator.claim
|
|
365
|
-
});
|
|
366
|
-
await pooled.confirm();
|
|
367
|
-
return pooled;
|
|
368
|
-
}
|
|
369
385
|
async close() {
|
|
370
386
|
const response = await fetch(
|
|
371
387
|
`${this.session.origin}/v1/boxes/${encodeURIComponent(this.session.boxId)}`,
|
|
@@ -380,7 +396,7 @@ var NanoBox = class _NanoBox {
|
|
|
380
396
|
}
|
|
381
397
|
}
|
|
382
398
|
};
|
|
383
|
-
async function
|
|
399
|
+
async function createRemoteSimulator(input) {
|
|
384
400
|
if (input.artifact.byteLength > RNX_CLOUD_MAX_ARTIFACT_BYTES) {
|
|
385
401
|
throw new Error(
|
|
386
402
|
`rnx Cloud artifact is ${input.artifact.byteLength} bytes and exceeds the ${RNX_CLOUD_MAX_ARTIFACT_BYTES}-byte limit`
|
|
@@ -424,9 +440,8 @@ async function createNanoBox(input) {
|
|
|
424
440
|
throw new Error("RNX Cloud create returned unreadable JSON");
|
|
425
441
|
}
|
|
426
442
|
const created = readBoxCreate(parsed, input.artifact.byteLength, sha256);
|
|
427
|
-
const
|
|
443
|
+
const simulator = new RemoteSimulator({
|
|
428
444
|
origin,
|
|
429
|
-
authorization: input.authorization,
|
|
430
445
|
boxId: created.receipt.boxId,
|
|
431
446
|
boxToken: created.boxToken,
|
|
432
447
|
simId: created.receipt.simulator.simId,
|
|
@@ -434,14 +449,14 @@ async function createNanoBox(input) {
|
|
|
434
449
|
claim: created.receipt.simulator.claim,
|
|
435
450
|
artifact: created.receipt.artifact
|
|
436
451
|
});
|
|
437
|
-
await
|
|
438
|
-
return
|
|
452
|
+
await simulator.confirm();
|
|
453
|
+
return simulator;
|
|
439
454
|
}
|
|
440
455
|
// Annotate the CommonJS export names for ESM import in node:
|
|
441
456
|
0 && (module.exports = {
|
|
442
|
-
NanoBox,
|
|
443
457
|
RNX_CLOUD_COMMAND_TYPES,
|
|
444
458
|
RNX_CLOUD_MAX_ARTIFACT_BYTES,
|
|
445
|
-
|
|
459
|
+
RemoteSimulator,
|
|
460
|
+
createRemoteSimulator,
|
|
446
461
|
isRnxCloudCommandType
|
|
447
462
|
});
|
package/dist-lib/cloud.mjs
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
/*! rnx v0.1.
|
|
1
|
+
/*! rnx v0.1.433 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
|
|
2
2
|
var __defProp = Object.defineProperty;
|
|
3
3
|
var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
|
|
4
4
|
var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
|
|
@@ -12,6 +12,63 @@ function isLoopbackHost(hostname) {
|
|
|
12
12
|
return normalized === "localhost" || normalized.endsWith(".localhost") || normalized === "0.0.0.0" || normalized === "::1" || /^127(?:\.\d{1,3}){3}$/.test(normalized);
|
|
13
13
|
}
|
|
14
14
|
|
|
15
|
+
// src/capture-contract.ts
|
|
16
|
+
var RNX_SCREEN_CAPTURE_VERSION = 1;
|
|
17
|
+
function captureRecord(value) {
|
|
18
|
+
return value !== null && typeof value === "object" && !Array.isArray(value);
|
|
19
|
+
}
|
|
20
|
+
function captureInteger(value) {
|
|
21
|
+
return typeof value === "number" && Number.isSafeInteger(value);
|
|
22
|
+
}
|
|
23
|
+
function captureNumber(value) {
|
|
24
|
+
return typeof value === "number" && Number.isFinite(value);
|
|
25
|
+
}
|
|
26
|
+
function captureNullableString(value) {
|
|
27
|
+
return value === null || typeof value === "string";
|
|
28
|
+
}
|
|
29
|
+
function captureRect(value) {
|
|
30
|
+
return captureRecord(value) && captureNumber(value.x) && captureNumber(value.y) && captureNumber(value.width) && captureNumber(value.height);
|
|
31
|
+
}
|
|
32
|
+
function captureOptionalString(value) {
|
|
33
|
+
return value === void 0 || typeof value === "string";
|
|
34
|
+
}
|
|
35
|
+
function captureOptionalNullableString(value) {
|
|
36
|
+
return value === void 0 || captureNullableString(value);
|
|
37
|
+
}
|
|
38
|
+
function captureFontRegistration(value) {
|
|
39
|
+
return captureRecord(value) && typeof value.family === "string" && value.family.length > 0 && captureOptionalString(value.url) && captureOptionalString(value.sourceLabel) && captureOptionalNullableString(value.parsedFamily) && captureOptionalNullableString(value.parsedPostScript) && captureOptionalNullableString(value.fullName);
|
|
40
|
+
}
|
|
41
|
+
function capturePoint(value) {
|
|
42
|
+
return captureRecord(value) && captureNumber(value.x) && captureNumber(value.y);
|
|
43
|
+
}
|
|
44
|
+
function captureNode(value) {
|
|
45
|
+
if (!captureRecord(value) || !captureInteger(value.nodeId) || !(value.parentNodeId === null || captureInteger(value.parentNodeId)) || !Array.isArray(value.childNodeIds) || !value.childNodeIds.every(captureInteger) || !captureInteger(value.paintIndex) || typeof value.type !== "string" || !captureNullableString(value.id) || !captureNullableString(value.testID) || !captureNullableString(value.text) || !captureInteger(value.childCount) || !captureRecord(value.accessibility) || !captureRecord(value.interaction) || !captureRecord(value.layout) || !captureRecord(value.style) || !captureRecord(value.source) || !captureRecord(value.props) || !captureRecord(value.inspection)) {
|
|
46
|
+
return false;
|
|
47
|
+
}
|
|
48
|
+
const accessibility = value.accessibility;
|
|
49
|
+
if (typeof accessibility.accessible !== "boolean" || !captureNullableString(accessibility.label) || !captureNullableString(accessibility.role) || !captureNullableString(accessibility.hint) || !(accessibility.liveRegion === null || accessibility.liveRegion === "none" || accessibility.liveRegion === "polite" || accessibility.liveRegion === "assertive") || !(accessibility.state === null || captureRecord(accessibility.state)) || !(accessibility.value === null || captureRecord(accessibility.value))) {
|
|
50
|
+
return false;
|
|
51
|
+
}
|
|
52
|
+
const interaction = value.interaction;
|
|
53
|
+
if (typeof interaction.pressed !== "boolean" || typeof interaction.pressable !== "boolean" || typeof interaction.textInput !== "boolean" || !(interaction.textSelection === null || captureRecord(interaction.textSelection)) || typeof interaction.secureTextEntry !== "boolean" || !captureNullableString(interaction.placeholder) || !capturePoint(interaction.scrollOffset) || !(interaction.zoomScale === null || captureNumber(interaction.zoomScale)) || typeof interaction.nativePinchEnabled !== "boolean" || !(interaction.contentOffsetProp === null || captureRecord(interaction.contentOffsetProp)) || !(interaction.strokeDashoffsetProp === null || captureNumber(interaction.strokeDashoffsetProp))) {
|
|
54
|
+
return false;
|
|
55
|
+
}
|
|
56
|
+
const layout = value.layout;
|
|
57
|
+
if (!captureRect(layout.local) || !(layout.frame === null || captureRect(layout.frame)) || !capturePoint(layout.absolutePosition) || !(layout.visibleFrame === null || captureRect(layout.visibleFrame))) {
|
|
58
|
+
return false;
|
|
59
|
+
}
|
|
60
|
+
const style = value.style;
|
|
61
|
+
return captureRecord(style.resolved) && captureRecord(style.authored) && captureRecord(style.computed) && captureRecord(style.tokenBindings) && (value.textLines === void 0 || Array.isArray(value.textLines));
|
|
62
|
+
}
|
|
63
|
+
function isRnxScreenCapture(value) {
|
|
64
|
+
if (!captureRecord(value) || value.contractVersion !== RNX_SCREEN_CAPTURE_VERSION || !captureInteger(value.capturedAt) || !captureRecord(value.tree) || !(value.fonts === void 0 || Array.isArray(value.fonts) && value.fonts.length <= 200 && value.fonts.every(captureFontRegistration)) || !(value.visual === void 0 || captureRecord(value.visual))) {
|
|
65
|
+
return false;
|
|
66
|
+
}
|
|
67
|
+
const tree = value.tree;
|
|
68
|
+
const visual = value.visual;
|
|
69
|
+
return captureRecord(tree.viewport) && captureInteger(tree.viewport.width) && tree.viewport.width > 0 && captureInteger(tree.viewport.height) && tree.viewport.height > 0 && captureInteger(tree.rootNodeId) && (tree.commitRevision === void 0 || captureInteger(tree.commitRevision)) && Array.isArray(tree.nodes) && tree.nodes.every(captureNode) && (visual === void 0 || visual.kind === "png" && (visual.producer === "headless-cpu-app-surface" || visual.producer === "browser-compositor-app-surface") && typeof visual.dataUri === "string" && visual.dataUri.startsWith("data:image/png;base64,") && captureInteger(visual.pixelWidth) && visual.pixelWidth > 0 && captureInteger(visual.pixelHeight) && visual.pixelHeight > 0);
|
|
70
|
+
}
|
|
71
|
+
|
|
15
72
|
// src/cloud-contract.ts
|
|
16
73
|
var RNX_CLOUD_MAX_ARTIFACT_BYTES = 20 * 1024 * 1024;
|
|
17
74
|
var RNX_CLOUD_DESIGN_MAX_STORAGE_BYTES = 1024 * 1024;
|
|
@@ -173,13 +230,48 @@ function cloudCommand(command) {
|
|
|
173
230
|
}
|
|
174
231
|
return { ...clean, type: command.type };
|
|
175
232
|
}
|
|
176
|
-
var
|
|
233
|
+
var RemoteSimulator = class {
|
|
177
234
|
constructor(session) {
|
|
178
235
|
__publicField(this, "session");
|
|
236
|
+
// driving verbs live here so the client reads the way the CLI does. bound to
|
|
237
|
+
// this simulator at construction, and every verb reads the session live, so a
|
|
238
|
+
// confirmed claim reaches commands issued after it.
|
|
239
|
+
__publicField(this, "rnx");
|
|
179
240
|
this.session = session;
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
241
|
+
this.rnx = {
|
|
242
|
+
command: (command, options) => this.sendCommand(command, options),
|
|
243
|
+
describe: () => this.sendCommand({ type: "tree" }),
|
|
244
|
+
do: (command) => this.sendCommand(command),
|
|
245
|
+
wait: (condition, options) => {
|
|
246
|
+
const timeoutMs = options?.maxMs ?? DEFAULT_WAIT_READY_MS;
|
|
247
|
+
const waitCondition = condition === "ready" ? { type: "ready" } : condition;
|
|
248
|
+
return this.sendCommand(
|
|
249
|
+
{
|
|
250
|
+
type: "waitFor",
|
|
251
|
+
waitForOptions: { condition: waitCondition, timeoutMs }
|
|
252
|
+
},
|
|
253
|
+
{ timeoutMs: timeoutMs + 1e3 }
|
|
254
|
+
);
|
|
255
|
+
},
|
|
256
|
+
screenshot: async (options) => {
|
|
257
|
+
const result = await this.sendCommand({
|
|
258
|
+
type: "screenshot",
|
|
259
|
+
layers: options?.layers ?? "tenant"
|
|
260
|
+
});
|
|
261
|
+
if (typeof result !== "string" || !result.startsWith("data:image/")) {
|
|
262
|
+
throw new Error("RNX Cloud screenshot did not return an image data url");
|
|
263
|
+
}
|
|
264
|
+
return result;
|
|
265
|
+
},
|
|
266
|
+
capture: async () => {
|
|
267
|
+
const result = await this.sendCommand({ type: "capture" });
|
|
268
|
+
if (!isRnxScreenCapture(result)) {
|
|
269
|
+
throw new Error("RNX Cloud capture returned an invalid screen capture");
|
|
270
|
+
}
|
|
271
|
+
return result;
|
|
272
|
+
},
|
|
273
|
+
reset: () => this.sendCommand({ type: "reset" })
|
|
274
|
+
};
|
|
183
275
|
}
|
|
184
276
|
get simId() {
|
|
185
277
|
return this.session.simId;
|
|
@@ -189,17 +281,12 @@ var NanoBox = class _NanoBox {
|
|
|
189
281
|
}
|
|
190
282
|
get receipt() {
|
|
191
283
|
return {
|
|
192
|
-
|
|
193
|
-
size: "nano",
|
|
284
|
+
simId: this.session.simId,
|
|
194
285
|
artifact: this.session.artifact,
|
|
195
|
-
|
|
196
|
-
simId: this.session.simId,
|
|
197
|
-
artifact: this.session.artifact,
|
|
198
|
-
claim: this.session.claim
|
|
199
|
-
}
|
|
286
|
+
claim: this.session.claim
|
|
200
287
|
};
|
|
201
288
|
}
|
|
202
|
-
async
|
|
289
|
+
async sendCommand(command, options) {
|
|
203
290
|
const body = {
|
|
204
291
|
id: globalThis.crypto.randomUUID(),
|
|
205
292
|
claimId: this.session.claim.id,
|
|
@@ -241,35 +328,6 @@ var NanoBox = class _NanoBox {
|
|
|
241
328
|
}
|
|
242
329
|
return parsed.result;
|
|
243
330
|
}
|
|
244
|
-
describe() {
|
|
245
|
-
return this.command({ type: "tree" });
|
|
246
|
-
}
|
|
247
|
-
do(command) {
|
|
248
|
-
return this.command(command);
|
|
249
|
-
}
|
|
250
|
-
wait(condition, options) {
|
|
251
|
-
const timeoutMs = options?.maxMs ?? DEFAULT_WAIT_READY_MS;
|
|
252
|
-
const waitCondition = condition === "ready" ? { type: "ready" } : condition;
|
|
253
|
-
return this.command(
|
|
254
|
-
{
|
|
255
|
-
type: "waitFor",
|
|
256
|
-
waitForOptions: { condition: waitCondition, timeoutMs }
|
|
257
|
-
},
|
|
258
|
-
{ timeoutMs: timeoutMs + 1e3 }
|
|
259
|
-
);
|
|
260
|
-
}
|
|
261
|
-
screenshot(options) {
|
|
262
|
-
return this.command({
|
|
263
|
-
type: "screenshot",
|
|
264
|
-
layers: options?.layers ?? "tenant"
|
|
265
|
-
});
|
|
266
|
-
}
|
|
267
|
-
capture() {
|
|
268
|
-
return this.command({ type: "capture" });
|
|
269
|
-
}
|
|
270
|
-
reset() {
|
|
271
|
-
return this.command({ type: "reset" });
|
|
272
|
-
}
|
|
273
331
|
async confirm() {
|
|
274
332
|
const response = await fetch(
|
|
275
333
|
`${this.session.origin}/v1/sims/${encodeURIComponent(this.session.simId)}/claim`,
|
|
@@ -297,48 +355,6 @@ var NanoBox = class _NanoBox {
|
|
|
297
355
|
this.session = { ...this.session, claim };
|
|
298
356
|
return claim;
|
|
299
357
|
}
|
|
300
|
-
async addSimulator(input = {}) {
|
|
301
|
-
const device = input.device?.trim() || DEFAULT_DEVICE;
|
|
302
|
-
const response = await fetch(
|
|
303
|
-
`${this.session.origin}/v1/boxes/${encodeURIComponent(this.session.boxId)}/simulators`,
|
|
304
|
-
{
|
|
305
|
-
method: "POST",
|
|
306
|
-
headers: {
|
|
307
|
-
authorization: `Bearer ${this.session.boxToken}`,
|
|
308
|
-
"x-rnx-account-authorization": this.session.authorization,
|
|
309
|
-
"content-type": "application/json"
|
|
310
|
-
},
|
|
311
|
-
body: JSON.stringify({
|
|
312
|
-
device,
|
|
313
|
-
...input.storageFrom === void 0 ? {} : { storageFrom: input.storageFrom }
|
|
314
|
-
})
|
|
315
|
-
}
|
|
316
|
-
);
|
|
317
|
-
const text = await response.text();
|
|
318
|
-
if (!response.ok) throw responseError(response.status, text);
|
|
319
|
-
let parsed;
|
|
320
|
-
try {
|
|
321
|
-
parsed = JSON.parse(text);
|
|
322
|
-
} catch {
|
|
323
|
-
throw new Error("RNX Cloud simulator create returned unreadable JSON");
|
|
324
|
-
}
|
|
325
|
-
if (!isRecord(parsed) || parsed.boxId !== this.session.boxId) {
|
|
326
|
-
throw new Error("RNX Cloud simulator create returned an invalid box id");
|
|
327
|
-
}
|
|
328
|
-
const simulator = readSimulatorCreate(
|
|
329
|
-
parsed.simulator,
|
|
330
|
-
this.session.artifact.id,
|
|
331
|
-
this.session.artifact.bytes
|
|
332
|
-
);
|
|
333
|
-
const pooled = new _NanoBox({
|
|
334
|
-
...this.session,
|
|
335
|
-
simId: simulator.simId,
|
|
336
|
-
simulatorToken: simulator.token,
|
|
337
|
-
claim: simulator.claim
|
|
338
|
-
});
|
|
339
|
-
await pooled.confirm();
|
|
340
|
-
return pooled;
|
|
341
|
-
}
|
|
342
358
|
async close() {
|
|
343
359
|
const response = await fetch(
|
|
344
360
|
`${this.session.origin}/v1/boxes/${encodeURIComponent(this.session.boxId)}`,
|
|
@@ -353,7 +369,7 @@ var NanoBox = class _NanoBox {
|
|
|
353
369
|
}
|
|
354
370
|
}
|
|
355
371
|
};
|
|
356
|
-
async function
|
|
372
|
+
async function createRemoteSimulator(input) {
|
|
357
373
|
if (input.artifact.byteLength > RNX_CLOUD_MAX_ARTIFACT_BYTES) {
|
|
358
374
|
throw new Error(
|
|
359
375
|
`rnx Cloud artifact is ${input.artifact.byteLength} bytes and exceeds the ${RNX_CLOUD_MAX_ARTIFACT_BYTES}-byte limit`
|
|
@@ -397,9 +413,8 @@ async function createNanoBox(input) {
|
|
|
397
413
|
throw new Error("RNX Cloud create returned unreadable JSON");
|
|
398
414
|
}
|
|
399
415
|
const created = readBoxCreate(parsed, input.artifact.byteLength, sha256);
|
|
400
|
-
const
|
|
416
|
+
const simulator = new RemoteSimulator({
|
|
401
417
|
origin,
|
|
402
|
-
authorization: input.authorization,
|
|
403
418
|
boxId: created.receipt.boxId,
|
|
404
419
|
boxToken: created.boxToken,
|
|
405
420
|
simId: created.receipt.simulator.simId,
|
|
@@ -407,13 +422,13 @@ async function createNanoBox(input) {
|
|
|
407
422
|
claim: created.receipt.simulator.claim,
|
|
408
423
|
artifact: created.receipt.artifact
|
|
409
424
|
});
|
|
410
|
-
await
|
|
411
|
-
return
|
|
425
|
+
await simulator.confirm();
|
|
426
|
+
return simulator;
|
|
412
427
|
}
|
|
413
428
|
export {
|
|
414
|
-
NanoBox,
|
|
415
429
|
RNX_CLOUD_COMMAND_TYPES,
|
|
416
430
|
RNX_CLOUD_MAX_ARTIFACT_BYTES,
|
|
417
|
-
|
|
431
|
+
RemoteSimulator,
|
|
432
|
+
createRemoteSimulator,
|
|
418
433
|
isRnxCloudCommandType
|
|
419
434
|
};
|
package/dist-lib/config.cjs
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
/*! rnx v0.1.
|
|
1
|
+
/*! rnx v0.1.433 | (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/detox/index.cjs
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
/*! rnx v0.1.
|
|
1
|
+
/*! rnx v0.1.433 | (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.
|
|
1
|
+
/*! rnx v0.1.433 | (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/home-paths.cjs
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
/*! rnx v0.1.
|
|
1
|
+
/*! rnx v0.1.433 | (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.
|
|
1
|
+
/*! rnx v0.1.433 | (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.
|
|
1
|
+
/*! rnx v0.1.433 | (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.
|
|
1
|
+
/*! rnx v0.1.433 | (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.
|
|
1
|
+
/*! rnx v0.1.433 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
|
|
2
2
|
|
|
3
3
|
// src/host/fetch-proxy-overrides.ts
|
|
4
4
|
var FETCH_PROXY_BROWSER_USER_AGENT = "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/146.0.0.0 Safari/537.36";
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
/*! rnx v0.1.
|
|
1
|
+
/*! rnx v0.1.433 | (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.
|
|
1
|
+
/*! rnx v0.1.433 | (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;
|