rnxsim 0.1.512 → 0.1.514
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/bridge-flow-runner.ts +39 -0
- package/cli/commands/maestro.ts +1 -1
- package/cli/outbound-endpoints.ts +1 -7
- 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 +57 -3
- package/dist-lib/cloud-contract.mjs +49 -2
- package/dist-lib/cloud.cjs +66 -8
- package/dist-lib/cloud.mjs +66 -8
- 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/jump-to-source-native.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 +26 -2
- package/dist-lib/swift.cjs +1 -1
- package/dist-lib/vite.cjs +1 -1
- package/package.json +1 -1
- package/src/cloud-contract.ts +120 -0
- package/src/cloud.ts +94 -7
|
@@ -197,6 +197,13 @@ export interface MaestroStep {
|
|
|
197
197
|
condition?: NonNullable<MaestroStep['when']>
|
|
198
198
|
commands: MaestroStep[]
|
|
199
199
|
}
|
|
200
|
+
// maestro retry: run the body, and on a failed step rerun the whole body.
|
|
201
|
+
// maxRetries counts retries after the first attempt (upstream
|
|
202
|
+
// retryCommand), so maxRetries: 3 allows at most 4 runs.
|
|
203
|
+
retry?: {
|
|
204
|
+
maxRetries?: number | string
|
|
205
|
+
commands: MaestroStep[]
|
|
206
|
+
}
|
|
200
207
|
scrollUntilVisible?: {
|
|
201
208
|
element: string
|
|
202
209
|
centerElement?: boolean
|
|
@@ -2333,6 +2340,10 @@ export class SootSimBridgeFlowRunner {
|
|
|
2333
2340
|
step.scrollUntilVisible ||
|
|
2334
2341
|
step.launchApp ||
|
|
2335
2342
|
step.runFlow ||
|
|
2343
|
+
// retry reruns its body on failure, so its wall time is the body's
|
|
2344
|
+
// times the retry count — the 10s no-progress watchdog is the wrong
|
|
2345
|
+
// budget and would report "bridge probably hung" for a slow retry.
|
|
2346
|
+
step.retry ||
|
|
2336
2347
|
// runScript http calls are synchronous with a 5-minute upstream
|
|
2337
2348
|
// timeout — the 10s watchdog would kill legitimate setup scripts.
|
|
2338
2349
|
step.runScript ||
|
|
@@ -2512,6 +2523,34 @@ export class SootSimBridgeFlowRunner {
|
|
|
2512
2523
|
}
|
|
2513
2524
|
} else if (step.stopApp !== undefined) {
|
|
2514
2525
|
await this.stopApp()
|
|
2526
|
+
} else if (step.retry && Array.isArray(step.retry.commands)) {
|
|
2527
|
+
// maestro retryCommand: rerun the whole body when any step in it fails,
|
|
2528
|
+
// up to maxRetries times after the first attempt. the body is replayed
|
|
2529
|
+
// through runStep so each nested command re-interpolates, exactly like
|
|
2530
|
+
// repeat; the last failure propagates so the flow still fails loudly.
|
|
2531
|
+
const rawMaxRetries = step.retry.maxRetries
|
|
2532
|
+
const maxRetries =
|
|
2533
|
+
rawMaxRetries === undefined || rawMaxRetries === null || rawMaxRetries === ''
|
|
2534
|
+
? 0
|
|
2535
|
+
: Number(rawMaxRetries)
|
|
2536
|
+
if (!Number.isInteger(maxRetries) || maxRetries < 0) {
|
|
2537
|
+
throw new Error(
|
|
2538
|
+
`retry.maxRetries is not a non-negative integer: ${rawMaxRetries}`,
|
|
2539
|
+
)
|
|
2540
|
+
}
|
|
2541
|
+
for (let attempt = 0; ; attempt++) {
|
|
2542
|
+
try {
|
|
2543
|
+
for (let j = 0; j < step.retry.commands.length; j++) {
|
|
2544
|
+
await this.runStep(step.retry.commands[j], j)
|
|
2545
|
+
}
|
|
2546
|
+
break
|
|
2547
|
+
} catch (error) {
|
|
2548
|
+
if (attempt >= maxRetries) throw error
|
|
2549
|
+
console.log(
|
|
2550
|
+
`[flow] retry ${attempt + 1}/${maxRetries} after: ${(error as Error).message.slice(0, 120)}`,
|
|
2551
|
+
)
|
|
2552
|
+
}
|
|
2553
|
+
}
|
|
2515
2554
|
} else if (step.clearState !== undefined) {
|
|
2516
2555
|
await this.clearState()
|
|
2517
2556
|
} else if (step.clearKeychain !== undefined) {
|
package/cli/commands/maestro.ts
CHANGED
|
@@ -84,7 +84,7 @@ supported verbs:
|
|
|
84
84
|
waitFor, extendedWaitUntil, waitForAnimationToEnd,
|
|
85
85
|
scroll, scrollUntilVisible, scrollTo, swipe, pinch,
|
|
86
86
|
takeScreenshot, dumpTree, back,
|
|
87
|
-
repeat (times), runFlow (file / inline commands / env / when),
|
|
87
|
+
repeat (times), retry (maxRetries + commands), runFlow (file / inline commands / env / when),
|
|
88
88
|
runScript (maestro JS: http, json(), output, env vars, console.log),
|
|
89
89
|
evalScript, copyTextFrom (\${maestro.copiedText}), openLink,
|
|
90
90
|
when: (visible / notVisible / platform / true),
|
|
@@ -164,16 +164,10 @@ export const DECLARED_OUTBOUND_CALLS: Record<string, OutboundCallDeclaration> =
|
|
|
164
164
|
category: 'contrast_user_action',
|
|
165
165
|
count: 1,
|
|
166
166
|
},
|
|
167
|
-
'packages/sootsim/src/cloud.ts :: fetch ::
|
|
167
|
+
'packages/sootsim/src/cloud.ts :: fetch :: url': {
|
|
168
168
|
category: 'rnx_cloud_sim',
|
|
169
169
|
count: 1,
|
|
170
170
|
},
|
|
171
|
-
'packages/sootsim/src/cloud.ts :: fetch :: `${this.session.origin}/v1/sims/${encodeURIComponent(this.session.simId)}/commands`':
|
|
172
|
-
{ category: 'rnx_cloud_sim', count: 1 },
|
|
173
|
-
'packages/sootsim/src/cloud.ts :: fetch :: `${this.session.origin}/v1/sims/${encodeURIComponent(this.session.simId)}/claim`':
|
|
174
|
-
{ category: 'rnx_cloud_sim', count: 1 },
|
|
175
|
-
'packages/sootsim/src/cloud.ts :: fetch :: `${this.session.origin}/v1/boxes/${encodeURIComponent(this.session.boxId)}`':
|
|
176
|
-
{ category: 'rnx_cloud_sim', count: 1 },
|
|
177
171
|
// maestro's flow `http` API. the url is whatever the flow author wrote, and
|
|
178
172
|
// it is fetched from a child process because that API is synchronous.
|
|
179
173
|
'packages/sootsim/cli/internal-child.ts :: fetch :: request.url': {
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
/*! rnx v0.1.
|
|
1
|
+
/*! rnx v0.1.514 | (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.514 | (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.514 | (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.514 | (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.514 | (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.514 | (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.514 | (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.514 | (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.514 | (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.514 | (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.514 | (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.514 | (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.514 | (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.514 | (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;
|
|
@@ -25,10 +25,17 @@ __export(cloud_contract_exports, {
|
|
|
25
25
|
RNX_CLOUD_COMMAND_TYPES: () => RNX_CLOUD_COMMAND_TYPES,
|
|
26
26
|
RNX_CLOUD_DESIGN_MAX_STORAGE_BYTES: () => RNX_CLOUD_DESIGN_MAX_STORAGE_BYTES,
|
|
27
27
|
RNX_CLOUD_DESIGN_MAX_STORAGE_ENTRIES: () => RNX_CLOUD_DESIGN_MAX_STORAGE_ENTRIES,
|
|
28
|
+
RNX_CLOUD_LABELS_MAX_COUNT: () => RNX_CLOUD_LABELS_MAX_COUNT,
|
|
29
|
+
RNX_CLOUD_LABEL_MAX_LENGTH: () => RNX_CLOUD_LABEL_MAX_LENGTH,
|
|
28
30
|
RNX_CLOUD_MAX_ARTIFACT_BYTES: () => RNX_CLOUD_MAX_ARTIFACT_BYTES,
|
|
29
31
|
RNX_CLOUD_TEST_FILES_MAX_BYTES: () => RNX_CLOUD_TEST_FILES_MAX_BYTES,
|
|
30
32
|
RNX_CLOUD_TEST_FILES_MAX_COUNT: () => RNX_CLOUD_TEST_FILES_MAX_COUNT,
|
|
31
|
-
isRnxCloudCommandType: () => isRnxCloudCommandType
|
|
33
|
+
isRnxCloudCommandType: () => isRnxCloudCommandType,
|
|
34
|
+
isRnxCloudSimStatus: () => isRnxCloudSimStatus,
|
|
35
|
+
isValidRnxCloudLabel: () => isValidRnxCloudLabel,
|
|
36
|
+
matchesRnxCloudLabels: () => matchesRnxCloudLabels,
|
|
37
|
+
parseRnxCloudLabels: () => parseRnxCloudLabels,
|
|
38
|
+
readRnxCloudLabels: () => readRnxCloudLabels
|
|
32
39
|
});
|
|
33
40
|
module.exports = __toCommonJS(cloud_contract_exports);
|
|
34
41
|
var RNX_CLOUD_MAX_ARTIFACT_BYTES = 20 * 1024 * 1024;
|
|
@@ -59,13 +66,60 @@ var RNX_CLOUD_COMMAND_TYPE_SET = new Set(RNX_CLOUD_COMMAND_TYPES);
|
|
|
59
66
|
function isRnxCloudCommandType(value) {
|
|
60
67
|
return RNX_CLOUD_COMMAND_TYPE_SET.has(value);
|
|
61
68
|
}
|
|
69
|
+
var RNX_CLOUD_LABELS_MAX_COUNT = 16;
|
|
70
|
+
var RNX_CLOUD_LABEL_MAX_LENGTH = 63;
|
|
71
|
+
var RNX_CLOUD_LABEL_CONTROL = /[\u0000-\u001f\u007f]/;
|
|
72
|
+
function isValidRnxCloudLabel(key, value) {
|
|
73
|
+
return key.length > 0 && key.length <= RNX_CLOUD_LABEL_MAX_LENGTH && value.length <= RNX_CLOUD_LABEL_MAX_LENGTH && !key.includes(",") && !key.includes("=") && !value.includes(",") && !RNX_CLOUD_LABEL_CONTROL.test(key) && !RNX_CLOUD_LABEL_CONTROL.test(value);
|
|
74
|
+
}
|
|
75
|
+
function parseRnxCloudLabels(value) {
|
|
76
|
+
if (value === "") return {};
|
|
77
|
+
const entries = value.split(",");
|
|
78
|
+
if (entries.length > RNX_CLOUD_LABELS_MAX_COUNT) return null;
|
|
79
|
+
const labels = {};
|
|
80
|
+
for (const entry of entries) {
|
|
81
|
+
const separator = entry.indexOf("=");
|
|
82
|
+
if (separator < 1) return null;
|
|
83
|
+
const key = entry.slice(0, separator).trim();
|
|
84
|
+
const label = entry.slice(separator + 1).trim();
|
|
85
|
+
if (!isValidRnxCloudLabel(key, label)) return null;
|
|
86
|
+
if (Object.hasOwn(labels, key)) return null;
|
|
87
|
+
labels[key] = label;
|
|
88
|
+
}
|
|
89
|
+
return labels;
|
|
90
|
+
}
|
|
91
|
+
function readRnxCloudLabels(value) {
|
|
92
|
+
if (typeof value !== "object" || value === null || Array.isArray(value)) return null;
|
|
93
|
+
const entries = Object.entries(value);
|
|
94
|
+
if (entries.length > RNX_CLOUD_LABELS_MAX_COUNT) return null;
|
|
95
|
+
const labels = {};
|
|
96
|
+
for (const [key, label] of entries) {
|
|
97
|
+
if (typeof label !== "string") return null;
|
|
98
|
+
if (!isValidRnxCloudLabel(key, label)) return null;
|
|
99
|
+
labels[key] = label;
|
|
100
|
+
}
|
|
101
|
+
return labels;
|
|
102
|
+
}
|
|
103
|
+
function matchesRnxCloudLabels(labels, selector) {
|
|
104
|
+
return Object.entries(selector).every(([key, value]) => labels[key] === value);
|
|
105
|
+
}
|
|
106
|
+
function isRnxCloudSimStatus(value) {
|
|
107
|
+
return value === "creating" || value === "open" || value === "hibernated" || value === "deleting" || value === "deleted";
|
|
108
|
+
}
|
|
62
109
|
// Annotate the CommonJS export names for ESM import in node:
|
|
63
110
|
0 && (module.exports = {
|
|
64
111
|
RNX_CLOUD_COMMAND_TYPES,
|
|
65
112
|
RNX_CLOUD_DESIGN_MAX_STORAGE_BYTES,
|
|
66
113
|
RNX_CLOUD_DESIGN_MAX_STORAGE_ENTRIES,
|
|
114
|
+
RNX_CLOUD_LABELS_MAX_COUNT,
|
|
115
|
+
RNX_CLOUD_LABEL_MAX_LENGTH,
|
|
67
116
|
RNX_CLOUD_MAX_ARTIFACT_BYTES,
|
|
68
117
|
RNX_CLOUD_TEST_FILES_MAX_BYTES,
|
|
69
118
|
RNX_CLOUD_TEST_FILES_MAX_COUNT,
|
|
70
|
-
isRnxCloudCommandType
|
|
119
|
+
isRnxCloudCommandType,
|
|
120
|
+
isRnxCloudSimStatus,
|
|
121
|
+
isValidRnxCloudLabel,
|
|
122
|
+
matchesRnxCloudLabels,
|
|
123
|
+
parseRnxCloudLabels,
|
|
124
|
+
readRnxCloudLabels
|
|
71
125
|
});
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
/*! rnx v0.1.
|
|
1
|
+
/*! rnx v0.1.514 | (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;
|
|
@@ -29,12 +29,59 @@ var RNX_CLOUD_COMMAND_TYPE_SET = new Set(RNX_CLOUD_COMMAND_TYPES);
|
|
|
29
29
|
function isRnxCloudCommandType(value) {
|
|
30
30
|
return RNX_CLOUD_COMMAND_TYPE_SET.has(value);
|
|
31
31
|
}
|
|
32
|
+
var RNX_CLOUD_LABELS_MAX_COUNT = 16;
|
|
33
|
+
var RNX_CLOUD_LABEL_MAX_LENGTH = 63;
|
|
34
|
+
var RNX_CLOUD_LABEL_CONTROL = /[\u0000-\u001f\u007f]/;
|
|
35
|
+
function isValidRnxCloudLabel(key, value) {
|
|
36
|
+
return key.length > 0 && key.length <= RNX_CLOUD_LABEL_MAX_LENGTH && value.length <= RNX_CLOUD_LABEL_MAX_LENGTH && !key.includes(",") && !key.includes("=") && !value.includes(",") && !RNX_CLOUD_LABEL_CONTROL.test(key) && !RNX_CLOUD_LABEL_CONTROL.test(value);
|
|
37
|
+
}
|
|
38
|
+
function parseRnxCloudLabels(value) {
|
|
39
|
+
if (value === "") return {};
|
|
40
|
+
const entries = value.split(",");
|
|
41
|
+
if (entries.length > RNX_CLOUD_LABELS_MAX_COUNT) return null;
|
|
42
|
+
const labels = {};
|
|
43
|
+
for (const entry of entries) {
|
|
44
|
+
const separator = entry.indexOf("=");
|
|
45
|
+
if (separator < 1) return null;
|
|
46
|
+
const key = entry.slice(0, separator).trim();
|
|
47
|
+
const label = entry.slice(separator + 1).trim();
|
|
48
|
+
if (!isValidRnxCloudLabel(key, label)) return null;
|
|
49
|
+
if (Object.hasOwn(labels, key)) return null;
|
|
50
|
+
labels[key] = label;
|
|
51
|
+
}
|
|
52
|
+
return labels;
|
|
53
|
+
}
|
|
54
|
+
function readRnxCloudLabels(value) {
|
|
55
|
+
if (typeof value !== "object" || value === null || Array.isArray(value)) return null;
|
|
56
|
+
const entries = Object.entries(value);
|
|
57
|
+
if (entries.length > RNX_CLOUD_LABELS_MAX_COUNT) return null;
|
|
58
|
+
const labels = {};
|
|
59
|
+
for (const [key, label] of entries) {
|
|
60
|
+
if (typeof label !== "string") return null;
|
|
61
|
+
if (!isValidRnxCloudLabel(key, label)) return null;
|
|
62
|
+
labels[key] = label;
|
|
63
|
+
}
|
|
64
|
+
return labels;
|
|
65
|
+
}
|
|
66
|
+
function matchesRnxCloudLabels(labels, selector) {
|
|
67
|
+
return Object.entries(selector).every(([key, value]) => labels[key] === value);
|
|
68
|
+
}
|
|
69
|
+
function isRnxCloudSimStatus(value) {
|
|
70
|
+
return value === "creating" || value === "open" || value === "hibernated" || value === "deleting" || value === "deleted";
|
|
71
|
+
}
|
|
32
72
|
export {
|
|
33
73
|
RNX_CLOUD_COMMAND_TYPES,
|
|
34
74
|
RNX_CLOUD_DESIGN_MAX_STORAGE_BYTES,
|
|
35
75
|
RNX_CLOUD_DESIGN_MAX_STORAGE_ENTRIES,
|
|
76
|
+
RNX_CLOUD_LABELS_MAX_COUNT,
|
|
77
|
+
RNX_CLOUD_LABEL_MAX_LENGTH,
|
|
36
78
|
RNX_CLOUD_MAX_ARTIFACT_BYTES,
|
|
37
79
|
RNX_CLOUD_TEST_FILES_MAX_BYTES,
|
|
38
80
|
RNX_CLOUD_TEST_FILES_MAX_COUNT,
|
|
39
|
-
isRnxCloudCommandType
|
|
81
|
+
isRnxCloudCommandType,
|
|
82
|
+
isRnxCloudSimStatus,
|
|
83
|
+
isValidRnxCloudLabel,
|
|
84
|
+
matchesRnxCloudLabels,
|
|
85
|
+
parseRnxCloudLabels,
|
|
86
|
+
readRnxCloudLabels
|
|
40
87
|
};
|
package/dist-lib/cloud.cjs
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
/*! rnx v0.1.
|
|
1
|
+
/*! rnx v0.1.514 | (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;
|
|
@@ -136,6 +136,8 @@ var rnxPublicBrand = Object.freeze({
|
|
|
136
136
|
// src/cloud.ts
|
|
137
137
|
var DEFAULT_DEVICE = "iphone-16";
|
|
138
138
|
var DEFAULT_WAIT_READY_MS = 2e4;
|
|
139
|
+
var CLOUD_MAX_RETRIES = 2;
|
|
140
|
+
var CLOUD_NEVER_RETRY_CODES = /* @__PURE__ */ new Set(["concurrency_limit", "early_access"]);
|
|
139
141
|
function isRecord(value) {
|
|
140
142
|
return value !== null && typeof value === "object" && !Array.isArray(value);
|
|
141
143
|
}
|
|
@@ -173,6 +175,62 @@ function responseError(status, text) {
|
|
|
173
175
|
`RNX Cloud request failed (${status})${text.trim() ? `: ${text.trim()}` : ""}`
|
|
174
176
|
);
|
|
175
177
|
}
|
|
178
|
+
function readCloudErrorCode(text) {
|
|
179
|
+
let parsed;
|
|
180
|
+
try {
|
|
181
|
+
parsed = JSON.parse(text);
|
|
182
|
+
} catch {
|
|
183
|
+
return null;
|
|
184
|
+
}
|
|
185
|
+
if (!isRecord(parsed)) return null;
|
|
186
|
+
if (typeof parsed.error === "string") return parsed.error;
|
|
187
|
+
if (isRecord(parsed.error) && typeof parsed.error.code === "string") {
|
|
188
|
+
return parsed.error.code;
|
|
189
|
+
}
|
|
190
|
+
return null;
|
|
191
|
+
}
|
|
192
|
+
function readRetryAfterMs(response, text) {
|
|
193
|
+
const header = response.headers.get("retry-after");
|
|
194
|
+
if (header !== null) {
|
|
195
|
+
const seconds = Number(header.trim());
|
|
196
|
+
if (Number.isFinite(seconds) && seconds >= 0) return seconds * 1e3;
|
|
197
|
+
}
|
|
198
|
+
let parsed;
|
|
199
|
+
try {
|
|
200
|
+
parsed = JSON.parse(text);
|
|
201
|
+
} catch {
|
|
202
|
+
return null;
|
|
203
|
+
}
|
|
204
|
+
if (isRecord(parsed) && typeof parsed.retryAfterMs === "number" && Number.isFinite(parsed.retryAfterMs) && parsed.retryAfterMs >= 0) {
|
|
205
|
+
return parsed.retryAfterMs;
|
|
206
|
+
}
|
|
207
|
+
return null;
|
|
208
|
+
}
|
|
209
|
+
function sleep(ms) {
|
|
210
|
+
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
211
|
+
}
|
|
212
|
+
async function fetchWithCloudRetry(url, init, options) {
|
|
213
|
+
let attempt = 0;
|
|
214
|
+
for (; ; ) {
|
|
215
|
+
const response = await fetch(
|
|
216
|
+
url,
|
|
217
|
+
options?.timeoutMs === void 0 ? init : { ...init, signal: AbortSignal.timeout(options.timeoutMs) }
|
|
218
|
+
);
|
|
219
|
+
if (response.ok) return response;
|
|
220
|
+
const retryableStatus = response.status === 429 || response.status >= 500;
|
|
221
|
+
if (!retryableStatus || attempt >= CLOUD_MAX_RETRIES) return response;
|
|
222
|
+
const text = await response.text();
|
|
223
|
+
const code = readCloudErrorCode(text);
|
|
224
|
+
const retryable = response.status >= 500 ? !(code !== null && CLOUD_NEVER_RETRY_CODES.has(code)) : code === "rate_limited";
|
|
225
|
+
if (!retryable) {
|
|
226
|
+
return new Response(text, { status: response.status, headers: response.headers });
|
|
227
|
+
}
|
|
228
|
+
if (response.status === 429) {
|
|
229
|
+
await sleep(readRetryAfterMs(response, text) ?? 1e3);
|
|
230
|
+
}
|
|
231
|
+
attempt += 1;
|
|
232
|
+
}
|
|
233
|
+
}
|
|
176
234
|
function copyArrayBuffer(bytes) {
|
|
177
235
|
const copy = new ArrayBuffer(bytes.byteLength);
|
|
178
236
|
new Uint8Array(copy).set(bytes);
|
|
@@ -321,7 +379,7 @@ var RemoteSimulator = class {
|
|
|
321
379
|
};
|
|
322
380
|
let response;
|
|
323
381
|
try {
|
|
324
|
-
response = await
|
|
382
|
+
response = await fetchWithCloudRetry(
|
|
325
383
|
`${this.session.origin}/v1/sims/${encodeURIComponent(this.session.simId)}/commands`,
|
|
326
384
|
{
|
|
327
385
|
method: "POST",
|
|
@@ -329,9 +387,9 @@ var RemoteSimulator = class {
|
|
|
329
387
|
authorization: `Bearer ${this.session.simulatorToken}`,
|
|
330
388
|
"content-type": "application/json"
|
|
331
389
|
},
|
|
332
|
-
body: JSON.stringify(body)
|
|
333
|
-
|
|
334
|
-
}
|
|
390
|
+
body: JSON.stringify(body)
|
|
391
|
+
},
|
|
392
|
+
options?.timeoutMs === void 0 ? void 0 : { timeoutMs: options.timeoutMs }
|
|
335
393
|
);
|
|
336
394
|
} catch (error) {
|
|
337
395
|
throw new Error(
|
|
@@ -356,7 +414,7 @@ var RemoteSimulator = class {
|
|
|
356
414
|
return parsed.result;
|
|
357
415
|
}
|
|
358
416
|
async confirm() {
|
|
359
|
-
const response = await
|
|
417
|
+
const response = await fetchWithCloudRetry(
|
|
360
418
|
`${this.session.origin}/v1/sims/${encodeURIComponent(this.session.simId)}/claim`,
|
|
361
419
|
{
|
|
362
420
|
method: "POST",
|
|
@@ -383,7 +441,7 @@ var RemoteSimulator = class {
|
|
|
383
441
|
return claim;
|
|
384
442
|
}
|
|
385
443
|
async close() {
|
|
386
|
-
const response = await
|
|
444
|
+
const response = await fetchWithCloudRetry(
|
|
387
445
|
`${this.session.origin}/v1/boxes/${encodeURIComponent(this.session.boxId)}`,
|
|
388
446
|
{
|
|
389
447
|
method: "DELETE",
|
|
@@ -414,7 +472,7 @@ async function createRemoteSimulator(input) {
|
|
|
414
472
|
const device = input.device?.trim() || DEFAULT_DEVICE;
|
|
415
473
|
let response;
|
|
416
474
|
try {
|
|
417
|
-
response = await
|
|
475
|
+
response = await fetchWithCloudRetry(`${origin}/v1/boxes`, {
|
|
418
476
|
method: "POST",
|
|
419
477
|
headers: {
|
|
420
478
|
authorization: input.authorization,
|
package/dist-lib/cloud.mjs
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
/*! rnx v0.1.
|
|
1
|
+
/*! rnx v0.1.514 | (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);
|
|
@@ -109,6 +109,8 @@ var rnxPublicBrand = Object.freeze({
|
|
|
109
109
|
// src/cloud.ts
|
|
110
110
|
var DEFAULT_DEVICE = "iphone-16";
|
|
111
111
|
var DEFAULT_WAIT_READY_MS = 2e4;
|
|
112
|
+
var CLOUD_MAX_RETRIES = 2;
|
|
113
|
+
var CLOUD_NEVER_RETRY_CODES = /* @__PURE__ */ new Set(["concurrency_limit", "early_access"]);
|
|
112
114
|
function isRecord(value) {
|
|
113
115
|
return value !== null && typeof value === "object" && !Array.isArray(value);
|
|
114
116
|
}
|
|
@@ -146,6 +148,62 @@ function responseError(status, text) {
|
|
|
146
148
|
`RNX Cloud request failed (${status})${text.trim() ? `: ${text.trim()}` : ""}`
|
|
147
149
|
);
|
|
148
150
|
}
|
|
151
|
+
function readCloudErrorCode(text) {
|
|
152
|
+
let parsed;
|
|
153
|
+
try {
|
|
154
|
+
parsed = JSON.parse(text);
|
|
155
|
+
} catch {
|
|
156
|
+
return null;
|
|
157
|
+
}
|
|
158
|
+
if (!isRecord(parsed)) return null;
|
|
159
|
+
if (typeof parsed.error === "string") return parsed.error;
|
|
160
|
+
if (isRecord(parsed.error) && typeof parsed.error.code === "string") {
|
|
161
|
+
return parsed.error.code;
|
|
162
|
+
}
|
|
163
|
+
return null;
|
|
164
|
+
}
|
|
165
|
+
function readRetryAfterMs(response, text) {
|
|
166
|
+
const header = response.headers.get("retry-after");
|
|
167
|
+
if (header !== null) {
|
|
168
|
+
const seconds = Number(header.trim());
|
|
169
|
+
if (Number.isFinite(seconds) && seconds >= 0) return seconds * 1e3;
|
|
170
|
+
}
|
|
171
|
+
let parsed;
|
|
172
|
+
try {
|
|
173
|
+
parsed = JSON.parse(text);
|
|
174
|
+
} catch {
|
|
175
|
+
return null;
|
|
176
|
+
}
|
|
177
|
+
if (isRecord(parsed) && typeof parsed.retryAfterMs === "number" && Number.isFinite(parsed.retryAfterMs) && parsed.retryAfterMs >= 0) {
|
|
178
|
+
return parsed.retryAfterMs;
|
|
179
|
+
}
|
|
180
|
+
return null;
|
|
181
|
+
}
|
|
182
|
+
function sleep(ms) {
|
|
183
|
+
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
184
|
+
}
|
|
185
|
+
async function fetchWithCloudRetry(url, init, options) {
|
|
186
|
+
let attempt = 0;
|
|
187
|
+
for (; ; ) {
|
|
188
|
+
const response = await fetch(
|
|
189
|
+
url,
|
|
190
|
+
options?.timeoutMs === void 0 ? init : { ...init, signal: AbortSignal.timeout(options.timeoutMs) }
|
|
191
|
+
);
|
|
192
|
+
if (response.ok) return response;
|
|
193
|
+
const retryableStatus = response.status === 429 || response.status >= 500;
|
|
194
|
+
if (!retryableStatus || attempt >= CLOUD_MAX_RETRIES) return response;
|
|
195
|
+
const text = await response.text();
|
|
196
|
+
const code = readCloudErrorCode(text);
|
|
197
|
+
const retryable = response.status >= 500 ? !(code !== null && CLOUD_NEVER_RETRY_CODES.has(code)) : code === "rate_limited";
|
|
198
|
+
if (!retryable) {
|
|
199
|
+
return new Response(text, { status: response.status, headers: response.headers });
|
|
200
|
+
}
|
|
201
|
+
if (response.status === 429) {
|
|
202
|
+
await sleep(readRetryAfterMs(response, text) ?? 1e3);
|
|
203
|
+
}
|
|
204
|
+
attempt += 1;
|
|
205
|
+
}
|
|
206
|
+
}
|
|
149
207
|
function copyArrayBuffer(bytes) {
|
|
150
208
|
const copy = new ArrayBuffer(bytes.byteLength);
|
|
151
209
|
new Uint8Array(copy).set(bytes);
|
|
@@ -294,7 +352,7 @@ var RemoteSimulator = class {
|
|
|
294
352
|
};
|
|
295
353
|
let response;
|
|
296
354
|
try {
|
|
297
|
-
response = await
|
|
355
|
+
response = await fetchWithCloudRetry(
|
|
298
356
|
`${this.session.origin}/v1/sims/${encodeURIComponent(this.session.simId)}/commands`,
|
|
299
357
|
{
|
|
300
358
|
method: "POST",
|
|
@@ -302,9 +360,9 @@ var RemoteSimulator = class {
|
|
|
302
360
|
authorization: `Bearer ${this.session.simulatorToken}`,
|
|
303
361
|
"content-type": "application/json"
|
|
304
362
|
},
|
|
305
|
-
body: JSON.stringify(body)
|
|
306
|
-
|
|
307
|
-
}
|
|
363
|
+
body: JSON.stringify(body)
|
|
364
|
+
},
|
|
365
|
+
options?.timeoutMs === void 0 ? void 0 : { timeoutMs: options.timeoutMs }
|
|
308
366
|
);
|
|
309
367
|
} catch (error) {
|
|
310
368
|
throw new Error(
|
|
@@ -329,7 +387,7 @@ var RemoteSimulator = class {
|
|
|
329
387
|
return parsed.result;
|
|
330
388
|
}
|
|
331
389
|
async confirm() {
|
|
332
|
-
const response = await
|
|
390
|
+
const response = await fetchWithCloudRetry(
|
|
333
391
|
`${this.session.origin}/v1/sims/${encodeURIComponent(this.session.simId)}/claim`,
|
|
334
392
|
{
|
|
335
393
|
method: "POST",
|
|
@@ -356,7 +414,7 @@ var RemoteSimulator = class {
|
|
|
356
414
|
return claim;
|
|
357
415
|
}
|
|
358
416
|
async close() {
|
|
359
|
-
const response = await
|
|
417
|
+
const response = await fetchWithCloudRetry(
|
|
360
418
|
`${this.session.origin}/v1/boxes/${encodeURIComponent(this.session.boxId)}`,
|
|
361
419
|
{
|
|
362
420
|
method: "DELETE",
|
|
@@ -387,7 +445,7 @@ async function createRemoteSimulator(input) {
|
|
|
387
445
|
const device = input.device?.trim() || DEFAULT_DEVICE;
|
|
388
446
|
let response;
|
|
389
447
|
try {
|
|
390
|
-
response = await
|
|
448
|
+
response = await fetchWithCloudRetry(`${origin}/v1/boxes`, {
|
|
391
449
|
method: "POST",
|
|
392
450
|
headers: {
|
|
393
451
|
authorization: input.authorization,
|
package/dist-lib/config.cjs
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
/*! rnx v0.1.
|
|
1
|
+
/*! rnx v0.1.514 | (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.514 | (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.514 | (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.514 | (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.514 | (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.514 | (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.514 | (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.514 | (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.514 | (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.514 | (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/index.cjs
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
/*! rnx v0.1.
|
|
1
|
+
/*! rnx v0.1.514 | (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.514 | (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.514 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
|
|
2
2
|
let __sootsim_import_meta_url = ''; try { __sootsim_import_meta_url = require('url').pathToFileURL(__filename).href; } catch {}
|
|
3
3
|
"use strict";
|
|
4
4
|
var __create = Object.create;
|
package/dist-lib/menu.cjs
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
/*! rnx v0.1.
|
|
1
|
+
/*! rnx v0.1.514 | (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/menu.mjs
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
/*! rnx v0.1.
|
|
1
|
+
/*! rnx v0.1.514 | (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.514 | (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/metro.cjs
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
/*! rnx v0.1.
|
|
1
|
+
/*! rnx v0.1.514 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
|
|
2
2
|
let __sootsim_import_meta_url = ''; try { __sootsim_import_meta_url = require('url').pathToFileURL(__filename).href; } catch {}
|
|
3
3
|
"use strict";
|
|
4
4
|
var __create = Object.create;
|
package/dist-lib/profiles.cjs
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
/*! rnx v0.1.
|
|
1
|
+
/*! rnx v0.1.514 | (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.514 | (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.514 | (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/render-mode.cjs
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
/*! rnx v0.1.
|
|
1
|
+
/*! rnx v0.1.514 | (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.514 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
|
|
2
2
|
let __sootsim_import_meta_url = ''; try { __sootsim_import_meta_url = require('url').pathToFileURL(__filename).href; } catch {}
|
|
3
3
|
"use strict";
|
|
4
4
|
var __create = Object.create;
|
package/dist-lib/sdk.cjs
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
/*! rnx v0.1.
|
|
1
|
+
/*! rnx v0.1.514 | (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/sdk.mjs
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
/*! rnx v0.1.
|
|
1
|
+
/*! rnx v0.1.514 | (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);
|
package/dist-lib/skills.cjs
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
/*! rnx v0.1.
|
|
1
|
+
/*! rnx v0.1.514 | (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;
|
|
@@ -38159,7 +38159,10 @@ var init_bridge_flow_runner = __esm({
|
|
|
38159
38159
|
}
|
|
38160
38160
|
}
|
|
38161
38161
|
try {
|
|
38162
|
-
const hasExplicitWait = !!(step.extendedWaitUntil || step.waitFor || step.scrollUntilVisible || step.launchApp || step.runFlow || //
|
|
38162
|
+
const hasExplicitWait = !!(step.extendedWaitUntil || step.waitFor || step.scrollUntilVisible || step.launchApp || step.runFlow || // retry reruns its body on failure, so its wall time is the body's
|
|
38163
|
+
// times the retry count — the 10s no-progress watchdog is the wrong
|
|
38164
|
+
// budget and would report "bridge probably hung" for a slow retry.
|
|
38165
|
+
step.retry || // runScript http calls are synchronous with a 5-minute upstream
|
|
38163
38166
|
// timeout — the 10s watchdog would kill legitimate setup scripts.
|
|
38164
38167
|
step.runScript || // takeScreenshot self-governs: it retries a bounded visual settle that
|
|
38165
38168
|
// already fails with its own reason. sharing the watchdog's 10s budget
|
|
@@ -38310,6 +38313,27 @@ var init_bridge_flow_runner = __esm({
|
|
|
38310
38313
|
}
|
|
38311
38314
|
} else if (step.stopApp !== void 0) {
|
|
38312
38315
|
await this.stopApp();
|
|
38316
|
+
} else if (step.retry && Array.isArray(step.retry.commands)) {
|
|
38317
|
+
const rawMaxRetries = step.retry.maxRetries;
|
|
38318
|
+
const maxRetries = rawMaxRetries === void 0 || rawMaxRetries === null || rawMaxRetries === "" ? 0 : Number(rawMaxRetries);
|
|
38319
|
+
if (!Number.isInteger(maxRetries) || maxRetries < 0) {
|
|
38320
|
+
throw new Error(
|
|
38321
|
+
`retry.maxRetries is not a non-negative integer: ${rawMaxRetries}`
|
|
38322
|
+
);
|
|
38323
|
+
}
|
|
38324
|
+
for (let attempt = 0; ; attempt++) {
|
|
38325
|
+
try {
|
|
38326
|
+
for (let j = 0; j < step.retry.commands.length; j++) {
|
|
38327
|
+
await this.runStep(step.retry.commands[j], j);
|
|
38328
|
+
}
|
|
38329
|
+
break;
|
|
38330
|
+
} catch (error) {
|
|
38331
|
+
if (attempt >= maxRetries) throw error;
|
|
38332
|
+
console.log(
|
|
38333
|
+
`[flow] retry ${attempt + 1}/${maxRetries} after: ${error.message.slice(0, 120)}`
|
|
38334
|
+
);
|
|
38335
|
+
}
|
|
38336
|
+
}
|
|
38313
38337
|
} else if (step.clearState !== void 0) {
|
|
38314
38338
|
await this.clearState();
|
|
38315
38339
|
} else if (step.clearKeychain !== void 0) {
|
package/dist-lib/swift.cjs
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
/*! rnx v0.1.
|
|
1
|
+
/*! rnx v0.1.514 | (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/vite.cjs
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
/*! rnx v0.1.
|
|
1
|
+
/*! rnx v0.1.514 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
|
|
2
2
|
let __sootsim_import_meta_url = ''; try { __sootsim_import_meta_url = require('url').pathToFileURL(__filename).href; } catch {}
|
|
3
3
|
"use strict";
|
|
4
4
|
var __create = Object.create;
|
package/package.json
CHANGED
package/src/cloud-contract.ts
CHANGED
|
@@ -58,3 +58,123 @@ export interface RnxCloudBoxCreateReceipt {
|
|
|
58
58
|
}
|
|
59
59
|
simulator: RnxCloudCreateReceipt
|
|
60
60
|
}
|
|
61
|
+
|
|
62
|
+
// what a cloud simulator reports. the stored lifecycle values are
|
|
63
|
+
// `creating`/`open`/`hibernated`/`deleting`; `deleted` is only ever a response,
|
|
64
|
+
// answered by a delete, because a deleted simulator has no row left to read.
|
|
65
|
+
export type RnxCloudSimStatus =
|
|
66
|
+
| 'creating'
|
|
67
|
+
| 'open'
|
|
68
|
+
| 'hibernated'
|
|
69
|
+
| 'deleting'
|
|
70
|
+
| 'deleted'
|
|
71
|
+
|
|
72
|
+
// one simulator as the instance list reports it: the lifecycle view plus the
|
|
73
|
+
// labels it was created with.
|
|
74
|
+
export interface RnxCloudSimView {
|
|
75
|
+
simId: string
|
|
76
|
+
status: RnxCloudSimStatus
|
|
77
|
+
labels: Record<string, string>
|
|
78
|
+
artifact: { sha256: string; bytes: number }
|
|
79
|
+
claim: RnxCloudClaim | null
|
|
80
|
+
createdAt: number
|
|
81
|
+
lastActiveAt: number
|
|
82
|
+
lastHibernatedAt?: number
|
|
83
|
+
storageFrom?: string
|
|
84
|
+
/** the idle window the creator set, or null for the service default. */
|
|
85
|
+
inactivityTimeoutMs: number | null
|
|
86
|
+
/** the instant the creator's hard timeout stops this simulator, or null. */
|
|
87
|
+
hardTimeoutAt: number | null
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
// one simulator as create and get report it, with the watch URL a browser
|
|
91
|
+
// opens to see it.
|
|
92
|
+
export interface RnxCloudSimInstance extends RnxCloudSimView {
|
|
93
|
+
/** a watch URL with its grant in the fragment, or null when none can be
|
|
94
|
+
* minted yet: an unconfirmed simulator is not watchable. */
|
|
95
|
+
streamUrl: string | null
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
// the create/reuse answer: the receipt the box path also returns, plus what
|
|
99
|
+
// only the instance API knows.
|
|
100
|
+
export interface RnxCloudSimCreateResponse extends RnxCloudCreateReceipt {
|
|
101
|
+
token: string
|
|
102
|
+
status: RnxCloudSimStatus
|
|
103
|
+
labels: Record<string, string>
|
|
104
|
+
streamUrl: string | null
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
// one grammar for the create map and the list selector: `key=value,key2=value2`.
|
|
108
|
+
// a value may be empty; a key may not; a repeated key is the caller's mistake
|
|
109
|
+
// rather than a silent last-one-wins. commas and control characters never
|
|
110
|
+
// belong in a key or value, and 63 characters is the ceiling for either.
|
|
111
|
+
export const RNX_CLOUD_LABELS_MAX_COUNT = 16
|
|
112
|
+
export const RNX_CLOUD_LABEL_MAX_LENGTH = 63
|
|
113
|
+
|
|
114
|
+
const RNX_CLOUD_LABEL_CONTROL = /[\u0000-\u001f\u007f]/
|
|
115
|
+
|
|
116
|
+
export function isValidRnxCloudLabel(key: string, value: string): boolean {
|
|
117
|
+
return (
|
|
118
|
+
key.length > 0 &&
|
|
119
|
+
key.length <= RNX_CLOUD_LABEL_MAX_LENGTH &&
|
|
120
|
+
value.length <= RNX_CLOUD_LABEL_MAX_LENGTH &&
|
|
121
|
+
!key.includes(',') &&
|
|
122
|
+
!key.includes('=') &&
|
|
123
|
+
!value.includes(',') &&
|
|
124
|
+
!RNX_CLOUD_LABEL_CONTROL.test(key) &&
|
|
125
|
+
!RNX_CLOUD_LABEL_CONTROL.test(value)
|
|
126
|
+
)
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
/** the wire form, or null when it is not one. `''` is the empty map. */
|
|
130
|
+
export function parseRnxCloudLabels(value: string): Record<string, string> | null {
|
|
131
|
+
if (value === '') return {}
|
|
132
|
+
const entries = value.split(',')
|
|
133
|
+
if (entries.length > RNX_CLOUD_LABELS_MAX_COUNT) return null
|
|
134
|
+
const labels: Record<string, string> = {}
|
|
135
|
+
for (const entry of entries) {
|
|
136
|
+
const separator = entry.indexOf('=')
|
|
137
|
+
if (separator < 1) return null
|
|
138
|
+
const key = entry.slice(0, separator).trim()
|
|
139
|
+
const label = entry.slice(separator + 1).trim()
|
|
140
|
+
if (!isValidRnxCloudLabel(key, label)) return null
|
|
141
|
+
if (Object.hasOwn(labels, key)) return null
|
|
142
|
+
labels[key] = label
|
|
143
|
+
}
|
|
144
|
+
return labels
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
/** the same grammar with the map already split apart, as a json body carries
|
|
148
|
+
* it. anything the wire form would refuse is refused here too. */
|
|
149
|
+
export function readRnxCloudLabels(value: unknown): Record<string, string> | null {
|
|
150
|
+
if (typeof value !== 'object' || value === null || Array.isArray(value)) return null
|
|
151
|
+
const entries = Object.entries(value)
|
|
152
|
+
if (entries.length > RNX_CLOUD_LABELS_MAX_COUNT) return null
|
|
153
|
+
const labels: Record<string, string> = {}
|
|
154
|
+
for (const [key, label] of entries) {
|
|
155
|
+
if (typeof label !== 'string') return null
|
|
156
|
+
if (!isValidRnxCloudLabel(key, label)) return null
|
|
157
|
+
labels[key] = label
|
|
158
|
+
}
|
|
159
|
+
return labels
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
/** every selector entry must be present with the same value. an empty
|
|
163
|
+
* selector selects everything. */
|
|
164
|
+
export function matchesRnxCloudLabels(
|
|
165
|
+
labels: Record<string, string>,
|
|
166
|
+
selector: Record<string, string>,
|
|
167
|
+
): boolean {
|
|
168
|
+
return Object.entries(selector).every(([key, value]) => labels[key] === value)
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
/** the selector an instance list filters by, given the statuses it accepts. */
|
|
172
|
+
export function isRnxCloudSimStatus(value: string): value is RnxCloudSimStatus {
|
|
173
|
+
return (
|
|
174
|
+
value === 'creating' ||
|
|
175
|
+
value === 'open' ||
|
|
176
|
+
value === 'hibernated' ||
|
|
177
|
+
value === 'deleting' ||
|
|
178
|
+
value === 'deleted'
|
|
179
|
+
)
|
|
180
|
+
}
|
package/src/cloud.ts
CHANGED
|
@@ -26,6 +26,15 @@ export type { RnxCloudClaim, RnxCloudCreateReceipt, RnxScreenCapture }
|
|
|
26
26
|
const DEFAULT_DEVICE = 'iphone-16'
|
|
27
27
|
const DEFAULT_WAIT_READY_MS = 20_000
|
|
28
28
|
|
|
29
|
+
// how many times a request goes back after a retryable refusal or a server
|
|
30
|
+
// error. the sim service passes the account's own 429 bodies through, so the
|
|
31
|
+
// code on the body is what decides: `rate_limited` carries a `retry-after`
|
|
32
|
+
// and is worth waiting for, while `concurrency_limit` refuses until the
|
|
33
|
+
// customer stops something and retrying only hammers a closed door.
|
|
34
|
+
// `early_access` and 402 never change on retry either.
|
|
35
|
+
const CLOUD_MAX_RETRIES = 2
|
|
36
|
+
const CLOUD_NEVER_RETRY_CODES = new Set(['concurrency_limit', 'early_access'])
|
|
37
|
+
|
|
29
38
|
export type RemoteCommand = {
|
|
30
39
|
type: (typeof RNX_CLOUD_COMMAND_TYPES)[number]
|
|
31
40
|
[key: string]: unknown
|
|
@@ -117,6 +126,86 @@ function responseError(status: number, text: string): Error {
|
|
|
117
126
|
)
|
|
118
127
|
}
|
|
119
128
|
|
|
129
|
+
function readCloudErrorCode(text: string): string | null {
|
|
130
|
+
// the account api answers `{ error: 'code', message }` and the sim service
|
|
131
|
+
// `{ error: { code, message } }`; both reach this client, so both read.
|
|
132
|
+
let parsed: unknown
|
|
133
|
+
try {
|
|
134
|
+
parsed = JSON.parse(text)
|
|
135
|
+
} catch {
|
|
136
|
+
return null
|
|
137
|
+
}
|
|
138
|
+
if (!isRecord(parsed)) return null
|
|
139
|
+
if (typeof parsed.error === 'string') return parsed.error
|
|
140
|
+
if (isRecord(parsed.error) && typeof parsed.error.code === 'string') {
|
|
141
|
+
return parsed.error.code
|
|
142
|
+
}
|
|
143
|
+
return null
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
function readRetryAfterMs(response: Response, text: string): number | null {
|
|
147
|
+
const header = response.headers.get('retry-after')
|
|
148
|
+
if (header !== null) {
|
|
149
|
+
const seconds = Number(header.trim())
|
|
150
|
+
if (Number.isFinite(seconds) && seconds >= 0) return seconds * 1000
|
|
151
|
+
}
|
|
152
|
+
let parsed: unknown
|
|
153
|
+
try {
|
|
154
|
+
parsed = JSON.parse(text)
|
|
155
|
+
} catch {
|
|
156
|
+
return null
|
|
157
|
+
}
|
|
158
|
+
if (
|
|
159
|
+
isRecord(parsed) &&
|
|
160
|
+
typeof parsed.retryAfterMs === 'number' &&
|
|
161
|
+
Number.isFinite(parsed.retryAfterMs) &&
|
|
162
|
+
parsed.retryAfterMs >= 0
|
|
163
|
+
) {
|
|
164
|
+
return parsed.retryAfterMs
|
|
165
|
+
}
|
|
166
|
+
return null
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
function sleep(ms: number): Promise<void> {
|
|
170
|
+
return new Promise((resolve) => setTimeout(resolve, ms))
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
// one fetch with the cloud retry policy: `rate_limited` waits out its
|
|
174
|
+
// `retry-after` and 5xx goes again at once, each at most twice, and nothing
|
|
175
|
+
// else is retried. the body is buffered only on a retryable status, so every
|
|
176
|
+
// other refusal reaches the caller on its original response.
|
|
177
|
+
async function fetchWithCloudRetry(
|
|
178
|
+
url: string,
|
|
179
|
+
init: RequestInit,
|
|
180
|
+
options?: { timeoutMs?: number },
|
|
181
|
+
): Promise<Response> {
|
|
182
|
+
let attempt = 0
|
|
183
|
+
for (;;) {
|
|
184
|
+
const response = await fetch(
|
|
185
|
+
url,
|
|
186
|
+
options?.timeoutMs === undefined
|
|
187
|
+
? init
|
|
188
|
+
: { ...init, signal: AbortSignal.timeout(options.timeoutMs) },
|
|
189
|
+
)
|
|
190
|
+
if (response.ok) return response
|
|
191
|
+
const retryableStatus = response.status === 429 || response.status >= 500
|
|
192
|
+
if (!retryableStatus || attempt >= CLOUD_MAX_RETRIES) return response
|
|
193
|
+
const text = await response.text()
|
|
194
|
+
const code = readCloudErrorCode(text)
|
|
195
|
+
const retryable =
|
|
196
|
+
response.status >= 500
|
|
197
|
+
? !(code !== null && CLOUD_NEVER_RETRY_CODES.has(code))
|
|
198
|
+
: code === 'rate_limited'
|
|
199
|
+
if (!retryable) {
|
|
200
|
+
return new Response(text, { status: response.status, headers: response.headers })
|
|
201
|
+
}
|
|
202
|
+
if (response.status === 429) {
|
|
203
|
+
await sleep(readRetryAfterMs(response, text) ?? 1000)
|
|
204
|
+
}
|
|
205
|
+
attempt += 1
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
|
|
120
209
|
function copyArrayBuffer(bytes: Uint8Array): ArrayBuffer {
|
|
121
210
|
const copy = new ArrayBuffer(bytes.byteLength)
|
|
122
211
|
new Uint8Array(copy).set(bytes)
|
|
@@ -325,7 +414,7 @@ export class RemoteSimulator {
|
|
|
325
414
|
}
|
|
326
415
|
let response: Response
|
|
327
416
|
try {
|
|
328
|
-
response = await
|
|
417
|
+
response = await fetchWithCloudRetry(
|
|
329
418
|
`${this.session.origin}/v1/sims/${encodeURIComponent(this.session.simId)}/commands`,
|
|
330
419
|
{
|
|
331
420
|
method: 'POST',
|
|
@@ -334,10 +423,8 @@ export class RemoteSimulator {
|
|
|
334
423
|
'content-type': 'application/json',
|
|
335
424
|
},
|
|
336
425
|
body: JSON.stringify(body),
|
|
337
|
-
...(options?.timeoutMs
|
|
338
|
-
? { signal: AbortSignal.timeout(options.timeoutMs) }
|
|
339
|
-
: {}),
|
|
340
426
|
},
|
|
427
|
+
options?.timeoutMs === undefined ? undefined : { timeoutMs: options.timeoutMs },
|
|
341
428
|
)
|
|
342
429
|
} catch (error) {
|
|
343
430
|
throw new Error(
|
|
@@ -365,7 +452,7 @@ export class RemoteSimulator {
|
|
|
365
452
|
}
|
|
366
453
|
|
|
367
454
|
async confirm(): Promise<RnxCloudClaim> {
|
|
368
|
-
const response = await
|
|
455
|
+
const response = await fetchWithCloudRetry(
|
|
369
456
|
`${this.session.origin}/v1/sims/${encodeURIComponent(this.session.simId)}/claim`,
|
|
370
457
|
{
|
|
371
458
|
method: 'POST',
|
|
@@ -393,7 +480,7 @@ export class RemoteSimulator {
|
|
|
393
480
|
}
|
|
394
481
|
|
|
395
482
|
async close(): Promise<void> {
|
|
396
|
-
const response = await
|
|
483
|
+
const response = await fetchWithCloudRetry(
|
|
397
484
|
`${this.session.origin}/v1/boxes/${encodeURIComponent(this.session.boxId)}`,
|
|
398
485
|
{
|
|
399
486
|
method: 'DELETE',
|
|
@@ -427,7 +514,7 @@ export async function createRemoteSimulator(
|
|
|
427
514
|
const device = input.device?.trim() || DEFAULT_DEVICE
|
|
428
515
|
let response: Response
|
|
429
516
|
try {
|
|
430
|
-
response = await
|
|
517
|
+
response = await fetchWithCloudRetry(`${origin}/v1/boxes`, {
|
|
431
518
|
method: 'POST',
|
|
432
519
|
headers: {
|
|
433
520
|
authorization: input.authorization,
|