rnxsim 0.1.513 → 0.1.515
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/cloud-client.ts +18 -8
- package/cli/commands/inspect/get-layout.ts +2 -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 +64 -1
- package/dist-lib/bridge-contract-input.mjs +63 -1
- package/dist-lib/bridge-contract.cjs +73 -3
- package/dist-lib/bridge-contract.mjs +69 -2
- 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 +117 -22
- package/dist-lib/cloud-contract.mjs +104 -21
- package/dist-lib/cloud.cjs +121 -27
- package/dist-lib/cloud.mjs +121 -27
- 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 +45 -20
- 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 +62 -24
- 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 +62 -24
- package/dist-lib/swift.cjs +1 -1
- package/dist-lib/vite.cjs +1 -1
- package/package.json +2 -1
- package/src/bridge-contract-input.ts +74 -0
- package/src/bridge-contract.ts +103 -0
- package/src/cloud-contract.ts +191 -19
- package/src/cloud.ts +104 -7
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
/*! rnx v0.1.
|
|
1
|
+
/*! rnx v0.1.515 | (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,13 +22,25 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
|
|
|
22
22
|
// src/cloud-contract.ts
|
|
23
23
|
var cloud_contract_exports = {};
|
|
24
24
|
__export(cloud_contract_exports, {
|
|
25
|
+
RNX_CLOUD_ALL_COMMAND_SCOPES: () => RNX_CLOUD_ALL_COMMAND_SCOPES,
|
|
26
|
+
RNX_CLOUD_COMMAND_SCOPES: () => RNX_CLOUD_COMMAND_SCOPES,
|
|
25
27
|
RNX_CLOUD_COMMAND_TYPES: () => RNX_CLOUD_COMMAND_TYPES,
|
|
26
28
|
RNX_CLOUD_DESIGN_MAX_STORAGE_BYTES: () => RNX_CLOUD_DESIGN_MAX_STORAGE_BYTES,
|
|
27
29
|
RNX_CLOUD_DESIGN_MAX_STORAGE_ENTRIES: () => RNX_CLOUD_DESIGN_MAX_STORAGE_ENTRIES,
|
|
30
|
+
RNX_CLOUD_LABELS_MAX_COUNT: () => RNX_CLOUD_LABELS_MAX_COUNT,
|
|
31
|
+
RNX_CLOUD_LABEL_MAX_LENGTH: () => RNX_CLOUD_LABEL_MAX_LENGTH,
|
|
28
32
|
RNX_CLOUD_MAX_ARTIFACT_BYTES: () => RNX_CLOUD_MAX_ARTIFACT_BYTES,
|
|
29
33
|
RNX_CLOUD_TEST_FILES_MAX_BYTES: () => RNX_CLOUD_TEST_FILES_MAX_BYTES,
|
|
30
34
|
RNX_CLOUD_TEST_FILES_MAX_COUNT: () => RNX_CLOUD_TEST_FILES_MAX_COUNT,
|
|
31
|
-
|
|
35
|
+
RNX_CLOUD_TOKEN_SCOPES: () => RNX_CLOUD_TOKEN_SCOPES,
|
|
36
|
+
isRnxCloudCommandType: () => isRnxCloudCommandType,
|
|
37
|
+
isRnxCloudSimStatus: () => isRnxCloudSimStatus,
|
|
38
|
+
isValidRnxCloudLabel: () => isValidRnxCloudLabel,
|
|
39
|
+
matchesRnxCloudLabels: () => matchesRnxCloudLabels,
|
|
40
|
+
parseRnxCloudLabels: () => parseRnxCloudLabels,
|
|
41
|
+
readRnxCloudLabels: () => readRnxCloudLabels,
|
|
42
|
+
rnxCloudCommandScope: () => rnxCloudCommandScope,
|
|
43
|
+
rnxCloudScopesAllowCommand: () => rnxCloudScopesAllowCommand
|
|
32
44
|
});
|
|
33
45
|
module.exports = __toCommonJS(cloud_contract_exports);
|
|
34
46
|
var RNX_CLOUD_MAX_ARTIFACT_BYTES = 20 * 1024 * 1024;
|
|
@@ -36,36 +48,119 @@ var RNX_CLOUD_DESIGN_MAX_STORAGE_ENTRIES = 256;
|
|
|
36
48
|
var RNX_CLOUD_DESIGN_MAX_STORAGE_BYTES = 1024 * 1024;
|
|
37
49
|
var RNX_CLOUD_TEST_FILES_MAX_COUNT = 256;
|
|
38
50
|
var RNX_CLOUD_TEST_FILES_MAX_BYTES = 5e5;
|
|
39
|
-
var
|
|
40
|
-
|
|
41
|
-
"
|
|
42
|
-
"
|
|
43
|
-
"
|
|
44
|
-
"
|
|
45
|
-
"
|
|
46
|
-
"
|
|
47
|
-
"
|
|
48
|
-
"
|
|
49
|
-
"
|
|
50
|
-
"
|
|
51
|
-
"
|
|
52
|
-
"
|
|
53
|
-
"
|
|
54
|
-
"
|
|
55
|
-
"
|
|
56
|
-
"
|
|
57
|
-
|
|
51
|
+
var RNX_CLOUD_COMMAND_SCOPES = {
|
|
52
|
+
state: "read",
|
|
53
|
+
tree: "read",
|
|
54
|
+
query: "read",
|
|
55
|
+
resolve: "read",
|
|
56
|
+
screenshot: "read",
|
|
57
|
+
capture: "read",
|
|
58
|
+
captureRegions: "read",
|
|
59
|
+
memory: "read",
|
|
60
|
+
diagnostics: "read",
|
|
61
|
+
storageSnapshot: "read",
|
|
62
|
+
perform: "drive",
|
|
63
|
+
waitFor: "drive",
|
|
64
|
+
tap: "drive",
|
|
65
|
+
longPress: "drive",
|
|
66
|
+
settle: "drive",
|
|
67
|
+
openUrl: "drive",
|
|
68
|
+
setAppearance: "drive",
|
|
69
|
+
keyboard: "drive",
|
|
70
|
+
focus: "drive",
|
|
71
|
+
flowStatus: "drive",
|
|
72
|
+
reset: "reset",
|
|
73
|
+
camera: "media",
|
|
74
|
+
// string evaluation and arbitrary bridge calls are maestro's boundary: the
|
|
75
|
+
// customer sdk never carries this scope, and the service grants it only to
|
|
76
|
+
// the account api key caller. close rides along, since ending the page ends
|
|
77
|
+
// the sim and belongs to the sim's owner rather than any driver.
|
|
78
|
+
evaluate: "debug",
|
|
79
|
+
call: "debug",
|
|
80
|
+
close: "debug"
|
|
81
|
+
};
|
|
82
|
+
function scopeTableKeys() {
|
|
83
|
+
return Object.keys(RNX_CLOUD_COMMAND_SCOPES).filter(
|
|
84
|
+
(key) => Object.prototype.hasOwnProperty.call(RNX_CLOUD_COMMAND_SCOPES, key)
|
|
85
|
+
);
|
|
86
|
+
}
|
|
87
|
+
var RNX_CLOUD_COMMAND_TYPES = Object.freeze(scopeTableKeys());
|
|
58
88
|
var RNX_CLOUD_COMMAND_TYPE_SET = new Set(RNX_CLOUD_COMMAND_TYPES);
|
|
59
89
|
function isRnxCloudCommandType(value) {
|
|
60
90
|
return RNX_CLOUD_COMMAND_TYPE_SET.has(value);
|
|
61
91
|
}
|
|
92
|
+
function rnxCloudCommandScope(type) {
|
|
93
|
+
return RNX_CLOUD_COMMAND_SCOPES[type];
|
|
94
|
+
}
|
|
95
|
+
var RNX_CLOUD_TOKEN_SCOPES = Object.freeze([
|
|
96
|
+
"read",
|
|
97
|
+
"drive",
|
|
98
|
+
"reset",
|
|
99
|
+
"media"
|
|
100
|
+
]);
|
|
101
|
+
var RNX_CLOUD_ALL_COMMAND_SCOPES = Object.freeze(["read", "drive", "reset", "media", "debug"]);
|
|
102
|
+
function rnxCloudScopesAllowCommand(scopes, type) {
|
|
103
|
+
return scopes.includes(RNX_CLOUD_COMMAND_SCOPES[type]);
|
|
104
|
+
}
|
|
105
|
+
var RNX_CLOUD_LABELS_MAX_COUNT = 16;
|
|
106
|
+
var RNX_CLOUD_LABEL_MAX_LENGTH = 63;
|
|
107
|
+
var RNX_CLOUD_LABEL_CONTROL = /[\u0000-\u001f\u007f]/;
|
|
108
|
+
function isValidRnxCloudLabel(key, value) {
|
|
109
|
+
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);
|
|
110
|
+
}
|
|
111
|
+
function parseRnxCloudLabels(value) {
|
|
112
|
+
if (value === "") return {};
|
|
113
|
+
const entries = value.split(",");
|
|
114
|
+
if (entries.length > RNX_CLOUD_LABELS_MAX_COUNT) return null;
|
|
115
|
+
const labels = {};
|
|
116
|
+
for (const entry of entries) {
|
|
117
|
+
const separator = entry.indexOf("=");
|
|
118
|
+
if (separator < 1) return null;
|
|
119
|
+
const key = entry.slice(0, separator).trim();
|
|
120
|
+
const label = entry.slice(separator + 1).trim();
|
|
121
|
+
if (!isValidRnxCloudLabel(key, label)) return null;
|
|
122
|
+
if (Object.hasOwn(labels, key)) return null;
|
|
123
|
+
labels[key] = label;
|
|
124
|
+
}
|
|
125
|
+
return labels;
|
|
126
|
+
}
|
|
127
|
+
function readRnxCloudLabels(value) {
|
|
128
|
+
if (typeof value !== "object" || value === null || Array.isArray(value)) return null;
|
|
129
|
+
const entries = Object.entries(value);
|
|
130
|
+
if (entries.length > RNX_CLOUD_LABELS_MAX_COUNT) return null;
|
|
131
|
+
const labels = {};
|
|
132
|
+
for (const [key, label] of entries) {
|
|
133
|
+
if (typeof label !== "string") return null;
|
|
134
|
+
if (!isValidRnxCloudLabel(key, label)) return null;
|
|
135
|
+
labels[key] = label;
|
|
136
|
+
}
|
|
137
|
+
return labels;
|
|
138
|
+
}
|
|
139
|
+
function matchesRnxCloudLabels(labels, selector) {
|
|
140
|
+
return Object.entries(selector).every(([key, value]) => labels[key] === value);
|
|
141
|
+
}
|
|
142
|
+
function isRnxCloudSimStatus(value) {
|
|
143
|
+
return value === "creating" || value === "open" || value === "hibernated" || value === "deleting" || value === "deleted";
|
|
144
|
+
}
|
|
62
145
|
// Annotate the CommonJS export names for ESM import in node:
|
|
63
146
|
0 && (module.exports = {
|
|
147
|
+
RNX_CLOUD_ALL_COMMAND_SCOPES,
|
|
148
|
+
RNX_CLOUD_COMMAND_SCOPES,
|
|
64
149
|
RNX_CLOUD_COMMAND_TYPES,
|
|
65
150
|
RNX_CLOUD_DESIGN_MAX_STORAGE_BYTES,
|
|
66
151
|
RNX_CLOUD_DESIGN_MAX_STORAGE_ENTRIES,
|
|
152
|
+
RNX_CLOUD_LABELS_MAX_COUNT,
|
|
153
|
+
RNX_CLOUD_LABEL_MAX_LENGTH,
|
|
67
154
|
RNX_CLOUD_MAX_ARTIFACT_BYTES,
|
|
68
155
|
RNX_CLOUD_TEST_FILES_MAX_BYTES,
|
|
69
156
|
RNX_CLOUD_TEST_FILES_MAX_COUNT,
|
|
70
|
-
|
|
157
|
+
RNX_CLOUD_TOKEN_SCOPES,
|
|
158
|
+
isRnxCloudCommandType,
|
|
159
|
+
isRnxCloudSimStatus,
|
|
160
|
+
isValidRnxCloudLabel,
|
|
161
|
+
matchesRnxCloudLabels,
|
|
162
|
+
parseRnxCloudLabels,
|
|
163
|
+
readRnxCloudLabels,
|
|
164
|
+
rnxCloudCommandScope,
|
|
165
|
+
rnxCloudScopesAllowCommand
|
|
71
166
|
});
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
/*! rnx v0.1.
|
|
1
|
+
/*! rnx v0.1.515 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
|
|
2
2
|
|
|
3
3
|
// src/cloud-contract.ts
|
|
4
4
|
var RNX_CLOUD_MAX_ARTIFACT_BYTES = 20 * 1024 * 1024;
|
|
@@ -6,35 +6,118 @@ var RNX_CLOUD_DESIGN_MAX_STORAGE_ENTRIES = 256;
|
|
|
6
6
|
var RNX_CLOUD_DESIGN_MAX_STORAGE_BYTES = 1024 * 1024;
|
|
7
7
|
var RNX_CLOUD_TEST_FILES_MAX_COUNT = 256;
|
|
8
8
|
var RNX_CLOUD_TEST_FILES_MAX_BYTES = 5e5;
|
|
9
|
-
var
|
|
10
|
-
|
|
11
|
-
"
|
|
12
|
-
"
|
|
13
|
-
"
|
|
14
|
-
"
|
|
15
|
-
"
|
|
16
|
-
"
|
|
17
|
-
"
|
|
18
|
-
"
|
|
19
|
-
"
|
|
20
|
-
"
|
|
21
|
-
"
|
|
22
|
-
"
|
|
23
|
-
"
|
|
24
|
-
"
|
|
25
|
-
"
|
|
26
|
-
"
|
|
27
|
-
|
|
9
|
+
var RNX_CLOUD_COMMAND_SCOPES = {
|
|
10
|
+
state: "read",
|
|
11
|
+
tree: "read",
|
|
12
|
+
query: "read",
|
|
13
|
+
resolve: "read",
|
|
14
|
+
screenshot: "read",
|
|
15
|
+
capture: "read",
|
|
16
|
+
captureRegions: "read",
|
|
17
|
+
memory: "read",
|
|
18
|
+
diagnostics: "read",
|
|
19
|
+
storageSnapshot: "read",
|
|
20
|
+
perform: "drive",
|
|
21
|
+
waitFor: "drive",
|
|
22
|
+
tap: "drive",
|
|
23
|
+
longPress: "drive",
|
|
24
|
+
settle: "drive",
|
|
25
|
+
openUrl: "drive",
|
|
26
|
+
setAppearance: "drive",
|
|
27
|
+
keyboard: "drive",
|
|
28
|
+
focus: "drive",
|
|
29
|
+
flowStatus: "drive",
|
|
30
|
+
reset: "reset",
|
|
31
|
+
camera: "media",
|
|
32
|
+
// string evaluation and arbitrary bridge calls are maestro's boundary: the
|
|
33
|
+
// customer sdk never carries this scope, and the service grants it only to
|
|
34
|
+
// the account api key caller. close rides along, since ending the page ends
|
|
35
|
+
// the sim and belongs to the sim's owner rather than any driver.
|
|
36
|
+
evaluate: "debug",
|
|
37
|
+
call: "debug",
|
|
38
|
+
close: "debug"
|
|
39
|
+
};
|
|
40
|
+
function scopeTableKeys() {
|
|
41
|
+
return Object.keys(RNX_CLOUD_COMMAND_SCOPES).filter(
|
|
42
|
+
(key) => Object.prototype.hasOwnProperty.call(RNX_CLOUD_COMMAND_SCOPES, key)
|
|
43
|
+
);
|
|
44
|
+
}
|
|
45
|
+
var RNX_CLOUD_COMMAND_TYPES = Object.freeze(scopeTableKeys());
|
|
28
46
|
var RNX_CLOUD_COMMAND_TYPE_SET = new Set(RNX_CLOUD_COMMAND_TYPES);
|
|
29
47
|
function isRnxCloudCommandType(value) {
|
|
30
48
|
return RNX_CLOUD_COMMAND_TYPE_SET.has(value);
|
|
31
49
|
}
|
|
50
|
+
function rnxCloudCommandScope(type) {
|
|
51
|
+
return RNX_CLOUD_COMMAND_SCOPES[type];
|
|
52
|
+
}
|
|
53
|
+
var RNX_CLOUD_TOKEN_SCOPES = Object.freeze([
|
|
54
|
+
"read",
|
|
55
|
+
"drive",
|
|
56
|
+
"reset",
|
|
57
|
+
"media"
|
|
58
|
+
]);
|
|
59
|
+
var RNX_CLOUD_ALL_COMMAND_SCOPES = Object.freeze(["read", "drive", "reset", "media", "debug"]);
|
|
60
|
+
function rnxCloudScopesAllowCommand(scopes, type) {
|
|
61
|
+
return scopes.includes(RNX_CLOUD_COMMAND_SCOPES[type]);
|
|
62
|
+
}
|
|
63
|
+
var RNX_CLOUD_LABELS_MAX_COUNT = 16;
|
|
64
|
+
var RNX_CLOUD_LABEL_MAX_LENGTH = 63;
|
|
65
|
+
var RNX_CLOUD_LABEL_CONTROL = /[\u0000-\u001f\u007f]/;
|
|
66
|
+
function isValidRnxCloudLabel(key, value) {
|
|
67
|
+
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);
|
|
68
|
+
}
|
|
69
|
+
function parseRnxCloudLabels(value) {
|
|
70
|
+
if (value === "") return {};
|
|
71
|
+
const entries = value.split(",");
|
|
72
|
+
if (entries.length > RNX_CLOUD_LABELS_MAX_COUNT) return null;
|
|
73
|
+
const labels = {};
|
|
74
|
+
for (const entry of entries) {
|
|
75
|
+
const separator = entry.indexOf("=");
|
|
76
|
+
if (separator < 1) return null;
|
|
77
|
+
const key = entry.slice(0, separator).trim();
|
|
78
|
+
const label = entry.slice(separator + 1).trim();
|
|
79
|
+
if (!isValidRnxCloudLabel(key, label)) return null;
|
|
80
|
+
if (Object.hasOwn(labels, key)) return null;
|
|
81
|
+
labels[key] = label;
|
|
82
|
+
}
|
|
83
|
+
return labels;
|
|
84
|
+
}
|
|
85
|
+
function readRnxCloudLabels(value) {
|
|
86
|
+
if (typeof value !== "object" || value === null || Array.isArray(value)) return null;
|
|
87
|
+
const entries = Object.entries(value);
|
|
88
|
+
if (entries.length > RNX_CLOUD_LABELS_MAX_COUNT) return null;
|
|
89
|
+
const labels = {};
|
|
90
|
+
for (const [key, label] of entries) {
|
|
91
|
+
if (typeof label !== "string") return null;
|
|
92
|
+
if (!isValidRnxCloudLabel(key, label)) return null;
|
|
93
|
+
labels[key] = label;
|
|
94
|
+
}
|
|
95
|
+
return labels;
|
|
96
|
+
}
|
|
97
|
+
function matchesRnxCloudLabels(labels, selector) {
|
|
98
|
+
return Object.entries(selector).every(([key, value]) => labels[key] === value);
|
|
99
|
+
}
|
|
100
|
+
function isRnxCloudSimStatus(value) {
|
|
101
|
+
return value === "creating" || value === "open" || value === "hibernated" || value === "deleting" || value === "deleted";
|
|
102
|
+
}
|
|
32
103
|
export {
|
|
104
|
+
RNX_CLOUD_ALL_COMMAND_SCOPES,
|
|
105
|
+
RNX_CLOUD_COMMAND_SCOPES,
|
|
33
106
|
RNX_CLOUD_COMMAND_TYPES,
|
|
34
107
|
RNX_CLOUD_DESIGN_MAX_STORAGE_BYTES,
|
|
35
108
|
RNX_CLOUD_DESIGN_MAX_STORAGE_ENTRIES,
|
|
109
|
+
RNX_CLOUD_LABELS_MAX_COUNT,
|
|
110
|
+
RNX_CLOUD_LABEL_MAX_LENGTH,
|
|
36
111
|
RNX_CLOUD_MAX_ARTIFACT_BYTES,
|
|
37
112
|
RNX_CLOUD_TEST_FILES_MAX_BYTES,
|
|
38
113
|
RNX_CLOUD_TEST_FILES_MAX_COUNT,
|
|
39
|
-
|
|
114
|
+
RNX_CLOUD_TOKEN_SCOPES,
|
|
115
|
+
isRnxCloudCommandType,
|
|
116
|
+
isRnxCloudSimStatus,
|
|
117
|
+
isValidRnxCloudLabel,
|
|
118
|
+
matchesRnxCloudLabels,
|
|
119
|
+
parseRnxCloudLabels,
|
|
120
|
+
readRnxCloudLabels,
|
|
121
|
+
rnxCloudCommandScope,
|
|
122
|
+
rnxCloudScopesAllowCommand
|
|
40
123
|
};
|
package/dist-lib/cloud.cjs
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
/*! rnx v0.1.
|
|
1
|
+
/*! rnx v0.1.515 | (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;
|
|
@@ -99,29 +99,60 @@ function isRnxScreenCapture(value) {
|
|
|
99
99
|
// src/cloud-contract.ts
|
|
100
100
|
var RNX_CLOUD_MAX_ARTIFACT_BYTES = 20 * 1024 * 1024;
|
|
101
101
|
var RNX_CLOUD_DESIGN_MAX_STORAGE_BYTES = 1024 * 1024;
|
|
102
|
-
var
|
|
103
|
-
|
|
104
|
-
"
|
|
105
|
-
"
|
|
106
|
-
"
|
|
107
|
-
"
|
|
108
|
-
"
|
|
109
|
-
"
|
|
110
|
-
"
|
|
111
|
-
"
|
|
112
|
-
"
|
|
113
|
-
"
|
|
114
|
-
"
|
|
115
|
-
"
|
|
116
|
-
"
|
|
117
|
-
"
|
|
118
|
-
"
|
|
119
|
-
"
|
|
120
|
-
|
|
102
|
+
var RNX_CLOUD_COMMAND_SCOPES = {
|
|
103
|
+
state: "read",
|
|
104
|
+
tree: "read",
|
|
105
|
+
query: "read",
|
|
106
|
+
resolve: "read",
|
|
107
|
+
screenshot: "read",
|
|
108
|
+
capture: "read",
|
|
109
|
+
captureRegions: "read",
|
|
110
|
+
memory: "read",
|
|
111
|
+
diagnostics: "read",
|
|
112
|
+
storageSnapshot: "read",
|
|
113
|
+
perform: "drive",
|
|
114
|
+
waitFor: "drive",
|
|
115
|
+
tap: "drive",
|
|
116
|
+
longPress: "drive",
|
|
117
|
+
settle: "drive",
|
|
118
|
+
openUrl: "drive",
|
|
119
|
+
setAppearance: "drive",
|
|
120
|
+
keyboard: "drive",
|
|
121
|
+
focus: "drive",
|
|
122
|
+
flowStatus: "drive",
|
|
123
|
+
reset: "reset",
|
|
124
|
+
camera: "media",
|
|
125
|
+
// string evaluation and arbitrary bridge calls are maestro's boundary: the
|
|
126
|
+
// customer sdk never carries this scope, and the service grants it only to
|
|
127
|
+
// the account api key caller. close rides along, since ending the page ends
|
|
128
|
+
// the sim and belongs to the sim's owner rather than any driver.
|
|
129
|
+
evaluate: "debug",
|
|
130
|
+
call: "debug",
|
|
131
|
+
close: "debug"
|
|
132
|
+
};
|
|
133
|
+
function scopeTableKeys() {
|
|
134
|
+
return Object.keys(RNX_CLOUD_COMMAND_SCOPES).filter(
|
|
135
|
+
(key) => Object.prototype.hasOwnProperty.call(RNX_CLOUD_COMMAND_SCOPES, key)
|
|
136
|
+
);
|
|
137
|
+
}
|
|
138
|
+
var RNX_CLOUD_COMMAND_TYPES = Object.freeze(scopeTableKeys());
|
|
121
139
|
var RNX_CLOUD_COMMAND_TYPE_SET = new Set(RNX_CLOUD_COMMAND_TYPES);
|
|
122
140
|
function isRnxCloudCommandType(value) {
|
|
123
141
|
return RNX_CLOUD_COMMAND_TYPE_SET.has(value);
|
|
124
142
|
}
|
|
143
|
+
function rnxCloudCommandScope(type) {
|
|
144
|
+
return RNX_CLOUD_COMMAND_SCOPES[type];
|
|
145
|
+
}
|
|
146
|
+
var RNX_CLOUD_TOKEN_SCOPES = Object.freeze([
|
|
147
|
+
"read",
|
|
148
|
+
"drive",
|
|
149
|
+
"reset",
|
|
150
|
+
"media"
|
|
151
|
+
]);
|
|
152
|
+
var RNX_CLOUD_ALL_COMMAND_SCOPES = Object.freeze(["read", "drive", "reset", "media", "debug"]);
|
|
153
|
+
function rnxCloudScopesAllowCommand(scopes, type) {
|
|
154
|
+
return scopes.includes(RNX_CLOUD_COMMAND_SCOPES[type]);
|
|
155
|
+
}
|
|
125
156
|
|
|
126
157
|
// src/public-brand.ts
|
|
127
158
|
var name = "rnx";
|
|
@@ -136,6 +167,8 @@ var rnxPublicBrand = Object.freeze({
|
|
|
136
167
|
// src/cloud.ts
|
|
137
168
|
var DEFAULT_DEVICE = "iphone-16";
|
|
138
169
|
var DEFAULT_WAIT_READY_MS = 2e4;
|
|
170
|
+
var CLOUD_MAX_RETRIES = 2;
|
|
171
|
+
var CLOUD_NEVER_RETRY_CODES = /* @__PURE__ */ new Set(["concurrency_limit", "early_access"]);
|
|
139
172
|
function isRecord(value) {
|
|
140
173
|
return value !== null && typeof value === "object" && !Array.isArray(value);
|
|
141
174
|
}
|
|
@@ -173,6 +206,62 @@ function responseError(status, text) {
|
|
|
173
206
|
`RNX Cloud request failed (${status})${text.trim() ? `: ${text.trim()}` : ""}`
|
|
174
207
|
);
|
|
175
208
|
}
|
|
209
|
+
function readCloudErrorCode(text) {
|
|
210
|
+
let parsed;
|
|
211
|
+
try {
|
|
212
|
+
parsed = JSON.parse(text);
|
|
213
|
+
} catch {
|
|
214
|
+
return null;
|
|
215
|
+
}
|
|
216
|
+
if (!isRecord(parsed)) return null;
|
|
217
|
+
if (typeof parsed.error === "string") return parsed.error;
|
|
218
|
+
if (isRecord(parsed.error) && typeof parsed.error.code === "string") {
|
|
219
|
+
return parsed.error.code;
|
|
220
|
+
}
|
|
221
|
+
return null;
|
|
222
|
+
}
|
|
223
|
+
function readRetryAfterMs(response, text) {
|
|
224
|
+
const header = response.headers.get("retry-after");
|
|
225
|
+
if (header !== null) {
|
|
226
|
+
const seconds = Number(header.trim());
|
|
227
|
+
if (Number.isFinite(seconds) && seconds >= 0) return seconds * 1e3;
|
|
228
|
+
}
|
|
229
|
+
let parsed;
|
|
230
|
+
try {
|
|
231
|
+
parsed = JSON.parse(text);
|
|
232
|
+
} catch {
|
|
233
|
+
return null;
|
|
234
|
+
}
|
|
235
|
+
if (isRecord(parsed) && typeof parsed.retryAfterMs === "number" && Number.isFinite(parsed.retryAfterMs) && parsed.retryAfterMs >= 0) {
|
|
236
|
+
return parsed.retryAfterMs;
|
|
237
|
+
}
|
|
238
|
+
return null;
|
|
239
|
+
}
|
|
240
|
+
function sleep(ms) {
|
|
241
|
+
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
242
|
+
}
|
|
243
|
+
async function fetchWithCloudRetry(url, init, options) {
|
|
244
|
+
let attempt = 0;
|
|
245
|
+
for (; ; ) {
|
|
246
|
+
const response = await fetch(
|
|
247
|
+
url,
|
|
248
|
+
options?.timeoutMs === void 0 ? init : { ...init, signal: AbortSignal.timeout(options.timeoutMs) }
|
|
249
|
+
);
|
|
250
|
+
if (response.ok) return response;
|
|
251
|
+
const retryableStatus = response.status === 429 || response.status >= 500;
|
|
252
|
+
if (!retryableStatus || attempt >= CLOUD_MAX_RETRIES) return response;
|
|
253
|
+
const text = await response.text();
|
|
254
|
+
const code = readCloudErrorCode(text);
|
|
255
|
+
const retryable = response.status >= 500 ? !(code !== null && CLOUD_NEVER_RETRY_CODES.has(code)) : code === "rate_limited";
|
|
256
|
+
if (!retryable) {
|
|
257
|
+
return new Response(text, { status: response.status, headers: response.headers });
|
|
258
|
+
}
|
|
259
|
+
if (response.status === 429) {
|
|
260
|
+
await sleep(readRetryAfterMs(response, text) ?? 1e3);
|
|
261
|
+
}
|
|
262
|
+
attempt += 1;
|
|
263
|
+
}
|
|
264
|
+
}
|
|
176
265
|
function copyArrayBuffer(bytes) {
|
|
177
266
|
const copy = new ArrayBuffer(bytes.byteLength);
|
|
178
267
|
new Uint8Array(copy).set(bytes);
|
|
@@ -255,6 +344,11 @@ function cloudCommand(command) {
|
|
|
255
344
|
if (!isRnxCloudCommandType(command.type)) {
|
|
256
345
|
throw new Error(`RNX Cloud does not support bridge command type ${command.type}`);
|
|
257
346
|
}
|
|
347
|
+
if (!rnxCloudScopesAllowCommand(RNX_CLOUD_TOKEN_SCOPES, command.type)) {
|
|
348
|
+
throw new Error(
|
|
349
|
+
`RNX Cloud command ${command.type} requires the ${rnxCloudCommandScope(command.type)} scope`
|
|
350
|
+
);
|
|
351
|
+
}
|
|
258
352
|
return { ...clean, type: command.type };
|
|
259
353
|
}
|
|
260
354
|
var RemoteSimulator = class {
|
|
@@ -321,7 +415,7 @@ var RemoteSimulator = class {
|
|
|
321
415
|
};
|
|
322
416
|
let response;
|
|
323
417
|
try {
|
|
324
|
-
response = await
|
|
418
|
+
response = await fetchWithCloudRetry(
|
|
325
419
|
`${this.session.origin}/v1/sims/${encodeURIComponent(this.session.simId)}/commands`,
|
|
326
420
|
{
|
|
327
421
|
method: "POST",
|
|
@@ -329,9 +423,9 @@ var RemoteSimulator = class {
|
|
|
329
423
|
authorization: `Bearer ${this.session.simulatorToken}`,
|
|
330
424
|
"content-type": "application/json"
|
|
331
425
|
},
|
|
332
|
-
body: JSON.stringify(body)
|
|
333
|
-
|
|
334
|
-
}
|
|
426
|
+
body: JSON.stringify(body)
|
|
427
|
+
},
|
|
428
|
+
options?.timeoutMs === void 0 ? void 0 : { timeoutMs: options.timeoutMs }
|
|
335
429
|
);
|
|
336
430
|
} catch (error) {
|
|
337
431
|
throw new Error(
|
|
@@ -356,7 +450,7 @@ var RemoteSimulator = class {
|
|
|
356
450
|
return parsed.result;
|
|
357
451
|
}
|
|
358
452
|
async confirm() {
|
|
359
|
-
const response = await
|
|
453
|
+
const response = await fetchWithCloudRetry(
|
|
360
454
|
`${this.session.origin}/v1/sims/${encodeURIComponent(this.session.simId)}/claim`,
|
|
361
455
|
{
|
|
362
456
|
method: "POST",
|
|
@@ -383,7 +477,7 @@ var RemoteSimulator = class {
|
|
|
383
477
|
return claim;
|
|
384
478
|
}
|
|
385
479
|
async close() {
|
|
386
|
-
const response = await
|
|
480
|
+
const response = await fetchWithCloudRetry(
|
|
387
481
|
`${this.session.origin}/v1/boxes/${encodeURIComponent(this.session.boxId)}`,
|
|
388
482
|
{
|
|
389
483
|
method: "DELETE",
|
|
@@ -414,7 +508,7 @@ async function createRemoteSimulator(input) {
|
|
|
414
508
|
const device = input.device?.trim() || DEFAULT_DEVICE;
|
|
415
509
|
let response;
|
|
416
510
|
try {
|
|
417
|
-
response = await
|
|
511
|
+
response = await fetchWithCloudRetry(`${origin}/v1/boxes`, {
|
|
418
512
|
method: "POST",
|
|
419
513
|
headers: {
|
|
420
514
|
authorization: input.authorization,
|