sootsim 0.1.85 → 0.1.87

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 (146) hide show
  1. package/dist-cli/bin.js +4 -4
  2. package/dist-cli/chunks/{agent-T3DUH5YJ.js → agent-JVF2PSHI.js} +2 -2
  3. package/dist-cli/chunks/{agent-wrapper-NSBF4THI.js → agent-wrapper-F2F4AOBI.js} +2 -2
  4. package/dist-cli/chunks/{assert-X3F7TRCZ.js → assert-YYD6OU4X.js} +2 -2
  5. package/dist-cli/chunks/auto-bootstrap-NUDEO3WI.js +2 -0
  6. package/dist-cli/chunks/beta-KQR3AUDC.js +2 -0
  7. package/dist-cli/chunks/{chunk-EKXK3SWK.js → chunk-356M3TGV.js} +2 -2
  8. package/dist-cli/chunks/{chunk-Y5PLPEEU.js → chunk-4QWGWI5X.js} +2 -2
  9. package/dist-cli/chunks/{chunk-EFM53PZ5.js → chunk-5UEPOBEU.js} +1 -1
  10. package/dist-cli/chunks/{chunk-QLJNSOS7.js → chunk-6JITQIIF.js} +1 -1
  11. package/dist-cli/chunks/{chunk-DWTLRPEN.js → chunk-7KZTQHB3.js} +2 -2
  12. package/dist-cli/chunks/{chunk-OXOARRKR.js → chunk-7SX73XWN.js} +10 -10
  13. package/dist-cli/chunks/{chunk-5DIGWOY7.js → chunk-BDMAV7YE.js} +1 -1
  14. package/dist-cli/chunks/{chunk-CF2LPRXD.js → chunk-BGA7UNHQ.js} +2 -2
  15. package/dist-cli/chunks/{chunk-MAO7F5PH.js → chunk-BREFZK7S.js} +3 -3
  16. package/dist-cli/chunks/chunk-CIRLGKNJ.js +2 -0
  17. package/dist-cli/chunks/{chunk-KUSQ4NNJ.js → chunk-CQGEFQ2O.js} +1 -1
  18. package/dist-cli/chunks/{chunk-5S6D7K4L.js → chunk-F2V2RDSF.js} +2 -2
  19. package/dist-cli/chunks/chunk-FYFVAKLG.js +1 -0
  20. package/dist-cli/chunks/{chunk-E2QE5FFP.js → chunk-G4DPGAY7.js} +1 -1
  21. package/dist-cli/chunks/{chunk-5N3V7OCG.js → chunk-HSIKVDO7.js} +2 -2
  22. package/dist-cli/chunks/{chunk-RZHREO3M.js → chunk-HUL7SDXP.js} +2 -2
  23. package/dist-cli/chunks/{chunk-HQDJ5BOF.js → chunk-IFTNXJFC.js} +1 -1
  24. package/dist-cli/chunks/{chunk-OISHLFON.js → chunk-JIGBO7T2.js} +1 -1
  25. package/dist-cli/chunks/{chunk-NVTL3JQG.js → chunk-JNC2KM5L.js} +1 -1
  26. package/dist-cli/chunks/{chunk-ZO3VHP6W.js → chunk-KHCGD2SK.js} +22 -10
  27. package/dist-cli/chunks/chunk-KOJH7M2Y.js +24 -0
  28. package/dist-cli/chunks/{chunk-BZL6D4TV.js → chunk-KRG3TVPS.js} +63 -62
  29. package/dist-cli/chunks/{chunk-OUNLJM56.js → chunk-L7NMKMAC.js} +2 -2
  30. package/dist-cli/chunks/{chunk-4EVSIUNB.js → chunk-LAFA2UUY.js} +2 -2
  31. package/dist-cli/chunks/{chunk-SBGOUA6F.js → chunk-LKF24E4V.js} +2 -2
  32. package/dist-cli/chunks/{chunk-AFNDVS4E.js → chunk-MAFNPEGR.js} +2 -2
  33. package/dist-cli/chunks/{chunk-GTAD6IUV.js → chunk-MDZ6HMDB.js} +1 -1
  34. package/dist-cli/chunks/chunk-NNBW2HSI.js +1 -0
  35. package/dist-cli/chunks/{chunk-EBEL6TTJ.js → chunk-OB6UTULM.js} +2 -2
  36. package/dist-cli/chunks/{chunk-7LKUN46F.js → chunk-OOMEG6UD.js} +2 -2
  37. package/dist-cli/chunks/{chunk-UYRGCJ4N.js → chunk-P7TSRSCR.js} +45 -45
  38. package/dist-cli/chunks/{chunk-BESAZ2HA.js → chunk-PJA4MECT.js} +2 -2
  39. package/dist-cli/chunks/{chunk-4QZHZ6BC.js → chunk-PQ64ESHO.js} +2 -2
  40. package/dist-cli/chunks/{chunk-AC6QGW22.js → chunk-PQIWV724.js} +2 -2
  41. package/dist-cli/chunks/{chunk-H44IQHKZ.js → chunk-PRQGETWQ.js} +1 -1
  42. package/dist-cli/chunks/{chunk-BHZJ6RIH.js → chunk-PV7UPMMH.js} +2 -2
  43. package/dist-cli/chunks/{chunk-PHPXGLME.js → chunk-QFHW7D44.js} +1 -1
  44. package/dist-cli/chunks/{chunk-O6N2CEET.js → chunk-QI3CAQIS.js} +2 -2
  45. package/dist-cli/chunks/{chunk-G7CIZ5S3.js → chunk-RFES5JTB.js} +3 -3
  46. package/dist-cli/chunks/chunk-SFGIFF2S.js +2 -0
  47. package/dist-cli/chunks/chunk-TRLVCBYL.js +1 -0
  48. package/dist-cli/chunks/{chunk-WGDL5V6C.js → chunk-Y2H2L6L7.js} +1 -1
  49. package/dist-cli/chunks/{chunk-3WGHC7JN.js → chunk-ZKJ42ZMK.js} +2 -2
  50. package/dist-cli/chunks/cli-version-QYZHMOJT.js +2 -0
  51. package/dist-cli/chunks/{compat-PCXGGZBZ.js → compat-46LSYJLF.js} +3 -3
  52. package/dist-cli/chunks/{config-LULEVEYL.js → config-P5NLMUL2.js} +2 -2
  53. package/dist-cli/chunks/{control-6P6HY7UF.js → control-3O7JEUFC.js} +2 -2
  54. package/dist-cli/chunks/{cpu-profile-NOK73ZYW.js → cpu-profile-LDMMDC7S.js} +2 -2
  55. package/dist-cli/chunks/{daemon-4A3DMUYL.js → daemon-BL3MXXR3.js} +3 -3
  56. package/dist-cli/chunks/{debug-74BWB2ZG.js → debug-SQA6GG37.js} +3 -3
  57. package/dist-cli/chunks/{detox-HEOMINSC.js → detox-TY6AOSA7.js} +2 -2
  58. package/dist-cli/chunks/{device-TTXXBJFZ.js → device-QWFX4556.js} +2 -2
  59. package/dist-cli/chunks/{diagnose-QZ3GOHSE.js → diagnose-P2UVBUN6.js} +2 -2
  60. package/dist-cli/chunks/drivers-HPRXOC6D.js +2 -0
  61. package/dist-cli/chunks/{electron-QVOWV44R.js → electron-U3KDMBJM.js} +3 -3
  62. package/dist-cli/chunks/flow-XGMUH4JT.js +2 -0
  63. package/dist-cli/chunks/help-HZCKWAH5.js +2 -0
  64. package/dist-cli/chunks/{hints-YKWRNMJC.js → hints-2IYL3NF4.js} +2 -2
  65. package/dist-cli/chunks/{home-paths-SFADSTJM.js → home-paths-5SZOYDCC.js} +2 -2
  66. package/dist-cli/chunks/{inspect-LEWGQCIU.js → inspect-FA4L7WIE.js} +107 -107
  67. package/dist-cli/chunks/install-SYVS2T2T.js +2 -0
  68. package/dist-cli/chunks/{install-desktop-22HYQZ2G.js → install-desktop-OLT6LS5L.js} +3 -3
  69. package/dist-cli/chunks/{keys-3ZT3MICU.js → keys-3OXB23J4.js} +2 -2
  70. package/dist-cli/chunks/{launch-ZXW2NFLG.js → launch-HEXKSA3X.js} +3 -3
  71. package/dist-cli/chunks/{login-NJKJ7GZO.js → login-DKQYESDF.js} +4 -4
  72. package/dist-cli/chunks/{logout-VMMQL7CB.js → logout-FMJJ3BR2.js} +2 -2
  73. package/dist-cli/chunks/{maestro-OJY4MTI7.js → maestro-Z24ESGQW.js} +2 -2
  74. package/dist-cli/chunks/{preview-QU2GXTEV.js → preview-ODKBHTV5.js} +2 -2
  75. package/dist-cli/chunks/{profile-7APWK47T.js → profile-2PIY7B3L.js} +2 -2
  76. package/dist-cli/chunks/{react-RSVO5JZZ.js → react-HL4CHJS4.js} +2 -2
  77. package/dist-cli/chunks/{record-UWH4MDEO.js → record-4LYFSZUK.js} +2 -2
  78. package/dist-cli/chunks/runtime-JML6VARG.js +2 -0
  79. package/dist-cli/chunks/{runtime-delivery-QMKGRV7N.js → runtime-delivery-U7WIYI7J.js} +2 -2
  80. package/dist-cli/chunks/{screenshot-43M27ALE.js → screenshot-YUA2BHDF.js} +2 -2
  81. package/dist-cli/chunks/{screenshot-mode-EBYYN6TY.js → screenshot-mode-UIL75CHP.js} +2 -2
  82. package/dist-cli/chunks/{screenshots-7TQZL6Z6.js → screenshots-YJWODQGP.js} +2 -2
  83. package/dist-cli/chunks/server-J644PTIB.js +40 -0
  84. package/dist-cli/chunks/setup-repo-GSEZY74V.js +2 -0
  85. package/dist-cli/chunks/{skills-RQA6EJQL.js → skills-PEBZZZTL.js} +2 -2
  86. package/dist-cli/chunks/{start-ZT6MBYND.js → start-JCJQRDDQ.js} +4 -4
  87. package/dist-cli/chunks/store-XGTUSOGS.js +2 -0
  88. package/dist-cli/chunks/telemetry-Y3IESY7P.js +2 -0
  89. package/dist-cli/chunks/{test-RNRX5SWV.js → test-Z3NU6IN7.js} +3 -3
  90. package/dist-cli/chunks/{three-mode-TQZH25ZO.js → three-mode-CFSZ2ZOW.js} +2 -2
  91. package/dist-cli/chunks/{timeline-GGN3AY6P.js → timeline-GEND6OI3.js} +2 -2
  92. package/dist-cli/chunks/{upgrade-XT22D67C.js → upgrade-6GFR2ZB7.js} +3 -3
  93. package/dist-cli/chunks/upload-OPMPP35I.js +2 -0
  94. package/dist-cli/chunks/{web-KEHVF5MB.js → web-7A27OUAC.js} +2 -2
  95. package/dist-cli/chunks/{what-happened-PATQRJ5T.js → what-happened-57G5T2GM.js} +2 -2
  96. package/dist-cli/chunks/{whoami-CXVY26VV.js → whoami-3ICC26FV.js} +2 -2
  97. package/dist-lib/agent-daemon-client.cjs +1 -1
  98. package/dist-lib/agent-events.cjs +1 -1
  99. package/dist-lib/agent-sessions.cjs +1 -1
  100. package/dist-lib/attached-projects.cjs +1 -1
  101. package/dist-lib/auth/shared-session.cjs +1 -1
  102. package/dist-lib/backend-origin.cjs +1 -1
  103. package/dist-lib/beta.cjs +1 -1
  104. package/dist-lib/beta.mjs +15 -0
  105. package/dist-lib/bridge-constants.cjs +1 -1
  106. package/dist-lib/cli-constants.cjs +1 -1
  107. package/dist-lib/config.cjs +1 -1
  108. package/dist-lib/detox/index.cjs +1 -1
  109. package/dist-lib/dev-bundle-resolution.cjs +1 -1
  110. package/dist-lib/home-paths.cjs +1 -1
  111. package/dist-lib/host/bridge-host.cjs +244 -35
  112. package/dist-lib/host/fetch-proxy-handler.cjs +24 -4
  113. package/dist-lib/host/fetch-proxy-overrides.cjs +1 -1
  114. package/dist-lib/host/fetch-proxy-overrides.mjs +33 -0
  115. package/dist-lib/host/websocket-proxy.cjs +207 -0
  116. package/dist-lib/index.cjs +1 -1
  117. package/dist-lib/metro.cjs +1 -1
  118. package/dist-lib/profiles.cjs +1 -1
  119. package/dist-lib/render-mode.cjs +1 -1
  120. package/dist-lib/scripts/demo-app-registry.cjs +14 -3
  121. package/dist-lib/scripts/dev-server-scanner.cjs +14 -3
  122. package/dist-lib/skills.cjs +290 -73
  123. package/dist-lib/vite.cjs +1 -1
  124. package/package.json +7 -1
  125. package/scripts/demo-app-registry.ts +17 -1
  126. package/src/host/bridge-host.ts +8 -1
  127. package/src/host/fetch-proxy-handler.ts +26 -3
  128. package/src/host/websocket-proxy.ts +201 -0
  129. package/dist-cli/chunks/auto-bootstrap-47RN2V5G.js +0 -2
  130. package/dist-cli/chunks/beta-BRCGAF2N.js +0 -2
  131. package/dist-cli/chunks/chunk-36RPD6JI.js +0 -2
  132. package/dist-cli/chunks/chunk-4DBPNLGI.js +0 -1
  133. package/dist-cli/chunks/chunk-PQFFUJR6.js +0 -24
  134. package/dist-cli/chunks/chunk-QQAECG5B.js +0 -2
  135. package/dist-cli/chunks/chunk-SSCA2AEA.js +0 -1
  136. package/dist-cli/chunks/chunk-ZFAM4N5B.js +0 -1
  137. package/dist-cli/chunks/cli-version-WPFDM2A6.js +0 -2
  138. package/dist-cli/chunks/drivers-QRPWNOIT.js +0 -2
  139. package/dist-cli/chunks/flow-QMA7GVN6.js +0 -2
  140. package/dist-cli/chunks/install-7N2N7Q32.js +0 -2
  141. package/dist-cli/chunks/runtime-3FUENRHM.js +0 -2
  142. package/dist-cli/chunks/server-VCFM25Z6.js +0 -35
  143. package/dist-cli/chunks/setup-repo-HFH4VKJQ.js +0 -2
  144. package/dist-cli/chunks/store-BJBTDSZE.js +0 -2
  145. package/dist-cli/chunks/telemetry-ZZZKTILZ.js +0 -2
  146. package/dist-cli/chunks/upload-NC2AYLC5.js +0 -2
