peachsim 0.1.1406 → 0.1.1465

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.
Files changed (150) hide show
  1. package/LICENSE +8 -4
  2. package/README.md +22 -2
  3. package/cli/app-fonts.ts +50 -44
  4. package/cli/bin.ts +5 -4
  5. package/cli/bridge-diagnostics.ts +5 -0
  6. package/cli/bridge-flow-runner.ts +21 -13
  7. package/cli/cloud-client.ts +4 -3
  8. package/cli/commands/control.ts +155 -123
  9. package/cli/commands/daemon-mac-app.ts +3 -3
  10. package/cli/commands/daemon.ts +2 -2
  11. package/cli/commands/do-chain.ts +9 -2
  12. package/cli/commands/electron.ts +4 -1
  13. package/cli/commands/inspect/core.ts +1 -1
  14. package/cli/commands/inspect/settle.ts +19 -7
  15. package/cli/commands/inspect/settling.ts +92 -56
  16. package/cli/commands/inspect/wait-idle.ts +21 -9
  17. package/cli/commands/inspect/wait-ready.ts +22 -8
  18. package/cli/commands/inspect.ts +101 -134
  19. package/cli/commands/setup.ts +26 -16
  20. package/cli/commands/upgrade.ts +53 -9
  21. package/cli/desktop-companion.ts +1 -1
  22. package/cli/drivers/playwright-sim-host.ts +32 -13
  23. package/cli/drivers/playwright.ts +3 -3
  24. package/cli/main.ts +14 -5
  25. package/cli/outbound-endpoints.ts +1 -9
  26. package/detox/index.ts +6 -1
  27. package/dist-lib/agent-daemon-client.cjs +1 -1
  28. package/dist-lib/agent-events.cjs +1 -1
  29. package/dist-lib/attached-projects.cjs +1 -1
  30. package/dist-lib/auth/shared-session.cjs +1 -1
  31. package/dist-lib/backend-origin.cjs +1 -1
  32. package/dist-lib/beta.cjs +1 -1
  33. package/dist-lib/beta.mjs +1 -1
  34. package/dist-lib/bridge-constants.cjs +1 -1
  35. package/dist-lib/bridge-contract-input.cjs +1 -1
  36. package/dist-lib/bridge-contract-input.mjs +1 -1
  37. package/dist-lib/bridge-contract.cjs +3 -3
  38. package/dist-lib/bridge-contract.mjs +3 -3
  39. package/dist-lib/bundle-channel.cjs +322 -274
  40. package/dist-lib/capture-contract.cjs +1 -1
  41. package/dist-lib/capture-contract.mjs +1 -1
  42. package/dist-lib/cloud-contract.cjs +1 -1
  43. package/dist-lib/cloud-contract.mjs +1 -1
  44. package/dist-lib/cloud-test-args.cjs +1 -1
  45. package/dist-lib/cloud-test-args.mjs +1 -1
  46. package/dist-lib/cloud.cjs +1 -1
  47. package/dist-lib/cloud.mjs +1 -1
  48. package/dist-lib/config.cjs +1 -1
  49. package/dist-lib/config.mjs +1 -1
  50. package/dist-lib/detox/index.cjs +512 -122
  51. package/dist-lib/dev-bundle-resolution.cjs +1 -1
  52. package/dist-lib/expo-swift-bundle.cjs +69 -33
  53. package/dist-lib/expo-swift-metadata.cjs +1 -1
  54. package/dist-lib/expo-swift-metadata.mjs +1 -1
  55. package/dist-lib/home-paths.cjs +1 -1
  56. package/dist-lib/host/bridge-host.cjs +3650 -3528
  57. package/dist-lib/host/fetch-proxy-handler.cjs +1 -1
  58. package/dist-lib/host/fetch-proxy-overrides.cjs +1 -1
  59. package/dist-lib/host/fetch-proxy-overrides.mjs +1 -1
  60. package/dist-lib/host/replacement-module-handler.cjs +1 -1
  61. package/dist-lib/host/websocket-proxy.cjs +1 -1
  62. package/dist-lib/index.cjs +327 -123
  63. package/dist-lib/jump-to-source-babel.cjs +1 -1
  64. package/dist-lib/jump-to-source-native.cjs +1 -1
  65. package/dist-lib/kotlin-host.cjs +10 -5
  66. package/dist-lib/menu.cjs +1 -1
  67. package/dist-lib/menu.mjs +1 -1
  68. package/dist-lib/metro-fingerprint-registry.cjs +1 -1
  69. package/dist-lib/metro-fingerprint-registry.mjs +1 -1
  70. package/dist-lib/metro-production-bundle.cjs +1 -1
  71. package/dist-lib/metro-production-bundle.mjs +1 -1
  72. package/dist-lib/metro.cjs +49 -47
  73. package/dist-lib/native-app-identity-project.cjs +1 -1
  74. package/dist-lib/native-app-identity-project.mjs +1 -1
  75. package/dist-lib/native-app-identity.cjs +1 -1
  76. package/dist-lib/native-app-identity.mjs +1 -1
  77. package/dist-lib/native-firebase-metadata.cjs +1 -1
  78. package/dist-lib/native-firebase-metadata.mjs +1 -1
  79. package/dist-lib/plist.cjs +1 -1
  80. package/dist-lib/plist.mjs +1 -1
  81. package/dist-lib/profiles.cjs +1 -1
  82. package/dist-lib/public-brand.cjs +1 -1
  83. package/dist-lib/react-native-host-modules.cjs +1 -1
  84. package/dist-lib/react-native-host-modules.mjs +1 -1
  85. package/dist-lib/scripts/dev-server-scanner.cjs +23 -17
  86. package/dist-lib/sdk.cjs +99 -61
  87. package/dist-lib/sdk.mjs +97 -61
  88. package/dist-lib/skills.cjs +3347 -3051
  89. package/dist-lib/swift-compile.cjs +26 -12
  90. package/dist-lib/swift-compile.mjs +26 -12
  91. package/dist-lib/swift-package.cjs +1 -1
  92. package/dist-lib/swift-package.mjs +1 -1
  93. package/dist-lib/swift-submit.cjs +2 -2
  94. package/dist-lib/swift-submit.mjs +2 -2
  95. package/dist-lib/swift-toolchain.cjs +1 -1
  96. package/dist-lib/swift.cjs +1 -1
  97. package/dist-lib/vite-swift.cjs +66 -31
  98. package/dist-lib/vite.cjs +1 -1
  99. package/dist-lib/worklet-executable.cjs +5 -1
  100. package/dist-lib/worklet-executable.mjs +5 -1
  101. package/kotlin/AppSources/android/view/Window.kt +2 -0
  102. package/kotlin/AppSources/dev/peach/app/PeachApp.kt +1 -1
  103. package/kotlin/ComposeSources/PeachComposeHost.kt +35 -9
  104. package/kotlin/ExpoComposeSources/dev/peach/expo/PeachExpoCompose.kt +2 -2
  105. package/kotlin/ExpoSources/dev/peach/expo/PeachExpoRuntime.kt +9 -6
  106. package/kotlin/ExpoSources/dev/peach/expo/PeachExpoTypes.kt +4 -4
  107. package/kotlin/ExpoSources/expo/modules/kotlin/modules/Module.kt +2 -2
  108. package/kotlin/ExpoSources/expo/modules/kotlin/viewevent/ViewEvent.kt +22 -8
  109. package/kotlin/ExpoSources/expo/modules/kotlin/views/ExpoView.kt +0 -3
  110. package/kotlin/ExpoSources/expo/modules/kotlin/views/ViewDefinitionBuilder.kt +10 -9
  111. package/kotlin/ExpoSources/expo/modules/kotlin/views/ViewProps.kt +6 -5
  112. package/kotlin/fixtures/import-drawing/Drawing.d.kt.ts +7 -0
  113. package/kotlin/fixtures/import-drawing/Drawing.kt +101 -0
  114. package/kotlin/fixtures/import-drawing/ImportDrawing.native.tsx +18 -0
  115. package/kotlin/fixtures/import-drawing/README.md +34 -0
  116. package/kotlin/fixtures/import-drawing/app/_layout.tsx +4 -0
  117. package/kotlin/fixtures/import-drawing/app/index+spa.tsx +1 -0
  118. package/kotlin/fixtures/import-drawing/package.json +23 -0
  119. package/kotlin/fixtures/import-drawing/tsconfig.json +20 -0
  120. package/kotlin/fixtures/import-drawing/vite.config.ts +20 -0
  121. package/kotlin/fixtures/import-scroll/ImportNested.native.tsx +10 -0
  122. package/kotlin/fixtures/import-scroll/Nested.d.kt.ts +4 -0
  123. package/kotlin/fixtures/import-scroll/README.md +15 -0
  124. package/kotlin/fixtures/import-scroll/app/nested+spa.tsx +1 -0
  125. package/kotlin/fixtures/import-values/ImportValues.native.tsx +26 -0
  126. package/kotlin/fixtures/import-values/README.md +6 -1
  127. package/kotlin/fixtures/import-values/Values.d.kt.ts +4 -0
  128. package/kotlin/fixtures/import-values/Values.kt +18 -0
  129. package/kotlin/tools/expo-types.main.kts +17 -5
  130. package/package.json +2 -1
  131. package/scripts/dev-server-scanner.ts +33 -23
  132. package/src/assetCatalogContract.ts +7 -0
  133. package/src/bridge-contract.ts +21 -3
  134. package/src/connect.ts +18 -5
  135. package/src/desktop-host-delivery.ts +33 -3
  136. package/src/expo-swift-host.ts +6 -3
  137. package/src/host/bridge-host.ts +2 -0
  138. package/src/host/fetch-proxy-transport.ts +8 -0
  139. package/src/kotlin-host.ts +11 -5
  140. package/src/native-firebase-config.ts +95 -54
  141. package/src/process-output.ts +16 -0
  142. package/src/sdk.ts +6 -1
  143. package/src/sim-client.ts +6 -1
  144. package/src/swift-compile.ts +36 -15
  145. package/src/swift-distribution.lock.json +8 -8
  146. package/src/swift-standin-emit.ts +10 -1
  147. package/src/swift-standins.ts +21 -7
  148. package/src/swift-submit.ts +6 -1
  149. package/src/worklet-executable.ts +7 -2
  150. /package/kotlin/fixtures/{kotlin-app-variants → import-scroll}/Nested.kt +0 -0
