peachsim 0.1.1406 → 0.1.1463

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 (149) 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 +22 -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 +322 -45
  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 +2959 -2780
  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 +1 -1
  100. package/dist-lib/worklet-executable.mjs +1 -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/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.1463 | (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;
@@ -398,9 +398,14 @@ function readExpoTypes(output) {
398
398
  };
399
399
  }),
400
400
  views: row.views.map((view) => {
401
- if (!isRecord(view) || typeof view.name !== "string" || typeof view.hidden !== "boolean" || typeof view.props !== "string")
401
+ if (!isRecord(view) || typeof view.name !== "string" || typeof view.hidden !== "boolean" || typeof view.props !== "string" || typeof view.appContext !== "boolean")
402
402
  throw new Error("expo-types printed an invalid view");
403
- return { name: view.name, hidden: view.hidden, props: view.props };
403
+ return {
404
+ name: view.name,
405
+ hidden: view.hidden,
406
+ props: view.props,
407
+ appContext: view.appContext
408
+ };
404
409
  }),
405
410
  props: row.props.map((entry) => {
406
411
  if (!isRecord(entry) || typeof entry.name !== "string" || typeof entry.hidden !== "boolean" || !Array.isArray(entry.states) || !entry.states.every((state) => typeof state === "string"))
@@ -413,7 +418,7 @@ function readExpoTypes(output) {
413
418
  var expoTypeScans = /* @__PURE__ */ new Map();
414
419
  function scanExpoTypes(toolchain, script, sources) {
415
420
  const candidates = sources.filter(
416
- (file) => /\bRecord\b|\benum\s+class\b|\bExpoComposeView\b|\bExpoView\b|\bComposeProps\b/.test(
421
+ (file) => /\bRecord\b|\benum\s+class\b|\bExpoComposeView\b|\bExpoView\b|\bComposeProps\b|:\s*(?:[A-Za-z0-9_.]+\.)?(?:View|FrameLayout|LinearLayout|ViewGroup)\b/.test(
417
422
  import_node_fs.default.readFileSync(file, "utf8")
418
423
  )
419
424
  );
@@ -494,7 +499,7 @@ function expoTypeSources(files) {
494
499
  }
495
500
  const views = [
496
501
  ...file.views.filter((view) => !view.hidden).map(
497
- (view) => ` dev.peach.expo.PeachExpoTypes.view(${view.name}::class, ${view.props ? `${view.props}::class` : "null"}) { context, appContext -> ${view.name}(context, appContext) }`
502
+ (view) => ` dev.peach.expo.PeachExpoTypes.view(${view.name}::class, ${view.props ? `${view.props}::class` : "null"}) { context, appContext -> ${view.name}(${view.appContext ? "context, appContext" : "context"}) }`
498
503
  ),
499
504
  ...file.props.filter((entry) => !entry.hidden).map(
500
505
  (entry) => [
package/dist-lib/menu.cjs CHANGED
@@ -1,4 +1,4 @@
1
- /*! peach v0.1.1406 | (c) 2026 Tamagui LLC | Proprietary; see LICENSE */
1
+ /*! peach v0.1.1463 | (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 __defProp = Object.defineProperty;
package/dist-lib/menu.mjs CHANGED
@@ -1,4 +1,4 @@
1
- /*! peach v0.1.1406 | (c) 2026 Tamagui LLC | Proprietary; see LICENSE */
1
+ /*! peach v0.1.1463 | (c) 2026 Tamagui LLC | Proprietary; see LICENSE */
2
2
 
3
3
  // src/public-brand.ts
4
4
  var name = "Peach";
@@ -1,4 +1,4 @@
1
- /*! peach v0.1.1406 | (c) 2026 Tamagui LLC | Proprietary; see LICENSE */
1
+ /*! peach v0.1.1463 | (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 __defProp = Object.defineProperty;
@@ -1,4 +1,4 @@
1
- /*! peach v0.1.1406 | (c) 2026 Tamagui LLC | Proprietary; see LICENSE */
1
+ /*! peach v0.1.1463 | (c) 2026 Tamagui LLC | Proprietary; see LICENSE */
2
2
 
3
3
  // src/is-record.ts
4
4
  function isRecord(value) {
@@ -1,4 +1,4 @@
1
- /*! peach v0.1.1406 | (c) 2026 Tamagui LLC | Proprietary; see LICENSE */
1
+ /*! peach v0.1.1463 | (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 __defProp = Object.defineProperty;
@@ -1,4 +1,4 @@
1
- /*! peach v0.1.1406 | (c) 2026 Tamagui LLC | Proprietary; see LICENSE */
1
+ /*! peach v0.1.1463 | (c) 2026 Tamagui LLC | Proprietary; see LICENSE */
2
2
 
3
3
  // src/metro-production-bundle.ts
4
4
  var RNXSIM_METRO_MODULE_PATHS_PREFIX = "globalThis.__sootsimModulePaths=";
@@ -1,4 +1,4 @@
1
- /*! peach v0.1.1406 | (c) 2026 Tamagui LLC | Proprietary; see LICENSE */
1
+ /*! peach v0.1.1463 | (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;
@@ -3964,59 +3964,61 @@ var import_node_fs6 = __toESM(require("node:fs"), 1);
3964
3964
  var import_node_os = __toESM(require("node:os"), 1);
3965
3965
  var import_node_path6 = __toESM(require("node:path"), 1);
3966
3966
  init_is_record();
3967
- function readNativeFirebaseConfig(projectRoot, platforms = ["ios", "android"], iosTarget) {
3968
- const result = {};
3969
- let config = {};
3970
- const appJsonPath = import_node_path6.default.join(projectRoot, "app.json");
3971
- const appJson = import_node_fs6.default.existsSync(appJsonPath) ? JSON.parse(import_node_fs6.default.readFileSync(appJsonPath, "utf8")) : null;
3972
- const staticExpo = isRecord3(appJson) && (isRecord3(appJson.expo) || [appJson.ios, appJson.android].some(
3973
- (value) => isRecord3(value) && typeof value.googleServicesFile === "string"
3974
- ));
3975
- const dynamicExpo = [
3976
- "app.config.js",
3977
- "app.config.ts",
3978
- "app.config.cjs",
3979
- "app.config.mjs"
3980
- ].some((name2) => import_node_fs6.default.existsSync(import_node_path6.default.join(projectRoot, name2)));
3981
- if (staticExpo || dynamicExpo) {
3982
- const directory = import_node_fs6.default.mkdtempSync(import_node_path6.default.join(import_node_os.default.tmpdir(), "peach-expo-config-"));
3983
- const resultPath = import_node_path6.default.join(directory, "config.json");
3984
- try {
3985
- const child = (0, import_node_child_process.spawnSync)(
3986
- "node",
3987
- [
3988
- "--input-type=commonjs",
3989
- "-e",
3990
- `const { createRequire } = require('node:module');
3967
+ var EXPO_CONFIG_SCRIPT = `const { createRequire } = require('node:module');
3991
3968
  const { writeFileSync } = require('node:fs');
3992
3969
  const { join } = require('node:path');
3993
3970
  const root = process.argv[1];
3994
3971
  const { getConfig } = createRequire(join(root, 'package.json'))('@expo/config');
3995
3972
  const result = JSON.stringify(getConfig(root, { skipSDKVersionRequirement: true }).exp);
3996
3973
  if (Buffer.byteLength(result) > 1024 * 1024) throw new Error('Expo native configuration exceeds 1 MiB.');
3997
- writeFileSync(process.argv[2], result, { mode: 0o600 });`,
3998
- import_node_path6.default.resolve(projectRoot),
3999
- resultPath
4000
- ],
4001
- {
4002
- cwd: projectRoot,
4003
- encoding: "utf8",
4004
- stdio: ["ignore", "ignore", "pipe"],
4005
- timeout: 3e4,
4006
- maxBuffer: 1024 * 1024
4007
- }
4008
- );
4009
- if (child.error) throw child.error;
4010
- if (child.status !== 0)
4011
- throw new Error(child.stderr || "Expo native configuration evaluation failed.");
4012
- const resolved = JSON.parse(import_node_fs6.default.readFileSync(resultPath, "utf8"));
4013
- if (!isRecord3(resolved))
4014
- throw new Error("Expo native configuration is unavailable.");
4015
- config = resolved;
4016
- } finally {
4017
- import_node_fs6.default.rmSync(directory, { recursive: true, force: true });
4018
- }
3974
+ writeFileSync(process.argv[2], result, { mode: 0o600 });`;
3975
+ function hasExpoConfig(projectRoot) {
3976
+ const appJsonPath = import_node_path6.default.join(projectRoot, "app.json");
3977
+ const appJson = import_node_fs6.default.existsSync(appJsonPath) ? JSON.parse(import_node_fs6.default.readFileSync(appJsonPath, "utf8")) : null;
3978
+ const staticExpo = isRecord3(appJson) && (isRecord3(appJson.expo) || [appJson.ios, appJson.android].some(
3979
+ (value) => isRecord3(value) && typeof value.googleServicesFile === "string"
3980
+ ));
3981
+ return staticExpo || ["app.config.js", "app.config.ts", "app.config.cjs", "app.config.mjs"].some(
3982
+ (name2) => import_node_fs6.default.existsSync(import_node_path6.default.join(projectRoot, name2))
3983
+ );
3984
+ }
3985
+ function expoConfigArgs(projectRoot, resultPath) {
3986
+ return [
3987
+ "--input-type=commonjs",
3988
+ "-e",
3989
+ EXPO_CONFIG_SCRIPT,
3990
+ import_node_path6.default.resolve(projectRoot),
3991
+ resultPath
3992
+ ];
3993
+ }
3994
+ function readExpoConfigResult(resultPath, status, stderr) {
3995
+ if (status !== 0)
3996
+ throw new Error(stderr || "Expo native configuration evaluation failed.");
3997
+ const resolved = JSON.parse(import_node_fs6.default.readFileSync(resultPath, "utf8"));
3998
+ if (!isRecord3(resolved)) throw new Error("Expo native configuration is unavailable.");
3999
+ return resolved;
4000
+ }
4001
+ var resultDirectory = () => import_node_fs6.default.mkdtempSync(import_node_path6.default.join(import_node_os.default.tmpdir(), "peach-expo-config-"));
4002
+ function readExpoConfig(projectRoot) {
4003
+ if (!hasExpoConfig(projectRoot)) return {};
4004
+ const directory = resultDirectory();
4005
+ const resultPath = import_node_path6.default.join(directory, "config.json");
4006
+ try {
4007
+ const child = (0, import_node_child_process.spawnSync)("node", expoConfigArgs(projectRoot, resultPath), {
4008
+ cwd: projectRoot,
4009
+ encoding: "utf8",
4010
+ stdio: ["ignore", "ignore", "pipe"],
4011
+ timeout: 3e4,
4012
+ maxBuffer: 1024 * 1024
4013
+ });
4014
+ if (child.error) throw child.error;
4015
+ return readExpoConfigResult(resultPath, child.status, child.stderr);
4016
+ } finally {
4017
+ import_node_fs6.default.rmSync(directory, { recursive: true, force: true });
4019
4018
  }
4019
+ }
4020
+ function readNativeFirebaseConfig(projectRoot, platforms = ["ios", "android"], iosTarget, config = readExpoConfig(projectRoot)) {
4021
+ const result = {};
4020
4022
  const ios = config.ios;
4021
4023
  if (platforms.includes("ios") && (!isRecord3(ios) || typeof ios.googleServicesFile !== "string")) {
4022
4024
  const iosRoot = import_node_path6.default.join(projectRoot, "ios");
@@ -1,4 +1,4 @@
1
- /*! peach v0.1.1406 | (c) 2026 Tamagui LLC | Proprietary; see LICENSE */
1
+ /*! peach v0.1.1463 | (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;
@@ -1,4 +1,4 @@
1
- /*! peach v0.1.1406 | (c) 2026 Tamagui LLC | Proprietary; see LICENSE */
1
+ /*! peach v0.1.1463 | (c) 2026 Tamagui LLC | Proprietary; see LICENSE */
2
2
 
3
3
  // src/native-app-identity-project.ts
4
4
  import fs2 from "node:fs";
@@ -1,4 +1,4 @@
1
- /*! peach v0.1.1406 | (c) 2026 Tamagui LLC | Proprietary; see LICENSE */
1
+ /*! peach v0.1.1463 | (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 __defProp = Object.defineProperty;
@@ -1,4 +1,4 @@
1
- /*! peach v0.1.1406 | (c) 2026 Tamagui LLC | Proprietary; see LICENSE */
1
+ /*! peach v0.1.1463 | (c) 2026 Tamagui LLC | Proprietary; see LICENSE */
2
2
 
3
3
  // src/openstep-plist.ts
4
4
  function parseOpenStepPlist(text) {
@@ -1,4 +1,4 @@
1
- /*! peach v0.1.1406 | (c) 2026 Tamagui LLC | Proprietary; see LICENSE */
1
+ /*! peach v0.1.1463 | (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 __defProp = Object.defineProperty;
@@ -1,4 +1,4 @@
1
- /*! peach v0.1.1406 | (c) 2026 Tamagui LLC | Proprietary; see LICENSE */
1
+ /*! peach v0.1.1463 | (c) 2026 Tamagui LLC | Proprietary; see LICENSE */
2
2
 
3
3
  // src/native-firebase-metadata.ts
4
4
  var PREFIX = "globalThis.__peachNativeFirebaseConfig=";
@@ -1,4 +1,4 @@
1
- /*! peach v0.1.1406 | (c) 2026 Tamagui LLC | Proprietary; see LICENSE */
1
+ /*! peach v0.1.1463 | (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;
@@ -1,4 +1,4 @@
1
- /*! peach v0.1.1406 | (c) 2026 Tamagui LLC | Proprietary; see LICENSE */
1
+ /*! peach v0.1.1463 | (c) 2026 Tamagui LLC | Proprietary; see LICENSE */
2
2
 
3
3
  // src/plist.ts
4
4
  import plist from "plist";
@@ -1,4 +1,4 @@
1
- /*! peach v0.1.1406 | (c) 2026 Tamagui LLC | Proprietary; see LICENSE */
1
+ /*! peach v0.1.1463 | (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;
@@ -1,4 +1,4 @@
1
- /*! peach v0.1.1406 | (c) 2026 Tamagui LLC | Proprietary; see LICENSE */
1
+ /*! peach v0.1.1463 | (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 __defProp = Object.defineProperty;
@@ -1,4 +1,4 @@
1
- /*! peach v0.1.1406 | (c) 2026 Tamagui LLC | Proprietary; see LICENSE */
1
+ /*! peach v0.1.1463 | (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 __defProp = Object.defineProperty;
@@ -1,4 +1,4 @@
1
- /*! peach v0.1.1406 | (c) 2026 Tamagui LLC | Proprietary; see LICENSE */
1
+ /*! peach v0.1.1463 | (c) 2026 Tamagui LLC | Proprietary; see LICENSE */
2
2
 
3
3
  // src/react-native-host-modules.ts
4
4
  var REACT_NATIVE_PASSTHROUGH_SPECIFIERS = [
@@ -1,4 +1,4 @@
1
- /*! peach v0.1.1406 | (c) 2026 Tamagui LLC | Proprietary; see LICENSE */
1
+ /*! peach v0.1.1463 | (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;
@@ -1459,26 +1459,32 @@ var knownNonPatched = /* @__PURE__ */ new Set();
1459
1459
  var knownNonExpo = /* @__PURE__ */ new Set();
1460
1460
  var knownOne = /* @__PURE__ */ new Set();
1461
1461
  async function probePort(port, buildIconProxyUrl, listeningProcess) {
1462
- await loadOptionalDemoApps();
1462
+ const demoApps = await loadOptionalDemoApps();
1463
1463
  const probeHostname = await tcpPing(port);
1464
1464
  if (!probeHostname) return null;
1465
1465
  const suppliedPid = listeningProcess?.pid;
1466
- const ownerPid = suppliedPid && suppliedPid > 0 ? suppliedPid : await resolveListeningPid(port);
1467
- const ownerCwd = ownerPid ? await resolveProcessCwd(ownerPid) : null;
1468
- const owner = {
1469
- ...ownerPid ? { pid: ownerPid } : {},
1470
- ...ownerCwd ? { cwd: ownerCwd } : {}
1471
- };
1466
+ const ownerPromise = (async () => {
1467
+ if (!listeningProcess && demoApps.length === 0) return {};
1468
+ const ownerPid = suppliedPid && suppliedPid > 0 ? suppliedPid : await resolveListeningPid(port);
1469
+ const ownerCwd = ownerPid ? await resolveProcessCwd(ownerPid) : null;
1470
+ return {
1471
+ ...ownerPid ? { pid: ownerPid } : {},
1472
+ ...ownerCwd ? { cwd: ownerCwd } : {}
1473
+ };
1474
+ })();
1472
1475
  const onePath = `/node_modules/one/metro-entry.bundle?platform=ios&dev=true`;
1473
- const [sootsimRes, statusRes, manifestRes, expoRes, swiftRes, oneScanRes] = await Promise.all([
1474
- knownNonPatched.has(port) ? Promise.resolve(null) : httpGet(probeHostname, port, "/__peachsim/"),
1475
- httpGet(probeHostname, port, "/status"),
1476
- knownOne.has(port) ? Promise.resolve(null) : httpGet(probeHostname, port, "/", "GET", MANIFEST_TIMEOUT_MS, {
1477
- "expo-platform": "ios"
1478
- }),
1479
- knownNonExpo.has(port) ? Promise.resolve(null) : httpGet(probeHostname, port, "/_expo/status"),
1480
- httpGet(probeHostname, port, SWIFT_DISCOVERY_PATH),
1481
- httpGet(probeHostname, port, "/__server-scan", "GET", MANIFEST_TIMEOUT_MS)
1476
+ const [[sootsimRes, statusRes, manifestRes, expoRes, swiftRes, oneScanRes], owner] = await Promise.all([
1477
+ Promise.all([
1478
+ knownNonPatched.has(port) ? Promise.resolve(null) : httpGet(probeHostname, port, "/__peachsim/"),
1479
+ httpGet(probeHostname, port, "/status"),
1480
+ knownOne.has(port) ? Promise.resolve(null) : httpGet(probeHostname, port, "/", "GET", MANIFEST_TIMEOUT_MS, {
1481
+ "expo-platform": "ios"
1482
+ }),
1483
+ knownNonExpo.has(port) ? Promise.resolve(null) : httpGet(probeHostname, port, "/_expo/status"),
1484
+ httpGet(probeHostname, port, SWIFT_DISCOVERY_PATH),
1485
+ httpGet(probeHostname, port, "/__server-scan", "GET", MANIFEST_TIMEOUT_MS)
1486
+ ]),
1487
+ ownerPromise
1482
1488
  ]);
1483
1489
  const oneScan = oneScanRes?.statusCode === 200 ? safeParseManifest(oneScanRes.body) : null;
1484
1490
  if (Array.isArray(oneScan)) {
package/dist-lib/sdk.cjs CHANGED
@@ -1,4 +1,4 @@
1
- /*! peach v0.1.1406 | (c) 2026 Tamagui LLC | Proprietary; see LICENSE */
1
+ /*! peach v0.1.1463 | (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 __defProp = Object.defineProperty;
@@ -23,9 +23,11 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
23
23
  var sdk_exports = {};
24
24
  __export(sdk_exports, {
25
25
  DEBUG_CHANNELS: () => DEBUG_CHANNELS,
26
+ IdleObservationError: () => IdleObservationError,
26
27
  LAYOUT_GET_NATIVE_EVAL: () => LAYOUT_GET_NATIVE_EVAL,
27
28
  MERGED_CONSOLE_COUNT_EVAL: () => MERGED_CONSOLE_COUNT_EVAL,
28
29
  NOISY_TIMELINE_KINDS: () => NOISY_TIMELINE_KINDS,
30
+ RuntimeReadinessUnsupportedError: () => RuntimeReadinessUnsupportedError,
29
31
  SimClient: () => SimClient,
30
32
  SimClientError: () => SimClientError,
31
33
  SimConnectError: () => SimConnectError,
@@ -111,10 +113,10 @@ module.exports = __toCommonJS(sdk_exports);
111
113
  var SEMANTIC_READY_CONTENT_NODE_FLOOR = 100;
112
114
  var HEADLESS_TENANT_FETCH_HUNG_MARKER = "headless tenant fetch hung";
113
115
  function readyProbeHasContent(probe) {
114
- return (probe.browserSurfaceCount ?? 0) > 0 || probe.liveFrameActive || probe.targets > 0 || probe.nodes >= SEMANTIC_READY_CONTENT_NODE_FLOOR;
116
+ return probe.paintedAppContent === true || (probe.browserSurfaceCount ?? 0) > 0 || probe.liveFrameActive || probe.targets > 0 || probe.nodes >= SEMANTIC_READY_CONTENT_NODE_FLOOR;
115
117
  }
116
118
  function readyProbeHasTargetContent(probe) {
117
- return (probe.browserSurfaceCount ?? 0) > 0 || probe.liveFrameActive || probe.targets > 0;
119
+ return probe.paintedAppContent === true || (probe.browserSurfaceCount ?? 0) > 0 || probe.liveFrameActive || probe.targets > 0;
118
120
  }
119
121
  function readyProbeIsReady(probe) {
120
122
  return (probe.flag === true ? readyProbeHasContent(probe) : readyProbeHasTargetContent(probe)) && probe.externalReady !== false && !probe.externalError && !probe.loadingText;
@@ -1440,7 +1442,7 @@ function formatTimelinePayload(kind, d) {
1440
1442
  case "notification":
1441
1443
  return `${d.title ?? ""}${d.body ? ` \u2014 ${d.body}` : ""}`;
1442
1444
  case "fetch":
1443
- return `${d.method ?? "GET"} ${d.url ?? ""}${d.status ? ` -> ${d.status}` : ""}`;
1445
+ return `${d.method ?? "GET"} ${d.url ?? ""}${d.status ? ` -> ${d.status}` : ""}${d.error ? ` -> ${d.error}` : ""}`;
1444
1446
  case "console":
1445
1447
  case "console-log":
1446
1448
  return `${d.level ?? "log"}: ${(d.message ?? "").toString().slice(0, 120)}`;
@@ -1535,6 +1537,18 @@ var RuntimeReadinessUnsupportedError = class extends Error {
1535
1537
  }
1536
1538
  code = "runtime_readiness_unsupported";
1537
1539
  };
1540
+ var IdleObservationError = class extends Error {
1541
+ constructor(elapsedMs, failure) {
1542
+ const detail = failure instanceof Error ? failure.message : String(failure);
1543
+ super(`idle observation failed after ${elapsedMs}ms: ${detail}`, {
1544
+ cause: failure
1545
+ });
1546
+ this.elapsedMs = elapsedMs;
1547
+ this.failure = failure;
1548
+ this.name = "IdleObservationError";
1549
+ }
1550
+ code = "idle_observation_failed";
1551
+ };
1538
1552
  async function waitForSootsimIdle({
1539
1553
  bridge,
1540
1554
  simId,
@@ -1545,6 +1559,7 @@ async function waitForSootsimIdle({
1545
1559
  paintStill = false
1546
1560
  }) {
1547
1561
  let result;
1562
+ const observationStartedAt = Date.now();
1548
1563
  try {
1549
1564
  result = await bridge.send(
1550
1565
  {
@@ -1575,27 +1590,23 @@ async function waitForSootsimIdle({
1575
1590
  let screenPixels = null
1576
1591
  try {
1577
1592
 
1578
- // route-aware settle: a tap that pushes/pops a screen is async \u2014 the
1579
- // old screen still renders for a moment, then the new one mounts and
1580
- // its content loads. a pure layout-hash check reports "idle" on the
1581
- // outgoing screen or on the incoming skeleton, so a driver re-taps
1582
- // and stacks duplicate navigations. drain any in-flight screen
1583
- // transition FIRST, bounded by the overall budget. when no
1584
- // transition is happening this returns in ~80ms (startWindowMs), so
1585
- // a plain button tap barely pays for it.
1586
- try {
1587
- const wfst = window.__sootsimTest?.waitForScreenTransitions
1588
- if (typeof wfst === 'function') {
1593
+ // discover transitions while observing layout. when motion starts,
1594
+ // observations from before its completion cannot prove the new screen.
1595
+ let transitionWait = (async () => {
1596
+ try {
1597
+ const wfst = window.__sootsimTest?.waitForScreenTransitions
1589
1598
  const remaining = deadline - Date.now()
1590
- if (remaining > 120) {
1591
- await wfst({
1599
+ if (typeof wfst === 'function' && remaining > 120) {
1600
+ const transition = await wfst({
1592
1601
  timeoutMs: Math.min(remaining - 80, 4000),
1593
1602
  settleMs: 64,
1594
1603
  startWindowMs: 80,
1595
1604
  })
1605
+ return transition?.started === true
1596
1606
  }
1597
- }
1598
- } catch {}
1607
+ } catch {}
1608
+ return false
1609
+ })()
1599
1610
 
1600
1611
  // a worker that cannot answer within the remaining budget is busy, not
1601
1612
  // idle: its poll reads as unsettled. bounding each read by the budget
@@ -1620,17 +1631,51 @@ async function waitForSootsimIdle({
1620
1631
  let nodeCount = null
1621
1632
  let renderStatsAvailable = false
1622
1633
  let shellAnimating = false
1634
+ let shellBlockers = ''
1623
1635
  let webViewStarting = false
1624
1636
  let webViewBlocker = ''
1637
+ // the reads are independent, so they run concurrently: a loaded sim
1638
+ // answers each one late, and a poll that waits for them in turn
1639
+ // costs their sum, which fits too few polls in the budget to settle.
1625
1640
  // strict also waits out shell motion: a system alert, sheet or menu
1626
1641
  // animates in the shell worker while the app's own stats read still,
1627
1642
  // so its presentation is complete only once the shell's list empties.
1628
- if (strict) {
1629
- const motion = await answer(() => window.__sootsimTest?.listAnimations?.()).catch(() => null)
1643
+ const motionRead = strict
1644
+ ? answer(() => window.__sootsimTest?.listAnimations?.()).catch(() => null)
1645
+ : null
1646
+ const statsRead = answer(() => window.__sootsimRenderHost?.queryStats?.()).catch(() => null)
1647
+ // image preparation ends in the tenant before the compositor decodes
1648
+ // and realizes its pixels. both owners must finish before settling.
1649
+ // the compositor rejects a stats request it is too busy to answer.
1650
+ const compositorRead = answer(() => window.__sootsimCompositor.getStats()).catch(() => BUSY)
1651
+ const countsRead = Promise.resolve().then(() => window.__sootsimTest?.getRequestCounts?.()).catch(() => null)
1652
+ // mounted-root membership: the live node count moves while the tree
1653
+ // mounts, unmounts or recycles, in either render mode.
1654
+ const nodeCountRead = Promise.resolve().then(() => window.__sootsimTest?.getNodeCount?.()).catch(() => null)
1655
+ // the mounted hierarchy in render-worker mode comes from the test
1656
+ // bridge: window.__sootsimRoot is an empty placeholder there, so a
1657
+ // walk over it hashes every screen to the same empty string while
1658
+ // it moves. listInspectable is the worker-backed read describe
1659
+ // uses; a worker too busy to answer it reads as unsettled. tight
1660
+ // budgets skip this read and settle on the cheaper signals above.
1661
+ const hierarchyRead =
1662
+ fullGeometry && typeof window.__sootsimTest?.listInspectable === 'function'
1663
+ ? answer(() => window.__sootsimTest.listInspectable({})).catch(() => null)
1664
+ : null
1665
+ if (motionRead) {
1666
+ const motion = await motionRead
1630
1667
  if (motion === BUSY) workerBusy = true
1631
- else shellAnimating = Array.isArray(motion) && motion.some((anim) => anim.realm === 'shell' && anim.priority !== 'low')
1668
+ else if (Array.isArray(motion)) {
1669
+ const blocking = motion.filter((anim) => anim.realm === 'shell' && anim.priority !== 'low')
1670
+ shellAnimating = blocking.length > 0
1671
+ // name what holds the settle so a timeout points at its owner.
1672
+ shellBlockers = blocking
1673
+ .slice(0, 4)
1674
+ .map((anim) => anim.source + '/' + anim.kind + '#' + anim.id + ' at ' + anim.current + (anim.loop ? ' loop' : ''))
1675
+ .join(', ')
1676
+ }
1632
1677
  }
1633
- const stats = await answer(() => window.__sootsimRenderHost?.queryStats?.()).catch(() => null)
1678
+ const stats = await statsRead
1634
1679
  if (stats === BUSY) {
1635
1680
  workerBusy = true
1636
1681
  } else if (stats) {
@@ -1667,10 +1712,7 @@ async function waitForSootsimIdle({
1667
1712
  // mounting or remounting, even with no animation flag raised.
1668
1713
  appCommits = typeof stats.appCommitCount === 'number' ? stats.appCommitCount : null
1669
1714
  }
1670
- // image preparation ends in the tenant before the compositor decodes
1671
- // and realizes its pixels. both owners must finish before settling.
1672
- // the compositor rejects a stats request it is too busy to answer.
1673
- const compositor = await answer(() => window.__sootsimCompositor.getStats()).catch(() => BUSY)
1715
+ const compositor = await compositorRead
1674
1716
  if (compositor === BUSY) {
1675
1717
  workerBusy = true
1676
1718
  } else {
@@ -1681,31 +1723,12 @@ async function waitForSootsimIdle({
1681
1723
  webViewBlocker = 'compositor webView capture not settled'
1682
1724
  }
1683
1725
  }
1684
- try {
1685
- const counts = await window.__sootsimTest?.getRequestCounts?.()
1686
- requestTotal = typeof counts?.total === 'number' ? counts.total : 0
1687
- requestInFlight = typeof counts?.inFlight === 'number' ? counts.inFlight : 0
1688
- } catch {}
1689
- // mounted-root membership: the live node count moves while the tree
1690
- // mounts, unmounts or recycles, in either render mode.
1691
- try {
1692
- const total = await window.__sootsimTest?.getNodeCount?.()
1693
- nodeCount = typeof total === 'number' ? total : null
1694
- } catch {}
1695
- // the mounted hierarchy in render-worker mode comes from the test
1696
- // bridge: window.__sootsimRoot is an empty placeholder there, so a
1697
- // walk over it hashes every screen to the same empty string while
1698
- // it moves. listInspectable is the worker-backed read describe
1699
- // uses; a worker too busy to answer it reads as unsettled. tight
1700
- // budgets skip this read and settle on the cheaper signals above.
1701
- let hierarchy = null
1702
- if (fullGeometry && typeof window.__sootsimTest?.listInspectable === 'function') {
1703
- try {
1704
- hierarchy = await answer(() => window.__sootsimTest.listInspectable({}))
1705
- } catch {
1706
- hierarchy = null
1707
- }
1708
- }
1726
+ const counts = await countsRead
1727
+ requestTotal = typeof counts?.total === 'number' ? counts.total : 0
1728
+ requestInFlight = typeof counts?.inFlight === 'number' ? counts.inFlight : 0
1729
+ const total = await nodeCountRead
1730
+ nodeCount = typeof total === 'number' ? total : null
1731
+ let hierarchy = hierarchyRead ? await hierarchyRead : null
1709
1732
  if (hierarchy === BUSY) {
1710
1733
  workerBusy = true
1711
1734
  hierarchy = null
@@ -1781,7 +1804,7 @@ async function waitForSootsimIdle({
1781
1804
  pixelFrameToken = token
1782
1805
  }
1783
1806
  }
1784
- return { layout: nodes.join(';'), screenPixels, animating, shellAnimating, layoutDirty, pendingFetches, workerBusy, webViewStarting, webViewBlocker, renderStatsAvailable, requestTotal, requestInFlight, appCommits, nodeCount }
1807
+ return { layout: nodes.join(';'), screenPixels, animating, shellAnimating, shellBlockers, layoutDirty, pendingFetches, workerBusy, webViewStarting, webViewBlocker, renderStatsAvailable, requestTotal, requestInFlight, appCommits, nodeCount }
1785
1808
  }
1786
1809
 
1787
1810
  // how long generic background network is allowed to keep us waiting AFTER
@@ -1868,6 +1891,19 @@ async function waitForSootsimIdle({
1868
1891
  Date.now() - visuallyStillSince >= requiredStillMs &&
1869
1892
  (networkQuiet || Date.now() - visuallyStillSince >= networkQuietGraceMs)
1870
1893
  ) {
1894
+ if (transitionWait) {
1895
+ const started = await transitionWait
1896
+ transitionWait = null
1897
+ if (started) {
1898
+ lastLayout = ''
1899
+ lastRequestTotal = -1
1900
+ lastAppCommits = null
1901
+ lastNodeCount = null
1902
+ stable = 0
1903
+ visuallyStillSince = 0
1904
+ continue
1905
+ }
1906
+ }
1871
1907
  return { settled: true, elapsed: Date.now() - start, blockedBy: '' }
1872
1908
  }
1873
1909
  } else {
@@ -1886,7 +1922,7 @@ async function waitForSootsimIdle({
1886
1922
  const blockers = []
1887
1923
  if (strict && !last.renderStatsAvailable) blockers.push('render stats unavailable')
1888
1924
  if (last.animating) blockers.push('animations still running')
1889
- if (last.shellAnimating) blockers.push('shell animations still running')
1925
+ if (last.shellAnimating) blockers.push('shell animations still running (' + last.shellBlockers + ')')
1890
1926
  if (last.layoutDirty) blockers.push('layout still dirty')
1891
1927
  if (last.appCommits !== null && lastAppCommits !== null && last.appCommits !== lastAppCommits) blockers.push('layout commits still landing')
1892
1928
  if (last.nodeCount !== null && lastNodeCount !== null && last.nodeCount !== lastNodeCount) blockers.push('node count still changing')
@@ -1917,12 +1953,7 @@ async function waitForSootsimIdle({
1917
1953
  }
1918
1954
  );
1919
1955
  } catch (error) {
1920
- const message = error instanceof Error ? error.message : String(error);
1921
- return {
1922
- settled: false,
1923
- elapsed: maxMs,
1924
- blockedBy: message
1925
- };
1956
+ throw new IdleObservationError(Math.max(0, Date.now() - observationStartedAt), error);
1926
1957
  }
1927
1958
  if (result?.error === "runtime_readiness_unsupported" && typeof result.runtimeVersion === "string" && Array.isArray(result.missingFields) && result.missingFields.every((field) => typeof field === "string")) {
1928
1959
  throw new RuntimeReadinessUnsupportedError(
@@ -2557,7 +2588,12 @@ var SimClient = class {
2557
2588
  if (!status.ready) throw new SimReadyTimeoutError(status);
2558
2589
  return status;
2559
2590
  }
2560
- /** wait for layout/animation/transition settle after an interaction. */
2591
+ /**
2592
+ * wait for layout/animation/transition settle after an interaction.
2593
+ * a still-busy guest returns settled false with its own elapsed time.
2594
+ * a failed idle read throws IdleObservationError with the host elapsed
2595
+ * time and the original failure.
2596
+ */
2561
2597
  settle(opts = {}) {
2562
2598
  return waitForSootsimIdle({
2563
2599
  bridge: this,
@@ -2829,9 +2865,11 @@ var SimClient = class {
2829
2865
  // Annotate the CommonJS export names for ESM import in node:
2830
2866
  0 && (module.exports = {
2831
2867
  DEBUG_CHANNELS,
2868
+ IdleObservationError,
2832
2869
  LAYOUT_GET_NATIVE_EVAL,
2833
2870
  MERGED_CONSOLE_COUNT_EVAL,
2834
2871
  NOISY_TIMELINE_KINDS,
2872
+ RuntimeReadinessUnsupportedError,
2835
2873
  SimClient,
2836
2874
  SimClientError,
2837
2875
  SimConnectError,