peachsim 0.1.627 → 0.1.629
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/LICENSE +1 -1
- package/cli/bin.ts +6 -2
- package/cli/bridge-flow-runner.ts +79 -72
- package/cli/commands/cleanup.ts +6 -6
- package/cli/commands/control.ts +4 -5
- package/cli/commands/detox.ts +25 -11
- package/cli/commands/flow.ts +3 -2
- package/cli/commands/inspect/core.ts +5 -0
- package/cli/commands/inspect.ts +43 -49
- package/cli/commands/mode.ts +11 -7
- package/cli/commands/report-issue.ts +1 -1
- package/cli/commands/setup.ts +16 -11
- package/cli/commands/show-touches-mode.ts +33 -0
- package/cli/commands/skills.ts +16 -0
- package/cli/commands/test.ts +8 -1
- package/cli/commands/welcome.ts +3 -3
- package/cli/drivers/playwright-sim-host.ts +6 -5
- package/cli/help-core.ts +9 -4
- package/cli/internal-child.ts +14 -2
- package/cli/levenshtein.ts +27 -0
- package/cli/main.ts +28 -18
- package/cli/ws-bridge.ts +3 -2
- package/detox/index.ts +234 -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 +1 -1
- package/dist-lib/cloud-contract.mjs +1 -1
- package/dist-lib/cloud-test-args.cjs +1 -1
- package/dist-lib/cloud-test-args.mjs +1 -1
- package/dist-lib/cloud.cjs +1 -1
- package/dist-lib/cloud.mjs +1 -1
- package/dist-lib/config.cjs +1 -1
- package/dist-lib/detox/index.cjs +170 -13
- package/dist-lib/dev-bundle-resolution.cjs +2 -2
- package/dist-lib/home-paths.cjs +1 -1
- package/dist-lib/host/bridge-host.cjs +57 -97
- 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 +44 -5
- 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 +7 -1
- package/dist-lib/menu.mjs +7 -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 +43 -4
- 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 +159 -210
- package/dist-lib/swift-compile.cjs +1 -1
- package/dist-lib/swift-compile.mjs +1 -1
- package/dist-lib/swift-package.cjs +1 -1
- package/dist-lib/swift-package.mjs +1 -1
- package/dist-lib/swift-submit.cjs +1 -1
- package/dist-lib/swift-submit.mjs +1 -1
- package/dist-lib/swift.cjs +7276 -7131
- package/dist-lib/vite-kotlin.cjs +1 -1
- package/dist-lib/vite-swift.cjs +1 -1
- package/dist-lib/vite.cjs +43 -4
- package/package.json +1 -1
- package/skills/contrast/SKILL.md +1 -1
- package/src/dev-bundle-resolution.ts +1 -1
- package/src/host/bridge-host.ts +2 -34
- package/src/menu.ts +7 -0
- package/src/native-seam-manifest.ts +4 -16
- package/src/runtime-assets.ts +59 -2
- package/src/screenshots/frame-compose.ts +4 -1
- package/src/vite-plugin.ts +723 -25
package/dist-lib/detox/index.cjs
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
/*! rnx v0.1.
|
|
1
|
+
/*! rnx v0.1.629 | (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;
|
|
@@ -776,12 +776,22 @@ function resolveBrowserCompositeCdpClip(request, metrics) {
|
|
|
776
776
|
}
|
|
777
777
|
const devicePixelRatio = physicalWidth / cssWidth;
|
|
778
778
|
const padding = 1;
|
|
779
|
+
const { rect } = request;
|
|
780
|
+
const left = Math.floor((rect.x - padding) * devicePixelRatio) / devicePixelRatio;
|
|
781
|
+
const top = Math.floor((rect.y - padding) * devicePixelRatio) / devicePixelRatio;
|
|
782
|
+
const right = Math.ceil((rect.x + rect.width + padding) * devicePixelRatio) / devicePixelRatio;
|
|
783
|
+
const bottom = Math.ceil((rect.y + rect.height + padding) * devicePixelRatio) / devicePixelRatio;
|
|
784
|
+
const outputScale = request.outputWidth / rect.width;
|
|
779
785
|
return {
|
|
780
|
-
|
|
781
|
-
|
|
782
|
-
|
|
783
|
-
|
|
784
|
-
|
|
786
|
+
clip: {
|
|
787
|
+
x: left,
|
|
788
|
+
y: top,
|
|
789
|
+
width: right - left,
|
|
790
|
+
height: bottom - top,
|
|
791
|
+
scale: outputScale / devicePixelRatio
|
|
792
|
+
},
|
|
793
|
+
originX: Math.round((rect.x - left) * outputScale),
|
|
794
|
+
originY: Math.round((rect.y - top) * outputScale)
|
|
785
795
|
};
|
|
786
796
|
}
|
|
787
797
|
function readBrowserCompositeCaptureRequest(value) {
|
|
@@ -2194,6 +2204,41 @@ function reapOwnedBrowser() {
|
|
|
2194
2204
|
} catch {
|
|
2195
2205
|
}
|
|
2196
2206
|
}
|
|
2207
|
+
var CONTEXT_MEDIA_QUIESCE_TIMEOUT_MS = 2500;
|
|
2208
|
+
async function quiesceContextMedia(context) {
|
|
2209
|
+
const pages = context.pages();
|
|
2210
|
+
if (pages.length === 0) return;
|
|
2211
|
+
const sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
|
|
2212
|
+
await Promise.race([
|
|
2213
|
+
Promise.all(
|
|
2214
|
+
pages.map(
|
|
2215
|
+
(page) => page.evaluate(() => {
|
|
2216
|
+
const doc = globalThis.document;
|
|
2217
|
+
if (!doc) return;
|
|
2218
|
+
if (doc.pictureInPictureElement && typeof doc.exitPictureInPicture === "function") {
|
|
2219
|
+
void doc.exitPictureInPicture().catch(() => {
|
|
2220
|
+
});
|
|
2221
|
+
}
|
|
2222
|
+
doc.querySelectorAll("video").forEach((v) => {
|
|
2223
|
+
try {
|
|
2224
|
+
if (v.srcObject && typeof v.srcObject.getTracks === "function") {
|
|
2225
|
+
;
|
|
2226
|
+
v.srcObject.getTracks().forEach((t) => t.stop());
|
|
2227
|
+
v.srcObject = null;
|
|
2228
|
+
}
|
|
2229
|
+
v.pause();
|
|
2230
|
+
v.remove();
|
|
2231
|
+
} catch {
|
|
2232
|
+
}
|
|
2233
|
+
});
|
|
2234
|
+
}).catch(() => {
|
|
2235
|
+
})
|
|
2236
|
+
)
|
|
2237
|
+
),
|
|
2238
|
+
sleep(CONTEXT_MEDIA_QUIESCE_TIMEOUT_MS)
|
|
2239
|
+
]).catch(() => {
|
|
2240
|
+
});
|
|
2241
|
+
}
|
|
2197
2242
|
async function closeContext() {
|
|
2198
2243
|
if (_browserCompromised) {
|
|
2199
2244
|
throw new Error(`sootsim browser is compromised: ${_browserCompromised}`);
|
|
@@ -2202,6 +2247,7 @@ async function closeContext() {
|
|
|
2202
2247
|
const context = _context;
|
|
2203
2248
|
const closingContextId = contextIdentity;
|
|
2204
2249
|
try {
|
|
2250
|
+
await quiesceContextMedia(context);
|
|
2205
2251
|
await withLifecycleTimeout("context.close()", closingContextId, () => context.close());
|
|
2206
2252
|
_context = null;
|
|
2207
2253
|
_page = null;
|
|
@@ -2456,7 +2502,9 @@ async function focusElementForTextEntry(el) {
|
|
|
2456
2502
|
if (await isFocusedTextInputNode(page, node)) return;
|
|
2457
2503
|
await el.tap();
|
|
2458
2504
|
await pollUntil(
|
|
2459
|
-
() => page.evaluate(
|
|
2505
|
+
() => page.evaluate(
|
|
2506
|
+
async () => (await window.__sootsimTest.getFocusedNode?.())?.nodeId ?? null
|
|
2507
|
+
),
|
|
2460
2508
|
(focusedNodeId) => focusedNodeId === node.nodeId,
|
|
2461
2509
|
{
|
|
2462
2510
|
timeoutMs: 5e3,
|
|
@@ -3072,7 +3120,13 @@ function createSootSimElement(matcher) {
|
|
|
3072
3120
|
identifier: node.testID || node.id || "",
|
|
3073
3121
|
visible: node.layout.width > 0 && node.layout.height > 0,
|
|
3074
3122
|
enabled: !node.accessibilityState?.disabled,
|
|
3075
|
-
...node
|
|
3123
|
+
...node,
|
|
3124
|
+
frame: node.absolutePosition ? {
|
|
3125
|
+
x: node.absolutePosition.x,
|
|
3126
|
+
y: node.absolutePosition.y,
|
|
3127
|
+
width: node.absolutePosition.width ?? node.frame?.width ?? 0,
|
|
3128
|
+
height: node.absolutePosition.height ?? node.frame?.height ?? 0
|
|
3129
|
+
} : node.frame
|
|
3076
3130
|
};
|
|
3077
3131
|
},
|
|
3078
3132
|
atIndex(index) {
|
|
@@ -3084,6 +3138,72 @@ function createSootSimElement(matcher) {
|
|
|
3084
3138
|
function element(matcher) {
|
|
3085
3139
|
return createSootSimElement(matcher);
|
|
3086
3140
|
}
|
|
3141
|
+
function detoxNotificationToApnsPayload(params) {
|
|
3142
|
+
const trigger = objectOrEmpty(objectOrEmpty(params).trigger);
|
|
3143
|
+
const supported = ["push", "calendar", "location", "timeInterval"];
|
|
3144
|
+
if (typeof trigger.type !== "string" || !supported.includes(trigger.type)) {
|
|
3145
|
+
throw new Error(
|
|
3146
|
+
`Missing trigger or invalid trigger type. A 'trigger' key must exist, with one of the following types: '${supported.join("', '")}'`
|
|
3147
|
+
);
|
|
3148
|
+
}
|
|
3149
|
+
if (trigger.type !== "push") {
|
|
3150
|
+
throw new Error(
|
|
3151
|
+
`sootsim device.sendUserNotification: trigger type '${trigger.type}' is not simulated, only 'push'`
|
|
3152
|
+
);
|
|
3153
|
+
}
|
|
3154
|
+
const assign = (record, key, value) => {
|
|
3155
|
+
if (value === void 0) delete record[key];
|
|
3156
|
+
else record[key] = value;
|
|
3157
|
+
};
|
|
3158
|
+
const payload = { ...objectOrEmpty(params.payload) };
|
|
3159
|
+
const aps = { ...objectOrEmpty(payload.aps) };
|
|
3160
|
+
const alert = { ...objectOrEmpty(aps.alert) };
|
|
3161
|
+
assign(alert, "title", params.title);
|
|
3162
|
+
assign(alert, "subtitle", params.subtitle);
|
|
3163
|
+
assign(alert, "body", params.body);
|
|
3164
|
+
aps.alert = alert;
|
|
3165
|
+
assign(aps, "badge", params.badge);
|
|
3166
|
+
assign(aps, "category", params.category);
|
|
3167
|
+
assign(aps, "content-available", params["content-available"]);
|
|
3168
|
+
payload.aps = aps;
|
|
3169
|
+
return {
|
|
3170
|
+
payload,
|
|
3171
|
+
actionId: typeof params["action-identifier"] === "string" ? params["action-identifier"] : void 0,
|
|
3172
|
+
userText: typeof params["user-text"] === "string" ? params["user-text"] : void 0
|
|
3173
|
+
};
|
|
3174
|
+
}
|
|
3175
|
+
function objectOrEmpty(value) {
|
|
3176
|
+
return value !== null && typeof value === "object" && !Array.isArray(value) ? { ...value } : {};
|
|
3177
|
+
}
|
|
3178
|
+
async function postPreparedRemotePush(prepared, launch) {
|
|
3179
|
+
const { payload, actionId, userText } = prepared;
|
|
3180
|
+
const page = getPage();
|
|
3181
|
+
await page.evaluate(
|
|
3182
|
+
({ request }) => {
|
|
3183
|
+
const bridges = window.SootSim?.bridges;
|
|
3184
|
+
const target = bridges?.shellHost;
|
|
3185
|
+
const post = target?.postNativeUIRequest;
|
|
3186
|
+
if (typeof post !== "function") {
|
|
3187
|
+
throw new Error(
|
|
3188
|
+
"sootsim device.sendUserNotification: simulator shell unavailable \u2014 call device.launchApp() first"
|
|
3189
|
+
);
|
|
3190
|
+
}
|
|
3191
|
+
post.call(target, request);
|
|
3192
|
+
},
|
|
3193
|
+
{
|
|
3194
|
+
request: {
|
|
3195
|
+
kind: "notification.remote-push",
|
|
3196
|
+
payload,
|
|
3197
|
+
launch,
|
|
3198
|
+
...actionId !== void 0 ? { actionId } : {},
|
|
3199
|
+
...userText !== void 0 ? { userText } : {}
|
|
3200
|
+
}
|
|
3201
|
+
}
|
|
3202
|
+
);
|
|
3203
|
+
}
|
|
3204
|
+
async function postRemotePushToSimulator(params, launch) {
|
|
3205
|
+
await postPreparedRemotePush(detoxNotificationToApnsPayload(params), launch);
|
|
3206
|
+
}
|
|
3087
3207
|
var device = {
|
|
3088
3208
|
_currentUrl: "",
|
|
3089
3209
|
_platform: DETOX_PLATFORM,
|
|
@@ -3111,6 +3231,9 @@ var device = {
|
|
|
3111
3231
|
);
|
|
3112
3232
|
_suspendedAppId = null;
|
|
3113
3233
|
await waitForSootsimTree(page, 1e4);
|
|
3234
|
+
if (opts?.userNotification) {
|
|
3235
|
+
await postRemotePushToSimulator(opts.userNotification, true);
|
|
3236
|
+
}
|
|
3114
3237
|
return;
|
|
3115
3238
|
}
|
|
3116
3239
|
if (!_browser) {
|
|
@@ -3151,16 +3274,17 @@ var device = {
|
|
|
3151
3274
|
const request = readBrowserCompositeCaptureRequest(value);
|
|
3152
3275
|
const session = await source.page.context().newCDPSession(source.page);
|
|
3153
3276
|
try {
|
|
3277
|
+
const { clip, originX, originY } = resolveBrowserCompositeCdpClip(
|
|
3278
|
+
request,
|
|
3279
|
+
await session.send("Page.getLayoutMetrics")
|
|
3280
|
+
);
|
|
3154
3281
|
const result = await session.send("Page.captureScreenshot", {
|
|
3155
3282
|
format: "png",
|
|
3156
3283
|
fromSurface: true,
|
|
3157
3284
|
captureBeyondViewport: true,
|
|
3158
|
-
clip
|
|
3159
|
-
request,
|
|
3160
|
-
await session.send("Page.getLayoutMetrics")
|
|
3161
|
-
)
|
|
3285
|
+
clip
|
|
3162
3286
|
});
|
|
3163
|
-
return "data:image/png;base64," + result.data;
|
|
3287
|
+
return { dataUrl: "data:image/png;base64," + result.data, originX, originY };
|
|
3164
3288
|
} finally {
|
|
3165
3289
|
await session.detach();
|
|
3166
3290
|
}
|
|
@@ -3185,6 +3309,20 @@ var device = {
|
|
|
3185
3309
|
contextId: contextIdentity,
|
|
3186
3310
|
operation: "launchApp"
|
|
3187
3311
|
});
|
|
3312
|
+
if (opts?.userNotification) {
|
|
3313
|
+
const prepared = detoxNotificationToApnsPayload(opts.userNotification);
|
|
3314
|
+
await pollUntil(
|
|
3315
|
+
() => postPreparedRemotePush(prepared, true).then(
|
|
3316
|
+
() => true,
|
|
3317
|
+
() => false
|
|
3318
|
+
),
|
|
3319
|
+
Boolean,
|
|
3320
|
+
{
|
|
3321
|
+
timeoutMs: 6e4,
|
|
3322
|
+
label: "SootSim shell to accept launch notification"
|
|
3323
|
+
}
|
|
3324
|
+
);
|
|
3325
|
+
}
|
|
3188
3326
|
await waitForSootsimTree(_page, 3e4);
|
|
3189
3327
|
await waitForSootsimSurfaceMetrics(_page, 3e4);
|
|
3190
3328
|
await waitForSootsimShellReady(_page, 3e4);
|
|
@@ -3219,6 +3357,12 @@ var device = {
|
|
|
3219
3357
|
await waitForSootsimShellReady(page, 1e4);
|
|
3220
3358
|
await waitForSootsimWorkletsIdle(page, 3e3);
|
|
3221
3359
|
},
|
|
3360
|
+
// detox device.sendUserNotification on ios: the notification goes straight
|
|
3361
|
+
// to the app's notification center delegate. an active app gets willPresent;
|
|
3362
|
+
// otherwise the app gets the tap response.
|
|
3363
|
+
async sendUserNotification(params) {
|
|
3364
|
+
await postRemotePushToSimulator(params, false);
|
|
3365
|
+
},
|
|
3222
3366
|
async takeScreenshot(name2) {
|
|
3223
3367
|
return writeSootsimScreenshot(name2);
|
|
3224
3368
|
},
|
|
@@ -3924,7 +4068,20 @@ var device = {
|
|
|
3924
4068
|
},
|
|
3925
4069
|
async shake() {
|
|
3926
4070
|
},
|
|
4071
|
+
// set the simulated device location at the platform level, the same step
|
|
4072
|
+
// native detox's setLocation takes: on iOS it drives the simulator location
|
|
4073
|
+
// (AppleSimUtils/simctl location set) and CLLocationManager delivers the fix
|
|
4074
|
+
// asynchronously. here the platform is the harness browser, so grant page
|
|
4075
|
+
// geolocation and override the context fix; the guest location seam observes
|
|
4076
|
+
// it through navigator.geolocation exactly like the app observes Core
|
|
4077
|
+
// Location. app permission state is untouched, matching native.
|
|
3927
4078
|
async setLocation(lat, lon) {
|
|
4079
|
+
const page = getPage();
|
|
4080
|
+
const context = _context ?? page.context();
|
|
4081
|
+
await context.grantPermissions(["geolocation"], {
|
|
4082
|
+
origin: new URL(page.url()).origin
|
|
4083
|
+
});
|
|
4084
|
+
await context.setGeolocation({ latitude: lat, longitude: lon });
|
|
3928
4085
|
},
|
|
3929
4086
|
async setStatusBar(config) {
|
|
3930
4087
|
await dispatchStatusBarOverride(config);
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
/*! rnx v0.1.
|
|
1
|
+
/*! rnx v0.1.629 | (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;
|
|
@@ -93,7 +93,7 @@ function normalizeNativeDevBundleUrl(bundleUrl) {
|
|
|
93
93
|
var DEFAULT_TEST_DRIVE_PORT = 8081;
|
|
94
94
|
function buildUnresolvedTargetError(targetLabel) {
|
|
95
95
|
return new Error(
|
|
96
|
-
`could not resolve a native bundle for ${targetLabel}. pass an explicit bundle URL or open Connect and choose the app there.`
|
|
96
|
+
`could not resolve a native bundle for ${targetLabel}. start the app's dev server (for example npx expo start), pass an explicit bundle URL, or open Connect and choose the app there.`
|
|
97
97
|
);
|
|
98
98
|
}
|
|
99
99
|
function inferManifestFramework(launchUrl, sdkVersion) {
|
package/dist-lib/home-paths.cjs
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
/*! rnx v0.1.
|
|
1
|
+
/*! rnx v0.1.629 | (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.629 | (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;
|
|
@@ -939,7 +939,7 @@ function rotateDevice(device, side) {
|
|
|
939
939
|
const barrelProtrusion = device.housing?.hingeBarrel?.protrusion ?? 0;
|
|
940
940
|
if (side === "left") insets.top += barrelProtrusion;
|
|
941
941
|
else insets.bottom += barrelProtrusion;
|
|
942
|
-
const safeArea = device.model === "ipad-pro-11" ? { top: 10, bottom: 20, left: 0, right: 0 } : device.model === "iphone-duo" ? { top: 0, bottom:
|
|
942
|
+
const safeArea = device.model === "ipad-pro-11" ? { top: 10, bottom: 20, left: 0, right: 0 } : device.model === "iphone-duo" ? { top: 0, bottom: 34, left: 0, right: 84 } : device.platform === "ios" && device.homeIndicatorHeight > 0 ? {
|
|
943
943
|
top: 0,
|
|
944
944
|
bottom: 20,
|
|
945
945
|
left: device.safeAreaInsets.top,
|
|
@@ -974,71 +974,24 @@ function rotateDevice(device, side) {
|
|
|
974
974
|
// the bars stay on the interface's top and bottom; a cutout's inset moves
|
|
975
975
|
// to whichever side the cutout turned to.
|
|
976
976
|
safeAreaInsets: side === "left" ? safeArea : { ...safeArea, left: safeArea.right, right: safeArea.left },
|
|
977
|
-
statusBarHeight: device.platform === "ios" && device.model !== "ipad-pro-11"
|
|
978
|
-
|
|
977
|
+
statusBarHeight: device.platform === "ios" && device.model !== "ipad-pro-11" ? 0 : device.statusBarHeight,
|
|
978
|
+
// the indicator's band is the landscape bottom inset
|
|
979
|
+
homeIndicatorHeight: device.platform === "ios" && device.homeIndicatorHeight > 0 ? safeArea.bottom : device.homeIndicatorHeight
|
|
979
980
|
};
|
|
980
981
|
}
|
|
981
|
-
function
|
|
982
|
+
function defaultLandscapeSide(model, posture) {
|
|
983
|
+
return model === "iphone-duo" && resolveDevicePosture(model, posture) === "closed" ? "right" : "left";
|
|
984
|
+
}
|
|
985
|
+
function getDevice(model, posture, orientation, landscapeSide) {
|
|
982
986
|
const device = devices[model];
|
|
987
|
+
const side = landscapeSide ?? defaultLandscapeSide(model, posture);
|
|
983
988
|
if (!device.supportedPostures) {
|
|
984
|
-
return orientation === "landscape" && model !== "canvas-workspace" ? rotateDevice(device,
|
|
989
|
+
return orientation === "landscape" && model !== "canvas-workspace" ? rotateDevice(device, side) : device;
|
|
985
990
|
}
|
|
986
991
|
const resolvedPosture = resolveDevicePosture(model, posture);
|
|
987
992
|
const resolvedOrientation = orientation ?? deviceDefaultOrientation(model, resolvedPosture);
|
|
988
993
|
if (resolvedPosture === "closed") {
|
|
989
|
-
|
|
990
|
-
const insets = device.frameInsets;
|
|
991
|
-
const radii = device.cornerRadius;
|
|
992
|
-
const body = device.frameCornerRadius ?? resolveDeviceFrameCorners(device).frameRadius;
|
|
993
|
-
const housing = device.housing;
|
|
994
|
-
const protrusion = housing?.hingeBarrel?.protrusion ?? 0;
|
|
995
|
-
return {
|
|
996
|
-
...device,
|
|
997
|
-
width: device.height,
|
|
998
|
-
height: device.width,
|
|
999
|
-
orientation: "landscape",
|
|
1000
|
-
cornerRadius: {
|
|
1001
|
-
topLeft: radii.topRight,
|
|
1002
|
-
topRight: radii.bottomRight,
|
|
1003
|
-
bottomRight: radii.bottomLeft,
|
|
1004
|
-
bottomLeft: radii.topLeft
|
|
1005
|
-
},
|
|
1006
|
-
continuousCornerRadius: {
|
|
1007
|
-
topLeft: device.continuousCornerRadius.topRight,
|
|
1008
|
-
topRight: device.continuousCornerRadius.bottomRight,
|
|
1009
|
-
bottomRight: device.continuousCornerRadius.bottomLeft,
|
|
1010
|
-
bottomLeft: device.continuousCornerRadius.topLeft
|
|
1011
|
-
},
|
|
1012
|
-
frameInsets: {
|
|
1013
|
-
top: insets.right,
|
|
1014
|
-
right: insets.bottom,
|
|
1015
|
-
bottom: insets.left + protrusion,
|
|
1016
|
-
left: insets.top
|
|
1017
|
-
},
|
|
1018
|
-
frameCornerRadius: {
|
|
1019
|
-
topLeft: body.topRight,
|
|
1020
|
-
topRight: body.bottomRight,
|
|
1021
|
-
bottomRight: body.bottomLeft,
|
|
1022
|
-
bottomLeft: body.topLeft
|
|
1023
|
-
},
|
|
1024
|
-
housing: housing ? {
|
|
1025
|
-
rail: {
|
|
1026
|
-
top: housing.rail.right,
|
|
1027
|
-
right: housing.rail.bottom,
|
|
1028
|
-
bottom: housing.rail.left,
|
|
1029
|
-
left: housing.rail.top
|
|
1030
|
-
},
|
|
1031
|
-
hingeBarrel: null
|
|
1032
|
-
} : void 0,
|
|
1033
|
-
cameraCutout: device.cameraCutout ? {
|
|
1034
|
-
diameter: device.cameraCutout.diameter,
|
|
1035
|
-
top: device.cameraCutout.top,
|
|
1036
|
-
leading: device.cameraCutout.trailing
|
|
1037
|
-
} : null,
|
|
1038
|
-
safeAreaInsets: { top: 0, bottom: 34, left: 84, right: 0 },
|
|
1039
|
-
// vertically compact, so the status bar is hidden.
|
|
1040
|
-
statusBarHeight: 0
|
|
1041
|
-
};
|
|
994
|
+
return resolvedOrientation === "portrait" ? device : rotateDevice(device, side);
|
|
1042
995
|
}
|
|
1043
996
|
const isRotatedPortrait = resolvedOrientation === "portrait";
|
|
1044
997
|
return {
|
|
@@ -1565,10 +1518,12 @@ var init_devices = __esm({
|
|
|
1565
1518
|
posture: "closed",
|
|
1566
1519
|
supportedPostures: ["closed", "open"]
|
|
1567
1520
|
}),
|
|
1521
|
+
// the ios 27.1 simulator's camera occlusion region: 37pt, 29 1/3 in from
|
|
1522
|
+
// the top and trailing edges
|
|
1568
1523
|
cameraCutout: {
|
|
1569
1524
|
diameter: 37,
|
|
1570
|
-
top:
|
|
1571
|
-
trailing:
|
|
1525
|
+
top: 88 / 3,
|
|
1526
|
+
trailing: 88 / 3
|
|
1572
1527
|
}
|
|
1573
1528
|
},
|
|
1574
1529
|
"ipad-pro-11": {
|
|
@@ -6161,10 +6116,12 @@ function createRuntimeDelivery(product) {
|
|
|
6161
6116
|
);
|
|
6162
6117
|
import_node_fs6.default.rmSync(tmpDir, { recursive: true, force: true });
|
|
6163
6118
|
try {
|
|
6164
|
-
|
|
6119
|
+
if (!opts.quiet)
|
|
6120
|
+
process.stderr.write(`${product.id}: downloading runtime ${version}\u2026
|
|
6165
6121
|
`);
|
|
6166
6122
|
await downloadToFile(tarUrl, runtimeArchivePath);
|
|
6167
|
-
|
|
6123
|
+
if (!opts.quiet)
|
|
6124
|
+
process.stderr.write(`${product.id}: extracting runtime ${version}\u2026
|
|
6168
6125
|
`);
|
|
6169
6126
|
const actualSha = await sha256File(runtimeArchivePath);
|
|
6170
6127
|
if (actualSha !== entry.sha256) {
|
|
@@ -6483,6 +6440,41 @@ function resolveRuntimeRootForHostname(hostname) {
|
|
|
6483
6440
|
const version = runtimeVersionFromHostname(hostname);
|
|
6484
6441
|
return version ? resolveInstalledRuntimeRoot(version) : null;
|
|
6485
6442
|
}
|
|
6443
|
+
function sendFileWithRanges(req, res, filePath, total, headers) {
|
|
6444
|
+
const head = (req?.method || "GET").toUpperCase() === "HEAD";
|
|
6445
|
+
const range = /^bytes=(\d*)-(\d*)$/.exec(req?.headers?.range || "");
|
|
6446
|
+
const invalid = range && range[1] && range[2] && Number(range[2]) < Number(range[1]);
|
|
6447
|
+
if (range && (range[1] || range[2]) && !invalid) {
|
|
6448
|
+
const [, startRaw, endRaw] = range;
|
|
6449
|
+
const start = startRaw ? Number(startRaw) : Math.max(0, total - Number(endRaw));
|
|
6450
|
+
const end = startRaw && endRaw ? Math.min(Number(endRaw), total - 1) : total - 1;
|
|
6451
|
+
if (start > end || start >= total) {
|
|
6452
|
+
res.writeHead(416, { ...headers, "Content-Range": `bytes */${total}` });
|
|
6453
|
+
res.end();
|
|
6454
|
+
return;
|
|
6455
|
+
}
|
|
6456
|
+
res.writeHead(206, {
|
|
6457
|
+
...headers,
|
|
6458
|
+
"Content-Range": `bytes ${start}-${end}/${total}`,
|
|
6459
|
+
"Accept-Ranges": "bytes",
|
|
6460
|
+
"Content-Length": String(end - start + 1)
|
|
6461
|
+
});
|
|
6462
|
+
if (head) res.end();
|
|
6463
|
+
else streamFile(res, import_fs.default.createReadStream(filePath, { start, end }));
|
|
6464
|
+
return;
|
|
6465
|
+
}
|
|
6466
|
+
res.writeHead(200, {
|
|
6467
|
+
...headers,
|
|
6468
|
+
"Accept-Ranges": "bytes",
|
|
6469
|
+
"Content-Length": String(total)
|
|
6470
|
+
});
|
|
6471
|
+
if (head || total === 0) res.end();
|
|
6472
|
+
else streamFile(res, import_fs.default.createReadStream(filePath, { start: 0, end: total - 1 }));
|
|
6473
|
+
}
|
|
6474
|
+
function streamFile(res, stream) {
|
|
6475
|
+
stream.on("error", (error) => res.destroy(error));
|
|
6476
|
+
stream.pipe(res);
|
|
6477
|
+
}
|
|
6486
6478
|
|
|
6487
6479
|
// src/runtime-delivery.ts
|
|
6488
6480
|
init_home_paths();
|
|
@@ -10189,42 +10181,10 @@ var SootSimBridgeHost = class _SootSimBridgeHost {
|
|
|
10189
10181
|
return;
|
|
10190
10182
|
}
|
|
10191
10183
|
const contentType = HTTP_MIME_TYPES[import_path3.default.extname(filePath).toLowerCase()] || "application/octet-stream";
|
|
10192
|
-
|
|
10193
|
-
const range = /^bytes=(\d*)-(\d*)$/.exec(req.headers.range || "");
|
|
10194
|
-
if (range) {
|
|
10195
|
-
const [, startRaw, endRaw] = range;
|
|
10196
|
-
const start = startRaw ? Number(startRaw) : 0;
|
|
10197
|
-
const end = endRaw ? Math.min(Number(endRaw), total - 1) : total - 1;
|
|
10198
|
-
if (!Number.isFinite(start) || start > end || start >= total) {
|
|
10199
|
-
res.writeHead(416, { ...cors, "Content-Range": `bytes */${total}` });
|
|
10200
|
-
res.end();
|
|
10201
|
-
return;
|
|
10202
|
-
}
|
|
10203
|
-
res.writeHead(206, {
|
|
10204
|
-
...cors,
|
|
10205
|
-
"Content-Type": contentType,
|
|
10206
|
-
"Content-Range": `bytes ${start}-${end}/${total}`,
|
|
10207
|
-
"Accept-Ranges": "bytes",
|
|
10208
|
-
"Content-Length": String(end - start + 1)
|
|
10209
|
-
});
|
|
10210
|
-
if (method === "HEAD") {
|
|
10211
|
-
res.end();
|
|
10212
|
-
return;
|
|
10213
|
-
}
|
|
10214
|
-
import_fs3.default.createReadStream(filePath, { start, end }).pipe(res);
|
|
10215
|
-
return;
|
|
10216
|
-
}
|
|
10217
|
-
res.writeHead(200, {
|
|
10184
|
+
sendFileWithRanges(req, res, filePath, stats.size, {
|
|
10218
10185
|
...cors,
|
|
10219
|
-
"Content-Type": contentType
|
|
10220
|
-
"Accept-Ranges": "bytes",
|
|
10221
|
-
"Content-Length": String(total)
|
|
10186
|
+
"Content-Type": contentType
|
|
10222
10187
|
});
|
|
10223
|
-
if (method === "HEAD") {
|
|
10224
|
-
res.end();
|
|
10225
|
-
return;
|
|
10226
|
-
}
|
|
10227
|
-
import_fs3.default.createReadStream(filePath).pipe(res);
|
|
10228
10188
|
}
|
|
10229
10189
|
handleServerScan(res) {
|
|
10230
10190
|
const sendJson = (body) => {
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
/*! rnx v0.1.
|
|
1
|
+
/*! rnx v0.1.629 | (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.629 | (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.629 | (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.629 | (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.629 | (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.629 | (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;
|
|
@@ -1028,7 +1028,7 @@ function resolveDefaultDevBridgeLockfile() {
|
|
|
1028
1028
|
) ?? sameCheckout[0];
|
|
1029
1029
|
}
|
|
1030
1030
|
}
|
|
1031
|
-
return lockfiles.find((lockfile) => lockfile.bridgePort === DEFAULT_SOOTSIM_BRIDGE_PORT) ??
|
|
1031
|
+
return lockfiles.find((lockfile) => lockfile.bridgePort === DEFAULT_SOOTSIM_BRIDGE_PORT) ?? null;
|
|
1032
1032
|
}
|
|
1033
1033
|
function resolveBridgeWorld() {
|
|
1034
1034
|
const homeDir = rnxHomeDir();
|
|
@@ -4013,7 +4013,11 @@ var MIME_TYPES = {
|
|
|
4013
4013
|
".woff": "font/woff",
|
|
4014
4014
|
".woff2": "font/woff2",
|
|
4015
4015
|
".mp3": "audio/mpeg",
|
|
4016
|
-
".wav": "audio/wav"
|
|
4016
|
+
".wav": "audio/wav",
|
|
4017
|
+
".mp4": "video/mp4",
|
|
4018
|
+
".m4v": "video/mp4",
|
|
4019
|
+
".mov": "video/quicktime",
|
|
4020
|
+
".webm": "video/webm"
|
|
4017
4021
|
};
|
|
4018
4022
|
var ROOT_RUNTIME_PATHS = [
|
|
4019
4023
|
"/assets/",
|
|
@@ -4027,7 +4031,7 @@ var ROOT_RUNTIME_PATHS = [
|
|
|
4027
4031
|
"/spike/",
|
|
4028
4032
|
"/test-wallpaper.jpg",
|
|
4029
4033
|
"/preview-sw.js",
|
|
4030
|
-
"/
|
|
4034
|
+
"/peach.svg",
|
|
4031
4035
|
"/bedrock-sqlite.wasm",
|
|
4032
4036
|
"/bedrock-sqlite.js",
|
|
4033
4037
|
"/sootsim/"
|
|
@@ -4111,7 +4115,42 @@ function serveRuntimeFile(req, res, fullPath) {
|
|
|
4111
4115
|
res.end();
|
|
4112
4116
|
return;
|
|
4113
4117
|
}
|
|
4114
|
-
|
|
4118
|
+
sendFileWithRanges(req, res, fullPath, stat.size, {});
|
|
4119
|
+
}
|
|
4120
|
+
function sendFileWithRanges(req, res, filePath, total, headers) {
|
|
4121
|
+
const head = (req?.method || "GET").toUpperCase() === "HEAD";
|
|
4122
|
+
const range = /^bytes=(\d*)-(\d*)$/.exec(req?.headers?.range || "");
|
|
4123
|
+
const invalid = range && range[1] && range[2] && Number(range[2]) < Number(range[1]);
|
|
4124
|
+
if (range && (range[1] || range[2]) && !invalid) {
|
|
4125
|
+
const [, startRaw, endRaw] = range;
|
|
4126
|
+
const start = startRaw ? Number(startRaw) : Math.max(0, total - Number(endRaw));
|
|
4127
|
+
const end = startRaw && endRaw ? Math.min(Number(endRaw), total - 1) : total - 1;
|
|
4128
|
+
if (start > end || start >= total) {
|
|
4129
|
+
res.writeHead(416, { ...headers, "Content-Range": `bytes */${total}` });
|
|
4130
|
+
res.end();
|
|
4131
|
+
return;
|
|
4132
|
+
}
|
|
4133
|
+
res.writeHead(206, {
|
|
4134
|
+
...headers,
|
|
4135
|
+
"Content-Range": `bytes ${start}-${end}/${total}`,
|
|
4136
|
+
"Accept-Ranges": "bytes",
|
|
4137
|
+
"Content-Length": String(end - start + 1)
|
|
4138
|
+
});
|
|
4139
|
+
if (head) res.end();
|
|
4140
|
+
else streamFile(res, import_fs3.default.createReadStream(filePath, { start, end }));
|
|
4141
|
+
return;
|
|
4142
|
+
}
|
|
4143
|
+
res.writeHead(200, {
|
|
4144
|
+
...headers,
|
|
4145
|
+
"Accept-Ranges": "bytes",
|
|
4146
|
+
"Content-Length": String(total)
|
|
4147
|
+
});
|
|
4148
|
+
if (head || total === 0) res.end();
|
|
4149
|
+
else streamFile(res, import_fs3.default.createReadStream(filePath, { start: 0, end: total - 1 }));
|
|
4150
|
+
}
|
|
4151
|
+
function streamFile(res, stream) {
|
|
4152
|
+
stream.on("error", (error) => res.destroy(error));
|
|
4153
|
+
stream.pipe(res);
|
|
4115
4154
|
}
|
|
4116
4155
|
|
|
4117
4156
|
// src/vite-plugin-one.ts
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
/*! rnx v0.1.
|
|
1
|
+
/*! rnx v0.1.629 | (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.629 | (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.629 | (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;
|
|
@@ -404,6 +404,12 @@ function windowMenu(state) {
|
|
|
404
404
|
checked: state.showBezels,
|
|
405
405
|
action: "toggle-bezels"
|
|
406
406
|
},
|
|
407
|
+
{
|
|
408
|
+
label: "Show Touches",
|
|
409
|
+
type: "checkbox",
|
|
410
|
+
checked: state.showTouches,
|
|
411
|
+
action: "toggle-touches"
|
|
412
|
+
},
|
|
407
413
|
{
|
|
408
414
|
label: "Show Menu Bar",
|
|
409
415
|
type: "checkbox",
|
package/dist-lib/menu.mjs
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
/*! rnx v0.1.
|
|
1
|
+
/*! rnx v0.1.629 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
|
|
2
2
|
|
|
3
3
|
// src/public-brand.ts
|
|
4
4
|
var name = "Peach";
|
|
@@ -363,6 +363,12 @@ function windowMenu(state) {
|
|
|
363
363
|
checked: state.showBezels,
|
|
364
364
|
action: "toggle-bezels"
|
|
365
365
|
},
|
|
366
|
+
{
|
|
367
|
+
label: "Show Touches",
|
|
368
|
+
type: "checkbox",
|
|
369
|
+
checked: state.showTouches,
|
|
370
|
+
action: "toggle-touches"
|
|
371
|
+
},
|
|
366
372
|
{
|
|
367
373
|
label: "Show Menu Bar",
|
|
368
374
|
type: "checkbox",
|