@@ -1,4 +1,4 @@
1
- /*! sootsim v0.1.85 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
1
+ /*! sootsim v0.1.87 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
2
2
  let __sootsim_import_meta_url = ''; try { __sootsim_import_meta_url = require('url').pathToFileURL(__filename).href; } catch {}
3
3
  "use strict";
4
4
  var __create = Object.create;
@@ -10124,11 +10124,22 @@ var init_demo_app_registry = __esm({
10124
10124
  // be holding pglite locks on ~/takeout/.orez (soot can attach takeout as
10125
10125
  // a project and spin up its own orez against the same data dir).
10126
10126
  readyTimeoutMs: 24e4,
10127
+ managedPorts: (p) => {
10128
+ const offset = p - 8081;
10129
+ return [5433 + offset, 4848 + offset, 9200 + offset];
10130
+ },
10127
10131
  command: (p) => ({
10128
- cmd: "bun lite",
10132
+ cmd: "bun lite:demo",
10129
10133
  env: {
10134
+ TAKEOUT_ENV_MODE: "development",
10130
10135
  PORT_OFFSET: String(p - 8081),
10131
- OREZ_DATA_DIR: `${HOME}/.cache/sootsim-demo/takeout-orez`
10136
+ OREZ_DATA_DIR: `${HOME}/.cache/sootsim-demo/takeout-orez`,
10137
+ VITE_DEMO_MODE: "1",
10138
+ ZERO_APP_ID: "takeout",
10139
+ ZERO_APP_PUBLICATIONS: "zero_takeout",
10140
+ ZERO_CVR_MAX_CONNS: "4",
10141
+ ZERO_NUM_SYNC_WORKERS: "2",
10142
+ ZERO_UPSTREAM_MAX_CONNS: "8"
10132
10143
  }
10133
10144
  })
10134
10145
  },
@@ -12440,6 +12451,18 @@ function buildFetchProxyHeaders(reqHeaders, targetUrl) {
12440
12451
  );
12441
12452
  return headers;
12442
12453
  }
12454
+ function buildAppApiProxyHeaders(reqHeaders, targetUrl) {
12455
+ const headers = {};
12456
+ for (const [key, value] of Object.entries(reqHeaders)) {
12457
+ if (!value) continue;
12458
+ if (APP_API_HEADER_REWRITES.has(key.toLowerCase())) continue;
12459
+ headers[key] = value;
12460
+ }
12461
+ headers.host = targetUrl.host;
12462
+ headers.origin = targetUrl.origin;
12463
+ headers.referer = `${targetUrl.origin}/`;
12464
+ return headers;
12465
+ }
12443
12466
  function isFetchProxyRequestUrl(rawUrl) {
12444
12467
  return rawUrl?.startsWith("/__fetch-proxy?") || rawUrl?.startsWith("/__proxy?") || false;
12445
12468
  }
@@ -12550,9 +12573,7 @@ function handleAppApiRequest(req, res) {
12550
12573
  return true;
12551
12574
  }
12552
12575
  const transport = targetUrl.protocol === "https:" ? import_https.default : import_http2.default;
12553
- const fwdHeaders = { ...req.headers };
12554
- delete fwdHeaders.host;
12555
- fwdHeaders.host = targetUrl.host;
12576
+ const fwdHeaders = buildAppApiProxyHeaders(req.headers, targetUrl);
12556
12577
  const proxyReq = transport.request(
12557
12578
  {
12558
12579
  hostname: targetUrl.hostname,
@@ -12582,7 +12603,7 @@ function handleAppApiRequest(req, res) {
12582
12603
  req.pipe(proxyReq);
12583
12604
  return true;
12584
12605
  }
12585
- var import_http2, import_https, STRIP_FETCH_PROXY_HEADERS, FETCH_PROXY_CORS_HEADERS;
12606
+ var import_http2, import_https, STRIP_FETCH_PROXY_HEADERS, FETCH_PROXY_CORS_HEADERS, APP_API_HEADER_REWRITES;
12586
12607
  var init_fetch_proxy_handler = __esm({
12587
12608
  "src/host/fetch-proxy-handler.ts"() {
12588
12609
  "use strict";
@@ -12615,6 +12636,14 @@ var init_fetch_proxy_handler = __esm({
12615
12636
  "access-control-expose-headers": "*",
12616
12637
  "access-control-max-age": "3600"
12617
12638
  };
12639
+ APP_API_HEADER_REWRITES = /* @__PURE__ */ new Set([
12640
+ "host",
12641
+ "origin",
12642
+ "referer",
12643
+ "sec-fetch-site",
12644
+ "sec-fetch-mode",
12645
+ "sec-fetch-dest"
12646
+ ]);
12618
12647
  }
