sootsim 0.1.83 → 0.1.84

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 (207) hide show
  1. package/README.md +0 -1
  2. package/detox/colors.ts +54 -0
  3. package/detox/config-loader.ts +135 -0
  4. package/detox/expectations.ts +477 -0
  5. package/detox/gestures.ts +442 -0
  6. package/detox/index.ts +1436 -0
  7. package/detox/jest-environment.ts +86 -0
  8. package/detox/jest-preset.cjs +50 -0
  9. package/detox/matchers.ts +29 -0
  10. package/detox/navigation.ts +43 -0
  11. package/detox/run-test.ts +113 -0
  12. package/detox/screenshots/animated-color-test-rest-norngh.png +0 -0
  13. package/detox/screenshots/color-test-after-drag-norngh.png +0 -0
  14. package/detox/screenshots/color-test-rest-norngh.png +0 -0
  15. package/detox/screenshots/theme-blue-toggle.png +0 -0
  16. package/detox/screenshots/theme-blue.png +0 -0
  17. package/detox/screenshots/theme-red-toggle.png +0 -0
  18. package/detox/screenshots/theme-red.png +0 -0
  19. package/dist-cli/bin.js +3 -3
  20. package/dist-cli/chunks/{agent-MQ7GLVIB.js → agent-2CWD6W6P.js} +2 -2
  21. package/dist-cli/chunks/{agent-wrapper-7KAFDQCN.js → agent-wrapper-5W3LOX6S.js} +2 -2
  22. package/dist-cli/chunks/{assert-TV46GUNU.js → assert-ZOMAMKRT.js} +2 -2
  23. package/dist-cli/chunks/auto-bootstrap-NYYSMTIM.js +2 -0
  24. package/dist-cli/chunks/beta-4K2SQACK.js +2 -0
  25. package/dist-cli/chunks/chunk-3HXQ7MJK.js +79 -0
  26. package/dist-cli/chunks/{chunk-4LS5MZAI.js → chunk-4K7BH2D4.js} +3 -3
  27. package/dist-cli/chunks/{chunk-FJYT7XL2.js → chunk-4OPRODFA.js} +2 -2
  28. package/dist-cli/chunks/{chunk-DP7O5MHK.js → chunk-4OWVPRZV.js} +2 -2
  29. package/dist-cli/chunks/{chunk-PM5NVKLP.js → chunk-5XCXOLG2.js} +2 -2
  30. package/dist-cli/chunks/chunk-67ZZ2CM5.js +1 -0
  31. package/dist-cli/chunks/{chunk-WN7M3QON.js → chunk-73UZXB4B.js} +2 -2
  32. package/dist-cli/chunks/{chunk-5DJXZIFZ.js → chunk-7NWNTUJF.js} +1 -1
  33. package/dist-cli/chunks/{chunk-Y2VJBRSP.js → chunk-7YHDJLO2.js} +1 -1
  34. package/dist-cli/chunks/{chunk-6NN2D4EJ.js → chunk-AJVTY6KY.js} +1 -1
  35. package/dist-cli/chunks/chunk-AWSQUOAS.js +67 -0
  36. package/dist-cli/chunks/{chunk-CJY3AVI7.js → chunk-BCBNVJVG.js} +1 -1
  37. package/dist-cli/chunks/{chunk-OYMFNU3M.js → chunk-BKBL6K2G.js} +1 -1
  38. package/dist-cli/chunks/{chunk-IBNRRAES.js → chunk-C3DPQZ4J.js} +2 -2
  39. package/dist-cli/chunks/chunk-D3ZSBIIY.js +2 -0
  40. package/dist-cli/chunks/{chunk-2AWQ7OB2.js → chunk-D4HUVLZR.js} +1 -1
  41. package/dist-cli/chunks/{chunk-F3HP444U.js → chunk-DUUSJDES.js} +1 -1
  42. package/dist-cli/chunks/{chunk-277XAALA.js → chunk-ELJLF4SG.js} +3 -3
  43. package/dist-cli/chunks/{chunk-RH4F2TF7.js → chunk-EQ7TFQ2F.js} +1 -1
  44. package/dist-cli/chunks/{chunk-HNWEELAE.js → chunk-EQCKGC4B.js} +1 -1
  45. package/dist-cli/chunks/chunk-FUCGLWNN.js +1 -0
  46. package/dist-cli/chunks/{chunk-FRM355UL.js → chunk-HYPJW65U.js} +2 -2
  47. package/dist-cli/chunks/chunk-IILJQCZA.js +2 -0
  48. package/dist-cli/chunks/{chunk-Y4BUVURT.js → chunk-KU6MSPAH.js} +2 -2
  49. package/dist-cli/chunks/{chunk-DM6WT7QM.js → chunk-OOOR7NT2.js} +1 -1
  50. package/dist-cli/chunks/{chunk-HAWOAQAG.js → chunk-P7WDNKOS.js} +3 -3
  51. package/dist-cli/chunks/{chunk-6TNANCQC.js → chunk-PPKKA5VW.js} +2 -2
  52. package/dist-cli/chunks/{chunk-JQ7ZXOXJ.js → chunk-PS2G44GT.js} +2 -2
  53. package/dist-cli/chunks/{chunk-ECJBV65H.js → chunk-QMSJR5R2.js} +2 -2
  54. package/dist-cli/chunks/{chunk-J2GYISVJ.js → chunk-RF4R2U46.js} +2 -2
  55. package/dist-cli/chunks/{chunk-VMXWC2JO.js → chunk-RIXUH3NK.js} +2 -2
  56. package/dist-cli/chunks/{chunk-2PY3UZVO.js → chunk-SFGUPL2X.js} +2 -2
  57. package/dist-cli/chunks/{chunk-572VSFNP.js → chunk-SQX5CAYG.js} +1 -1
  58. package/dist-cli/chunks/{chunk-NXATOWWF.js → chunk-SQZAC7C4.js} +1 -1
  59. package/dist-cli/chunks/{chunk-WTKTOL3C.js → chunk-SV7FOGJ3.js} +2 -2
  60. package/dist-cli/chunks/{chunk-JHJNODXN.js → chunk-TK3OJSEO.js} +2 -2
  61. package/dist-cli/chunks/{chunk-KASUZ5XV.js → chunk-TL7SIZ7S.js} +1 -1
  62. package/dist-cli/chunks/{chunk-6XZOEBTZ.js → chunk-V2GQ4WXJ.js} +2 -2
  63. package/dist-cli/chunks/{chunk-IP3QJLRH.js → chunk-VH7F45CN.js} +1 -1
  64. package/dist-cli/chunks/chunk-WNVNU2OW.js +4 -0
  65. package/dist-cli/chunks/{chunk-YUELRHGB.js → chunk-XQ2OBHBE.js} +2 -2
  66. package/dist-cli/chunks/{chunk-CYV6Y6YV.js → chunk-YCIA4BHJ.js} +2 -2
  67. package/dist-cli/chunks/chunk-ZSMMJMPA.js +1 -0
  68. package/dist-cli/chunks/cli-version-QB4VH24H.js +2 -0
  69. package/dist-cli/chunks/{compat-QLLWBTS3.js → compat-FWSEEGEH.js} +3 -3
  70. package/dist-cli/chunks/{config-2DSLDCXV.js → config-CYI2WAGP.js} +2 -2
  71. package/dist-cli/chunks/control-UXY7YQVX.js +2 -0
  72. package/dist-cli/chunks/{cpu-profile-GEIKHCPC.js → cpu-profile-IKAE3KTY.js} +2 -2
  73. package/dist-cli/chunks/{daemon-4EBUFN4D.js → daemon-ZUMF53YB.js} +2 -2
  74. package/dist-cli/chunks/{debug-WGD6XWOF.js → debug-P6KULKKS.js} +3 -3
  75. package/dist-cli/chunks/{detox-LNKGRZU6.js → detox-SPWAZCYG.js} +2 -2
  76. package/dist-cli/chunks/{device-AYKXKVIQ.js → device-JWEPK6I2.js} +2 -2
  77. package/dist-cli/chunks/{diagnose-TMXSDOOC.js → diagnose-IZODTXV2.js} +2 -2
  78. package/dist-cli/chunks/drivers-MK6WJKBC.js +2 -0
  79. package/dist-cli/chunks/{electron-QFPF7TBY.js → electron-R5GP6RVB.js} +3 -3
  80. package/dist-cli/chunks/flow-6O4GEOPJ.js +2 -0
  81. package/dist-cli/chunks/{hints-MXKRR4TG.js → hints-DYDNYX7N.js} +2 -2
  82. package/dist-cli/chunks/{home-paths-REMWQDAO.js → home-paths-GLMX5OKL.js} +2 -2
  83. package/dist-cli/chunks/{inspect-XGSQNFV7.js → inspect-FJOPCTY2.js} +3 -3
  84. package/dist-cli/chunks/install-A3TUGGHN.js +2 -0
  85. package/dist-cli/chunks/{install-desktop-NQG3RZSA.js → install-desktop-YPJZMZM5.js} +3 -3
  86. package/dist-cli/chunks/{keys-5QZWXL3F.js → keys-GSYPHWNY.js} +2 -2
  87. package/dist-cli/chunks/{launch-SBXOZWKO.js → launch-4G2PKW5X.js} +3 -3
  88. package/dist-cli/chunks/{login-EACQXE24.js → login-KJQGHA64.js} +4 -4
  89. package/dist-cli/chunks/{logout-IBQLMUML.js → logout-XM2SYH5C.js} +2 -2
  90. package/dist-cli/chunks/{maestro-LFYXUX7O.js → maestro-EOWGI7DG.js} +2 -2
  91. package/dist-cli/chunks/{preview-U4SBOEGQ.js → preview-F73TKK37.js} +2 -2
  92. package/dist-cli/chunks/{profile-GWS5ECMY.js → profile-22FDKBUO.js} +2 -2
  93. package/dist-cli/chunks/{react-QDHLMVYL.js → react-5L6VPFUP.js} +2 -2
  94. package/dist-cli/chunks/{record-BUEUWPDI.js → record-JZXCQ4IN.js} +2 -2
  95. package/dist-cli/chunks/runtime-EEBX7CFV.js +2 -0
  96. package/dist-cli/chunks/{runtime-delivery-G7L6RVZ7.js → runtime-delivery-LXUM3R4A.js} +2 -2
  97. package/dist-cli/chunks/{screenshot-T2HBA3VI.js → screenshot-HDRRG33Q.js} +2 -2
  98. package/dist-cli/chunks/{screenshot-mode-EG5HMIH3.js → screenshot-mode-WY63LZIX.js} +2 -2
  99. package/dist-cli/chunks/{screenshots-S52AFHTV.js → screenshots-MPV2ENL5.js} +2 -2
  100. package/dist-cli/chunks/{server-MFFVYUGG.js → server-5LBMCJ3G.js} +2 -2
  101. package/dist-cli/chunks/setup-repo-SZSYNKNI.js +2 -0
  102. package/dist-cli/chunks/{skills-HQGWBS2O.js → skills-BQ73YOBF.js} +2 -2
  103. package/dist-cli/chunks/{start-E3DRYY7W.js → start-2WU4W6ZU.js} +4 -4
  104. package/dist-cli/chunks/store-RE45SUBF.js +2 -0
  105. package/dist-cli/chunks/telemetry-DG6GJLCP.js +2 -0
  106. package/dist-cli/chunks/{test-ZY3EF62K.js → test-OVO4CQTG.js} +3 -3
  107. package/dist-cli/chunks/{three-mode-WSPKQCJ5.js → three-mode-BKM3KFM7.js} +2 -2
  108. package/dist-cli/chunks/{timeline-3XAB5EWZ.js → timeline-MDXGEDQL.js} +2 -2
  109. package/dist-cli/chunks/{upgrade-WNENPFM5.js → upgrade-JGQABWVF.js} +2 -2
  110. package/dist-cli/chunks/upload-UJNUA4ZV.js +2 -0
  111. package/dist-cli/chunks/{web-D2AOZY44.js → web-WYFAYQ72.js} +2 -2
  112. package/dist-cli/chunks/{what-happened-F43KNSG6.js → what-happened-PZW2KW6A.js} +2 -2
  113. package/dist-cli/chunks/{whoami-T22VBR7C.js → whoami-7ATWJQS6.js} +2 -2
  114. package/dist-lib/agent-daemon-client.cjs +1 -1
  115. package/dist-lib/agent-events.cjs +1 -1
  116. package/dist-lib/agent-sessions.cjs +1 -1
  117. package/dist-lib/attached-projects.cjs +1 -1
  118. package/dist-lib/auth/shared-session.cjs +1 -1
  119. package/dist-lib/backend-origin.cjs +1 -1
  120. package/dist-lib/beta.cjs +44 -0
  121. package/dist-lib/bridge-constants.cjs +1 -1
  122. package/dist-lib/cli-constants.cjs +1 -1
  123. package/dist-lib/config.cjs +1 -1
  124. package/dist-lib/detox/index.cjs +1770 -0
  125. package/dist-lib/detox/jest-preset.cjs +50 -0
  126. package/dist-lib/dev-bundle-resolution.cjs +1 -1
  127. package/dist-lib/home-paths.cjs +1 -1
  128. package/dist-lib/host/bridge-host.cjs +1 -1
  129. package/dist-lib/host/fetch-proxy-handler.cjs +1 -1
  130. package/dist-lib/host/fetch-proxy-overrides.cjs +1 -1
  131. package/dist-lib/index.cjs +1 -1
  132. package/dist-lib/metro.cjs +1 -1
  133. package/dist-lib/profiles.cjs +1 -1
  134. package/dist-lib/render-mode.cjs +1 -1
  135. package/dist-lib/scripts/demo-app-registry.cjs +809 -0
  136. package/dist-lib/scripts/dev-server-scanner.cjs +1269 -0
  137. package/dist-lib/skills.cjs +8322 -0
  138. package/dist-lib/vite-base.cjs +3 -3
  139. package/dist-lib/vite.cjs +1 -1
  140. package/package.json +39 -10
  141. package/scripts/demo-app-registry.ts +989 -0
  142. package/scripts/dev-server-scanner.ts +674 -0
  143. package/src/agent-daemon-client.ts +390 -0
  144. package/src/agent-events.ts +71 -0
  145. package/src/agent-prompt.ts +71 -0
  146. package/src/agent-sessions.ts +572 -0
  147. package/src/attached-projects.ts +536 -0
  148. package/src/auth/shared-session.ts +199 -0
  149. package/src/backend-origin.ts +49 -0
  150. package/src/beta.ts +21 -0
  151. package/src/bridge-constants.ts +10 -0
  152. package/src/cli-constants.ts +1 -0
  153. package/src/cli-version.ts +30 -0
  154. package/src/codex-client.ts +215 -0
  155. package/src/config.ts +110 -0
  156. package/src/dev-bundle-resolution.ts +180 -0
  157. package/src/home-paths.ts +382 -0
  158. package/src/host/agent-host.ts +576 -0
  159. package/src/host/bridge-host.ts +2293 -0
  160. package/src/host/fetch-proxy-handler.ts +288 -0
  161. package/src/host/fetch-proxy-overrides.ts +39 -0
  162. package/src/host/open-url.ts +234 -0
  163. package/src/index.ts +9 -0
  164. package/src/metro-plugin.ts +207 -0
  165. package/src/native-dev-bundle-url.ts +62 -0
  166. package/src/native-seam-manifest.ts +313 -0
  167. package/src/profiles.ts +179 -0
  168. package/src/render-mode.ts +27 -0
  169. package/src/runtime-delivery.ts +334 -0
  170. package/src/screenshots/compose.ts +422 -0
  171. package/src/screenshots/frame-compose.ts +438 -0
  172. package/src/screenshots/orchestrate.ts +244 -0
  173. package/src/screenshots/registry.ts +58 -0
  174. package/src/screenshots/schema.ts +364 -0
  175. package/src/skills/builtin/a11y-review.ts +126 -0
  176. package/src/skills/builtin/compat-check.ts +104 -0
  177. package/src/skills/builtin/perf-profile.ts +84 -0
  178. package/src/skills/builtin/screenshot-all.ts +46 -0
  179. package/src/skills/builtin/test-flow.ts +118 -0
  180. package/src/skills/builtin/visual-diff.ts +94 -0
  181. package/src/skills/registry.ts +107 -0
  182. package/src/skills/types.ts +41 -0
  183. package/src/vite-plugin-one.ts +187 -0
  184. package/src/vite-plugin.ts +1381 -0
  185. package/src/worklets-babel.ts +132 -0
  186. package/dist-cli/chunks/auto-bootstrap-FQS4ZD2K.js +0 -2
  187. package/dist-cli/chunks/beta-VG7CDY2U.js +0 -2
  188. package/dist-cli/chunks/chunk-2OIBDYHW.js +0 -1
  189. package/dist-cli/chunks/chunk-6BNLVMXA.js +0 -1
  190. package/dist-cli/chunks/chunk-6XD6CBJM.js +0 -2
  191. package/dist-cli/chunks/chunk-CHQTO426.js +0 -1
  192. package/dist-cli/chunks/chunk-FAPYGVIU.js +0 -4
  193. package/dist-cli/chunks/chunk-PEHFE3LG.js +0 -64
  194. package/dist-cli/chunks/chunk-RXH2SLKF.js +0 -2
  195. package/dist-cli/chunks/chunk-UXQWC5ZR.js +0 -79
  196. package/dist-cli/chunks/chunk-XFQL74PF.js +0 -5
  197. package/dist-cli/chunks/cli-version-PWF6I6LY.js +0 -2
  198. package/dist-cli/chunks/control-UIOXGYXU.js +0 -2
  199. package/dist-cli/chunks/demo-app-registry-G3BDOFWC.js +0 -2
  200. package/dist-cli/chunks/drivers-IDQF34HP.js +0 -2
  201. package/dist-cli/chunks/flow-3JN3Y7RF.js +0 -2
  202. package/dist-cli/chunks/install-2N3YOOSN.js +0 -2
  203. package/dist-cli/chunks/runtime-PVB4VGUH.js +0 -2
  204. package/dist-cli/chunks/setup-repo-YOF7NV5D.js +0 -2
  205. package/dist-cli/chunks/store-MAI6D3UO.js +0 -2
  206. package/dist-cli/chunks/telemetry-RCQKCJTH.js +0 -2
  207. package/dist-cli/chunks/upload-YLJ4RA73.js +0 -2
