rnxsim 0.1.420 → 0.1.422
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/cli/outbound-endpoints.ts +12 -0
- 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 +1 -1
- 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 +447 -0
- package/dist-lib/cloud.mjs +419 -0
- 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 +1 -1
- 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 +1 -1
- 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 +1 -1
- package/dist-lib/vite.cjs +1 -1
- package/package.json +8 -1
- package/src/cloud.ts +499 -0
|
@@ -137,6 +137,18 @@ export const DECLARED_OUTBOUND_CALLS: Record<string, OutboundCallDeclaration> =
|
|
|
137
137
|
category: 'guest_app_network',
|
|
138
138
|
count: 1,
|
|
139
139
|
},
|
|
140
|
+
'packages/sootsim/src/cloud.ts :: fetch :: `${origin}/v1/boxes`': {
|
|
141
|
+
category: 'rnx_cloud_sim',
|
|
142
|
+
count: 1,
|
|
143
|
+
},
|
|
144
|
+
'packages/sootsim/src/cloud.ts :: fetch :: `${this.session.origin}/v1/sims/${encodeURIComponent(this.session.simId)}/commands`':
|
|
145
|
+
{ category: 'rnx_cloud_sim', count: 1 },
|
|
146
|
+
'packages/sootsim/src/cloud.ts :: fetch :: `${this.session.origin}/v1/sims/${encodeURIComponent(this.session.simId)}/claim`':
|
|
147
|
+
{ category: 'rnx_cloud_sim', count: 1 },
|
|
148
|
+
'packages/sootsim/src/cloud.ts :: fetch :: `${this.session.origin}/v1/boxes/${encodeURIComponent(this.session.boxId)}/simulators`':
|
|
149
|
+
{ category: 'rnx_cloud_sim', count: 1 },
|
|
150
|
+
'packages/sootsim/src/cloud.ts :: fetch :: `${this.session.origin}/v1/boxes/${encodeURIComponent(this.session.boxId)}`':
|
|
151
|
+
{ category: 'rnx_cloud_sim', count: 1 },
|
|
140
152
|
// maestro's flow `http` API. the url is whatever the flow author wrote, and
|
|
141
153
|
// it is fetched from a child process because that API is synchronous.
|
|
142
154
|
'packages/sootsim/cli/internal-child.ts :: fetch :: request.url': {
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
/*! rnx v0.1.
|
|
1
|
+
/*! rnx v0.1.422 | (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.422 | (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.422 | (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.422 | (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.422 | (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.422 | (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.422 | (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.
|
|
1
|
+
/*! rnx v0.1.422 | (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.
|
|
1
|
+
/*! rnx v0.1.422 | (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.422 | (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.422 | (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.422 | (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.422 | (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.422 | (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;
|
|
@@ -0,0 +1,447 @@
|
|
|
1
|
+
/*! rnx v0.1.422 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
|
|
2
|
+
let __sootsim_import_meta_url = ''; try { __sootsim_import_meta_url = require('url').pathToFileURL(__filename).href; } catch {}
|
|
3
|
+
"use strict";
|
|
4
|
+
var __defProp = Object.defineProperty;
|
|
5
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
6
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
7
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
8
|
+
var __export = (target, all) => {
|
|
9
|
+
for (var name2 in all)
|
|
10
|
+
__defProp(target, name2, { get: all[name2], enumerable: true });
|
|
11
|
+
};
|
|
12
|
+
var __copyProps = (to, from, except, desc) => {
|
|
13
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
14
|
+
for (let key of __getOwnPropNames(from))
|
|
15
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
16
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
17
|
+
}
|
|
18
|
+
return to;
|
|
19
|
+
};
|
|
20
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
21
|
+
|
|
22
|
+
// src/cloud.ts
|
|
23
|
+
var cloud_exports = {};
|
|
24
|
+
__export(cloud_exports, {
|
|
25
|
+
NanoBox: () => NanoBox,
|
|
26
|
+
RNX_CLOUD_COMMAND_TYPES: () => RNX_CLOUD_COMMAND_TYPES,
|
|
27
|
+
RNX_CLOUD_MAX_ARTIFACT_BYTES: () => RNX_CLOUD_MAX_ARTIFACT_BYTES,
|
|
28
|
+
createNanoBox: () => createNanoBox,
|
|
29
|
+
isRnxCloudCommandType: () => isRnxCloudCommandType
|
|
30
|
+
});
|
|
31
|
+
module.exports = __toCommonJS(cloud_exports);
|
|
32
|
+
|
|
33
|
+
// src/backend-origin.ts
|
|
34
|
+
function normalizeHostname(hostname) {
|
|
35
|
+
return hostname.replace(/^\[|\]$/g, "").toLowerCase();
|
|
36
|
+
}
|
|
37
|
+
function isLoopbackHost(hostname) {
|
|
38
|
+
const normalized = normalizeHostname(hostname);
|
|
39
|
+
return normalized === "localhost" || normalized.endsWith(".localhost") || normalized === "0.0.0.0" || normalized === "::1" || /^127(?:\.\d{1,3}){3}$/.test(normalized);
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
// src/cloud-contract.ts
|
|
43
|
+
var RNX_CLOUD_MAX_ARTIFACT_BYTES = 20 * 1024 * 1024;
|
|
44
|
+
var RNX_CLOUD_DESIGN_MAX_STORAGE_BYTES = 1024 * 1024;
|
|
45
|
+
var RNX_CLOUD_COMMAND_TYPES = Object.freeze([
|
|
46
|
+
"state",
|
|
47
|
+
"query",
|
|
48
|
+
"resolve",
|
|
49
|
+
"perform",
|
|
50
|
+
"waitFor",
|
|
51
|
+
"reset",
|
|
52
|
+
"screenshot",
|
|
53
|
+
"capture",
|
|
54
|
+
"captureRegions",
|
|
55
|
+
"settle",
|
|
56
|
+
"setAppearance",
|
|
57
|
+
"openUrl",
|
|
58
|
+
"tree",
|
|
59
|
+
"tap",
|
|
60
|
+
"longPress",
|
|
61
|
+
"memory",
|
|
62
|
+
"diagnostics"
|
|
63
|
+
]);
|
|
64
|
+
var RNX_CLOUD_COMMAND_TYPE_SET = new Set(RNX_CLOUD_COMMAND_TYPES);
|
|
65
|
+
function isRnxCloudCommandType(value) {
|
|
66
|
+
return RNX_CLOUD_COMMAND_TYPE_SET.has(value);
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
// src/public-brand.ts
|
|
70
|
+
var name = "rnx";
|
|
71
|
+
var rnxPublicBrand = Object.freeze({
|
|
72
|
+
name,
|
|
73
|
+
packageName: "rnxsim",
|
|
74
|
+
commandName: "rnx",
|
|
75
|
+
domain: "rnxsim.com",
|
|
76
|
+
origin: "https://rnxsim.com"
|
|
77
|
+
});
|
|
78
|
+
|
|
79
|
+
// src/cloud.ts
|
|
80
|
+
var DEFAULT_DEVICE = "iphone-16";
|
|
81
|
+
var DEFAULT_WAIT_READY_MS = 2e4;
|
|
82
|
+
function isRecord(value) {
|
|
83
|
+
return value !== null && typeof value === "object" && !Array.isArray(value);
|
|
84
|
+
}
|
|
85
|
+
function normalizeCloudOrigin(source) {
|
|
86
|
+
let parsed;
|
|
87
|
+
try {
|
|
88
|
+
parsed = new URL(source);
|
|
89
|
+
} catch {
|
|
90
|
+
throw new Error(`invalid RNX Cloud origin: ${source}`);
|
|
91
|
+
}
|
|
92
|
+
if (parsed.protocol !== "https:" && parsed.protocol !== "http:" || parsed.username || parsed.password || parsed.pathname !== "/" || parsed.search || parsed.hash) {
|
|
93
|
+
throw new Error(`RNX Cloud origin must be an HTTP(S) origin: ${source}`);
|
|
94
|
+
}
|
|
95
|
+
if (parsed.protocol === "http:" && !isLoopbackHost(parsed.hostname)) {
|
|
96
|
+
throw new Error(`RNX Cloud origin requires HTTPS outside loopback: ${source}`);
|
|
97
|
+
}
|
|
98
|
+
return parsed.origin;
|
|
99
|
+
}
|
|
100
|
+
function resolveOrigin(value) {
|
|
101
|
+
const configured = value?.trim() || process.env.RNX_CLOUD_ORIGIN?.trim();
|
|
102
|
+
return normalizeCloudOrigin(configured || rnxPublicBrand.origin);
|
|
103
|
+
}
|
|
104
|
+
function responseError(status, text) {
|
|
105
|
+
if (text) {
|
|
106
|
+
try {
|
|
107
|
+
const parsed = JSON.parse(text);
|
|
108
|
+
const error = isRecord(parsed) ? parsed.error : null;
|
|
109
|
+
if (isRecord(error) && typeof error.message === "string") {
|
|
110
|
+
return new Error(`RNX Cloud request failed (${status}): ${error.message}`);
|
|
111
|
+
}
|
|
112
|
+
} catch {
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
return new Error(
|
|
116
|
+
`RNX Cloud request failed (${status})${text.trim() ? `: ${text.trim()}` : ""}`
|
|
117
|
+
);
|
|
118
|
+
}
|
|
119
|
+
function copyArrayBuffer(bytes) {
|
|
120
|
+
const copy = new ArrayBuffer(bytes.byteLength);
|
|
121
|
+
new Uint8Array(copy).set(bytes);
|
|
122
|
+
return copy;
|
|
123
|
+
}
|
|
124
|
+
async function sha256Hex(bytes) {
|
|
125
|
+
const digest = await globalThis.crypto.subtle.digest("SHA-256", copyArrayBuffer(bytes));
|
|
126
|
+
const view = new Uint8Array(digest);
|
|
127
|
+
let hex = "";
|
|
128
|
+
for (const byte of view) hex += byte.toString(16).padStart(2, "0");
|
|
129
|
+
return hex;
|
|
130
|
+
}
|
|
131
|
+
function readJsArtifact(bytes) {
|
|
132
|
+
let source;
|
|
133
|
+
try {
|
|
134
|
+
source = new TextDecoder("utf-8", { fatal: true }).decode(bytes);
|
|
135
|
+
} catch {
|
|
136
|
+
throw new Error("rnx Cloud artifact must be valid UTF-8 JavaScript, not bytecode");
|
|
137
|
+
}
|
|
138
|
+
if (source.includes("\0") || !source.includes("__d(") || !source.includes("__r(")) {
|
|
139
|
+
throw new Error("rnx Cloud artifact must be a Metro JavaScript bundle");
|
|
140
|
+
}
|
|
141
|
+
return source;
|
|
142
|
+
}
|
|
143
|
+
function readClaim(value) {
|
|
144
|
+
if (!isRecord(value) || typeof value.id !== "string" || !value.id || typeof value.expiresAt !== "number") {
|
|
145
|
+
throw new Error("RNX Cloud returned an invalid claim");
|
|
146
|
+
}
|
|
147
|
+
return { id: value.id, expiresAt: value.expiresAt };
|
|
148
|
+
}
|
|
149
|
+
function artifactDigestId(sha256) {
|
|
150
|
+
return `sha256:${sha256}`;
|
|
151
|
+
}
|
|
152
|
+
function readArtifact(value, expectedId, expectedBytes) {
|
|
153
|
+
if (!isRecord(value) || value.id !== expectedId || typeof value.bytes !== "number" || !Number.isInteger(value.bytes) || value.bytes !== expectedBytes) {
|
|
154
|
+
throw new Error("RNX Cloud returned an invalid artifact receipt");
|
|
155
|
+
}
|
|
156
|
+
return { id: expectedId, bytes: expectedBytes };
|
|
157
|
+
}
|
|
158
|
+
function readSimulatorCreate(value, expectedId, expectedBytes) {
|
|
159
|
+
if (!isRecord(value)) throw new Error("RNX Cloud create returned an invalid simulator");
|
|
160
|
+
const claim = readClaim(value.claim);
|
|
161
|
+
if (typeof value.simId !== "string" || !value.simId || typeof value.token !== "string") {
|
|
162
|
+
throw new Error("RNX Cloud create returned an invalid simulator");
|
|
163
|
+
}
|
|
164
|
+
return {
|
|
165
|
+
simId: value.simId,
|
|
166
|
+
token: value.token,
|
|
167
|
+
claim,
|
|
168
|
+
artifact: readArtifact(value.artifact, expectedId, expectedBytes)
|
|
169
|
+
};
|
|
170
|
+
}
|
|
171
|
+
function readBoxCreate(value, expectedBytes, expectedSha256) {
|
|
172
|
+
const artifactId = artifactDigestId(expectedSha256);
|
|
173
|
+
if (!isRecord(value)) throw new Error("RNX Cloud create returned invalid JSON");
|
|
174
|
+
const simulator = readSimulatorCreate(value.simulator, artifactId, expectedBytes);
|
|
175
|
+
if (typeof value.boxId !== "string" || !value.boxId || value.size !== "nano" || typeof value.token !== "string" || !value.token) {
|
|
176
|
+
throw new Error("RNX Cloud create returned an invalid box receipt");
|
|
177
|
+
}
|
|
178
|
+
return {
|
|
179
|
+
receipt: {
|
|
180
|
+
boxId: value.boxId,
|
|
181
|
+
size: "nano",
|
|
182
|
+
artifact: readArtifact(value.artifact, artifactId, expectedBytes),
|
|
183
|
+
simulator: {
|
|
184
|
+
simId: simulator.simId,
|
|
185
|
+
artifact: simulator.artifact,
|
|
186
|
+
claim: simulator.claim
|
|
187
|
+
}
|
|
188
|
+
},
|
|
189
|
+
boxToken: value.token,
|
|
190
|
+
simulatorToken: simulator.token
|
|
191
|
+
};
|
|
192
|
+
}
|
|
193
|
+
function cloudCommand(command) {
|
|
194
|
+
const clean = {};
|
|
195
|
+
for (const [key, value] of Object.entries(command)) {
|
|
196
|
+
if (key !== "id" && key !== "simId") clean[key] = value;
|
|
197
|
+
}
|
|
198
|
+
if (!isRnxCloudCommandType(command.type)) {
|
|
199
|
+
throw new Error(`RNX Cloud does not support bridge command type ${command.type}`);
|
|
200
|
+
}
|
|
201
|
+
return { ...clean, type: command.type };
|
|
202
|
+
}
|
|
203
|
+
var NanoBox = class _NanoBox {
|
|
204
|
+
session;
|
|
205
|
+
constructor(session) {
|
|
206
|
+
this.session = session;
|
|
207
|
+
}
|
|
208
|
+
get boxId() {
|
|
209
|
+
return this.session.boxId;
|
|
210
|
+
}
|
|
211
|
+
get simId() {
|
|
212
|
+
return this.session.simId;
|
|
213
|
+
}
|
|
214
|
+
get claim() {
|
|
215
|
+
return this.session.claim;
|
|
216
|
+
}
|
|
217
|
+
get receipt() {
|
|
218
|
+
return {
|
|
219
|
+
boxId: this.session.boxId,
|
|
220
|
+
size: "nano",
|
|
221
|
+
artifact: this.session.artifact,
|
|
222
|
+
simulator: {
|
|
223
|
+
simId: this.session.simId,
|
|
224
|
+
artifact: this.session.artifact,
|
|
225
|
+
claim: this.session.claim
|
|
226
|
+
}
|
|
227
|
+
};
|
|
228
|
+
}
|
|
229
|
+
async command(command, options) {
|
|
230
|
+
const body = {
|
|
231
|
+
id: globalThis.crypto.randomUUID(),
|
|
232
|
+
claimId: this.session.claim.id,
|
|
233
|
+
command: cloudCommand(command)
|
|
234
|
+
};
|
|
235
|
+
let response;
|
|
236
|
+
try {
|
|
237
|
+
response = await fetch(
|
|
238
|
+
`${this.session.origin}/v1/sims/${encodeURIComponent(this.session.simId)}/commands`,
|
|
239
|
+
{
|
|
240
|
+
method: "POST",
|
|
241
|
+
headers: {
|
|
242
|
+
authorization: `Bearer ${this.session.simulatorToken}`,
|
|
243
|
+
"content-type": "application/json"
|
|
244
|
+
},
|
|
245
|
+
body: JSON.stringify(body),
|
|
246
|
+
...options?.timeoutMs ? { signal: AbortSignal.timeout(options.timeoutMs) } : {}
|
|
247
|
+
}
|
|
248
|
+
);
|
|
249
|
+
} catch (error) {
|
|
250
|
+
throw new Error(
|
|
251
|
+
`could not reach RNX Cloud at ${this.session.origin}: ${error instanceof Error ? error.message : String(error)}`
|
|
252
|
+
);
|
|
253
|
+
}
|
|
254
|
+
const text = await response.text();
|
|
255
|
+
if (!response.ok) throw responseError(response.status, text);
|
|
256
|
+
let parsed;
|
|
257
|
+
try {
|
|
258
|
+
parsed = JSON.parse(text);
|
|
259
|
+
} catch {
|
|
260
|
+
throw new Error("RNX Cloud command returned unreadable JSON");
|
|
261
|
+
}
|
|
262
|
+
if (!isRecord(parsed) || parsed.id !== body.id) {
|
|
263
|
+
throw new Error("RNX Cloud command returned an invalid command receipt");
|
|
264
|
+
}
|
|
265
|
+
if (typeof parsed.error === "string" && parsed.error) throw new Error(parsed.error);
|
|
266
|
+
if (!Object.hasOwn(parsed, "result")) {
|
|
267
|
+
throw new Error("RNX Cloud command receipt has no result");
|
|
268
|
+
}
|
|
269
|
+
return parsed.result;
|
|
270
|
+
}
|
|
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
|
+
async confirm() {
|
|
301
|
+
const response = await fetch(
|
|
302
|
+
`${this.session.origin}/v1/sims/${encodeURIComponent(this.session.simId)}/claim`,
|
|
303
|
+
{
|
|
304
|
+
method: "POST",
|
|
305
|
+
headers: {
|
|
306
|
+
authorization: `Bearer ${this.session.simulatorToken}`,
|
|
307
|
+
"content-type": "application/json"
|
|
308
|
+
},
|
|
309
|
+
body: JSON.stringify({ claimId: this.session.claim.id })
|
|
310
|
+
}
|
|
311
|
+
);
|
|
312
|
+
const text = await response.text();
|
|
313
|
+
if (!response.ok) throw responseError(response.status, text);
|
|
314
|
+
let parsed;
|
|
315
|
+
try {
|
|
316
|
+
parsed = JSON.parse(text);
|
|
317
|
+
} catch {
|
|
318
|
+
throw new Error("RNX Cloud claim returned unreadable JSON");
|
|
319
|
+
}
|
|
320
|
+
const claim = readClaim(isRecord(parsed) ? parsed.claim : null);
|
|
321
|
+
if (claim.id !== this.session.claim.id) {
|
|
322
|
+
throw new Error("RNX Cloud confirmation replaced the initial claim");
|
|
323
|
+
}
|
|
324
|
+
this.session = { ...this.session, claim };
|
|
325
|
+
return claim;
|
|
326
|
+
}
|
|
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
|
+
async close() {
|
|
370
|
+
const response = await fetch(
|
|
371
|
+
`${this.session.origin}/v1/boxes/${encodeURIComponent(this.session.boxId)}`,
|
|
372
|
+
{
|
|
373
|
+
method: "DELETE",
|
|
374
|
+
headers: { authorization: `Bearer ${this.session.boxToken}` }
|
|
375
|
+
}
|
|
376
|
+
);
|
|
377
|
+
const text = await response.text();
|
|
378
|
+
if (!response.ok && response.status !== 404) {
|
|
379
|
+
throw responseError(response.status, text);
|
|
380
|
+
}
|
|
381
|
+
}
|
|
382
|
+
};
|
|
383
|
+
async function createNanoBox(input) {
|
|
384
|
+
if (input.artifact.byteLength > RNX_CLOUD_MAX_ARTIFACT_BYTES) {
|
|
385
|
+
throw new Error(
|
|
386
|
+
`rnx Cloud artifact is ${input.artifact.byteLength} bytes and exceeds the ${RNX_CLOUD_MAX_ARTIFACT_BYTES}-byte limit`
|
|
387
|
+
);
|
|
388
|
+
}
|
|
389
|
+
if (input.artifact.byteLength <= 0) {
|
|
390
|
+
throw new Error("rnx Cloud artifact is empty");
|
|
391
|
+
}
|
|
392
|
+
readJsArtifact(input.artifact);
|
|
393
|
+
const origin = resolveOrigin(input.origin);
|
|
394
|
+
const sha256 = await sha256Hex(input.artifact);
|
|
395
|
+
if (input.sha256 && input.sha256 !== sha256) {
|
|
396
|
+
throw new Error("rnx Cloud artifact sha256 does not match the provided digest");
|
|
397
|
+
}
|
|
398
|
+
const device = input.device?.trim() || DEFAULT_DEVICE;
|
|
399
|
+
let response;
|
|
400
|
+
try {
|
|
401
|
+
response = await fetch(`${origin}/v1/boxes`, {
|
|
402
|
+
method: "POST",
|
|
403
|
+
headers: {
|
|
404
|
+
authorization: input.authorization,
|
|
405
|
+
"content-type": "application/javascript",
|
|
406
|
+
"x-rnx-box-size": "nano",
|
|
407
|
+
"x-rnx-artifact-sha256": sha256,
|
|
408
|
+
"x-rnx-platform": "ios",
|
|
409
|
+
"x-rnx-device": device
|
|
410
|
+
},
|
|
411
|
+
body: copyArrayBuffer(input.artifact)
|
|
412
|
+
});
|
|
413
|
+
} catch (error) {
|
|
414
|
+
throw new Error(
|
|
415
|
+
`could not reach RNX Cloud at ${origin}: ${error instanceof Error ? error.message : String(error)}`
|
|
416
|
+
);
|
|
417
|
+
}
|
|
418
|
+
const responseText = await response.text();
|
|
419
|
+
if (!response.ok) throw responseError(response.status, responseText);
|
|
420
|
+
let parsed;
|
|
421
|
+
try {
|
|
422
|
+
parsed = JSON.parse(responseText);
|
|
423
|
+
} catch {
|
|
424
|
+
throw new Error("RNX Cloud create returned unreadable JSON");
|
|
425
|
+
}
|
|
426
|
+
const created = readBoxCreate(parsed, input.artifact.byteLength, sha256);
|
|
427
|
+
const box = new NanoBox({
|
|
428
|
+
origin,
|
|
429
|
+
authorization: input.authorization,
|
|
430
|
+
boxId: created.receipt.boxId,
|
|
431
|
+
boxToken: created.boxToken,
|
|
432
|
+
simId: created.receipt.simulator.simId,
|
|
433
|
+
simulatorToken: created.simulatorToken,
|
|
434
|
+
claim: created.receipt.simulator.claim,
|
|
435
|
+
artifact: created.receipt.artifact
|
|
436
|
+
});
|
|
437
|
+
await box.confirm();
|
|
438
|
+
return box;
|
|
439
|
+
}
|
|
440
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
441
|
+
0 && (module.exports = {
|
|
442
|
+
NanoBox,
|
|
443
|
+
RNX_CLOUD_COMMAND_TYPES,
|
|
444
|
+
RNX_CLOUD_MAX_ARTIFACT_BYTES,
|
|
445
|
+
createNanoBox,
|
|
446
|
+
isRnxCloudCommandType
|
|
447
|
+
});
|