12619
12648
  });
12620
12649
 
@@ -12771,6 +12800,186 @@ var init_open_url = __esm({
12771
12800
  }
12772
12801
  });
12773
12802
 
12803
+ // src/host/websocket-proxy.ts
12804
+ function rejectUpgrade(socket, status, message) {
12805
+ try {
12806
+ socket.write(
12807
+ `HTTP/1.1 ${status} ${message}\r
12808
+ Connection: close\r
12809
+ Content-Type: text/plain\r
12810
+ Content-Length: ${message.length}\r
12811
+ \r
12812
+ ${message}`
12813
+ );
12814
+ } catch {
12815
+ }
12816
+ socket.destroy();
12817
+ }
12818
+ function isSameOriginUpgrade(req) {
12819
+ const origin = req.headers.origin;
12820
+ const host = req.headers.host;
12821
+ if (!origin || !host) return false;
12822
+ try {
12823
+ return new URL(origin).host === host;
12824
+ } catch {
12825
+ return false;
12826
+ }
12827
+ }
12828
+ function decodeProxyHeaders(encoded) {
12829
+ if (!encoded) return {};
12830
+ const base64 = encoded.replace(/-/g, "+").replace(/_/g, "/");
12831
+ const padded = base64 + "=".repeat((4 - base64.length % 4) % 4);
12832
+ const parsed = JSON.parse(Buffer.from(padded, "base64").toString("utf8"));
12833
+ if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) return {};
12834
+ const headers = {};
12835
+ for (const [key, value] of Object.entries(parsed)) {
12836
+ if (value == null) continue;
12837
+ if (STRIP_UPSTREAM_HEADERS.has(key.toLowerCase())) continue;
12838
+ headers[key] = Array.isArray(value) ? value.join(", ") : String(value);
12839
+ }
12840
+ return headers;
12841
+ }
12842
+ function getDefaultWebSocketOrigin(targetUrl) {
12843
+ const origin = new URL(targetUrl.href);
12844
+ origin.protocol = targetUrl.protocol === "wss:" ? "https:" : "http:";
12845
+ return origin.origin;
12846
+ }
12847
+ function getRequestedProtocols(req) {
12848
+ const header = req.headers["sec-websocket-protocol"];
12849
+ const value = Array.isArray(header) ? header.join(",") : header || "";
12850
+ return value.split(",").map((part) => part.trim()).filter(Boolean);
12851
+ }
12852
+ function safeClose(ws, code, reason) {
12853
+ if (ws.readyState === import_ws.WebSocket.CLOSED || ws.readyState === import_ws.WebSocket.CLOSING) {
12854
+ return;
12855
+ }
12856
+ try {
12857
+ ws.close(code, reason);
12858
+ } catch {
12859
+ ws.terminate();
12860
+ }
12861
+ }
12862
+ function connectProxyPair(clientWs, upstream) {
12863
+ let closing = false;
12864
+ const closeBoth = (source, target, code, reason) => {
12865
+ if (closing) return;
12866
+ closing = true;
12867
+ safeClose(target, code, reason.toString());
12868
+ if (source.readyState === import_ws.WebSocket.OPEN) {
12869
+ safeClose(source, code, reason.toString());
12870
+ }
12871
+ };
12872
+ clientWs.on("message", (data, isBinary) => {
12873
+ if (upstream.readyState === import_ws.WebSocket.OPEN) {
12874
+ upstream.send(data, { binary: isBinary });
12875
+ }
12876
+ });
12877
+ upstream.on("message", (data, isBinary) => {
12878
+ if (clientWs.readyState === import_ws.WebSocket.OPEN) {
12879
+ clientWs.send(data, { binary: isBinary });
12880
+ }
12881
+ });
12882
+ clientWs.on("close", (code, reason) => closeBoth(clientWs, upstream, code, reason));
12883
+ upstream.on("close", (code, reason) => closeBoth(upstream, clientWs, code, reason));
12884
+ clientWs.on("error", () => safeClose(upstream, 1011, "proxy client error"));
12885
+ upstream.on("error", () => safeClose(clientWs, 1011, "upstream websocket error"));
12886
+ }
12887
+ function createUpstreamWebSocket(targetUrl, protocols, headers) {
12888
+ const upstreamHeaders = { ...headers };
12889
+ if (!Object.keys(upstreamHeaders).some((key) => key.toLowerCase() === "origin")) {
12890
+ upstreamHeaders.origin = getDefaultWebSocketOrigin(targetUrl);
12891
+ }
12892
+ return new import_ws.WebSocket(targetUrl.href, protocols, {
12893
+ headers: upstreamHeaders
12894
+ });
12895
+ }
12896
+ function isWebSocketProxyRequestUrl(rawUrl) {
12897
+ if (!rawUrl) return false;
12898
+ try {
12899
+ return new URL(rawUrl, "http://localhost").pathname === WEBSOCKET_PROXY_PATH;
12900
+ } catch {
12901
+ return false;
12902
+ }
12903
+ }
12904
+ function handleWebSocketProxyUpgrade(req, socket, head) {
12905
+ if (!isWebSocketProxyRequestUrl(req.url)) return false;
12906
+ if (!isSameOriginUpgrade(req)) {
12907
+ rejectUpgrade(socket, 403, "forbidden websocket proxy origin");
12908
+ return true;
12909
+ }
12910
+ let targetUrl;
12911
+ let headers;
12912
+ try {
12913
+ const requestUrl = new URL(req.url || "/", "http://localhost");
12914
+ const target = requestUrl.searchParams.get("url");
12915
+ if (!target) {
12916
+ rejectUpgrade(socket, 400, "missing websocket proxy url");
12917
+ return true;
12918
+ }
12919
+ targetUrl = new URL(target);
12920
+ if (targetUrl.protocol !== "ws:" && targetUrl.protocol !== "wss:") {
12921
+ rejectUpgrade(socket, 400, "invalid websocket proxy protocol");
12922
+ return true;
12923
+ }
12924
+ headers = decodeProxyHeaders(requestUrl.searchParams.get("headers"));
12925
+ } catch {
12926
+ rejectUpgrade(socket, 400, "invalid websocket proxy request");
12927
+ return true;
12928
+ }
12929
+ const protocols = getRequestedProtocols(req);
12930
+ const upstream = createUpstreamWebSocket(targetUrl, protocols, headers);
12931
+ let completed = false;
12932
+ socket.once("close", () => {
12933
+ if (!completed) upstream.terminate();
12934
+ });
12935
+ upstream.once("open", () => {
12936
+ if (completed) return;
12937
+ completed = true;
12938
+ const selectedProtocol = upstream.protocol;
12939
+ const proxyServer = new import_ws.WebSocketServer({
12940
+ noServer: true,
12941
+ clientTracking: false,
12942
+ handleProtocols(requestedProtocols) {
12943
+ return selectedProtocol || requestedProtocols.values().next().value || false;
12944
+ }
12945
+ });
12946
+ proxyServer.handleUpgrade(req, socket, head, (clientWs) => {
12947
+ connectProxyPair(clientWs, upstream);
12948
+ });
12949
+ });
12950
+ upstream.once("error", () => {
12951
+ if (completed) return;
12952
+ completed = true;
12953
+ rejectUpgrade(socket, 502, "upstream websocket error");
12954
+ });
12955
+ upstream.once("close", () => {
12956
+ if (completed) return;
12957
+ completed = true;
12958
+ rejectUpgrade(socket, 502, "upstream websocket closed");
12959
+ });
12960
+ return true;
12961
+ }
12962
+ var import_ws, WEBSOCKET_PROXY_PATH, STRIP_UPSTREAM_HEADERS;
12963
+ var init_websocket_proxy = __esm({
12964
+ "src/host/websocket-proxy.ts"() {
12965
+ "use strict";
12966
+ import_ws = require("ws");
12967
+ WEBSOCKET_PROXY_PATH = "/__websocket-proxy";
12968
+ STRIP_UPSTREAM_HEADERS = /* @__PURE__ */ new Set([
12969
+ "host",
12970
+ "connection",
12971
+ "upgrade",
12972
+ "transfer-encoding",
12973
+ "content-length",
12974
+ "sec-websocket-accept",
12975
+ "sec-websocket-extensions",
12976
+ "sec-websocket-key",
12977
+ "sec-websocket-protocol",
12978
+ "sec-websocket-version"
12979
+ ]);
12980
+ }
12981
+ });
12982
+
12774
12983
  // src/host/bridge-host.ts