@@ -0,0 +1,1269 @@
1
+ /*! sootsim v0.1.84 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
2
+ let __sootsim_import_meta_url = ''; try { __sootsim_import_meta_url = require('url').pathToFileURL(__filename).href; } catch {}
3
+ "use strict";
4
+ var __create = Object.create;
5
+ var __defProp = Object.defineProperty;
6
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
7
+ var __getOwnPropNames = Object.getOwnPropertyNames;
8
+ var __getProtoOf = Object.getPrototypeOf;
9
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
10
+ var __export = (target, all) => {
11
+ for (var name in all)
12
+ __defProp(target, name, { get: all[name], enumerable: true });
13
+ };
14
+ var __copyProps = (to, from, except, desc) => {
15
+ if (from && typeof from === "object" || typeof from === "function") {
16
+ for (let key of __getOwnPropNames(from))
17
+ if (!__hasOwnProp.call(to, key) && key !== except)
18
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
19
+ }
20
+ return to;
21
+ };
22
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
23
+ // If the importer is in node compatibility mode or this is not an ESM
24
+ // file that has been converted to a CommonJS file using a Babel-
25
+ // compatible transform (i.e. "__esModule" has not been set), then set
26
+ // "default" to the CommonJS "module.exports" for node compatibility.
27
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
28
+ mod
29
+ ));
30
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
31
+
32
+ // scripts/dev-server-scanner.ts
33
+ var dev_server_scanner_exports = {};
34
+ __export(dev_server_scanner_exports, {
35
+ __applyManifestForTests: () => __applyManifestForTests,
36
+ __resetScannerCache: () => __resetScannerCache,
37
+ __shouldReuseScannerCacheEntry: () => __shouldReuseScannerCacheEntry,
38
+ discoverListeningPorts: () => discoverListeningPorts,
39
+ discoverListeningProcesses: () => discoverListeningProcesses,
40
+ probePort: () => probePort,
41
+ resolveProcessCwd: () => resolveProcessCwd,
42
+ scanDevServers: () => scanDevServers
43
+ });
44
+ module.exports = __toCommonJS(dev_server_scanner_exports);
45
+ var import_child_process = require("child_process");
46
+ var import_http = __toESM(require("http"), 1);
47
+ var import_net = __toESM(require("net"), 1);
48
+ var import_util = require("util");
49
+
50
+ // src/config.ts
51
+ var SOOTSIM_CONFIG_QUERY_PARAM = "sootsimConfig";
52
+ function hasOwnKeys(value) {
53
+ return !!value && Object.keys(value).length > 0;
54
+ }
55
+ function hasSootSimConfig(config) {
56
+ if (!config) return false;
57
+ return hasOwnKeys(config.modules) || hasOwnKeys(config.turboModules) || hasOwnKeys(config.nativeModules) || hasOwnKeys(config.env) || hasOwnKeys(config.settings) || hasOwnKeys(config.initialState);
58
+ }
59
+ function applySootSimConfigToUrl(url, config) {
60
+ const parsed = new URL(url);
61
+ if (hasSootSimConfig(config)) {
62
+ parsed.searchParams.set(SOOTSIM_CONFIG_QUERY_PARAM, JSON.stringify(config));
63
+ } else {
64
+ parsed.searchParams.delete(SOOTSIM_CONFIG_QUERY_PARAM);
65
+ }
66
+ return parsed.toString();
67
+ }
68
+
69
+ // src/native-dev-bundle-url.ts
70
+ function isAbsoluteHttpUrl(url) {
71
+ return /^https?:\/\//i.test(url);
72
+ }
73
+ function isNativeDevBundlePath(pathname) {
74
+ return pathname.endsWith(".bundle");
75
+ }
76
+ function applyPreviewProdBundle(parsed) {
77
+ if (!process.env.SOOTSIM_PREVIEW_PROD_BUNDLE) return;
78
+ parsed.searchParams.set("dev", "false");
79
+ parsed.searchParams.set("minify", "true");
80
+ if (parsed.searchParams.has("hot")) parsed.searchParams.set("hot", "false");
81
+ }
82
+ function normalizeNativeDevBundleUrl(bundleUrl) {
83
+ try {
84
+ const isAbsolute = isAbsoluteHttpUrl(bundleUrl);
85
+ const parsed = new URL(bundleUrl, "http://soot.local");
86
+ parsed.pathname = parsed.pathname.replace(/\.\.bundle$/, ".bundle");
87
+ if (!isNativeDevBundlePath(parsed.pathname)) return bundleUrl;
88
+ parsed.searchParams.delete("transform.bytecode");
89
+ applyPreviewProdBundle(parsed);
90
+ if (isAbsolute) return parsed.toString();
91
+ return `${parsed.pathname}${parsed.search}${parsed.hash}`;
92
+ } catch {
93
+ return bundleUrl;
94
+ }
95
+ }
96
+
97
+ // scripts/demo-app-registry.ts
98
+ var import_node_fs = require("node:fs");
99
+ var import_node_os = require("node:os");
100
+ var import_node_path = require("node:path");
101
+ var HOME = (0, import_node_os.homedir)();
102
+ function findWorkspaceRoot(startDir) {
103
+ let dir = startDir;
104
+ while (true) {
105
+ if ((0, import_node_fs.existsSync)((0, import_node_path.join)(dir, "pnpm-workspace.yaml")) || (0, import_node_fs.existsSync)((0, import_node_path.join)(dir, "turbo.json")) || (0, import_node_fs.existsSync)((0, import_node_path.join)(dir, "nx.json")) || (0, import_node_fs.existsSync)((0, import_node_path.join)(dir, "lerna.json"))) {
106
+ return dir;
107
+ }
108
+ const packageJsonPath = (0, import_node_path.join)(dir, "package.json");
109
+ if ((0, import_node_fs.existsSync)(packageJsonPath)) {
110
+ try {
111
+ const pkg = JSON.parse((0, import_node_fs.readFileSync)(packageJsonPath, "utf8"));
112
+ if (pkg.workspaces) return dir;
113
+ } catch {
114
+ }
115
+ }
116
+ const parent = (0, import_node_path.dirname)(dir);
117
+ if (parent === dir) return null;
118
+ dir = parent;
119
+ }
120
+ }
121
+ function resolveWorkspaceScriptPath(workspaceRelativePath, packageRelativePath) {
122
+ const workspaceRoot = findWorkspaceRoot(process.cwd());
123
+ const candidates = [
124
+ workspaceRoot ? (0, import_node_path.resolve)(workspaceRoot, workspaceRelativePath) : null,
125
+ (0, import_node_path.resolve)(process.cwd(), workspaceRelativePath),
126
+ (0, import_node_path.resolve)(process.cwd(), packageRelativePath)
127
+ ].filter((candidate) => Boolean(candidate));
128
+ for (const candidate of candidates) {
129
+ if ((0, import_node_fs.existsSync)(candidate)) return candidate;
130
+ }
131
+ return candidates[0] ?? (0, import_node_path.resolve)(process.cwd(), workspaceRelativePath);
132
+ }
133
+ var getExpensifyProxyScript = () => resolveWorkspaceScriptPath(
134
+ "packages/sootsim-engine/scripts/expensify-web-proxy.ts",
135
+ "scripts/expensify-web-proxy.ts"
136
+ );
137
+ var getRainbowMetadataProxyScript = () => resolveWorkspaceScriptPath(
138
+ "packages/sootsim-engine/scripts/rainbow-metadata-proxy.ts",
139
+ "scripts/rainbow-metadata-proxy.ts"
140
+ );
141
+ var getMattermostRNUtilsNativeModule = () => resolveWorkspaceScriptPath(
142
+ "packages/compat/src/stubs/mattermost-rnutils-native.ts",
143
+ "../compat/src/stubs/mattermost-rnutils-native.ts"
144
+ );
145
+ var getMattermostKeychainNativeModule = () => resolveWorkspaceScriptPath(
146
+ "packages/compat/src/stubs/native-seams/react-native-keychain-manager.ts",
147
+ "../compat/src/stubs/native-seams/react-native-keychain-manager.ts"
148
+ );
149
+ var getMattermostNetworkClientNativeModule = () => resolveWorkspaceScriptPath(
150
+ "packages/compat/src/stubs/mattermost-network-client-native.ts",
151
+ "../compat/src/stubs/mattermost-network-client-native.ts"
152
+ );
153
+ var getMattermostPreviewServerScript = () => resolveWorkspaceScriptPath(
154
+ "packages/sootsim-engine/scripts/mattermost-preview-server.ts",
155
+ "scripts/mattermost-preview-server.ts"
156
+ );
157
+ var EXPENSIFY_NATIVE_PROXY_ENV = {
158
+ USE_NGROK: "true",
159
+ NGROK_URL: "http://localhost:9000/",
160
+ SECURE_NGROK_URL: "http://localhost:9000/"
161
+ };
162
+ var MATTERMOST_DIR = (0, import_node_path.join)(HOME, "github/mattermost-mobile");
163
+ var UNISWAP_REPO_DIR = (0, import_node_path.join)(HOME, "github/uniswap-interface");
164
+ var UNISWAP_APP_DIR = (0, import_node_path.join)(UNISWAP_REPO_DIR, "apps/mobile");
165
+ var UNISWAP_ENV_LOCAL_FILE = (0, import_node_path.join)(UNISWAP_REPO_DIR, ".env.defaults.local");
166
+ var UNISWAP_PLACEHOLDER = "stored-in-.env.local";
167
+ var UNISWAP_DEMO_ENV_MARKER = "# sootsim demo env overrides";
168
+ var UNISWAP_FORCE_UPGRADE_HOOK_FILE = (0, import_node_path.join)(
169
+ UNISWAP_REPO_DIR,
170
+ "packages/uniswap/src/features/forceUpgrade/hooks/useForceUpgradeStatus.ts"
171
+ );
172
+ var UNISWAP_FORCE_UPGRADE_NOTIFICATION_FILE = (0, import_node_path.join)(
173
+ UNISWAP_REPO_DIR,
174
+ "apps/mobile/src/notification-service/data-sources/createForceUpgradeNotificationDataSource.ts"
175
+ );
176
+ var UNISWAP_FORCE_UPGRADE_PATCH_MARKER = "SOOTSIM_DEMO_DISABLE_FORCE_UPGRADE";
177
+ function parseEnvFile(filePath) {
178
+ if (!(0, import_node_fs.existsSync)(filePath)) return {};
179
+ const env = {};
180
+ const source = (0, import_node_fs.readFileSync)(filePath, "utf8");
181
+ for (const rawLine of source.split(/\r?\n/)) {
182
+ const line = rawLine.trim();
183
+ if (!line || line.startsWith("#")) continue;
184
+ const match = line.match(/^([A-Za-z_][A-Za-z0-9_]*)\s*=\s*(.*)$/);
185
+ if (!match) continue;
186
+ let value = match[2].trim();
187
+ if (value.startsWith('"') && value.endsWith('"') || value.startsWith("'") && value.endsWith("'")) {
188
+ value = value.slice(1, -1);
189
+ }
190
+ env[match[1]] = value;
191
+ }
192
+ return env;
193
+ }
194
+ function isUsableUniswapEnvValue(value) {
195
+ if (!value) return false;
196
+ const trimmed = value.trim();
197
+ if (!trimmed) return false;
198
+ if (trimmed.includes(UNISWAP_PLACEHOLDER)) return false;
199
+ if (trimmed === "TRADING_API_KEY" || trimmed === "UNISWAP_API_KEY") return false;
200
+ return true;
201
+ }
202
+ function pickEnvValue(sources, keys) {
203
+ for (const source of sources) {
204
+ for (const key of keys) {
205
+ const value = source[key];
206
+ if (isUsableUniswapEnvValue(value)) return value.trim();
207
+ }
208
+ }
209
+ return void 0;
210
+ }
211
+ function resolveUniswapDemoEnv() {
212
+ const localEnv = parseEnvFile(UNISWAP_ENV_LOCAL_FILE);
213
+ const webEnv = parseEnvFile((0, import_node_path.join)(UNISWAP_REPO_DIR, "apps/web/.env"));
214
+ const sources = [
215
+ process.env,
216
+ localEnv,
217
+ webEnv
218
+ ];
219
+ const env = {};
220
+ const bindings = [
221
+ ["AMPLITUDE_PROXY_URL_OVERRIDE", ["REACT_APP_AMPLITUDE_PROXY_URL"]],
222
+ ["QUICKNODE_ENDPOINT_NAME", ["REACT_APP_QUICKNODE_ENDPOINT_NAME"]],
223
+ ["QUICKNODE_ENDPOINT_TOKEN", ["REACT_APP_QUICKNODE_ENDPOINT_TOKEN"]],
224
+ ["INFURA_KEY", ["REACT_APP_INFURA_KEY"]],
225
+ ["STATSIG_API_KEY", ["REACT_APP_STATSIG_API_KEY"]],
226
+ ["STATSIG_PROXY_URL_OVERRIDE", ["REACT_APP_STATSIG_PROXY_URL"]],
227
+ ["WALLETCONNECT_PROJECT_ID", ["REACT_APP_WALLET_CONNECT_PROJECT_ID"]],
228
+ ["WALLETCONNECT_PROJECT_ID_BETA", ["REACT_APP_WALLET_CONNECT_PROJECT_ID"]],
229
+ ["WALLETCONNECT_PROJECT_ID_DEV", ["REACT_APP_WALLET_CONNECT_PROJECT_ID"]],
230
+ ["TRADING_API_KEY", ["REACT_APP_TRADING_API_KEY"]],
231
+ ["UNISWAP_API_KEY", []]
232
+ ];
233
+ for (const [target, aliases] of bindings) {
234
+ const value = pickEnvValue(sources, [target, ...aliases]);
235
+ if (!value) continue;
236
+ env[target] = value;
237
+ for (const alias of aliases) {
238
+ env[alias] = value;
239
+ }
240
+ }
241
+ const hasPrivateGatewayKeys = isUsableUniswapEnvValue(env.TRADING_API_KEY) && isUsableUniswapEnvValue(env.UNISWAP_API_KEY);
242
+ if (!hasPrivateGatewayKeys) {
243
+ const publicGraphqlUrl = pickEnvValue(sources, ["GRAPHQL_URL_OVERRIDE", "REACT_APP_AWS_API_ENDPOINT"]) || "https://interface.gateway.uniswap.org/v1/graphql";
244
+ env.API_BASE_URL_OVERRIDE = "https://interface.gateway.uniswap.org";
245
+ env.API_BASE_URL_V2_OVERRIDE = "https://interface.gateway.uniswap.org/v2";
246
+ env.GRAPHQL_URL_OVERRIDE = publicGraphqlUrl;
247
+ env.TRADING_API_URL_OVERRIDE = "https://trading-api-labs.interface.gateway.uniswap.org";
248
+ env.FOR_API_URL_OVERRIDE = "https://for.interface.gateway.uniswap.org/v2/FOR.v1.FORService";
249
+ }
250
+ return env;
251
+ }
252
+ function ensureUniswapDemoEnvLocal() {
253
+ const existingSource = (0, import_node_fs.existsSync)(UNISWAP_ENV_LOCAL_FILE) ? (0, import_node_fs.readFileSync)(UNISWAP_ENV_LOCAL_FILE, "utf8") : "";
254
+ if (existingSource && !existingSource.includes(UNISWAP_DEMO_ENV_MARKER)) {
255
+ return;
256
+ }
257
+ const env = resolveUniswapDemoEnv();
258
+ const lines = [UNISWAP_DEMO_ENV_MARKER];
259
+ for (const [key, value] of Object.entries(env).sort(([a], [b]) => a.localeCompare(b))) {
260
+ lines.push(`${key}=${JSON.stringify(value)}`);
261
+ }
262
+ lines.push("");
263
+ (0, import_node_fs.writeFileSync)(UNISWAP_ENV_LOCAL_FILE, `${lines.join("\n")}
264
+ `);
265
+ }
266
+ function ensureUniswapForceUpgradePatched() {
267
+ const hookNeedle = `export function useForceUpgradeStatus(): ForceUpgradeStatus {
268
+ `;
269
+ const hookPatch = ` // sootsim demo: bypass the force-upgrade gate during local engine demos.
270
+ return 'not-required'
271
+
272
+ `;
273
+ const hookLegacyPatch = ` // sootsim demo: bypass the force-upgrade gate during local engine demos.
274
+ if (process.env.${UNISWAP_FORCE_UPGRADE_PATCH_MARKER} === 'true') {
275
+ return 'not-required'
276
+ }
277
+
278
+ `;
279
+ const notificationNeedle = ` const getForceUpgradeStatus = (): ForceUpgradeStatus => {
280
+ `;
281
+ const notificationPatch = ` // sootsim demo: bypass the force-upgrade gate during local engine demos.
282
+ return 'not-required'
283
+
284
+ `;
285
+ const notificationLegacyPatch = ` // sootsim demo: bypass the force-upgrade gate during local engine demos.
286
+ if (process.env.${UNISWAP_FORCE_UPGRADE_PATCH_MARKER} === 'true') {
287
+ return 'not-required'
288
+ }
289
+
290
+ `;
291
+ const patchWithMigration = (filePath, needle, patch, legacyPatch) => {
292
+ const source = (0, import_node_fs.readFileSync)(filePath, "utf8");
293
+ if (source.includes(patch)) return;
294
+ if (source.includes(legacyPatch)) {
295
+ (0, import_node_fs.writeFileSync)(filePath, source.replace(legacyPatch, patch));
296
+ return;
297
+ }
298
+ if (!source.includes(needle)) {
299
+ throw new Error(
300
+ `uniswap demo patch failed: expected snippet not found in ${filePath}`
301
+ );
302
+ }
303
+ (0, import_node_fs.writeFileSync)(filePath, source.replace(needle, `${needle}${patch}`));
304
+ };
305
+ patchWithMigration(
306
+ UNISWAP_FORCE_UPGRADE_HOOK_FILE,
307
+ hookNeedle,
308
+ hookPatch,
309
+ hookLegacyPatch
310
+ );
311
+ patchWithMigration(
312
+ UNISWAP_FORCE_UPGRADE_NOTIFICATION_FILE,
313
+ notificationNeedle,
314
+ notificationPatch,
315
+ notificationLegacyPatch
316
+ );
317
+ }
318
+ var JOPLIN_DIR = (0, import_node_path.join)(HOME, "github/joplin");
319
+ var JOPLIN_APP_DIR = (0, import_node_path.join)(JOPLIN_DIR, "packages/app-mobile");
320
+ var JOPLIN_WATCH_ROOTS = [
321
+ "packages/lib",
322
+ "packages/renderer",
323
+ "packages/turndown",
324
+ "packages/turndown-plugin-gfm",
325
+ "packages/editor",
326
+ "packages/tools",
327
+ "packages/utils",
328
+ "packages/fork-htmlparser2",
329
+ "packages/fork-uslug",
330
+ "packages/fork-sax",
331
+ "packages/htmlpack",
332
+ "packages/react-native-saf-x",
333
+ "packages/react-native-alarm-notification"
334
+ ];
335
+ function ensureJoplinWatchmanConfigs() {
336
+ if (!(0, import_node_fs.existsSync)(JOPLIN_DIR)) return;
337
+ for (const rel of JOPLIN_WATCH_ROOTS) {
338
+ const dir = (0, import_node_path.join)(JOPLIN_DIR, rel);
339
+ if (!(0, import_node_fs.existsSync)(dir)) continue;
340
+ const cfg = (0, import_node_path.join)(dir, ".watchmanconfig");
341
+ if (!(0, import_node_fs.existsSync)(cfg)) (0, import_node_fs.writeFileSync)(cfg, "{}\n");
342
+ }
343
+ }
344
+ var JOPLIN_BUILD_SENTINELS = [
345
+ "packages/lib/models/Setting.js",
346
+ "packages/turndown/lib/turndown.cjs.js",
347
+ "packages/app-mobile/pluginAssets/index.js"
348
+ ];
349
+ function ensureJoplinBuilt() {
350
+ if (!(0, import_node_fs.existsSync)(JOPLIN_DIR)) return;
351
+ const missing = JOPLIN_BUILD_SENTINELS.filter(
352
+ (rel) => !(0, import_node_fs.existsSync)((0, import_node_path.join)(JOPLIN_DIR, rel))
353
+ );
354
+ if (missing.length === 0) return;
355
+ const { execSync } = require("node:child_process");
356
+ execSync("yarn buildParallel", {
357
+ cwd: JOPLIN_DIR,
358
+ stdio: "inherit",
359
+ env: { ...process.env, NO_FLIPPER: "1", CI: "" }
360
+ });
361
+ const stillMissing = JOPLIN_BUILD_SENTINELS.filter(
362
+ (rel) => !(0, import_node_fs.existsSync)((0, import_node_path.join)(JOPLIN_DIR, rel))
363
+ );
364
+ if (stillMissing.length > 0) {
365
+ throw new Error(
366
+ `joplin demo: yarn buildParallel did not produce: ${stillMissing.join(", ")}`
367
+ );
368
+ }
369
+ }
370
+ var RAINBOW_DIR = (0, import_node_path.join)(HOME, "github/rainbow");
371
+ var RAINBOW_GRAPHQL_DIR = (0, import_node_path.join)(RAINBOW_DIR, "src/graphql");
372
+ var RAINBOW_GRAPHQL_CONFIG_FILE = (0, import_node_path.join)(RAINBOW_GRAPHQL_DIR, "config.js");
373
+ var RAINBOW_NETWORKS_FILE = (0, import_node_path.join)(RAINBOW_DIR, "src/references/networks.json");
374
+ var RAINBOW_METADATA_BASE_URL = "https://metadata.p.rainbow.me";
375
+ var RAINBOW_METADATA_PROXY_PORT = 9011;
376
+ var RAINBOW_DEMO_METADATA_BASE_URL = `http://127.0.0.1:${RAINBOW_METADATA_PROXY_PORT}`;
377
+ var RAINBOW_PUBLIC_ENS_GRAPHQL_URL = "https://api.thegraph.com/subgraphs/name/ensdomains/ens";
378
+ var RAINBOW_DEMO_QUOTE_SIGNER = "0x0000000000000000000000000000000000000000";
379
+ var RAINBOW_DEMO_RELAY_URL = "https://relay.rainbow.me";
380
+ var RAINBOW_DEMO_MASTER_KEY = "sootsim-rainbow-demo-master-key-do-not-use-for-real-wallets";
381
+ var RAINBOW_DEMO_RPC_PROXY_BASE_URL = "https://rpc.rainbow.me/v1";
382
+ var RAINBOW_DEMO_RPC_API_KEY = "";
383
+ var RAINBOW_DEMO_PUBLIC_RPC_URLS = {
384
+ "1": "https://ethereum-rpc.publicnode.com"
385
+ };
386
+ var RAINBOW_DEMO_SERVICE_API_KEY = "sootsim-rainbow-demo-api-key";
387
+ var RAINBOW_DEMO_SECURE_WALLET_HASH_KEY = "0x736f6f7473696d2d7261696e626f772d64656d6f2d686173682d6b6579000000";
388
+ var RAINBOW_GRAPHQL_SENTINELS = [
389
+ "src/graphql/__generated__/ens.ts",
390
+ "src/graphql/__generated__/metadata.ts",
391
+ "src/graphql/__generated__/metadataPOST.ts"
392
+ ];
393
+ function runRainbowSetupCommand(command, cwd) {
394
+ const { execSync } = require("node:child_process");
395
+ execSync(command, {
396
+ cwd,
397
+ stdio: "inherit",
398
+ env: {
399
+ ...process.env,
400
+ METADATA_BASE_URL: RAINBOW_METADATA_BASE_URL,
401
+ RAINBOW_RELAY_QUOTE_SIGNER: process.env.RAINBOW_RELAY_QUOTE_SIGNER ?? RAINBOW_DEMO_QUOTE_SIGNER
402
+ }
403
+ });
404
+ }
405
+ function ensureRainbowGraphqlConfig() {
406
+ if (!(0, import_node_fs.existsSync)(RAINBOW_GRAPHQL_DIR)) return;
407
+ const source = (0, import_node_fs.existsSync)(RAINBOW_GRAPHQL_CONFIG_FILE) ? (0, import_node_fs.readFileSync)(RAINBOW_GRAPHQL_CONFIG_FILE, "utf8") : "";
408
+ if (source.includes(RAINBOW_PUBLIC_ENS_GRAPHQL_URL) && source.includes(RAINBOW_METADATA_BASE_URL)) {
409
+ return;
410
+ }
411
+ (0, import_node_fs.writeFileSync)(
412
+ RAINBOW_GRAPHQL_CONFIG_FILE,
413
+ `exports.config = {
414
+ ens: {
415
+ __name: 'ens',
416
+ document: './queries/ens.graphql',
417
+ schema: {
418
+ method: 'POST',
419
+ url: '${RAINBOW_PUBLIC_ENS_GRAPHQL_URL}',
420
+ },
421
+ },
422
+ metadata: {
423
+ __name: 'metadata',
424
+ document: './queries/metadata.graphql',
425
+ schema: { method: 'GET', url: '${RAINBOW_METADATA_BASE_URL}/v1/graph' },
426
+ },
427
+ metadataPOST: {
428
+ __name: 'metadataPOST',
429
+ document: './queries/metadata.graphql',
430
+ schema: { method: 'POST', url: '${RAINBOW_METADATA_BASE_URL}/v1/graph' },
431
+ },
432
+ arc: {
433
+ __name: 'arc',
434
+ document: './queries/arc.graphql',
435
+ schema: {
436
+ method: 'GET',
437
+ url: 'https://arc-graphql.rainbow.me/graphql',
438
+ headers: {
439
+ 'x-api-key': 'ARC_GRAPHQL_API_KEY',
440
+ },
441
+ },
442
+ },
443
+ arcDev: {
444
+ __name: 'arcDev',
445
+ document: './queries/arc.graphql',
446
+ schema: {
447
+ method: 'GET',
448
+ url: 'https://arc-graphql.rainbowdotme.workers.dev/graphql',
449
+ headers: {},
450
+ },
451
+ },
452
+ };
453
+ `
454
+ );
455
+ }
456
+ function resolveRainbowDemoEnv() {
457
+ const env = {
458
+ ENABLE_DEV_MODE: "1",
459
+ IS_TESTING: "false",
460
+ METADATA_BASE_URL: process.env.RAINBOW_METADATA_BASE_URL ?? RAINBOW_DEMO_METADATA_BASE_URL,
461
+ ADDYS_API_KEY: process.env.ADDYS_API_KEY ?? RAINBOW_DEMO_SERVICE_API_KEY,
462
+ ADDYS_BASE_URL: process.env.ADDYS_BASE_URL ?? RAINBOW_DEMO_METADATA_BASE_URL,
463
+ PLATFORM_API_KEY: process.env.PLATFORM_API_KEY ?? RAINBOW_DEMO_SERVICE_API_KEY,
464
+ PLATFORM_BASE_URL: process.env.PLATFORM_BASE_URL ?? RAINBOW_DEMO_METADATA_BASE_URL,
465
+ RAINBOW_MASTER_KEY: process.env.RAINBOW_MASTER_KEY ?? RAINBOW_DEMO_MASTER_KEY,
466
+ RAINBOW_RELAY_QUOTE_SIGNER: process.env.RAINBOW_RELAY_QUOTE_SIGNER ?? RAINBOW_DEMO_QUOTE_SIGNER,
467
+ RAINBOW_RELAY_URL: process.env.RAINBOW_RELAY_URL ?? RAINBOW_DEMO_RELAY_URL,
468
+ RPC_PROXY_API_KEY_PROD: RAINBOW_DEMO_RPC_API_KEY,
469
+ RPC_PROXY_BASE_URL_PROD: process.env.RAINBOW_RPC_PROXY_BASE_URL ?? process.env.RPC_PROXY_BASE_URL_PROD ?? RAINBOW_DEMO_RPC_PROXY_BASE_URL,
470
+ SECURE_WALLET_HASH_KEY: process.env.SECURE_WALLET_HASH_KEY ?? RAINBOW_DEMO_SECURE_WALLET_HASH_KEY
471
+ };
472
+ const optionalEnvVars = [
473
+ "ADDYS_API_KEY",
474
+ "ADDYS_BASE_URL",
475
+ "IMGIX_DOMAIN",
476
+ "IMGIX_TOKEN",
477
+ "PLATFORM_API_KEY",
478
+ "PLATFORM_BASE_URL",
479
+ "RAINBOW_TEST_WALLET",
480
+ "RAINBOW_RELAY_API_KEY",
481
+ "RAINBOW_RELAY_URL",
482
+ "SECURE_WALLET_HASH_KEY",
483
+ "TOKEN_SEARCH_URL",
484
+ "WC_PROJECT_ID"
485
+ ];
486
+ for (const key of optionalEnvVars) {
487
+ const value = process.env[key];
488
+ if (value) env[key] = value;
489
+ }
490
+ if (!env.WC_PROJECT_ID && process.env.RAINBOW_WALLETCONNECT_PROJECT_ID) {
491
+ env.WC_PROJECT_ID = process.env.RAINBOW_WALLETCONNECT_PROJECT_ID;
492
+ }
493
+ return env;
494
+ }
495
+ function ensureRainbowDemoNetworks() {
496
+ if (!(0, import_node_fs.existsSync)(RAINBOW_NETWORKS_FILE)) return;
497
+ const payload = JSON.parse((0, import_node_fs.readFileSync)(RAINBOW_NETWORKS_FILE, "utf8"));
498
+ if (!Array.isArray(payload.networks)) return;
499
+ let changed = false;
500
+ for (const network of payload.networks) {
501
+ const url = network.id ? RAINBOW_DEMO_PUBLIC_RPC_URLS[network.id] : void 0;
502
+ if (!url || !network.defaultRPC) continue;
503
+ if (network.defaultRPC.url === url) continue;
504
+ network.defaultRPC.url = url;
505
+ changed = true;
506
+ }
507
+ if (changed) {
508
+ (0, import_node_fs.writeFileSync)(RAINBOW_NETWORKS_FILE, `${JSON.stringify(payload)}
509
+ `);
510
+ }
511
+ }
512
+ function ensureRainbowSetup() {
513
+ if (!(0, import_node_fs.existsSync)(RAINBOW_DIR)) return;
514
+ ensureRainbowGraphqlConfig();
515
+ if (!(0, import_node_fs.existsSync)((0, import_node_path.join)(RAINBOW_GRAPHQL_DIR, "node_modules/.bin/graphql-codegen"))) {
516
+ runRainbowSetupCommand("fnm exec --using=22 yarn install", RAINBOW_GRAPHQL_DIR);
517
+ }
518
+ const missingGraphql = RAINBOW_GRAPHQL_SENTINELS.some(
519
+ (rel) => !(0, import_node_fs.existsSync)((0, import_node_path.join)(RAINBOW_DIR, rel))
520
+ );
521
+ if (missingGraphql) {
522
+ runRainbowSetupCommand("fnm exec --using=22 yarn codegen", RAINBOW_GRAPHQL_DIR);
523
+ }
524
+ if (!(0, import_node_fs.existsSync)(RAINBOW_NETWORKS_FILE)) {
525
+ runRainbowSetupCommand("fnm exec --using=22 yarn fetch:networks", RAINBOW_DIR);
526
+ }
527
+ ensureRainbowDemoNetworks();
528
+ }
529
+ var ARTSY_DIR = (0, import_node_path.join)(HOME, "github/eigen");
530
+ var ARTSY_KEYS_FILE = (0, import_node_path.join)(ARTSY_DIR, "keys.shared.json");
531
+ var ARTSY_METAFLAGS_FILE = (0, import_node_path.join)(ARTSY_DIR, "metaflags.json");
532
+ var ARTSY_RELAY_SENTINEL = (0, import_node_path.join)(ARTSY_DIR, "src/__generated__/.relay-complete");
533
+ function readArtsyKeysPayload() {
534
+ if (!(0, import_node_fs.existsSync)(ARTSY_KEYS_FILE)) return void 0;
535
+ try {
536
+ const parsed = JSON.parse((0, import_node_fs.readFileSync)(ARTSY_KEYS_FILE, "utf8"));
537
+ if (!parsed || typeof parsed !== "object") return void 0;
538
+ const secure = parsed.secure && typeof parsed.secure === "object" ? parsed.secure : void 0;
539
+ const publicKeys = parsed.public && typeof parsed.public === "object" ? parsed.public : void 0;
540
+ if (!secure && !publicKeys) return void 0;
541
+ return { secure, public: publicKeys };
542
+ } catch {
543
+ return void 0;
544
+ }
545
+ }
546
+ function resolveArtsyRuntimeConfig() {
547
+ const email = process.env.SOOTSIM_ARTSY_EMAIL ?? process.env.MAESTRO_TEST_EMAIL;
548
+ const password = process.env.SOOTSIM_ARTSY_PASSWORD ?? process.env.MAESTRO_TEST_PASSWORD;
549
+ const keys = readArtsyKeysPayload();
550
+ const env = {};
551
+ if (email && password) {
552
+ env.SOOTSIM_LAUNCH_ARGUMENTS = JSON.stringify({
553
+ email,
554
+ password,
555
+ useMaestroInit: true
556
+ });
557
+ }
558
+ if (keys) {
559
+ env.SOOTSIM_REACT_NATIVE_KEYS_JSON = JSON.stringify(keys);
560
+ }
561
+ if (Object.keys(env).length === 0) return void 0;
562
+ return {
563
+ env
564
+ };
565
+ }
566
+ function ensureArtsySetup() {
567
+ if (!(0, import_node_fs.existsSync)(ARTSY_DIR)) return;
568
+ const { execSync } = require("node:child_process");
569
+ const yarnRelease = (0, import_node_path.join)(ARTSY_DIR, ".yarn/releases/yarn-4.10.3.cjs");
570
+ if ((0, import_node_fs.existsSync)(yarnRelease)) {
571
+ const src = (0, import_node_fs.readFileSync)(yarnRelease, "utf8");
572
+ const needle = '["clone","-c core.autocrlf=false",';
573
+ if (src.includes(needle)) {
574
+ (0, import_node_fs.writeFileSync)(
575
+ yarnRelease,
576
+ src.replace(needle, '["clone","-c","core.autocrlf=false",')
577
+ );
578
+ }
579
+ }
580
+ if (!(0, import_node_fs.existsSync)((0, import_node_path.join)(ARTSY_DIR, "node_modules/.yarn-state.yml"))) {
581
+ execSync("yarn install", {
582
+ cwd: ARTSY_DIR,
583
+ stdio: "inherit",
584
+ env: { ...process.env, YARN_CHECKSUM_BEHAVIOR: "update" }
585
+ });
586
+ }
587
+ if (!(0, import_node_fs.existsSync)(ARTSY_KEYS_FILE) || !(0, import_node_fs.existsSync)(ARTSY_METAFLAGS_FILE)) {
588
+ try {
589
+ execSync("yarn setup:oss", { cwd: ARTSY_DIR, stdio: "inherit" });
590
+ } catch {
591
+ if (!(0, import_node_fs.existsSync)(ARTSY_KEYS_FILE) || !(0, import_node_fs.existsSync)(ARTSY_METAFLAGS_FILE)) {
592
+ throw new Error("artsy demo: setup:oss did not create keys/metaflags");
593
+ }
594
+ }
595
+ }
596
+ const rnlaPkgJson = (0, import_node_path.join)(
597
+ ARTSY_DIR,
598
+ "node_modules/react-native-launch-arguments/package.json"
599
+ );
600
+ if ((0, import_node_fs.existsSync)(rnlaPkgJson)) {
601
+ const raw = (0, import_node_fs.readFileSync)(rnlaPkgJson, "utf8");
602
+ if (raw.includes('"dist/index.js"')) {
603
+ (0, import_node_fs.writeFileSync)(rnlaPkgJson, raw.replace('"dist/index.js"', '"src/index.ts"'));
604
+ }
605
+ }
606
+ if (!(0, import_node_fs.existsSync)(ARTSY_RELAY_SENTINEL)) {
607
+ execSync("yarn relay", { cwd: ARTSY_DIR, stdio: "inherit" });
608
+ (0, import_node_fs.writeFileSync)(ARTSY_RELAY_SENTINEL, "");
609
+ }
610
+ }
611
+ var APPS = [
612
+ {
613
+ name: "bluesky",
614
+ label: "Bluesky",
615
+ dir: (0, import_node_path.join)(HOME, "github/bluesky"),
616
+ preferredPort: 8082,
617
+ framework: "expo",
618
+ command: (p) => ({ cmd: `npx expo start --port ${p}` }),
619
+ credentials: {
620
+ envVars: ["SOOTSIM_BLUESKY_PASSWORD"],
621
+ known: { HANDLE: "natew.bsky.social" }
622
+ }
623
+ },
624
+ {
625
+ name: "3pc",
626
+ label: "3PunchConvo",
627
+ dir: (0, import_node_path.join)(HOME, "lightstrike-labs/three-punch-convo-app/apps/one"),
628
+ preferredPort: 8081,
629
+ framework: "one",
630
+ command: (p) => ({ cmd: "npx one dev", env: { ONE_PORT: String(p) } })
631
+ },
632
+ {
633
+ name: "uniswap",
634
+ label: "Uniswap",
635
+ dir: UNISWAP_APP_DIR,
636
+ preferredPort: 8085,
637
+ framework: "expo",
638
+ prepare: () => {
639
+ ensureUniswapDemoEnvLocal();
640
+ ensureUniswapForceUpgradePatched();
641
+ },
642
+ command: (p) => ({
643
+ cmd: `npx expo start --clear --port ${p}`,
644
+ // prefer the real local mobile env when present, otherwise fall back
645
+ // to Uniswap's checked-in public web RPC settings so demo boots cleanly.
646
+ env: resolveUniswapDemoEnv()
647
+ })
648
+ },
649
+ {
650
+ name: "takeout",
651
+ label: "Takeout",
652
+ dir: (0, import_node_path.join)(HOME, "takeout"),
653
+ preferredPort: 8086,
654
+ framework: "one",
655
+ // takeout needs more than Metro for the demo to actually work: better-auth
656
+ // (login), zero-cache (sync), and a postgres for both. `bun lite` brings
657
+ // up the orez-backed stack (PG + zero + s3 in one binary) plus the One
658
+ // dev server. takeout's env system shifts every port (web, pg, zero,
659
+ // minio) uniformly by PORT_OFFSET, so we derive offset = port - 8081
660
+ // (the base web port) to keep all backend ports clear of the default
661
+ // dev stack while pinning One to the demo slot. OREZ_DATA_DIR is isolated
662
+ // to a per-demo path so we don't fight a soot dev orez that may already
663
+ // be holding pglite locks on ~/takeout/.orez (soot can attach takeout as
664
+ // a project and spin up its own orez against the same data dir).
665
+ readyTimeoutMs: 24e4,
666
+ command: (p) => ({
667
+ cmd: "bun lite",
668
+ env: {
669
+ PORT_OFFSET: String(p - 8081),
670
+ OREZ_DATA_DIR: `${HOME}/.cache/sootsim-demo/takeout-orez`
671
+ }
672
+ })
673
+ },
674
+ {
675
+ name: "expensify",
676
+ label: "Expensify",
677
+ dir: (0, import_node_path.join)(HOME, "github/expensify"),
678
+ preferredPort: 8087,
679
+ framework: "rock",
680
+ runtimeConfig: {
681
+ env: EXPENSIFY_NATIVE_PROXY_ENV
682
+ },
683
+ sidecars: [
684
+ {
685
+ name: "web-proxy",
686
+ port: 9e3,
687
+ readyPath: "/api/Ping",
688
+ command: () => ({
689
+ cmd: `bun ${JSON.stringify(getExpensifyProxyScript())}`,
690
+ env: EXPENSIFY_NATIVE_PROXY_ENV
691
+ })
692
+ }
693
+ ],
694
+ command: (p) => ({
695
+ cmd: `fnm exec --using=20.20.0 npx rock start --port ${p} --no-interactive`,
696
+ env: EXPENSIFY_NATIVE_PROXY_ENV
697
+ })
698
+ },
699
+ {
700
+ name: "artsy",
701
+ label: "Artsy",
702
+ dir: ARTSY_DIR,
703
+ preferredPort: 8088,
704
+ framework: "expo",
705
+ runtimeConfig: resolveArtsyRuntimeConfig(),
706
+ prepare: () => {
707
+ ensureArtsySetup();
708
+ },
709
+ command: (p) => ({
710
+ // eigen's `yarn start` wraps `react-native start` with a relay watcher
711
+ // via concurrently; for the demo we run relay once in prepare and
712
+ // invoke the metro server directly so --port is respected.
713
+ cmd: `npx react-native start --port ${p}`
714
+ }),
715
+ credentials: {
716
+ envVars: ["SOOTSIM_ARTSY_EMAIL", "SOOTSIM_ARTSY_PASSWORD"],
717
+ note: "auto-login reuses Artsy\u2019s built-in Maestro launch-arguments hook"
718
+ }
719
+ },
720
+ {
721
+ name: "rainbow",
722
+ label: "Rainbow",
723
+ dir: RAINBOW_DIR,
724
+ preferredPort: 8089,
725
+ framework: "rock",
726
+ sidecars: [
727
+ {
728
+ name: "metadata-proxy",
729
+ port: RAINBOW_METADATA_PROXY_PORT,
730
+ readyPath: "/health",
731
+ command: () => ({
732
+ cmd: `bun ${JSON.stringify(getRainbowMetadataProxyScript())}`,
733
+ env: {
734
+ PORT: String(RAINBOW_METADATA_PROXY_PORT),
735
+ RAINBOW_PUBLIC_RPC_URLS: JSON.stringify(RAINBOW_DEMO_PUBLIC_RPC_URLS),
736
+ RAINBOW_UPSTREAM_METADATA_BASE_URL: RAINBOW_METADATA_BASE_URL
737
+ }
738
+ })
739
+ }
740
+ ],
741
+ prepare: () => {
742
+ ensureRainbowSetup();
743
+ },
744
+ command: (p) => ({
745
+ cmd: `fnm exec --using=22 yarn start --port ${p} --reset-cache`,
746
+ env: resolveRainbowDemoEnv()
747
+ }),
748
+ credentials: {
749
+ envVars: [
750
+ "RAINBOW_TEST_WALLET",
751
+ "RAINBOW_WALLETCONNECT_PROJECT_ID",
752
+ "WC_PROJECT_ID",
753
+ "IMGIX_DOMAIN",
754
+ "IMGIX_TOKEN"
755
+ ],
756
+ note: "launcher supplies a demo encryption key and public mainnet RPC; use only a public throwaway mnemonic for RAINBOW_TEST_WALLET"
757
+ }
758
+ },
759
+ {
760
+ name: "rocket-chat",
761
+ label: "Rocket.Chat",
762
+ dir: (0, import_node_path.join)(HOME, "github/Rocket.Chat.ReactNative"),
763
+ preferredPort: 8093,
764
+ framework: "expo",
765
+ command: (p) => ({
766
+ cmd: `npx react-native start --port ${p}`,
767
+ env: { RUNNING_E2E_TESTS: "true" }
768
+ }),
769
+ credentials: {
770
+ envVars: [
771
+ "ROCKET_CHAT_DEMO_SERVER",
772
+ "ROCKET_CHAT_DEMO_USERNAME",
773
+ "ROCKET_CHAT_DEMO_PASSWORD"
774
+ ],
775
+ known: { SERVER: "https://mobile.qa.rocket.chat" },
776
+ note: "use packages/sootsim-engine/scripts/rocket-chat-demo-auth.ts to create/login a disposable QA user and print the rocketchat://auth deep link"
777
+ }
778
+ },
779
+ {
780
+ name: "mattermost",
781
+ label: "Mattermost",
782
+ dir: MATTERMOST_DIR,
783
+ preferredPort: 8090,
784
+ framework: "expo",
785
+ sidecars: [
786
+ {
787
+ name: "preview-server",
788
+ port: 8065,
789
+ readyPath: "/api/v4/system/ping",
790
+ command: () => ({
791
+ cmd: `bun ${JSON.stringify(getMattermostPreviewServerScript())}`
792
+ })
793
+ }
794
+ ],
795
+ runtimeConfig: {
796
+ modules: {
797
+ // mattermost patches react-native-keychain's JS entry in its own
798
+ // repo; run that package and provide only the native manager seam.
799
+ "react-native-keychain": false,
800
+ "dist/assets/config.json": {
801
+ inline: {
802
+ AuthUrlScheme: "mmauth://",
803
+ AuthUrlSchemeDev: "mmauthbeta://",
804
+ DefaultServerUrl: "http://localhost:8065",
805
+ DefaultServerName: "Mattermost Demo",
806
+ TestServerUrl: "http://localhost:8065",
807
+ AutoSelectServerUrl: true,
808
+ WebsiteURL: "https://mattermost.com",
809
+ ServerNoticeURL: "https://github.com/mattermost/mattermost-server/blob/master/NOTICE.txt",
810
+ MobileNoticeURL: "https://github.com/mattermost/mattermost-mobile/blob/master/NOTICE.txt",
811
+ RudderApiKey: "",
812
+ SentryEnabled: false,
813
+ SentryDsnIos: "",
814
+ SentryDsnAndroid: "",
815
+ SentryOptions: {
816
+ deactivateStacktraceMerging: true,
817
+ autoBreadcrumbs: {
818
+ xhr: false,
819
+ console: true
820
+ },
821
+ severityLevelFilter: ["fatal"]
822
+ },
823
+ ShowReview: false,
824
+ ShowOnboarding: false,
825
+ ExperimentalNormalizeMarkdownLinks: false,
826
+ CustomRequestHeaders: {},
827
+ CollectNetworkMetrics: false
828
+ }
829
+ }
830
+ },
831
+ nativeModules: {
832
+ RNKeychainManager: { file: getMattermostKeychainNativeModule() },
833
+ RNUtils: { file: getMattermostRNUtilsNativeModule() },
834
+ GenericClient: { file: getMattermostNetworkClientNativeModule() },
835
+ ApiClient: { file: getMattermostNetworkClientNativeModule() },
836
+ WebSocketClient: { file: getMattermostNetworkClientNativeModule() }
837
+ }
838
+ },
839
+ command: (p) => ({
840
+ cmd: `npx react-native start --host 127.0.0.1 --port ${p}`
841
+ }),
842
+ credentials: {
843
+ known: {
844
+ SERVER: "http://localhost:8065",
845
+ USERNAME: "demo",
846
+ PASSWORD: "DemoPassword1!"
847
+ },
848
+ note: "local mattermost-preview seeded through the real REST API; no signup or OTP needed"
849
+ }
850
+ },
851
+ {
852
+ name: "joplin",
853
+ label: "Joplin",
854
+ dir: JOPLIN_APP_DIR,
855
+ preferredPort: 8084,
856
+ framework: "expo",
857
+ // joplin is local-first: sync.target defaults to 0 ("None") and the
858
+ // mobile startup runs WelcomeUtils.install() on first launch, which
859
+ // seeds a "Welcome!" folder + welcome notes. no login or external
860
+ // credentials are needed for a usable demo — just boot it. tenant
861
+ // bedrock SQLite (via react-native-sqlite-storage stub) carries the
862
+ // seeded notes across reloads.
863
+ prepare: () => {
864
+ ensureJoplinWatchmanConfigs();
865
+ ensureJoplinBuilt();
866
+ },
867
+ command: (p) => ({
868
+ cmd: `npx expo start --port ${p}`,
869
+ env: { BROWSERSLIST_IGNORE_OLD_DATA: "true" }
870
+ }),
871
+ credentials: {
872
+ note: "no login required \u2014 sync.target=0 (None), seed via WelcomeUtils"
873
+ }
874
+ }
875
+ ];
876
+
877
+ // scripts/dev-server-scanner.ts
878
+ var execP = (0, import_util.promisify)(import_child_process.exec);
879
+ var TIMEOUT_MS = 250;
880
+ var MANIFEST_TIMEOUT_MS = 1500;
881
+ var TCP_GATE_MS = 120;
882
+ function tcpPing(port, timeout = TCP_GATE_MS) {
883
+ return new Promise((resolve2) => {
884
+ const sock = new import_net.default.Socket();
885
+ let settled = false;
886
+ const done = (ok) => {
887
+ if (settled) return;
888
+ settled = true;
889
+ sock.destroy();
890
+ resolve2(ok);
891
+ };
892
+ sock.setTimeout(timeout);
893
+ sock.once("connect", () => done(true));
894
+ sock.once("timeout", () => done(false));
895
+ sock.once("error", () => done(false));
896
+ sock.connect(port, "localhost");
897
+ });
898
+ }
899
+ function httpGet(port, path, method = "GET", timeout = TIMEOUT_MS, headers = {}) {
900
+ return new Promise((resolve2) => {
901
+ const req = import_http.default.request(
902
+ { hostname: "localhost", port, path, method, timeout, headers },
903
+ (res) => {
904
+ let body = "";
905
+ res.on("data", (c) => body += c.toString());
906
+ const contentType = (() => {
907
+ const raw = res.headers["content-type"];
908
+ if (typeof raw === "string") return raw;
909
+ if (Array.isArray(raw)) return raw[0];
910
+ return void 0;
911
+ })();
912
+ res.on(
913
+ "end",
914
+ () => resolve2({ statusCode: res.statusCode || 0, body, contentType })
915
+ );
916
+ }
917
+ );
918
+ req.on("error", () => resolve2(null));
919
+ req.setTimeout(timeout, () => {
920
+ req.destroy();
921
+ resolve2(null);
922
+ });
923
+ req.end();
924
+ });
925
+ }
926
+ var FALLBACK_PORTS = [
927
+ 8081,
928
+ 8082,
929
+ 8083,
930
+ 8084,
931
+ 8085,
932
+ 8086,
933
+ 3e3,
934
+ 3001,
935
+ 19e3
936
+ ].map((port) => ({ port, pid: 0 }));
937
+ function acceptPort(port, excluded) {
938
+ if (port <= 0 || port >= 2e4) return false;
939
+ if (excluded.has(port)) return false;
940
+ if (port >= 5170 && port <= 5200) return false;
941
+ return true;
942
+ }
943
+ async function discoverListeningProcesses(excludePorts = []) {
944
+ const excluded = new Set(excludePorts);
945
+ try {
946
+ const { stdout } = await execP(
947
+ `lsof -iTCP -sTCP:LISTEN -P -n 2>/dev/null | grep -E '^(node|bun)'`,
948
+ { encoding: "utf8", timeout: 2e3 }
949
+ );
950
+ if (stdout.trim()) {
951
+ const seen = /* @__PURE__ */ new Map();
952
+ for (const line of stdout.trim().split("\n")) {
953
+ const parts = line.trim().split(/\s+/);
954
+ if (parts.length < 9) continue;
955
+ const pid = Number(parts[1]);
956
+ const addr = parts[8];
957
+ const m = addr.match(/:(\d+)$/);
958
+ if (!m) continue;
959
+ const port = Number(m[1]);
960
+ if (!acceptPort(port, excluded)) continue;
961
+ if (!seen.has(port)) seen.set(port, pid);
962
+ }
963
+ if (seen.size > 0) {
964
+ return [...seen.entries()].map(([port, pid]) => ({ port, pid }));
965
+ }
966
+ }
967
+ } catch {
968
+ }
969
+ try {
970
+ const { stdout } = await execP(`ss -tlnp 2>/dev/null | grep -E '"(node|bun)"'`, {
971
+ encoding: "utf8",
972
+ timeout: 2e3
973
+ });
974
+ if (stdout.trim()) {
975
+ const seen = /* @__PURE__ */ new Map();
976
+ for (const line of stdout.trim().split("\n")) {
977
+ const portMatch = line.match(/:(\d+)\s/);
978
+ const pidMatch = line.match(/pid=(\d+)/);
979
+ if (!portMatch) continue;
980
+ const port = Number(portMatch[1]);
981
+ const pid = pidMatch ? Number(pidMatch[1]) : 0;
982
+ if (!acceptPort(port, excluded)) continue;
983
+ if (!seen.has(port)) seen.set(port, pid);
984
+ }
985
+ if (seen.size > 0) {
986
+ return [...seen.entries()].map(([port, pid]) => ({ port, pid }));
987
+ }
988
+ }
989
+ } catch {
990
+ }
991
+ return FALLBACK_PORTS.filter((p) => acceptPort(p.port, excluded));
992
+ }
993
+ async function discoverListeningPorts(excludePorts = []) {
994
+ const processes = await discoverListeningProcesses(excludePorts);
995
+ return processes.map((p) => p.port);
996
+ }
997
+ var cwdByPid = /* @__PURE__ */ new Map();
998
+ async function resolveProcessCwd(pid) {
999
+ if (pid <= 0) return null;
1000
+ const cached = cwdByPid.get(pid);
1001
+ if (cached) return cached;
1002
+ try {
1003
+ const { stdout } = await execP(`lsof -p ${pid} -a -d cwd -Fn 2>/dev/null`, {
1004
+ encoding: "utf8",
1005
+ timeout: 1500
1006
+ });
1007
+ for (const line of stdout.split("\n")) {
1008
+ if (line.startsWith("n") && line.length > 1) {
1009
+ const cwd = line.slice(1).trim();
1010
+ if (cwd) {
1011
+ cwdByPid.set(pid, cwd);
1012
+ return cwd;
1013
+ }
1014
+ }
1015
+ }
1016
+ } catch {
1017
+ }
1018
+ return null;
1019
+ }
1020
+ function makeResult(port, framework) {
1021
+ return {
1022
+ port,
1023
+ framework,
1024
+ bundleUrl: withRuntimeConfig(
1025
+ port,
1026
+ `http://localhost:${port}/index.bundle?platform=ios&dev=true&hot=true&minify=false`
1027
+ ),
1028
+ hmrUrl: `ws://localhost:${port}/hot`,
1029
+ lastSeen: Date.now()
1030
+ };
1031
+ }
1032
+ function withRuntimeConfig(port, bundleUrl) {
1033
+ const knownApp = APPS.find((app) => app.preferredPort === port);
1034
+ const configured = knownApp?.runtimeConfig ? applySootSimConfigToUrl(bundleUrl, knownApp.runtimeConfig) : bundleUrl;
1035
+ return normalizeNativeDevBundleUrl(configured);
1036
+ }
1037
+ function isDirectOneBundleUrl(bundleUrl) {
1038
+ return bundleUrl.includes("/node_modules/one/metro-entry.bundle");
1039
+ }
1040
+ function safeParseManifest(body) {
1041
+ try {
1042
+ const parsed = JSON.parse(body);
1043
+ return parsed && typeof parsed === "object" ? parsed : null;
1044
+ } catch {
1045
+ return null;
1046
+ }
1047
+ }
1048
+ function applyManifest(result, manifestRes, buildIconProxyUrl) {
1049
+ if (!manifestRes) return result;
1050
+ try {
1051
+ const manifest = JSON.parse(manifestRes.body);
1052
+ const client = manifest?.extra?.expoClient || manifest?.extra || {};
1053
+ if (client.name) result.projectName = client.name;
1054
+ if (client.ios?.bundleIdentifier) result.bundleId = client.ios.bundleIdentifier;
1055
+ if (result.framework === "metro" && client.sdkVersion) result.framework = "expo";
1056
+ const launchUrl = manifest?.launchAsset?.url;
1057
+ if (launchUrl && !result.patched && !isDirectOneBundleUrl(result.bundleUrl)) {
1058
+ result.bundleUrl = withRuntimeConfig(result.port, launchUrl);
1059
+ }
1060
+ const rawIconUrl = client.iconUrl || client.ios?.iconUrl || client.icon || client.ios?.icon;
1061
+ if (rawIconUrl) {
1062
+ result.iconPath = rawIconUrl;
1063
+ if (buildIconProxyUrl) {
1064
+ if (rawIconUrl.startsWith("http")) {
1065
+ result.iconUrl = buildIconProxyUrl(rawIconUrl);
1066
+ } else {
1067
+ const cleanPath = rawIconUrl.replace(/^\.\//, "");
1068
+ result.iconUrl = buildIconProxyUrl(
1069
+ `http://localhost:${result.port}/assets/${cleanPath}`
1070
+ );
1071
+ }
1072
+ } else {
1073
+ result.iconUrl = rawIconUrl.startsWith("http") ? rawIconUrl : `http://localhost:${result.port}/assets/${rawIconUrl.replace(/^\.\//, "")}`;
1074
+ }
1075
+ }
1076
+ } catch {
1077
+ }
1078
+ return result;
1079
+ }
1080
+ function __applyManifestForTests(result, manifestBody) {
1081
+ return applyManifest(result, { statusCode: 200, body: manifestBody });
1082
+ }
1083
+ var knownNonPatched = /* @__PURE__ */ new Set();
1084
+ var knownNonExpo = /* @__PURE__ */ new Set();
1085
+ var knownOne = /* @__PURE__ */ new Set();
1086
+ async function probePort(port, buildIconProxyUrl) {
1087
+ if (!await tcpPing(port)) return null;
1088
+ const onePath = `/node_modules/one/metro-entry.bundle?platform=ios&dev=true`;
1089
+ const [sootsimRes, statusRes, manifestRes, expoRes] = await Promise.all([
1090
+ knownNonPatched.has(port) ? Promise.resolve(null) : httpGet(port, "/__soot/"),
1091
+ httpGet(port, "/status"),
1092
+ knownOne.has(port) ? Promise.resolve(null) : httpGet(port, "/", "GET", MANIFEST_TIMEOUT_MS, { "expo-platform": "ios" }),
1093
+ knownNonExpo.has(port) ? Promise.resolve(null) : httpGet(port, "/_expo/status")
1094
+ ]);
1095
+ if (expoRes && expoRes.statusCode === 200) {
1096
+ knownNonExpo.delete(port);
1097
+ } else if (!knownNonExpo.has(port)) {
1098
+ knownNonExpo.add(port);
1099
+ }
1100
+ const manifestParsed = manifestRes ? safeParseManifest(manifestRes.body) : null;
1101
+ const manifestLaunchUrl = typeof manifestParsed?.launchAsset?.url === "string" ? manifestParsed.launchAsset.url : null;
1102
+ const manifestClient = manifestParsed?.extra?.expoClient || manifestParsed?.extra || {};
1103
+ if (manifestParsed && (manifestLaunchUrl || typeof manifestClient.name === "string")) {
1104
+ knownNonPatched.add(port);
1105
+ const launchUrl = manifestLaunchUrl || `http://localhost:${port}/index.bundle?platform=ios&dev=true&hot=true&minify=false`;
1106
+ const framework = launchUrl.includes(
1107
+ "/one/metro-entry.bundle"
1108
+ ) ? "one" : "expo";
1109
+ return applyManifest(
1110
+ {
1111
+ port,
1112
+ framework,
1113
+ bundleUrl: withRuntimeConfig(port, launchUrl),
1114
+ hmrUrl: `ws://localhost:${port}/hot`,
1115
+ lastSeen: Date.now()
1116
+ },
1117
+ manifestRes,
1118
+ buildIconProxyUrl
1119
+ );
1120
+ }
1121
+ if (statusRes && statusRes.body.includes("packager-status:running")) {
1122
+ knownNonPatched.add(port);
1123
+ return applyManifest(
1124
+ makeResult(port, expoRes && expoRes.statusCode === 200 ? "expo" : "metro"),
1125
+ manifestRes,
1126
+ buildIconProxyUrl
1127
+ );
1128
+ }
1129
+ if (sootsimRes && sootsimRes.statusCode === 200 && sootsimRes.body.includes("sootsim-patched")) {
1130
+ knownNonPatched.delete(port);
1131
+ return applyManifest(
1132
+ {
1133
+ port,
1134
+ framework: "one",
1135
+ bundleUrl: withRuntimeConfig(port, `http://localhost:${port}/__soot/bundle.js`),
1136
+ hmrUrl: `ws://localhost:${port}/hot`,
1137
+ lastSeen: Date.now(),
1138
+ patched: true
1139
+ },
1140
+ manifestRes,
1141
+ buildIconProxyUrl
1142
+ );
1143
+ }
1144
+ const oneRes = await httpGet(port, onePath, "HEAD");
1145
+ if (oneRes && oneRes.statusCode > 0 && oneRes.statusCode < 400 && /application\/javascript/i.test(oneRes.contentType || "")) {
1146
+ knownNonPatched.add(port);
1147
+ knownOne.add(port);
1148
+ return applyManifest(
1149
+ {
1150
+ port,
1151
+ framework: "one",
1152
+ bundleUrl: withRuntimeConfig(
1153
+ port,
1154
+ `http://localhost:${port}${onePath}&minify=false`
1155
+ ),
1156
+ hmrUrl: `ws://localhost:${port}/hot`,
1157
+ lastSeen: Date.now()
1158
+ },
1159
+ manifestRes,
1160
+ buildIconProxyUrl
1161
+ );
1162
+ }
1163
+ knownNonPatched.add(port);
1164
+ return null;
1165
+ }
1166
+ function isSootSelfServer(server) {
1167
+ const projectName = server.projectName?.trim().toLowerCase();
1168
+ if (projectName === "soot" || projectName === "sootsim") return true;
1169
+ const bundleId = server.bundleId?.trim().toLowerCase();
1170
+ if (bundleId?.startsWith("dev.soot")) return true;
1171
+ return false;
1172
+ }
1173
+ var portCache = /* @__PURE__ */ new Map();
1174
+ var NEGATIVE_CACHE_TTL_MS = 3e4;
1175
+ var WEAK_RESULT_CACHE_TTL_MS = 1500;
1176
+ function isWeakCachedResult(result) {
1177
+ if (!result) return true;
1178
+ if (result.framework === "metro" || result.framework === "unknown") return true;
1179
+ return false;
1180
+ }
1181
+ function hasCurrentRuntimeConfig(result) {
1182
+ if (!result) return true;
1183
+ return withRuntimeConfig(result.port, result.bundleUrl) === result.bundleUrl;
1184
+ }
1185
+ function __shouldReuseScannerCacheEntry(entry, pid, now = Date.now()) {
1186
+ if (pid === 0) return false;
1187
+ if (entry.pid !== pid) return false;
1188
+ if (!hasCurrentRuntimeConfig(entry.result)) return false;
1189
+ const ageMs = now - entry.cachedAt;
1190
+ if (entry.result === null && ageMs >= NEGATIVE_CACHE_TTL_MS) return false;
1191
+ if (isWeakCachedResult(entry.result) && ageMs >= WEAK_RESULT_CACHE_TTL_MS) return false;
1192
+ return true;
1193
+ }
1194
+ function __resetScannerCache() {
1195
+ portCache.clear();
1196
+ knownNonPatched.clear();
1197
+ knownNonExpo.clear();
1198
+ knownOne.clear();
1199
+ }
1200
+ async function scanDevServers(opts = {}) {
1201
+ const processes = await discoverListeningProcesses(opts.excludePorts);
1202
+ const currentPorts = new Set(processes.map((p) => p.port));
1203
+ for (const p of [...portCache.keys()]) {
1204
+ if (!currentPorts.has(p)) portCache.delete(p);
1205
+ }
1206
+ for (const p of [...knownNonPatched]) {
1207
+ if (!currentPorts.has(p)) knownNonPatched.delete(p);
1208
+ }
1209
+ for (const p of [...knownNonExpo]) {
1210
+ if (!currentPorts.has(p)) knownNonExpo.delete(p);
1211
+ }
1212
+ for (const p of [...knownOne]) {
1213
+ if (!currentPorts.has(p)) knownOne.delete(p);
1214
+ }
1215
+ const results = [];
1216
+ const toProbe = [];
1217
+ for (const { port, pid } of processes) {
1218
+ const cached = portCache.get(port);
1219
+ if (cached && __shouldReuseScannerCacheEntry(cached, pid)) {
1220
+ if (cached.result) results.push(cached.result);
1221
+ continue;
1222
+ }
1223
+ if (cached && cached.pid !== pid) {
1224
+ knownNonPatched.delete(port);
1225
+ knownNonExpo.delete(port);
1226
+ knownOne.delete(port);
1227
+ }
1228
+ toProbe.push({ port, pid });
1229
+ }
1230
+ if (toProbe.length > 0) {
1231
+ const probed = await Promise.all(
1232
+ toProbe.map((p) => probePort(p.port, opts.buildIconProxyUrl))
1233
+ );
1234
+ probed.forEach((result, i) => {
1235
+ const { port, pid } = toProbe[i];
1236
+ if (pid !== 0) portCache.set(port, { pid, result, cachedAt: Date.now() });
1237
+ if (result) results.push(result);
1238
+ });
1239
+ }
1240
+ const pidByPort = /* @__PURE__ */ new Map();
1241
+ for (const { port, pid } of processes) {
1242
+ if (pid > 0) pidByPort.set(port, pid);
1243
+ }
1244
+ await Promise.all(
1245
+ results.map(async (result) => {
1246
+ const pid = pidByPort.get(result.port);
1247
+ if (!pid) return;
1248
+ result.pid = pid;
1249
+ const cwd = await resolveProcessCwd(pid);
1250
+ if (cwd) result.cwd = cwd;
1251
+ })
1252
+ );
1253
+ const livePids = new Set(pidByPort.values());
1254
+ for (const pid of [...cwdByPid.keys()]) {
1255
+ if (!livePids.has(pid)) cwdByPid.delete(pid);
1256
+ }
1257
+ return results.filter((r) => !isSootSelfServer(r));
1258
+ }
1259
+ // Annotate the CommonJS export names for ESM import in node:
1260
+ 0 && (module.exports = {
1261
+ __applyManifestForTests,
1262
+ __resetScannerCache,
1263
+ __shouldReuseScannerCacheEntry,
1264
+ discoverListeningPorts,
1265
+ discoverListeningProcesses,
1266
+ probePort,
1267
+ resolveProcessCwd,
1268
+ scanDevServers
1269
+ });