@@ -1,4 +1,4 @@
1
- /*! peach v0.1.1406 | (c) 2026 Tamagui LLC | Proprietary; see LICENSE */
1
+ /*! peach v0.1.1465 | (c) 2026 Tamagui LLC | Proprietary; see LICENSE */
2
2
  let __sootsim_import_meta_url = '', __sootsim_import_meta_dirname = ''; try { __sootsim_import_meta_url = require('url').pathToFileURL(__filename).href; __sootsim_import_meta_dirname = __dirname; } catch {}
3
3
  "use strict";
4
4
  var __create = Object.create;
@@ -1225,22 +1225,22 @@ var require_motion_change = __commonJS({
1225
1225
  var require_attempt_events = __commonJS({
1226
1226
  "detox/attempt-events.cjs"(exports2, module2) {
1227
1227
  "use strict";
1228
- var fs2 = require("node:fs");
1229
- var path2 = require("node:path");
1228
+ var fs3 = require("node:fs");
1229
+ var path3 = require("node:path");
1230
1230
  function attemptEventsPath() {
1231
1231
  const enabled = process.env.CONFORMANCE_PROOF === "1" || Boolean(process.env.CONFORMANCE_PROOF_DIR);
1232
1232
  if (!enabled) return null;
1233
- const root = path2.resolve(
1233
+ const root = path3.resolve(
1234
1234
  process.cwd(),
1235
1235
  process.env.CONFORMANCE_PROOF_DIR || "artifacts/conformance-proof/latest"
1236
1236
  );
1237
- return path2.join(root, "events.jsonl");
1237
+ return path3.join(root, "events.jsonl");
1238
1238
  }
1239
1239
  function writeAttemptEvent2(event) {
1240
1240
  const output = attemptEventsPath();
1241
1241
  if (output === null) return false;
1242
- fs2.mkdirSync(path2.dirname(output), { recursive: true });
1243
- fs2.appendFileSync(output, `${JSON.stringify(event)}
1242
+ fs3.mkdirSync(path3.dirname(output), { recursive: true });
1243
+ fs3.appendFileSync(output, `${JSON.stringify(event)}
1244
1244
  `);
1245
1245
  return true;
1246
1246
  }
@@ -1351,15 +1351,113 @@ __export(detox_exports, {
1351
1351
  });
1352
1352
  module.exports = __toCommonJS(detox_exports);
1353
1353
  var import_crypto = require("crypto");
1354
- var fs = __toESM(require("fs"), 1);
1354
+ var fs2 = __toESM(require("fs"), 1);
1355
1355
  var import_node_child_process2 = require("node:child_process");
1356
1356
  var import_node_module = require("node:module");
1357
1357
  var import_node_util = require("node:util");
1358
- var path = __toESM(require("path"), 1);
1358
+ var path2 = __toESM(require("path"), 1);
1359
1359
  var import_playwright_core = require("playwright-core");
1360
1360
 
1361
1361
  // ../../scripts/lib/reap-browser.ts
1362
+ var childProcess = __toESM(require("node:child_process"), 1);
1362
1363
  var import_node_child_process = require("node:child_process");
1364
+ var fs = __toESM(require("node:fs"), 1);
1365
+ var os = __toESM(require("node:os"), 1);
1366
+ var path = __toESM(require("node:path"), 1);
1367
+
1368
+ // ../../scripts/lib/chromium-admission.ts
1369
+ async function acquireChromiumAdmission(deps) {
1370
+ const { fs: fs3, os: os2, path: path3, childProcess: childProcess2, label } = deps;
1371
+ const dir = path3.join(
1372
+ process.platform === "win32" ? os2.tmpdir() : "/tmp",
1373
+ "chromium-admission"
1374
+ );
1375
+ fs3.mkdirSync(dir, { recursive: true });
1376
+ const limit = Math.max(2, Math.floor(os2.availableParallelism() / 3));
1377
+ const startedAt = Math.round(Date.now() / 1e3 - process.uptime());
1378
+ const name2 = `${process.pid}-${startedAt}-${Math.random().toString(36).slice(2, 10)}`;
1379
+ const ticket = path3.join(dir, name2);
1380
+ fs3.closeSync(fs3.openSync(ticket, "wx"));
1381
+ let released = false;
1382
+ const release = () => {
1383
+ if (released) return;
1384
+ released = true;
1385
+ process.removeListener("exit", release);
1386
+ try {
1387
+ fs3.unlinkSync(ticket);
1388
+ } catch {
1389
+ }
1390
+ };
1391
+ process.on("exit", release);
1392
+ const verified = /* @__PURE__ */ new Map();
1393
+ const live = (entry) => {
1394
+ const match = /^(\d+)-(\d+)-/.exec(entry);
1395
+ if (!match) return false;
1396
+ const pid = Number(match[1]);
1397
+ try {
1398
+ process.kill(pid, 0);
1399
+ } catch (err) {
1400
+ if (!(err instanceof Error && "code" in err && err.code === "EPERM")) return false;
1401
+ }
1402
+ const known = verified.get(entry);
1403
+ if (known !== void 0) return known;
1404
+ let same = pid === process.pid;
1405
+ if (!same) {
1406
+ try {
1407
+ const started = childProcess2.execFileSync("ps", ["-p", String(pid), "-o", "lstart="], { encoding: "utf8" }).trim();
1408
+ same = Math.abs(Date.parse(started) / 1e3 - Number(match[2])) <= 2;
1409
+ } catch {
1410
+ same = false;
1411
+ }
1412
+ }
1413
+ verified.set(entry, same);
1414
+ return same;
1415
+ };
1416
+ let waited = false;
1417
+ while (true) {
1418
+ const tickets = [];
1419
+ for (const entry of fs3.readdirSync(dir)) {
1420
+ if (entry !== name2 && !live(entry)) {
1421
+ try {
1422
+ fs3.unlinkSync(path3.join(dir, entry));
1423
+ } catch {
1424
+ }
1425
+ continue;
1426
+ }
1427
+ try {
1428
+ tickets.push({
1429
+ entry,
1430
+ created: fs3.statSync(path3.join(dir, entry), { bigint: true }).ctimeNs
1431
+ });
1432
+ } catch {
1433
+ }
1434
+ }
1435
+ tickets.sort(
1436
+ (a, b) => a.created === b.created ? a.entry < b.entry ? -1 : 1 : a.created < b.created ? -1 : 1
1437
+ );
1438
+ const rank = tickets.findIndex((t) => t.entry === name2);
1439
+ if (rank < 0) {
1440
+ fs3.closeSync(fs3.openSync(ticket, "wx"));
1441
+ continue;
1442
+ }
1443
+ if (rank < limit) {
1444
+ if (waited) process.stderr.write(`[chromium-admission] ${label}: admitted
1445
+ `);
1446
+ return release;
1447
+ }
1448
+ if (!waited) {
1449
+ const holders = tickets.slice(0, limit).map((t) => t.entry.split("-")[0]);
1450
+ process.stderr.write(
1451
+ `[chromium-admission] ${label}: ${limit} chromium launches already run on this machine (pids ${holders.join(" ")}), queued ${rank - limit + 1}
1452
+ `
1453
+ );
1454
+ waited = true;
1455
+ }
1456
+ await new Promise((resolve2) => setTimeout(resolve2, 500));
1457
+ }
1458
+ }
1459
+
1460
+ // ../../scripts/lib/reap-browser.ts
1363
1461
  var discoveredChromePids = /* @__PURE__ */ new WeakMap();
1364
1462
  var discoveredChromeProcesses = /* @__PURE__ */ new WeakMap();
1365
1463
  var reapPids = /* @__PURE__ */ new Map();
@@ -1647,7 +1745,20 @@ function installReaper() {
1647
1745
  process.on("exit", reap);
1648
1746
  }
1649
1747
  async function launchReapedScoped(launch, readIdentity = processIdentity) {
1650
- const browser = await launch();
1748
+ const releaseAdmission = await acquireChromiumAdmission({
1749
+ fs,
1750
+ os,
1751
+ path,
1752
+ childProcess,
1753
+ label: process.argv.slice(1, 3).join(" ")
1754
+ });
1755
+ let browser;
1756
+ try {
1757
+ browser = await launch();
1758
+ } catch (err) {
1759
+ releaseAdmission();
1760
+ throw err;
1761
+ }
1651
1762
  let root = rootChromePid(browser);
1652
1763
  if (root === null) {
1653
1764
  try {
@@ -1670,6 +1781,7 @@ async function launchReapedScoped(launch, readIdentity = processIdentity) {
1670
1781
  untrackReapPid(tracked);
1671
1782
  }
1672
1783
  mine.clear();
1784
+ releaseAdmission();
1673
1785
  });
1674
1786
  }
1675
1787
  const reapNow = () => {
@@ -1678,6 +1790,7 @@ async function launchReapedScoped(launch, readIdentity = processIdentity) {
1678
1790
  untrackReapPid(tracked);
1679
1791
  }
1680
1792
  mine.clear();
1793
+ releaseAdmission();
1681
1794
  };
1682
1795
  return { browser, reapNow };
1683
1796
  }
@@ -1822,13 +1935,22 @@ function platformChromeLaunch(launch, opts, rendererTarget, policy = {}) {
1822
1935
  return browser;
1823
1936
  };
1824
1937
  }
1825
- function softwareChromeLaunchOptions(opts) {
1938
+ function softwareChromeLaunchOptions(opts, runtime = currentRuntime()) {
1826
1939
  if (opts.ignoreDefaultArgs === true) {
1827
1940
  throw new Error(
1828
1941
  "[reap-browser] ignoreDefaultArgs=true bypasses required Chrome launch defaults"
1829
1942
  );
1830
1943
  }
1831
1944
  const callerArgs = Array.isArray(opts.args) ? opts.args.map(String) : [];
1945
+ if (runtime.platform === "linux" && runtime.env.PEACH_NATIVE_COMPOSITOR === "1") {
1946
+ const native = {
1947
+ ...opts,
1948
+ args: [...callerArgs, "--disable-gpu"]
1949
+ };
1950
+ delete native.channel;
1951
+ delete native.executablePath;
1952
+ return native;
1953
+ }
1832
1954
  const unmanagedCallerArgs = callerArgs.filter((arg) => {
1833
1955
  return !arg.startsWith("--use-angle=") && arg !== "--enable-gpu" && arg !== "--enable-gpu-rasterization" && arg !== "--enable-zero-copy" && arg !== "--ignore-gpu-blocklist" && arg !== "--disable-gpu-watchdog" && arg !== "--enable-skia-graphite" && !/^--enable-unsafe-webgpu(?:=.*)?$/i.test(arg) && !/^--enable-unsafe-swiftshader(?:=.*)?$/i.test(arg);
1834
1956
  });
@@ -1868,7 +1990,7 @@ function chromeLaunchOptions(opts = {}, runtime = currentRuntime()) {
1868
1990
  if (signalShutdownClaimed) {
1869
1991
  opts = { ...opts, handleSIGINT: false, handleSIGTERM: false, handleSIGHUP: false };
1870
1992
  }
1871
- return softwareChromeAllowed(runtime) ? softwareChromeLaunchOptions(opts) : gpuChromeLaunchOptions(opts, runtime);
1993
+ return softwareChromeAllowed(runtime) ? softwareChromeLaunchOptions(opts, runtime) : gpuChromeLaunchOptions(opts, runtime);
1872
1994
  }
1873
1995
  async function launchReapedChromeScoped(launch, opts = {}, rendererTarget, policy = {}) {
1874
1996
  return launchReapedScoped(
@@ -2404,14 +2526,14 @@ function withFrameEmbedderHeaders(headers) {
2404
2526
  ];
2405
2527
  }
2406
2528
  function firstPartyCookie(line, url) {
2407
- let location;
2529
+ let location2;
2408
2530
  try {
2409
- location = new URL(url);
2531
+ location2 = new URL(url);
2410
2532
  } catch {
2411
2533
  return null;
2412
2534
  }
2413
- const loopback = ["localhost", "127.0.0.1", "[::1]"].includes(location.hostname);
2414
- if (location.protocol !== "https:" && !(location.protocol === "http:" && loopback))
2535
+ const loopback = ["localhost", "127.0.0.1", "[::1]"].includes(location2.hostname);
2536
+ if (location2.protocol !== "https:" && !(location2.protocol === "http:" && loopback))
2415
2537
  return null;
2416
2538
  const [pair = "", ...attributes] = line.split(";");
2417
2539
  const separator = pair.indexOf("=");
@@ -2419,8 +2541,8 @@ function firstPartyCookie(line, url) {
2419
2541
  const cookie = {
2420
2542
  name: pair.slice(0, separator).trim(),
2421
2543
  value: pair.slice(separator + 1).trim(),
2422
- domain: location.hostname,
2423
- path: location.pathname.slice(0, location.pathname.lastIndexOf("/")) || "/",
2544
+ domain: location2.hostname,
2545
+ path: location2.pathname.slice(0, location2.pathname.lastIndexOf("/")) || "/",
2424
2546
  expires: -1,
2425
2547
  httpOnly: false,
2426
2548
  secure: true,
@@ -2436,7 +2558,7 @@ function firstPartyCookie(line, url) {
2436
2558
  if (key === "path" && value.startsWith("/")) cookie.path = value;
2437
2559
  if (key === "domain" && value) {
2438
2560
  const domain = value.replace(/^\./, "").toLowerCase();
2439
- if (location.hostname !== domain && !location.hostname.endsWith("." + domain))
2561
+ if (location2.hostname !== domain && !location2.hostname.endsWith("." + domain))
2440
2562
  return null;
2441
2563
  cookie.domain = "." + domain;
2442
2564
  }
@@ -2516,7 +2638,7 @@ function webViewAutomationNames(timingName, bootstrapSource) {
2516
2638
  bootstrapSource: `(${bootstrapSource})(${JSON.stringify(timingName)});`
2517
2639
  };
2518
2640
  }
2519
- async function automateWebViewFrames(context, names, helpers) {
2641
+ async function automateWebViewFrames(context, names, helpers, tenantWorkers) {
2520
2642
  await context.addInitScript({ content: names.bootstrapSource });
2521
2643
  const browser = context.browser();
2522
2644
  if (!browser) throw new Error("webview automation needs the browser behind its context");
@@ -2538,7 +2660,7 @@ async function automateWebViewFrames(context, names, helpers) {
2538
2660
  const expoPromptHeader = "__EXPO_DOM_WEBVIEW_JS_EVAL__";
2539
2661
  const evaluateExpoPrompt = (page, instanceId, webViewId, message) => {
2540
2662
  return new Promise((resolve2) => {
2541
- const workers = page.workers();
2663
+ const workers = tenantWorkers(page);
2542
2664
  let pending = workers.length;
2543
2665
  if (pending === 0) resolve2(null);
2544
2666
  for (const worker of workers) {
@@ -2828,9 +2950,18 @@ async function automateWebViewFrames(context, names, helpers) {
2828
2950
  );
2829
2951
  return answer;
2830
2952
  };
2831
- await browserSession.send("Fetch.enable", {
2832
- patterns: [{ urlPattern: "*", requestStage: "Request" }]
2833
- });
2953
+ let pausesEveryRequest = null;
2954
+ const pauseRequests = async () => {
2955
+ const every = byInstance.size > 0;
2956
+ if (every === pausesEveryRequest) return;
2957
+ pausesEveryRequest = every;
2958
+ await browserSession.send("Fetch.enable", {
2959
+ patterns: [
2960
+ every ? { urlPattern: "*", requestStage: "Request" } : { urlPattern: "*", resourceType: "Document", requestStage: "Request" }
2961
+ ]
2962
+ });
2963
+ };
2964
+ await pauseRequests();
2834
2965
  browserSession.on("Fetch.requestPaused", (event) => {
2835
2966
  const requestId = event.requestId;
2836
2967
  const frameId = typeof event.frameId === "string" ? event.frameId : "";
@@ -2965,18 +3096,18 @@ async function automateWebViewFrames(context, names, helpers) {
2965
3096
  responseHeaders: helpers.withFrameEmbedderHeaders(helpers.withoutFramingRefusals(received)).filter((header) => !/^content-(encoding|length)$/i.test(header.name)),
2966
3097
  body: ""
2967
3098
  });
2968
- const location = received.find((header) => header.name.toLowerCase() === "location");
2969
- if (location) {
3099
+ const location2 = received.find((header) => header.name.toLowerCase() === "location");
3100
+ if (location2) {
2970
3101
  let target = "";
2971
3102
  try {
2972
- target = new URL(location.value, event.request.url).href;
3103
+ target = new URL(location2.value, event.request.url).href;
2973
3104
  } catch {
2974
3105
  }
2975
3106
  if (helpers.isAppScheme(target))
2976
3107
  reportSchemeNavigation(bound.page, bound.instanceId, target);
2977
3108
  }
2978
- if (bound.navigation && location) {
2979
- const target = new URL(location.value, event.request.url).href;
3109
+ if (bound.navigation && location2) {
3110
+ const target = new URL(location2.value, event.request.url).href;
2980
3111
  if (bound.load) {
2981
3112
  const discardBody = (status === 301 || status === 302) && bound.load.method === "POST" || status === 303 && bound.load.method !== "HEAD";
2982
3113
  bound.load = {
@@ -3088,6 +3219,7 @@ async function automateWebViewFrames(context, names, helpers) {
3088
3219
  });
3089
3220
  }
3090
3221
  byInstance.delete(request.instanceId);
3222
+ await pauseRequests();
3091
3223
  return;
3092
3224
  }
3093
3225
  if (request.kind === "tap") {
@@ -3151,6 +3283,7 @@ async function automateWebViewFrames(context, names, helpers) {
3151
3283
  };
3152
3284
  byFrameId.set(frameId, bound);
3153
3285
  byInstance.set(request.instanceId, bound);
3286
+ await pauseRequests();
3154
3287
  await followFrameProcesses(source.page);
3155
3288
  if (request.beforeContent && !beforeKeys.has(request.beforeKey)) {
3156
3289
  beforeKeys.add(request.beforeKey);
@@ -3370,6 +3503,42 @@ ${WEBVIEW_FRAME_COLOR_SCHEME_SOURCE} var webKit = config.webKit || null;
3370
3503
  setMessageHandlers(webKit.messageHandlers);
3371
3504
  }
3372
3505
  var userScripts = (webKit ? webKit.userScripts : []).slice();
3506
+ if (webKit) {
3507
+ var themeColorFramePending = false;
3508
+ var reportedThemeColor;
3509
+ var themeColorContext;
3510
+ function reportThemeColor() {
3511
+ themeColorFramePending = false;
3512
+ var meta = document.querySelector('meta[name="theme-color"]');
3513
+ var content = meta && meta.getAttribute('content');
3514
+ var color = null;
3515
+ if (content && CSS.supports('color', content)) {
3516
+ if (!themeColorContext) {
3517
+ var canvas = document.createElement('canvas');
3518
+ canvas.width = canvas.height = 1;
3519
+ themeColorContext = canvas.getContext('2d', { willReadFrequently: true });
3520
+ if (!themeColorContext) throw new Error('WKWebView theme color has no color context');
3521
+ }
3522
+ themeColorContext.clearRect(0, 0, 1, 1);
3523
+ themeColorContext.fillStyle = content;
3524
+ themeColorContext.fillRect(0, 0, 1, 1);
3525
+ color = Array.from(themeColorContext.getImageData(0, 0, 1, 1).data, function(value) { return value / 255; });
3526
+ }
3527
+ var serialized = JSON.stringify(color);
3528
+ if (serialized === reportedThemeColor) return;
3529
+ reportedThemeColor = serialized;
3530
+ window.parent.postMessage({ __sootsimWebViewKind: 'webKitThemeColor', navigation: webKit.navigation, color: color }, '*');
3531
+ }
3532
+ function scheduleThemeColor() {
3533
+ if (document.readyState !== 'complete' || themeColorFramePending) return;
3534
+ themeColorFramePending = true;
3535
+ requestAnimationFrame(reportThemeColor);
3536
+ }
3537
+ document.addEventListener('DOMContentLoaded', function() {
3538
+ new MutationObserver(scheduleThemeColor).observe(document.head, { childList: true, subtree: true, attributes: true, attributeFilter: ['name', 'content', 'media'] });
3539
+ }, { once: true });
3540
+ window.addEventListener('load', scheduleThemeColor, { once: true });
3541
+ }
3373
3542
  userScripts.filter(function(script) { return script.time === 0; }).forEach(function(script) { (0,eval)(script.source); });
3374
3543
  document.addEventListener('DOMContentLoaded', function() {
3375
3544
  userScripts.filter(function(script) { return script.time === 1; }).forEach(function(script) { (0,eval)(script.source); });
@@ -3587,7 +3756,8 @@ ${WEBVIEW_FRAME_COLOR_SCHEME_SOURCE} var webKit = config.webKit || null;
3587
3756
  } catch (_) {
3588
3757
  return;
3589
3758
  }
3590
- if (target.origin === base.origin &&
3759
+ var shouldPerformDownload = anchor.hasAttribute('download');
3760
+ if (!shouldPerformDownload && target.origin === base.origin &&
3591
3761
  target.pathname === base.pathname &&
3592
3762
  target.search === base.search) {
3593
3763
  // the document carries a <base href> for source.baseUrl, so the
@@ -3618,6 +3788,7 @@ ${WEBVIEW_FRAME_COLOR_SCHEME_SOURCE} var webKit = config.webKit || null;
3618
3788
  requestId: requestId,
3619
3789
  url: String(target),
3620
3790
  navigationType: 'click',
3791
+ shouldPerformDownload: shouldPerformDownload,
3621
3792
  sameDocument: false
3622
3793
  }, '*');
3623
3794
  });
@@ -4227,11 +4398,31 @@ var AUTOMATION_SIM_IDLE_REAP_TTL_MS = 5 * 6e4;
4227
4398
  // src/home-paths.ts
4228
4399
  var DAEMON_LOCKFILE_MAX_BYTES = 16 * 1024;
4229
4400
 
4401
+ // ../peach-engine/src/tenant-bundle-mode.ts
4402
+ var import_metro_production_bundle = require("peachsim/metro-production-bundle");
4403
+
4404
+ // ../peach-engine/src/development-mode.ts
4405
+ var bridgeConstants = __toESM(require("peachsim/bridge-constants"), 1);
4406
+
4407
+ // ../peach-engine/src/tenant-runtime-environment.ts
4408
+ function readBrowserLocation() {
4409
+ try {
4410
+ return typeof location === "undefined" ? null : location;
4411
+ } catch {
4412
+ return null;
4413
+ }
4414
+ }
4415
+ var nativeRuntimeLocation = readBrowserLocation();
4416
+
4417
+ // ../peach-engine/src/development-mode.ts
4418
+ var { DEFAULT_SOOTSIM_BRIDGE_PORT: DEFAULT_SOOTSIM_BRIDGE_PORT2 } = bridgeConstants;
4419
+ var DAEMON_RUNTIME_PORT_MAX = DEFAULT_SOOTSIM_BRIDGE_PORT2 + 10;
4420
+
4230
4421
  // ../peach-engine/src/metro-fingerprint-registry-client.ts
4231
4422
  var import_metro_fingerprint_registry = require("peachsim/metro-fingerprint-registry");
4232
4423
 
4233
4424
  // ../peach-engine/src/metro-fingerprint.ts
4234
- var import_metro_production_bundle = require("peachsim/metro-production-bundle");
4425
+ var import_metro_production_bundle2 = require("peachsim/metro-production-bundle");
4235
4426
  var import_react_native_host_modules = require("peachsim/react-native-host-modules");
4236
4427
 
4237
4428
  // src/cloud-contract.ts
@@ -4359,17 +4550,17 @@ function visit(node, visitor) {
4359
4550
  visit.BREAK = BREAK;
4360
4551
  visit.SKIP = SKIP;
4361
4552
  visit.REMOVE = REMOVE;
4362
- function visit_(key, node, visitor, path2) {
4363
- const ctrl = callVisitor(key, node, visitor, path2);
4553
+ function visit_(key, node, visitor, path3) {
4554
+ const ctrl = callVisitor(key, node, visitor, path3);
4364
4555
  if (isNode(ctrl) || isPair(ctrl)) {
4365
- replaceNode(key, path2, ctrl);
4366
- return visit_(key, ctrl, visitor, path2);
4556
+ replaceNode(key, path3, ctrl);
4557
+ return visit_(key, ctrl, visitor, path3);
4367
4558
  }
4368
4559
  if (typeof ctrl !== "symbol") {
4369
4560
  if (isCollection(node)) {
4370
- path2 = Object.freeze(path2.concat(node));
4561
+ path3 = Object.freeze(path3.concat(node));
4371
4562
  for (let i = 0; i < node.items.length; ++i) {
4372
- const ci = visit_(i, node.items[i], visitor, path2);
4563
+ const ci = visit_(i, node.items[i], visitor, path3);
4373
4564
  if (typeof ci === "number")
4374
4565
  i = ci - 1;
4375
4566
  else if (ci === BREAK)
@@ -4380,13 +4571,13 @@ function visit_(key, node, visitor, path2) {
4380
4571
  }
4381
4572
  }
4382
4573
  } else if (isPair(node)) {
4383
- path2 = Object.freeze(path2.concat(node));
4384
- const ck = visit_("key", node.key, visitor, path2);
4574
+ path3 = Object.freeze(path3.concat(node));
4575
+ const ck = visit_("key", node.key, visitor, path3);
4385
4576
  if (ck === BREAK)
4386
4577
  return BREAK;
4387
4578
  else if (ck === REMOVE)
4388
4579
  node.key = null;
4389
- const cv = visit_("value", node.value, visitor, path2);
4580
+ const cv = visit_("value", node.value, visitor, path3);
4390
4581
  if (cv === BREAK)
4391
4582
  return BREAK;
4392
4583
  else if (cv === REMOVE)
@@ -4407,17 +4598,17 @@ async function visitAsync(node, visitor) {
4407
4598
  visitAsync.BREAK = BREAK;
4408
4599
  visitAsync.SKIP = SKIP;
4409
4600
  visitAsync.REMOVE = REMOVE;
4410
- async function visitAsync_(key, node, visitor, path2) {
4411
- const ctrl = await callVisitor(key, node, visitor, path2);
4601
+ async function visitAsync_(key, node, visitor, path3) {
4602
+ const ctrl = await callVisitor(key, node, visitor, path3);
4412
4603
  if (isNode(ctrl) || isPair(ctrl)) {
4413
- replaceNode(key, path2, ctrl);
4414
- return visitAsync_(key, ctrl, visitor, path2);
4604
+ replaceNode(key, path3, ctrl);
4605
+ return visitAsync_(key, ctrl, visitor, path3);
4415
4606
  }
4416
4607
  if (typeof ctrl !== "symbol") {
4417
4608
  if (isCollection(node)) {
4418
- path2 = Object.freeze(path2.concat(node));
4609
+ path3 = Object.freeze(path3.concat(node));
4419
4610
  for (let i = 0; i < node.items.length; ++i) {
4420
- const ci = await visitAsync_(i, node.items[i], visitor, path2);
4611
+ const ci = await visitAsync_(i, node.items[i], visitor, path3);
4421
4612
  if (typeof ci === "number")
4422
4613
  i = ci - 1;
4423
4614
  else if (ci === BREAK)
@@ -4428,13 +4619,13 @@ async function visitAsync_(key, node, visitor, path2) {
4428
4619
  }
4429
4620
  }
4430
4621
  } else if (isPair(node)) {
4431
- path2 = Object.freeze(path2.concat(node));
4432
- const ck = await visitAsync_("key", node.key, visitor, path2);
4622
+ path3 = Object.freeze(path3.concat(node));
4623
+ const ck = await visitAsync_("key", node.key, visitor, path3);
4433
4624
  if (ck === BREAK)
4434
4625
  return BREAK;
4435
4626
  else if (ck === REMOVE)
4436
4627
  node.key = null;
4437
- const cv = await visitAsync_("value", node.value, visitor, path2);
4628
+ const cv = await visitAsync_("value", node.value, visitor, path3);
4438
4629
  if (cv === BREAK)
4439
4630
  return BREAK;
4440
4631
  else if (cv === REMOVE)
@@ -4461,23 +4652,23 @@ function initVisitor(visitor) {
4461
4652
  }
4462
4653
  return visitor;
4463
4654
  }
4464
- function callVisitor(key, node, visitor, path2) {
4655
+ function callVisitor(key, node, visitor, path3) {
4465
4656
  if (typeof visitor === "function")
4466
- return visitor(key, node, path2);
4657
+ return visitor(key, node, path3);
4467
4658
  if (isMap(node))
4468
- return visitor.Map?.(key, node, path2);
4659
+ return visitor.Map?.(key, node, path3);
4469
4660
  if (isSeq(node))
4470
- return visitor.Seq?.(key, node, path2);
4661
+ return visitor.Seq?.(key, node, path3);
4471
4662
  if (isPair(node))
4472
- return visitor.Pair?.(key, node, path2);
4663
+ return visitor.Pair?.(key, node, path3);
4473
4664
  if (isScalar(node))
4474
- return visitor.Scalar?.(key, node, path2);
4665
+ return visitor.Scalar?.(key, node, path3);
4475
4666
  if (isAlias(node))
4476
- return visitor.Alias?.(key, node, path2);
4667
+ return visitor.Alias?.(key, node, path3);
4477
4668
  return void 0;
4478
4669
  }
4479
- function replaceNode(key, path2, node) {
4480
- const parent = path2[path2.length - 1];
4670
+ function replaceNode(key, path3, node) {
4671
+ const parent = path3[path3.length - 1];
4481
4672
  if (isCollection(parent)) {
4482
4673
  parent.items[key] = node;
4483
4674
  } else if (isPair(parent)) {
@@ -4957,10 +5148,10 @@ function createNode(value, tagName, ctx) {
4957
5148
  }
4958
5149
 
4959
5150
  // ../../node_modules/yaml/browser/dist/nodes/Collection.js
4960
- function collectionFromPath(schema4, path2, value) {
5151
+ function collectionFromPath(schema4, path3, value) {
4961
5152
  let v = value;
4962
- for (let i = path2.length - 1; i >= 0; --i) {
4963
- const k = path2[i];
5153
+ for (let i = path3.length - 1; i >= 0; --i) {
5154
+ const k = path3[i];
4964
5155
  if (typeof k === "number" && Number.isInteger(k) && k >= 0) {
4965
5156
  const a = [];
4966
5157
  a[k] = v;
@@ -4979,7 +5170,7 @@ function collectionFromPath(schema4, path2, value) {
4979
5170
  sourceObjects: /* @__PURE__ */ new Map()
4980
5171
  });
4981
5172
  }
4982
- var isEmptyPath = (path2) => path2 == null || typeof path2 === "object" && !!path2[Symbol.iterator]().next().done;
5173
+ var isEmptyPath = (path3) => path3 == null || typeof path3 === "object" && !!path3[Symbol.iterator]().next().done;
4983
5174
  var Collection = class extends NodeBase {
4984
5175
  constructor(type, schema4) {
4985
5176
  super(type);
@@ -5009,11 +5200,11 @@ var Collection = class extends NodeBase {
5009
5200
  * be a Pair instance or a `{ key, value }` object, which may not have a key
5010
5201
  * that already exists in the map.
5011
5202
  */
5012
- addIn(path2, value) {
5013
- if (isEmptyPath(path2))
5203
+ addIn(path3, value) {
5204
+ if (isEmptyPath(path3))
5014
5205
  this.add(value);
5015
5206
  else {
5016
- const [key, ...rest] = path2;
5207
+ const [key, ...rest] = path3;
5017
5208
  const node = this.get(key, true);
5018
5209
  if (isCollection(node))
5019
5210
  node.addIn(rest, value);
@@ -5027,8 +5218,8 @@ var Collection = class extends NodeBase {
5027
5218
  * Removes a value from the collection.
5028
5219
  * @returns `true` if the item was found and removed.
5029
5220
  */
5030
- deleteIn(path2) {
5031
- const [key, ...rest] = path2;
5221
+ deleteIn(path3) {
5222
+ const [key, ...rest] = path3;
5032
5223
  if (rest.length === 0)
5033
5224
  return this.delete(key);
5034
5225
  const node = this.get(key, true);
@@ -5042,8 +5233,8 @@ var Collection = class extends NodeBase {
5042
5233
  * scalar values from their surrounding node; to disable set `keepScalar` to
5043
5234
  * `true` (collections are always returned intact).
5044
5235
  */
5045
- getIn(path2, keepScalar) {
5046
- const [key, ...rest] = path2;
5236
+ getIn(path3, keepScalar) {
5237
+ const [key, ...rest] = path3;
5047
5238
  const node = this.get(key, true);
5048
5239
  if (rest.length === 0)
5049
5240
  return !keepScalar && isScalar(node) ? node.value : node;
@@ -5061,8 +5252,8 @@ var Collection = class extends NodeBase {
5061
5252
  /**
5062
5253
  * Checks if the collection includes a value with the key `key`.
5063
5254
  */
5064
- hasIn(path2) {
5065
- const [key, ...rest] = path2;
5255
+ hasIn(path3) {
5256
+ const [key, ...rest] = path3;
5066
5257
  if (rest.length === 0)
5067
5258
  return this.has(key);
5068
5259
  const node = this.get(key, true);
@@ -5072,8 +5263,8 @@ var Collection = class extends NodeBase {
5072
5263
  * Sets a value in this collection. For `!!set`, `value` needs to be a
5073
5264
  * boolean to add/remove the item from the set.
5074
5265
  */
5075
- setIn(path2, value) {
5076
- const [key, ...rest] = path2;
5266
+ setIn(path3, value) {
5267
+ const [key, ...rest] = path3;
5077
5268
  if (rest.length === 0) {
5078
5269
  this.set(key, value);
5079
5270
  } else {
@@ -6522,9 +6713,9 @@ function visit2(cst, visitor) {
6522
6713
  visit2.BREAK = BREAK2;
6523
6714
  visit2.SKIP = SKIP2;
6524
6715
  visit2.REMOVE = REMOVE2;
6525
- visit2.itemAtPath = (cst, path2) => {
6716
+ visit2.itemAtPath = (cst, path3) => {
6526
6717
  let item = cst;
6527
- for (const [field, index] of path2) {
6718
+ for (const [field, index] of path3) {
6528
6719
  const tok = item?.[field];
6529
6720
  if (tok && "items" in tok) {
6530
6721
  item = tok.items[index];
@@ -6533,23 +6724,23 @@ visit2.itemAtPath = (cst, path2) => {
6533
6724
  }
6534
6725
  return item;
6535
6726
  };
6536
- visit2.parentCollection = (cst, path2) => {
6537
- const parent = visit2.itemAtPath(cst, path2.slice(0, -1));
6538
- const field = path2[path2.length - 1][0];
6727
+ visit2.parentCollection = (cst, path3) => {
6728
+ const parent = visit2.itemAtPath(cst, path3.slice(0, -1));
6729
+ const field = path3[path3.length - 1][0];
6539
6730
  const coll = parent?.[field];
6540
6731
  if (coll && "items" in coll)
6541
6732
  return coll;
6542
6733
  throw new Error("Parent collection not found");
6543
6734
  };
6544
- function _visit(path2, item, visitor) {
6545
- let ctrl = visitor(item, path2);
6735
+ function _visit(path3, item, visitor) {
6736
+ let ctrl = visitor(item, path3);
6546
6737
  if (typeof ctrl === "symbol")
6547
6738
  return ctrl;
6548
6739
  for (const field of ["key", "value"]) {
6549
6740
  const token = item[field];
6550
6741
  if (token && "items" in token) {
6551
6742
  for (let i = 0; i < token.items.length; ++i) {
6552
- const ci = _visit(Object.freeze(path2.concat([[field, i]])), token.items[i], visitor);
6743
+ const ci = _visit(Object.freeze(path3.concat([[field, i]])), token.items[i], visitor);
6553
6744
  if (typeof ci === "number")
6554
6745
  i = ci - 1;
6555
6746
  else if (ci === BREAK2)
@@ -6560,10 +6751,10 @@ function _visit(path2, item, visitor) {
6560
6751
  }
6561
6752
  }
6562
6753
  if (typeof ctrl === "function" && field === "key")
6563
- ctrl = ctrl(item, path2);
6754
+ ctrl = ctrl(item, path3);
6564
6755
  }
6565
6756
  }
6566
- return typeof ctrl === "function" ? ctrl(item, path2) : ctrl;
6757
+ return typeof ctrl === "function" ? ctrl(item, path3) : ctrl;
6567
6758
  }
6568
6759
 
6569
6760
  // ../../node_modules/yaml/browser/dist/parse/lexer.js
@@ -7370,6 +7561,196 @@ var RUNTIME_PLATFORM_ADAPTERS = Object.freeze({
7370
7561
  android: ANDROID_ADAPTER
7371
7562
  });
7372
7563
 
7564
+ // ../peach-engine/src/settings/dynamic-type.ts
7565
+ function textMetrics(fontSize, lineHeight, leading, ascent) {
7566
+ return Object.freeze({ fontSize, lineHeight, leading, ascent });
7567
+ }
7568
+ var IOS_UIKIT_TEXT_METRICS = Object.freeze({
7569
+ xs: Object.freeze({
7570
+ largeTitle: textMetrics(31, 36.994141, 1.005859, 29.516602),
7571
+ title1: textMetrics(25, 29.833984, 1.166016, 23.803711),
7572
+ title2: textMetrics(19, 22.673828, 1.326172, 18.09082),
7573
+ title3: textMetrics(17, 20.287109, 1.712891, 16.186523),
7574
+ headline: textMetrics(14, 16.707031, 2.292969, 13.330078),
7575
+ body: textMetrics(14, 16.707031, 2.292969, 13.330078),
7576
+ callout: textMetrics(13, 15.513672, 2.486328, 12.37793),
7577
+ subheadline: textMetrics(12, 14.320312, 1.679687, 11.425781),
7578
+ footnote: textMetrics(12, 14.320312, 1.679687, 11.425781),
7579
+ caption1: textMetrics(11, 13.126953, -0.126953, 10.473633),
7580
+ caption2: textMetrics(11, 13.126953, -0.126953, 10.473633)
7581
+ }),
7582
+ s: Object.freeze({
7583
+ largeTitle: textMetrics(32, 38.1875, 0.8125, 30.46875),
7584
+ title1: textMetrics(26, 31.027344, 0.972656, 24.755859),
7585
+ title2: textMetrics(20, 23.867188, 1.132812, 19.042969),
7586
+ title3: textMetrics(18, 21.480469, 1.519531, 17.138672),
7587
+ headline: textMetrics(15, 17.900391, 2.099609, 14.282227),
7588
+ body: textMetrics(15, 17.900391, 2.099609, 14.282227),
7589
+ callout: textMetrics(14, 16.707031, 2.292969, 13.330078),
7590
+ subheadline: textMetrics(13, 15.513672, 2.486328, 12.37793),
7591
+ footnote: textMetrics(12, 14.320312, 1.679687, 11.425781),
7592
+ caption1: textMetrics(11, 13.126953, -0.126953, 10.473633),
7593
+ caption2: textMetrics(11, 13.126953, -0.126953, 10.473633)
7594
+ }),
7595
+ m: Object.freeze({
7596
+ largeTitle: textMetrics(33, 39.380859, 0.619141, 31.420898),
7597
+ title1: textMetrics(27, 32.220703, 0.779297, 25.708008),
7598
+ title2: textMetrics(21, 25.060547, 0.939453, 19.995117),
7599
+ title3: textMetrics(19, 22.673828, 1.326172, 18.09082),
7600
+ headline: textMetrics(16, 19.09375, 1.90625, 15.234375),
7601
+ body: textMetrics(16, 19.09375, 1.90625, 15.234375),
7602
+ callout: textMetrics(15, 17.900391, 2.099609, 14.282227),
7603
+ subheadline: textMetrics(14, 16.707031, 2.292969, 13.330078),
7604
+ footnote: textMetrics(12, 14.320312, 1.679687, 11.425781),
7605
+ caption1: textMetrics(11, 13.126953, -0.126953, 10.473633),
7606
+ caption2: textMetrics(11, 13.126953, -0.126953, 10.473633)
7607
+ }),
7608
+ l: Object.freeze({
7609
+ largeTitle: textMetrics(34, 40.574219, 0.425781, 32.373047),
7610
+ title1: textMetrics(28, 33.414062, 0.585937, 26.660156),
7611
+ title2: textMetrics(22, 26.253906, 1.746094, 20.947266),
7612
+ title3: textMetrics(20, 23.867188, 1.132812, 19.042969),
7613
+ headline: textMetrics(17, 20.287109, 1.712891, 16.186523),
7614
+ body: textMetrics(17, 20.287109, 1.712891, 16.186523),
7615
+ callout: textMetrics(16, 19.09375, 1.90625, 15.234375),
7616
+ subheadline: textMetrics(15, 17.900391, 2.099609, 14.282227),
7617
+ footnote: textMetrics(13, 15.513672, 2.486328, 12.37793),
7618
+ caption1: textMetrics(12, 14.320312, 1.679687, 11.425781),
7619
+ caption2: textMetrics(11, 13.126953, -0.126953, 10.473633)
7620
+ }),
7621
+ xl: Object.freeze({
7622
+ largeTitle: textMetrics(36, 42.960938, 0.039062, 34.277344),
7623
+ title1: textMetrics(30, 35.800781, 0.199219, 28.564453),
7624
+ title2: textMetrics(24, 28.640625, 1.359375, 22.851562),
7625
+ title3: textMetrics(22, 26.253906, 1.746094, 20.947266),
7626
+ headline: textMetrics(19, 22.673828, 1.326172, 18.09082),
7627
+ body: textMetrics(19, 22.673828, 1.326172, 18.09082),
7628
+ callout: textMetrics(18, 21.480469, 1.519531, 17.138672),
7629
+ subheadline: textMetrics(17, 20.287109, 1.712891, 16.186523),
7630
+ footnote: textMetrics(15, 17.900391, 2.099609, 14.282227),
7631
+ caption1: textMetrics(14, 16.707031, 2.292969, 13.330078),
7632
+ caption2: textMetrics(13, 15.513672, 2.486328, 12.37793)
7633
+ }),
7634
+ xxl: Object.freeze({
7635
+ largeTitle: textMetrics(38, 45.347656, 0.652344, 36.181641),
7636
+ title1: textMetrics(32, 38.1875, -0.1875, 30.46875),
7637
+ title2: textMetrics(26, 31.027344, 0.972656, 24.755859),
7638
+ title3: textMetrics(24, 28.640625, 1.359375, 22.851562),
7639
+ headline: textMetrics(21, 25.060547, 0.939453, 19.995117),
7640
+ body: textMetrics(21, 25.060547, 0.939453, 19.995117),
7641
+ callout: textMetrics(20, 23.867188, 1.132812, 19.042969),
7642
+ subheadline: textMetrics(19, 22.673828, 1.326172, 18.09082),
7643
+ footnote: textMetrics(17, 20.287109, 1.712891, 16.186523),
7644
+ caption1: textMetrics(16, 19.09375, 1.90625, 15.234375),
7645
+ caption2: textMetrics(15, 17.900391, 2.099609, 14.282227)
7646
+ }),
7647
+ xxxl: Object.freeze({
7648
+ largeTitle: textMetrics(40, 47.734375, 0.265625, 38.085938),
7649
+ title1: textMetrics(34, 40.574219, 0.425781, 32.373047),
7650
+ title2: textMetrics(28, 33.414062, 0.585937, 26.660156),
7651
+ title3: textMetrics(26, 31.027344, 0.972656, 24.755859),
7652
+ headline: textMetrics(23, 27.447266, 1.552734, 21.899414),
7653
+ body: textMetrics(23, 27.447266, 1.552734, 21.899414),
7654
+ callout: textMetrics(22, 26.253906, 1.746094, 20.947266),
7655
+ subheadline: textMetrics(21, 25.060547, 0.939453, 19.995117),
7656
+ footnote: textMetrics(19, 22.673828, 1.326172, 18.09082),
7657
+ caption1: textMetrics(18, 21.480469, 1.519531, 17.138672),
7658
+ caption2: textMetrics(17, 20.287109, 1.712891, 16.186523)
7659
+ }),
7660
+ ax1: Object.freeze({
7661
+ largeTitle: textMetrics(44, 52.507812, -0.507812, 41.894531),
7662
+ title1: textMetrics(38, 45.347656, 0.652344, 36.181641),
7663
+ title2: textMetrics(34, 40.574219, 0.425781, 32.373047),
7664
+ title3: textMetrics(31, 36.994141, 1.005859, 29.516602),
7665
+ headline: textMetrics(28, 33.414062, 0.585937, 26.660156),
7666
+ body: textMetrics(28, 33.414062, 0.585937, 26.660156),
7667
+ callout: textMetrics(26, 31.027344, 0.972656, 24.755859),
7668
+ subheadline: textMetrics(25, 29.833984, 1.166016, 23.803711),
7669
+ footnote: textMetrics(23, 27.447266, 1.552734, 21.899414),
7670
+ caption1: textMetrics(22, 26.253906, 0.746094, 20.947266),
7671
+ caption2: textMetrics(20, 23.867188, 1.132812, 19.042969)
7672
+ }),
7673
+ ax2: Object.freeze({
7674
+ largeTitle: textMetrics(48, 57.28125, -0.28125, 45.703125),
7675
+ title1: textMetrics(43, 51.314453, -0.314453, 40.942383),
7676
+ title2: textMetrics(39, 46.541016, 0.458984, 37.133789),
7677
+ title3: textMetrics(37, 44.154297, -0.154297, 35.229492),
7678
+ headline: textMetrics(33, 39.380859, 0.619141, 31.420898),
7679
+ body: textMetrics(33, 39.380859, 0.619141, 31.420898),
7680
+ callout: textMetrics(32, 38.1875, 0.8125, 30.46875),
7681
+ subheadline: textMetrics(30, 35.800781, 0.199219, 28.564453),
7682
+ footnote: textMetrics(27, 32.220703, 0.779297, 25.708008),
7683
+ caption1: textMetrics(26, 31.027344, 0.972656, 24.755859),
7684
+ caption2: textMetrics(24, 28.640625, 0.359375, 22.851562)
7685
+ }),
7686
+ ax3: Object.freeze({
7687
+ largeTitle: textMetrics(52, 62.054688, -1.054687, 49.511719),
7688
+ title1: textMetrics(48, 57.28125, -0.28125, 45.703125),
7689
+ title2: textMetrics(44, 52.507812, -0.507812, 41.894531),
7690
+ title3: textMetrics(43, 51.314453, -0.314453, 40.942383),
7691
+ headline: textMetrics(40, 47.734375, 0.265625, 38.085938),
7692
+ body: textMetrics(40, 47.734375, 0.265625, 38.085938),
7693
+ callout: textMetrics(38, 45.347656, 0.652344, 36.181641),
7694
+ subheadline: textMetrics(36, 42.960938, 0.039062, 34.277344),
7695
+ footnote: textMetrics(33, 39.380859, 0.619141, 31.420898),
7696
+ caption1: textMetrics(32, 38.1875, 0.8125, 30.46875),
7697
+ caption2: textMetrics(29, 34.607422, 0.392578, 27.612305)
7698
+ }),
7699
+ ax4: Object.freeze({
7700
+ largeTitle: textMetrics(56, 66.828125, -0.828125, 53.320312),
7701
+ title1: textMetrics(53, 63.248047, -2.248047, 50.463867),
7702
+ title2: textMetrics(50, 59.667969, -0.667969, 47.607422),
7703
+ title3: textMetrics(49, 58.474609, -0.474609, 46.655273),
7704
+ headline: textMetrics(47, 56.087891, -5.087891, 44.750977),
7705
+ body: textMetrics(47, 56.087891, -0.087891, 44.750977),
7706
+ callout: textMetrics(44, 52.507812, -0.507812, 41.894531),
7707
+ subheadline: textMetrics(42, 50.121094, -0.121094, 39.990234),
7708
+ footnote: textMetrics(38, 45.347656, 0.652344, 36.181641),
7709
+ caption1: textMetrics(37, 44.154297, -0.154297, 35.229492),
7710
+ caption2: textMetrics(34, 40.574219, 0.425781, 32.373047)
7711
+ }),
7712
+ ax5: Object.freeze({
7713
+ largeTitle: textMetrics(60, 71.601562, -1.601562, 57.128906),
7714
+ title1: textMetrics(58, 69.214844, -1.214844, 55.224609),
7715
+ title2: textMetrics(56, 66.828125, -0.828125, 53.320312),
7716
+ title3: textMetrics(55, 65.634766, -0.634766, 52.368164),
7717
+ headline: textMetrics(53, 63.248047, -1.248047, 50.463867),
7718
+ body: textMetrics(53, 63.248047, -1.248047, 50.463867),
7719
+ callout: textMetrics(51, 60.861328, -0.861328, 48.55957),
7720
+ subheadline: textMetrics(49, 58.474609, -0.474609, 46.655273),
7721
+ footnote: textMetrics(44, 52.507812, -0.507812, 41.894531),
7722
+ caption1: textMetrics(43, 51.314453, -0.314453, 40.942383),
7723
+ caption2: textMetrics(40, 47.734375, 0.265625, 38.085938)
7724
+ })
7725
+ });
7726
+
7727
+ // ../peach-engine/src/settings/react-native-configuration-values.ts
7728
+ var DEFAULT_REACT_NATIVE_CONFIGURATION = {
7729
+ // the appearance setting itself (automatic, light or dark); the resolved
7730
+ // scheme reaches workers through Appearance
7731
+ colorScheme: "auto",
7732
+ language: "en",
7733
+ region: "US",
7734
+ fontSize: 1,
7735
+ boldText: false,
7736
+ reduceMotion: false,
7737
+ largerAccessibilitySizes: false,
7738
+ glassTintAmount: 0.5,
7739
+ reduceTransparency: false,
7740
+ increaseContrast: false,
7741
+ showBorders: false,
7742
+ onOffLabels: false,
7743
+ differentiateWithoutColor: false,
7744
+ smartInvert: false,
7745
+ preferCrossFadeTransitions: false
7746
+ };
7747
+ var REACT_NATIVE_CONFIGURATION_KEYS = Object.keys(
7748
+ DEFAULT_REACT_NATIVE_CONFIGURATION
7749
+ ).filter(
7750
+ (key) => key in DEFAULT_REACT_NATIVE_CONFIGURATION
7751
+ );
7752
+ var snapshot = { ...DEFAULT_REACT_NATIVE_CONFIGURATION };
7753
+
7373
7754
  // ../peach-engine/src/engine/generated/language-font-manifest.ts
7374
7755
  var LANGUAGE_FONT_SUBSETS = [
7375
7756
  {
@@ -7705,7 +8086,7 @@ var LANGUAGE_FONT_SUBSETS = [
7705
8086
  ];
7706
8087
 
7707
8088
  // ../peach-engine/src/engine/generated/sf-pro-font.ts
7708
- var SF_PRO_FONT_URL = "/fonts/sf-pro.ttf?sha256=ba43865c3955d7d30888927bfdfef2476c932f9b930b5ad6adb50c33ac6a8de0";
8089
+ var SF_PRO_FONT_URL = "/fonts/sf-pro.ttf?sha256=c9bc31c271370f706950ecb918dec10776e546f5896ccb76fec2cda2368a84cb";
7709
8090
 
7710
8091
  // ../peach-engine/src/engine/font-config.ts
7711
8092
  var DEFAULT_FONT_FAMILY = "SF Pro";
@@ -7861,6 +8242,13 @@ var IOS_NAMED_FACES = [
7861
8242
  xHeight: 517
7862
8243
  })
7863
8244
  ];
8245
+ var IOS_FONT_DATA_FILES = new Map([
8246
+ ...IOS_NAMED_FACES.map(
8247
+ (face) => [face.postScript, face.file]
8248
+ ),
8249
+ ["Helvetica", "helvetica-regular.woff2"],
8250
+ ["Helvetica-Bold", "helvetica-bold.woff2"]
8251
+ ]);
7864
8252
  var EMOJI_FONT_FAMILY = "SootSimEmojiMetrics";
7865
8253
  var LANGUAGE_FONT_FAMILY_LIST = LANGUAGE_FONT_SUBSETS.filter(
7866
8254
  (s) => s.shaping === "ok"
@@ -8866,7 +9254,7 @@ function getSootsimNavigationDiagnostics(page) {
8866
9254
  // detox/index.ts
8867
9255
  var import_proof_frame = __toESM(require_proof_frame(), 1);
8868
9256
  var BASE_URL = process.env.PEACH_URL || "http://localhost:5173";
8869
- var SCREENSHOT_DIR = process.env.PEACH_SCREENSHOT_DIR || path.join(process.cwd(), "test", "detox-driver", "screenshots", String(process.pid));
9257
+ var SCREENSHOT_DIR = process.env.PEACH_SCREENSHOT_DIR || path2.join(process.cwd(), "test", "detox-driver", "screenshots", String(process.pid));
8870
9258
  var _browser = null;
8871
9259
  var _reapBrowserNow = null;
8872
9260
  var _context = null;
@@ -8939,14 +9327,14 @@ async function waitForSootsimSurfaceMetrics(page, timeout = 3e4) {
8939
9327
  if (!windowValue || typeof windowValue !== "object") return null;
8940
9328
  return windowValue;
8941
9329
  };
8942
- const snapshot = await window.__sootsimTest?.getSurfaceMetricsSnapshot?.();
8943
- const windowMetrics = metricsWindow(snapshot);
9330
+ const snapshot2 = await window.__sootsimTest?.getSurfaceMetricsSnapshot?.();
9331
+ const windowMetrics = metricsWindow(snapshot2);
8944
9332
  const width = windowMetrics?.width;
8945
9333
  const height = windowMetrics?.height;
8946
9334
  if (typeof width === "number" && typeof height === "number" && width > 0 && height > 0) {
8947
9335
  return { ready: true };
8948
9336
  }
8949
- return { ready: false, snapshot };
9337
+ return { ready: false, snapshot: snapshot2 };
8950
9338
  });
8951
9339
  if (lastSnapshot && typeof lastSnapshot === "object" && lastSnapshot.ready) {
8952
9340
  return;
@@ -9275,15 +9663,15 @@ async function waitForSootsimIdle(page, maxMs = 3e3, strict = false, transitionS
9275
9663
  let stable = 0;
9276
9664
  let lastSnapshot = null;
9277
9665
  while (Date.now() < deadline) {
9278
- const snapshot = await readSnapshot();
9279
- lastSnapshot = snapshot;
9280
- if ((!strict2 || snapshot.renderStatsAvailable) && !snapshot.animating && !snapshot.layoutDirty && !snapshot.webViewStarting && isLayoutStable(stableLayout, snapshot.layout)) {
9666
+ const snapshot2 = await readSnapshot();
9667
+ lastSnapshot = snapshot2;
9668
+ if ((!strict2 || snapshot2.renderStatsAvailable) && !snapshot2.animating && !snapshot2.layoutDirty && !snapshot2.webViewStarting && isLayoutStable(stableLayout, snapshot2.layout)) {
9281
9669
  stable++;
9282
9670
  if (stable >= requiredStablePolls) {
9283
9671
  return { settled: true, elapsed: Date.now() - start };
9284
9672
  }
9285
9673
  } else {
9286
- stableLayout = snapshot.layout;
9674
+ stableLayout = snapshot2.layout;
9287
9675
  stable = 0;
9288
9676
  }
9289
9677
  await sleep(pollMs);
@@ -9414,8 +9802,8 @@ async function focusElementForTextEntry(el) {
9414
9802
  );
9415
9803
  }
9416
9804
  function ensureScreenshotDir() {
9417
- if (!fs.existsSync(SCREENSHOT_DIR)) {
9418
- fs.mkdirSync(SCREENSHOT_DIR, { recursive: true });
9805
+ if (!fs2.existsSync(SCREENSHOT_DIR)) {
9806
+ fs2.mkdirSync(SCREENSHOT_DIR, { recursive: true });
9419
9807
  }
9420
9808
  }
9421
9809
  function decodePngDataUrl(dataUrl) {
@@ -9431,8 +9819,8 @@ function writeFastScreenshotFrames(namePrefix, frames) {
9431
9819
  ensureScreenshotDir();
9432
9820
  return frames.map((frame) => {
9433
9821
  const safeName = `${namePrefix}-${frame.label}`.replace(/[^a-zA-Z0-9._-]+/g, "-");
9434
- const filePath = path.join(SCREENSHOT_DIR, `${safeName}.png`);
9435
- fs.writeFileSync(filePath, decodePngDataUrl(frame.dataUrl));
9822
+ const filePath = path2.join(SCREENSHOT_DIR, `${safeName}.png`);
9823
+ fs2.writeFileSync(filePath, decodePngDataUrl(frame.dataUrl));
9436
9824
  const { dataUrl: _dataUrl, ...metadata } = frame;
9437
9825
  return {
9438
9826
  ...metadata,
@@ -9500,8 +9888,8 @@ async function captureSootsimPng(opts) {
9500
9888
  }
9501
9889
  async function writeSootsimScreenshot(name2, opts) {
9502
9890
  ensureScreenshotDir();
9503
- const screenshotPath = path.join(SCREENSHOT_DIR, `${name2}.png`);
9504
- fs.writeFileSync(screenshotPath, await captureSootsimPng(opts));
9891
+ const screenshotPath = path2.join(SCREENSHOT_DIR, `${name2}.png`);
9892
+ fs2.writeFileSync(screenshotPath, await captureSootsimPng(opts));
9505
9893
  return screenshotPath;
9506
9894
  }
9507
9895
  async function dispatchStatusBarOverride(config) {
@@ -10176,10 +10564,10 @@ var device = {
10176
10564
  }
10177
10565
  if (!_browser) {
10178
10566
  const executablePath = import_playwright_core.chromium.executablePath();
10179
- if (!fs.existsSync(executablePath)) {
10180
- const requireDriver = (0, import_node_module.createRequire)(path.join(__dirname, "index.cjs"));
10181
- const cliPath = path.join(
10182
- path.dirname(requireDriver.resolve("playwright-core/package.json")),
10567
+ if (!fs2.existsSync(executablePath)) {
10568
+ const requireDriver = (0, import_node_module.createRequire)(path2.join(__dirname, "index.cjs"));
10569
+ const cliPath = path2.join(
10570
+ path2.dirname(requireDriver.resolve("playwright-core/package.json")),
10183
10571
  "cli.js"
10184
10572
  );
10185
10573
  try {
@@ -10211,7 +10599,7 @@ var device = {
10211
10599
  viewport: { width: 500, height: 900 }
10212
10600
  };
10213
10601
  if (opts?.recordVideoDir) {
10214
- fs.mkdirSync(opts.recordVideoDir, { recursive: true });
10602
+ fs2.mkdirSync(opts.recordVideoDir, { recursive: true });
10215
10603
  contextOpts.recordVideo = {
10216
10604
  dir: opts.recordVideoDir,
10217
10605
  size: { width: 500, height: 900 }
@@ -10235,7 +10623,8 @@ var device = {
10235
10623
  `peachwv${(0, import_crypto.randomBytes)(12).toString("hex")}`,
10236
10624
  WEBVIEW_HOST_BOOTSTRAP_SOURCE
10237
10625
  ),
10238
- webViewAutomationHelpers
10626
+ webViewAutomationHelpers,
10627
+ (page) => page.workers()
10239
10628
  );
10240
10629
  await _context.exposeBinding("__sootsimHostCapture", async (source, value) => {
10241
10630
  const request = readBrowserCompositeCaptureRequest(value);
@@ -10337,8 +10726,8 @@ var device = {
10337
10726
  // frame-stability poll so callers can sample mid-transition.
10338
10727
  async takeScreenshotFast(name2) {
10339
10728
  ensureScreenshotDir();
10340
- const screenshotPath = path.join(SCREENSHOT_DIR, `${name2}.png`);
10341
- fs.writeFileSync(screenshotPath, await captureSootsimPngFast());
10729
+ const screenshotPath = path2.join(SCREENSHOT_DIR, `${name2}.png`);
10730
+ fs2.writeFileSync(screenshotPath, await captureSootsimPngFast());
10342
10731
  return screenshotPath;
10343
10732
  },
10344
10733
  // record the SootSim canvas via the engine's headless recorder
@@ -10408,8 +10797,8 @@ var device = {
10408
10797
  offset = result.offset;
10409
10798
  if (result.done) break;
10410
10799
  }
10411
- fs.mkdirSync(path.dirname(outPath), { recursive: true });
10412
- fs.writeFileSync(outPath, Buffer.concat(chunks));
10800
+ fs2.mkdirSync(path2.dirname(outPath), { recursive: true });
10801
+ fs2.writeFileSync(outPath, Buffer.concat(chunks));
10413
10802
  this._lastRecordingPath = outPath;
10414
10803
  return outPath;
10415
10804
  },
@@ -10499,22 +10888,22 @@ var device = {
10499
10888
  );
10500
10889
  return context.getImageData(0, 0, bounds.width, bounds.height).data;
10501
10890
  };
10502
- const encode = (snapshot) => {
10891
+ const encode = (snapshot2) => {
10503
10892
  const canvas = document.createElement("canvas");
10504
- canvas.width = snapshot.bitmap.width;
10505
- canvas.height = snapshot.bitmap.height;
10893
+ canvas.width = snapshot2.bitmap.width;
10894
+ canvas.height = snapshot2.bitmap.height;
10506
10895
  const context = canvas.getContext("2d");
10507
10896
  if (!context) throw new Error("peach motion capture needs a 2d canvas");
10508
- context.drawImage(snapshot.bitmap, 0, 0);
10509
- snapshot.bitmap.close();
10897
+ context.drawImage(snapshot2.bitmap, 0, 0);
10898
+ snapshot2.bitmap.close();
10510
10899
  return {
10511
- actualMs: snapshot.actualMs,
10512
- anchorId: snapshot.anchorId,
10900
+ actualMs: snapshot2.actualMs,
10901
+ anchorId: snapshot2.anchorId,
10513
10902
  dataUrl: canvas.toDataURL("image/png"),
10514
- label: snapshot.label,
10515
- offsetMs: snapshot.offsetMs,
10516
- frameIndex: snapshot.frameIndex,
10517
- virtualTimestampMs: snapshot.virtualTimestampMs
10903
+ label: snapshot2.label,
10904
+ offsetMs: snapshot2.offsetMs,
10905
+ frameIndex: snapshot2.frameIndex,
10906
+ virtualTimestampMs: snapshot2.virtualTimestampMs
10518
10907
  };
10519
10908
  };
10520
10909
  const interact = captureWindow.SootSim?.bridges?.interact;
@@ -10591,6 +10980,7 @@ var device = {
10591
10980
  let detectedMeasurement = null;
10592
10981
  let previousBitmap = null;
10593
10982
  if (input.platform === "android") {
10983
+ const receipt = await controller.flushFrame();
10594
10984
  const candidateBitmap = await captureBitmap();
10595
10985
  const bounds = boundsFor(candidateBitmap);
10596
10986
  const measurement = measureChange({
@@ -10602,7 +10992,7 @@ var device = {
10602
10992
  width: bounds.width
10603
10993
  });
10604
10994
  if (measurement.passedMinimum) {
10605
- visibleStart = controller.initialFrame;
10995
+ visibleStart = receipt;
10606
10996
  detectedMeasurement = measurement;
10607
10997
  keptFrames.set(visibleStart.frameIndex, candidateBitmap);
10608
10998
  } else {
@@ -10769,9 +11159,9 @@ var device = {
10769
11159
  }
10770
11160
  if (input.settleMs > 0) {
10771
11161
  const maximumPrimaryMs = snapshots.reduce(
10772
- (maximum, snapshot) => Math.max(
11162
+ (maximum, snapshot2) => Math.max(
10773
11163
  maximum,
10774
- snapshot.virtualTimestampMs - driveStart.virtualTimestampMs
11164
+ snapshot2.virtualTimestampMs - driveStart.virtualTimestampMs
10775
11165
  ),
10776
11166
  releasedOffsetMs
10777
11167
  );