12775
12984
  var bridge_host_exports = {};
12776
12985
  __export(bridge_host_exports, {
@@ -12804,7 +13013,7 @@ function unrefTimer(timer) {
12804
13013
  timer.unref();
12805
13014
  }
12806
13015
  }
12807
- var import_child_process4, import_fs3, import_http3, import_path3, import_ws, WRITE_COMMAND_TYPES, FORCE_CLOSE_GRACE_MS, FORCE_CLOSE_TERMINATE_MS, DAEMON_HEARTBEAT_INTERVAL_MS, DEFAULT_RUNTIME_UPDATE_INTERVAL_MS, RUNTIME_UPDATE_INTERVAL_ENV, HTTP_MIME_TYPES, SootSimBridgeHost;
13016
+ var import_child_process4, import_fs3, import_http3, import_path3, import_ws2, WRITE_COMMAND_TYPES, FORCE_CLOSE_GRACE_MS, FORCE_CLOSE_TERMINATE_MS, DAEMON_HEARTBEAT_INTERVAL_MS, DEFAULT_RUNTIME_UPDATE_INTERVAL_MS, RUNTIME_UPDATE_INTERVAL_ENV, HTTP_MIME_TYPES, SootSimBridgeHost;
12808
13017
  var init_bridge_host = __esm({
12809
13018
  "src/host/bridge-host.ts"() {
12810
13019
  "use strict";
@@ -12812,7 +13021,7 @@ var init_bridge_host = __esm({
12812
13021
  import_fs3 = __toESM(require("fs"), 1);
12813
13022
  import_http3 = require("http");
12814
13023
  import_path3 = __toESM(require("path"), 1);
12815
- import_ws = require("ws");
13024
+ import_ws2 = require("ws");
12816
13025
  init_dev_server_scanner();
12817
13026
  init_bridge_constants();
12818
13027
  init_cli_version();
@@ -12821,6 +13030,7 @@ var init_bridge_host = __esm({
12821
13030
  init_agent_host();
12822
13031
  init_fetch_proxy_handler();
12823
13032
  init_open_url();
13033
+ init_websocket_proxy();
12824
13034
  WRITE_COMMAND_TYPES = /* @__PURE__ */ new Set(["tap", "keyboard"]);
12825
13035
  FORCE_CLOSE_GRACE_MS = 2e3;
12826
13036
  FORCE_CLOSE_TERMINATE_MS = 1e3;
@@ -13006,8 +13216,14 @@ var init_bridge_host = __esm({
13006
13216
  `);
13007
13217
  });
13008
13218
  this.httpServer = server;
13009
- this.wss = new import_ws.WebSocketServer({ server });
13219
+ this.wss = new import_ws2.WebSocketServer({ noServer: true });
13010
13220
  this.wireWebSocketServer();
13221
+ server.on("upgrade", (req, socket, head) => {
13222
+ if (handleWebSocketProxyUpgrade(req, socket, head)) return;
13223
+ this.wss?.handleUpgrade(req, socket, head, (ws) => {
13224
+ this.wss?.emit("connection", ws, req);
13225
+ });
13226
+ });
13011
13227
  resolve7();
13012
13228
  });
13013
13229
  });
@@ -13171,7 +13387,7 @@ var init_bridge_host = __esm({
13171
13387
  config: next
13172
13388
  });
13173
13389
  for (const peer of this.sims.values()) {
13174
- if (peer.ws.readyState !== import_ws.WebSocket.OPEN) continue;
13390
+ if (peer.ws.readyState !== import_ws2.WebSocket.OPEN) continue;
13175
13391
  try {
13176
13392
  peer.ws.send(payload);
13177
13393
  } catch {
@@ -13227,7 +13443,7 @@ var init_bridge_host = __esm({
13227
13443
  const entry = this.cliBySentId.get(msg.id);
13228
13444
  if (entry) {
13229
13445
  this.cliBySentId.delete(msg.id);
13230
- if (entry.ws.readyState === import_ws.WebSocket.OPEN) {
13446
+ if (entry.ws.readyState === import_ws2.WebSocket.OPEN) {
13231
13447
  const otherCliCount = this.getOtherCliIdentityCount(entry.ws, entry.simId);
13232
13448
  const response = otherCliCount > 0 ? { ...msg, id: entry.originalId, _otherCliCount: otherCliCount } : { ...msg, id: entry.originalId };
13233
13449
  entry.ws.send(JSON.stringify(response));
@@ -13255,7 +13471,7 @@ var init_bridge_host = __esm({
13255
13471
  if (typeof msg.cliLabel === "string" && msg.cliLabel.trim()) {
13256
13472
  this.cliLabelBySocket.set(ws, msg.cliLabel.trim());
13257
13473
  }
13258
- if (ws.readyState === import_ws.WebSocket.OPEN) {
13474
+ if (ws.readyState === import_ws2.WebSocket.OPEN) {
13259
13475
  ws.send(
13260
13476
  JSON.stringify({
13261
13477
  id: msg.id,
@@ -13270,7 +13486,7 @@ var init_bridge_host = __esm({
13270
13486
  return;
13271
13487
  }
13272
13488
  if (msg.type === "bridge:list-sims") {
13273
- if (ws.readyState === import_ws.WebSocket.OPEN) {
13489
+ if (ws.readyState === import_ws2.WebSocket.OPEN) {
13274
13490
  ws.send(
13275
13491
  JSON.stringify({
13276
13492
  id: msg.id,
@@ -13285,7 +13501,7 @@ var init_bridge_host = __esm({
13285
13501
  throw new Error("bridge:open requires a url");
13286
13502
  }
13287
13503
  await this.openUrl(msg.url, { newWindow: msg.newWindow === true });
13288
- if (ws.readyState === import_ws.WebSocket.OPEN) {
13504
+ if (ws.readyState === import_ws2.WebSocket.OPEN) {
13289
13505
  ws.send(
13290
13506
  JSON.stringify({
13291
13507
  id: msg.id,
@@ -13301,7 +13517,7 @@ var init_bridge_host = __esm({
13301
13517
  force: msg.force === true
13302
13518
  });
13303
13519
  if (!outcome.granted) {
13304
- if (ws.readyState === import_ws.WebSocket.OPEN) {
13520
+ if (ws.readyState === import_ws2.WebSocket.OPEN) {
13305
13521
  ws.send(
13306
13522
  JSON.stringify({
13307
13523
  id: msg.id,
@@ -13317,7 +13533,7 @@ var init_bridge_host = __esm({
13317
13533
  targetSim2.id,
13318
13534
  outcome.bootedCount > 0 ? `cli force-claimed sim (booted ${outcome.bootedCount})` : "cli claimed sim"
13319
13535
  );
13320
- if (ws.readyState === import_ws.WebSocket.OPEN) {
13536
+ if (ws.readyState === import_ws2.WebSocket.OPEN) {
13321
13537
  ws.send(
13322
13538
  JSON.stringify({
13323
13539
  id: msg.id,
@@ -13336,7 +13552,7 @@ var init_bridge_host = __esm({
13336
13552
  if (shouldAcquireLease(msg)) {
13337
13553
  const outcome = this.tryAcquireLease(ws, targetSim);
13338
13554
  if (!outcome.granted) {
13339
- if (ws.readyState === import_ws.WebSocket.OPEN) {
13555
+ if (ws.readyState === import_ws2.WebSocket.OPEN) {
13340
13556
  ws.send(
13341
13557
  JSON.stringify({
13342
13558
  id: msg.id,
@@ -13362,7 +13578,7 @@ var init_bridge_host = __esm({
13362
13578
  targetSim.ws.send(JSON.stringify({ ...forwarded, id: sentId }));
13363
13579
  if (forwarded.type === "close") {
13364
13580
  this.cliBySentId.delete(sentId);
13365
- if (ws.readyState === import_ws.WebSocket.OPEN) {
13581
+ if (ws.readyState === import_ws2.WebSocket.OPEN) {
13366
13582
  ws.send(
13367
13583
  JSON.stringify({
13368
13584
  id: msg.id,
@@ -13377,7 +13593,7 @@ var init_bridge_host = __esm({
13377
13593
  unrefTimer(closeTimer);
13378
13594
  }
13379
13595
  } catch (err) {
13380
- if (ws.readyState === import_ws.WebSocket.OPEN) {
13596
+ if (ws.readyState === import_ws2.WebSocket.OPEN) {
13381
13597
  ws.send(
13382
13598
  JSON.stringify({
13383
13599
  id: msg.id,
@@ -13402,7 +13618,7 @@ var init_bridge_host = __esm({
13402
13618
  }
13403
13619
  for (const [sentId, entry] of this.cliBySentId) {
13404
13620
  if (entry.simId !== sim.id) continue;
13405
- if (entry.ws.readyState === import_ws.WebSocket.OPEN) {
13621
+ if (entry.ws.readyState === import_ws2.WebSocket.OPEN) {
13406
13622
  entry.ws.send(
13407
13623
  JSON.stringify({
13408
13624
  id: entry.originalId,
@@ -13608,7 +13824,7 @@ var init_bridge_host = __esm({
13608
13824
  runtimeDir: this.activeRuntimeDirPath
13609
13825
  });
13610
13826
  for (const sim of this.sims.values()) {
13611
- if (sim.ws.readyState === import_ws.WebSocket.OPEN) {
13827
+ if (sim.ws.readyState === import_ws2.WebSocket.OPEN) {
13612
13828
  try {
13613
13829
  sim.ws.send(payload);
13614
13830
  } catch {
@@ -13933,7 +14149,7 @@ var init_bridge_host = __esm({
13933
14149
  sweepDeadWebSockets() {
13934
14150
  if (!this.wss) return;
13935
14151
  for (const ws of this.wss.clients) {
13936
- if (ws.readyState !== import_ws.WebSocket.OPEN) continue;
14152
+ if (ws.readyState !== import_ws2.WebSocket.OPEN) continue;
13937
14153
  const alive = this.wsIsAlive.get(ws);
13938
14154
  if (alive === false) {
13939
14155
  try {
@@ -13954,7 +14170,7 @@ var init_bridge_host = __esm({
13954
14170
  }
13955
14171
  }
13956
14172
  closeSimSocketFromHost(ws) {
13957
- if (ws.readyState !== import_ws.WebSocket.OPEN) return;
14173
+ if (ws.readyState !== import_ws2.WebSocket.OPEN) return;
13958
14174
  try {
13959
14175
  ws.close(SOOTSIM_BRIDGE_SIM_CLOSE_CODE, SOOTSIM_BRIDGE_SIM_CLOSE_REASON);
13960
14176
  } catch {
@@ -13965,7 +14181,7 @@ var init_bridge_host = __esm({
13965
14181
  return;
13966
14182
  }
13967
14183
  const terminateTimer = setTimeout(() => {
13968
- if (ws.readyState === import_ws.WebSocket.CLOSED) return;
14184
+ if (ws.readyState === import_ws2.WebSocket.CLOSED) return;
13969
14185
  try {
13970
14186
  ws.terminate();
13971
14187
  } catch {
@@ -14114,7 +14330,7 @@ var init_bridge_host = __esm({
14114
14330
  try {
14115
14331
  readyState = sim.ws.readyState;
14116
14332
  } catch {
14117
- readyState = import_ws.WebSocket.CLOSED;
14333
+ readyState = import_ws2.WebSocket.CLOSED;
14118
14334
  }
14119
14335
  const lease = this.getActiveLease(sim);
14120
14336
  return {
@@ -14127,7 +14343,7 @@ var init_bridge_host = __esm({
14127
14343
  lastSeenAt: sim.lastSeenAt,
14128
14344
  lastActiveAt: sim.lastActiveAt || void 0,
14129
14345
  isPrimary: sim.id === this.primarySimId,
14130
- readyState: readyState === import_ws.WebSocket.OPEN ? "open" : readyState === import_ws.WebSocket.CLOSING ? "closing" : "closed",
14346
+ readyState: readyState === import_ws2.WebSocket.OPEN ? "open" : readyState === import_ws2.WebSocket.CLOSING ? "closing" : "closed",
14131
14347
  attachedCliCount: this.getAttachedCliCount(sim.id),
14132
14348
  lockedBy: lease ? lease.cliLabel || lease.cliIdentityKey : void 0,
14133
14349
  lockedByKind: lease ? lease.kind : void 0,
@@ -14244,18 +14460,18 @@ var init_bridge_host = __esm({
14244
14460
  getOpenSim(simId) {
14245
14461
  if (simId) {
14246
14462
  const sim = this.sims.get(simId);
14247
- if (sim?.ws.readyState === import_ws.WebSocket.OPEN) return sim;
14463
+ if (sim?.ws.readyState === import_ws2.WebSocket.OPEN) return sim;
14248
14464
  return null;
14249
14465
  }
14250
14466
  const primary = this.primarySimId != null ? this.sims.get(this.primarySimId) : null;
14251
- if (primary?.ws.readyState === import_ws.WebSocket.OPEN && primary.url) return primary;
14467
+ if (primary?.ws.readyState === import_ws2.WebSocket.OPEN && primary.url) return primary;
14252
14468
  let pagelessFallback = null;
14253
14469
  for (const sim of this.sims.values()) {
14254
- if (sim.ws.readyState !== import_ws.WebSocket.OPEN) continue;
14470
+ if (sim.ws.readyState !== import_ws2.WebSocket.OPEN) continue;
14255
14471
  if (sim.url) return sim;
14256
14472
  pagelessFallback ??= sim;
14257
14473
  }
14258
- if (primary?.ws.readyState === import_ws.WebSocket.OPEN) return primary;
14474
+ if (primary?.ws.readyState === import_ws2.WebSocket.OPEN) return primary;
14259
14475
  return pagelessFallback;
14260
14476
  }
14261
14477
  async waitForSim(simId, options = {}) {
@@ -14271,7 +14487,7 @@ var init_bridge_host = __esm({
14271
14487
  shouldPromoteSim(sim) {
14272
14488
  const current = this.primarySimId ? this.sims.get(this.primarySimId) : null;
14273
14489
  if (!sim.url) return !current;
14274
- const currentAlive = current?.ws.readyState === import_ws.WebSocket.OPEN;
14490
+ const currentAlive = current?.ws.readyState === import_ws2.WebSocket.OPEN;
14275
14491
  if (!current || !currentAlive || !current.url) return true;
14276
14492
  const isPrimaryCandidate = sim.origin?.includes(":5173");
14277
14493
  const currentIsPrimary = current.origin?.includes(":5173");
@@ -14279,7 +14495,7 @@ var init_bridge_host = __esm({
14279
14495
  }
14280
14496
  broadcastSimAssignments() {
14281
14497
  for (const sim of this.sims.values()) {
14282
- if (sim.ws.readyState !== import_ws.WebSocket.OPEN) continue;
14498
+ if (sim.ws.readyState !== import_ws2.WebSocket.OPEN) continue;
14283
14499
  sim.ws.send(
14284
14500
  JSON.stringify({
14285
14501
  type: "bridge:welcome",
@@ -14291,7 +14507,7 @@ var init_bridge_host = __esm({
14291
14507
  }
14292
14508
  broadcastSimClientStates() {
14293
14509
  for (const sim of this.sims.values()) {
14294
- if (sim.ws.readyState !== import_ws.WebSocket.OPEN) continue;
14510
+ if (sim.ws.readyState !== import_ws2.WebSocket.OPEN) continue;
14295
14511
  const lease = this.getActiveLease(sim);
14296
14512
  const message = {
14297
14513
  type: "bridge:client-state",
@@ -14356,7 +14572,7 @@ var init_bridge_host = __esm({
14356
14572
  const keys = /* @__PURE__ */ new Set();
14357
14573
  for (const [ws, attachedSimId] of this.cliSimBySocket) {
14358
14574
  if (attachedSimId !== simId) continue;
14359
- if (ws.readyState !== import_ws.WebSocket.OPEN) continue;
14575
+ if (ws.readyState !== import_ws2.WebSocket.OPEN) continue;
14360
14576
  const key = this.cliIdentityKeyBySocket.get(ws);
14361
14577
  keys.add(key ?? `ws-unknown-${keys.size}`);
14362
14578
  }
@@ -14369,7 +14585,7 @@ var init_bridge_host = __esm({
14369
14585
  const keys = /* @__PURE__ */ new Set();
14370
14586
  for (const [ws, attachedSimId] of this.cliSimBySocket) {
14371
14587
  if (attachedSimId !== simId) continue;
14372
- if (ws.readyState !== import_ws.WebSocket.OPEN) continue;
14588
+ if (ws.readyState !== import_ws2.WebSocket.OPEN) continue;
14373
14589
  const key = this.cliIdentityKeyBySocket.get(ws);
14374
14590
  if (key && key === selfKey) continue;
14375
14591
  keys.add(key ?? `ws-unknown-${keys.size}`);
@@ -14394,7 +14610,7 @@ var init_bridge_host = __esm({
14394
14610
  const nextId = requestedId?.trim();
14395
14611
  if (!nextId || nextId === sim.id) return false;
14396
14612
  const existing = this.sims.get(nextId);
14397
- if (existing && existing !== sim && existing.ws.readyState === import_ws.WebSocket.OPEN) {
14613
+ if (existing && existing !== sim && existing.ws.readyState === import_ws2.WebSocket.OPEN) {
14398
14614
  return false;
14399
14615
  }
14400
14616
  const restorable = this.getRestorableSimState(nextId);
@@ -14772,7 +14988,7 @@ function createBridge(wsPort, opts = {}) {
14772
14988
  let nextId = 1;
14773
14989
  const commandTimeoutMs = opts.commandTimeoutMs ?? 15e3;
14774
14990
  const pending = /* @__PURE__ */ new Map();
14775
- const ws = new import_ws2.WebSocket(`ws://localhost:${wsPort}`);
14991
+ const ws = new import_ws3.WebSocket(`ws://localhost:${wsPort}`);
14776
14992
  const identity = opts.simId ? {
14777
14993
  key: `sim:${opts.simId}`,
14778
14994
  source: "explicit-sim-id",
@@ -14925,14 +15141,14 @@ function createBridge(wsPort, opts = {}) {
14925
15141
  },
14926
15142
  close() {
14927
15143
  try {
14928
- if (ws.readyState === import_ws2.WebSocket.OPEN) {
15144
+ if (ws.readyState === import_ws3.WebSocket.OPEN) {
14929
15145
  ws.send(JSON.stringify({ type: "bridge:bye", id: 0 }));
14930
15146
  }
14931
15147
  } catch {
14932
15148
  }
14933
15149
  ws.close();
14934
15150
  const terminateTimer = setTimeout(() => {
14935
- if (ws.readyState !== import_ws2.WebSocket.CLOSED) {
15151
+ if (ws.readyState !== import_ws3.WebSocket.CLOSED) {
14936
15152
  ws.terminate();
14937
15153
  }
14938
15154
  }, 250);
@@ -15002,11 +15218,11 @@ async function callInBridge(bridge, path9, ...args) {
15002
15218
  async function callInBridgeWrite(bridge, path9, ...args) {
15003
15219
  return bridge.send({ type: "call", path: path9, args, acquireLock: true });
15004
15220
  }
15005
- var import_ws2, BridgeSimLockedError;
15221
+ var import_ws3, BridgeSimLockedError;
15006
15222
  var init_ws_bridge = __esm({
15007
15223
  "cli/ws-bridge.ts"() {
15008
15224
  "use strict";
15009
- import_ws2 = require("ws");
15225
+ import_ws3 = require("ws");
15010
15226
  init_bridge_constants();
15011
15227
  init_home_paths();
15012
15228
  init_current_sim();
@@ -16806,25 +17022,15 @@ var init_bridge_flow_runner = __esm({
16806
17022
  }
16807
17023
  async startProfile() {
16808
17024
  await this.evaluate(`((sessionKey) => {
16809
- const host = window.__sootsimRenderHost
16810
- if (host?.startPerfSession) {
16811
- host.startPerfSession(sessionKey)
16812
- window[sessionKey] = {
16813
- active: true,
16814
- mode: 'render-worker',
16815
- startedAt: performance.now(),
16816
- }
16817
- return
16818
- }
16819
-
16820
17025
  const perf = window.__sootsimPerf
16821
17026
  const a11y = window.__sootsimA11y
16822
- perf?.enableFrameStats?.()
17027
+ perf?.enableFrameStats?.(true)
16823
17028
  perf?.resetFrameStats?.()
16824
17029
  a11y?.resetProfile?.()
16825
17030
  window[sessionKey] = {
16826
17031
  active: true,
16827
- mode: 'main-thread',
17032
+ mode: window.__sootsimRenderHost ? 'render-worker' : 'main-thread',
17033
+ lastSamples: [],
16828
17034
  startedAt: performance.now(),
16829
17035
  }
16830
17036
  })(${JSON.stringify(CLI_PERF_SESSION_GLOBAL)})`);
@@ -16833,13 +17039,24 @@ var init_bridge_flow_runner = __esm({
16833
17039
  async stopProfile() {
16834
17040
  const result = await this.evaluate(`(async (sessionKey) => {
16835
17041
  const host = window.__sootsimRenderHost
16836
- if (host?.stopPerfSession) {
16837
- const stopped = await host.stopPerfSession(sessionKey)
16838
- if (!stopped || !Array.isArray(stopped.samples)) {
16839
- return { error: 'no render-worker perf samples available' }
17042
+ if (host?.flushSamples) {
17043
+ const perf = window.__sootsimPerf
17044
+ const session = window[sessionKey] || {}
17045
+ const priorSamples = session.active && Array.isArray(session.lastSamples)
17046
+ ? session.lastSamples
17047
+ : []
17048
+ const flushedSamples = await host.flushSamples()
17049
+ await perf?.disableFrameStats?.()
17050
+ const samples = priorSamples.concat(flushedSamples)
17051
+ window[sessionKey] = {
17052
+ ...session,
17053
+ active: false,
17054
+ mode: 'render-worker',
17055
+ lastSamples: samples,
17056
+ stoppedAt: performance.now(),
16840
17057
  }
16841
- const samples = stopped.samples
16842
- const frameTimes = samples.map((sample) => Number(sample?.[1]) || 0).filter((value) => value > 0)
17058
+
17059
+ const frameTimes = samples.map((sample) => Number(sample?.[1]) || 0)
16843
17060
  const sorted = [...frameTimes].sort((a, b) => a - b)
16844
17061
  const worstFrames = samples
16845
17062
  .slice()
@@ -16855,16 +17072,16 @@ var init_bridge_flow_runner = __esm({
16855
17072
 
16856
17073
  return {
16857
17074
  mode: 'render-worker',
16858
- frames: Number(stopped.frameCount) || frameTimes.length,
16859
- totalMs: Number(stopped.totalMs) || frameTimes.reduce((sum, value) => sum + value, 0),
16860
- avgMs: Number(stopped.avgMs) || (frameTimes.length ? frameTimes.reduce((sum, value) => sum + value, 0) / frameTimes.length : 0),
16861
- maxMs: Number(stopped.maxMs) || (sorted[sorted.length - 1] || 0),
16862
- layoutTotalMs: Number(stopped.layoutTotalMs) || samples.reduce((sum, sample) => sum + (Number(sample?.[2]) || 0), 0),
16863
- renderTotalMs: Number(stopped.renderTotalMs) || samples.reduce((sum, sample) => sum + (Number(sample?.[3]) || 0), 0),
16864
- copyTotalMs: Number(stopped.copyTotalMs) || samples.reduce((sum, sample) => sum + (Number(sample?.[4]) || 0), 0),
16865
- layoutAvgMs: Number(stopped.layoutAvgMs) || 0,
16866
- renderAvgMs: Number(stopped.renderAvgMs) || 0,
16867
- copyAvgMs: Number(stopped.copyAvgMs) || 0,
17075
+ frames: frameTimes.length,
17076
+ totalMs: frameTimes.reduce((sum, value) => sum + value, 0),
17077
+ avgMs: frameTimes.length ? frameTimes.reduce((sum, value) => sum + value, 0) / frameTimes.length : 0,
17078
+ maxMs: sorted[sorted.length - 1] || 0,
17079
+ layoutTotalMs: samples.reduce((sum, sample) => sum + (Number(sample?.[2]) || 0), 0),
17080
+ renderTotalMs: samples.reduce((sum, sample) => sum + (Number(sample?.[3]) || 0), 0),
17081
+ copyTotalMs: samples.reduce((sum, sample) => sum + (Number(sample?.[4]) || 0), 0),
17082
+ layoutAvgMs: frameTimes.length ? samples.reduce((sum, sample) => sum + (Number(sample?.[2]) || 0), 0) / frameTimes.length : 0,
17083
+ renderAvgMs: frameTimes.length ? samples.reduce((sum, sample) => sum + (Number(sample?.[3]) || 0), 0) / frameTimes.length : 0,
17084
+ copyAvgMs: frameTimes.length ? samples.reduce((sum, sample) => sum + (Number(sample?.[4]) || 0), 0) / frameTimes.length : 0,
16868
17085
  p50: sorted[Math.floor(sorted.length * 0.5)] || 0,
16869
17086
  p95: sorted[Math.floor(sorted.length * 0.95)] || 0,
16870
17087
  p99: sorted[Math.floor(sorted.length * 0.99)] || 0,
@@ -16878,11 +17095,11 @@ var init_bridge_flow_runner = __esm({
16878
17095
  const a11y = window.__sootsimA11y
16879
17096
  if (!perf && !a11y) return { error: 'no perf globals available' }
16880
17097
 
16881
- const frameStats = perf?.getFrameStats?.() || {}
17098
+ const stoppedStats = await perf?.disableFrameStats?.()
17099
+ const frameStats = stoppedStats || await perf?.getFrameStats?.() || {}
16882
17100
  const profile = a11y?.profile?.() || {}
16883
17101
  const recent = Array.isArray(frameStats.recentFrames) ? frameStats.recentFrames : []
16884
17102
  const sorted = [...recent].sort((a, b) => a - b)
16885
- perf?.disableFrameStats?.()
16886
17103
 
16887
17104
  return {
16888
17105
  mode: 'main-thread',
package/dist-lib/vite.cjs CHANGED
@@ -1,4 +1,4 @@
1
- /*! sootsim v0.1.85 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
1
+ /*! sootsim v0.1.87 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
2
2
  let __sootsim_import_meta_url = ''; try { __sootsim_import_meta_url = require('url').pathToFileURL(__filename).href; } catch {}
3
3
  "use strict";
4
4
  var __create = Object.create;