@deeeed/metamask-harness 0.51.1 → 0.51.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -2,6 +2,17 @@
2
2
 
3
3
  ## Unreleased
4
4
 
5
+ ## 0.51.3 - 2026-09-14
6
+
7
+ ### Fixed
8
+
9
+ - `fixtures set` on mobile bounds the setup-wallet leaf at six minutes instead of two: after an unlock the app hydrates every account before it answers the bridge again, and a large fixture on a loaded Mac took past the old bound while the wallet itself reached the unlocked home screen. `MM_HARNESS_FIXTURES_SET_TIMEOUT_MS` still overrides it.
10
+ ## 0.51.2 - 2026-09-14
11
+
12
+ ### Fixed
13
+
14
+ - Mobile native builds no longer pass `--no-bundler` to Expo: a Debug configuration starts the bundler regardless, so 0.51.1 left Expo attached to a stray Metro on 8081 and the launch never returned. Instead the build env answers Expo's one `lsof` lookup for the Metro listener from the harness's `metro.pid`; Expo's 350 ms lsof budget is what a busy Mac missed. A reused Metro listener now records its pid too.
15
+
5
16
  ## 0.51.1 - 2026-09-13
6
17
 
7
18
  ### Fixed
@@ -81,6 +81,46 @@ for _rb in "$SCRIPT_DIR/../shared/activate-repo-ruby.sh" "$SCRIPT_DIR/lib/activa
81
81
  [ -f "$_rb" ] && { . "$_rb"; break; }
82
82
  done
83
83
  unset _rb
84
+ # shellcheck disable=SC1091
85
+ for _hp in "$SCRIPT_DIR/../shared/harness-path.sh" "$SCRIPT_DIR/lib/harness-path.sh"; do
86
+ [ -f "$_hp" ] && { . "$_hp"; break; }
87
+ done
88
+ unset _hp
89
+
90
+ # Expo's run:ios / run:android bookkeeping asks lsof which process listens on
91
+ # the Metro port, before and after the native build, under a 350 ms budget.
92
+ # lsof scans every process on the machine, so a busy Mac misses that budget
93
+ # and Expo aborts a finished build with "Port became busy running another
94
+ # process while the app was compiling". The harness started that listener and
95
+ # recorded it in metro.pid: answer that one query from the record and hand
96
+ # every other lsof call to the real binary.
97
+ write_lsof_shim() {
98
+ local dir="$1" real_lsof
99
+ real_lsof="$(command -v lsof 2>/dev/null || true)"
100
+ [ -n "$real_lsof" ] || return 0
101
+ {
102
+ printf '#!/usr/bin/env bash\n'
103
+ printf 'REAL_LSOF=%q\n' "$real_lsof"
104
+ cat <<'SHIM'
105
+ # Exactly Expo's listener query and nothing else. A recycled pid after a Metro
106
+ # death is the only way this can lie, and a dead Metro fails the build anyway.
107
+ if [ $# -eq 4 ] && [ "$1" = "-i:${MM_HARNESS_BUILD_WATCHER_PORT:-}" ] && [ "$2" = "-P" ] && [ "$3" = "-t" ] && [ "$4" = "-sTCP:LISTEN" ] \
108
+ && [ -f "${MM_HARNESS_METRO_PID_FILE:-/nonexistent}" ]; then
109
+ pid="$(cat "$MM_HARNESS_METRO_PID_FILE" 2>/dev/null)"
110
+ if [ -n "$pid" ] && kill -0 "$pid" 2>/dev/null; then printf '%s\n' "$pid"; exit 0; fi
111
+ fi
112
+ exec "$REAL_LSOF" "$@"
113
+ SHIM
114
+ } > "$dir/lsof"
115
+ chmod +x "$dir/lsof"
116
+ }
117
+
118
+ metro_pid_file() {
119
+ command -v recipe_runtime_dir >/dev/null 2>&1 || return 1
120
+ local runtime
121
+ runtime="$(recipe_runtime_dir)" || return 1
122
+ printf '%s/%s/metro.pid' "$TARGET" "$runtime"
123
+ }
84
124
 
85
125
  # --- iOS helpers --------------------------------------------------------------
86
126
 
@@ -90,7 +130,7 @@ ios_app_installed() {
90
130
  }
91
131
 
92
132
  run_ios_native_build() (
93
- local sim_target="$1" bundle_id="$2" reason="$3" build_env="" build_script="" build_type=""
133
+ local sim_target="$1" bundle_id="$2" reason="$3" build_env="" build_script="" build_type="" shim_dir=""
94
134
  case "$bundle_id" in
95
135
  io.metamask.MetaMask|io.metamask) build_script="start:ios"; build_type="main" ;;
96
136
  io.metamask.MetaMask-Flask) build_script="start:ios:flask"; build_type="flask" ;;
@@ -102,11 +142,15 @@ run_ios_native_build() (
102
142
  printf '%s; installing with yarn %s (WATCHER_PORT=%s)\n' "$reason" "$build_script" "$PORT" >&2
103
143
  build_env="$(mktemp "${TMPDIR:-/tmp}/mm-harness-ios-build-env.XXXXXX")" || return 1
104
144
  chmod 600 "$build_env" || { rm -f "$build_env"; return 1; }
105
- trap 'rm -f "$build_env"' EXIT HUP INT TERM
145
+ shim_dir="$(mktemp -d "${TMPDIR:-/tmp}/mm-harness-build-shim.XXXXXX")" || { rm -f "$build_env"; return 1; }
146
+ trap 'rm -rf "$build_env" "$shim_dir"' EXIT HUP INT TERM
147
+ write_lsof_shim "$shim_dir"
106
148
  {
107
149
  printf 'export MM_HARNESS_BUILD_WATCHER_PORT=%q\n' "$PORT"
108
150
  printf 'export MM_HARNESS_BUILD_IOS_SIMULATOR=%q\n' "$sim_target"
109
151
  printf 'export MM_HARNESS_BUILD_TYPE=%q\n' "$build_type"
152
+ printf 'export MM_HARNESS_METRO_PID_FILE=%q\n' "$(metro_pid_file || true)"
153
+ printf 'export PATH=%q:"$PATH"\n' "$shim_dir"
110
154
  cat <<'BUILD_ENV'
111
155
  mm_harness_restore_build_target() {
112
156
  export WATCHER_PORT="$MM_HARNESS_BUILD_WATCHER_PORT"
@@ -126,31 +170,6 @@ source() {
126
170
  mm_harness_restore_build_target
127
171
  return "$status"
128
172
  }
129
- # The harness owns Metro on WATCHER_PORT. Expo's own bundler management
130
- # re-checks that port after the build with lsof under a 350 ms budget, which a
131
- # loaded machine misses, and then aborts with "Port became busy". Build only:
132
- # --no-bundler, which Expo refuses next to --port, so the port argument goes.
133
- mm_harness_expo_build_args() {
134
- local arg skip=false
135
- MM_HARNESS_EXPO_ARGS=()
136
- for arg in "$@"; do
137
- if [ "$skip" = true ]; then skip=false; continue; fi
138
- case "$arg" in
139
- --port) skip=true; continue ;;
140
- --port=*) continue ;;
141
- esac
142
- MM_HARNESS_EXPO_ARGS+=("$arg")
143
- done
144
- MM_HARNESS_EXPO_ARGS+=(--no-bundler)
145
- }
146
- yarn() {
147
- if [ "${1:-}" = expo ] && [ "${2:-}" = run:ios ]; then
148
- mm_harness_expo_build_args "$@"
149
- command yarn "${MM_HARNESS_EXPO_ARGS[@]}"
150
- else
151
- command yarn "$@"
152
- fi
153
- }
154
173
  mm_harness_restore_build_target
155
174
  BUILD_ENV
156
175
  } > "$build_env"
@@ -306,7 +325,7 @@ android_app_installed() {
306
325
  }
307
326
 
308
327
  run_android_native_build() (
309
- local serial="$1" expo_device="$2" pkg="$3" reason="$4" build_env="" build_script=""
328
+ local serial="$1" expo_device="$2" pkg="$3" reason="$4" build_env="" build_script="" shim_dir=""
310
329
  case "$pkg" in
311
330
  io.metamask) build_script="start:android" ;;
312
331
  io.metamask.flask) build_script="start:android:flask" ;;
@@ -318,11 +337,15 @@ run_android_native_build() (
318
337
  printf '%s; installing with yarn %s (WATCHER_PORT=%s)\n' "$reason" "$build_script" "$PORT" >&2
319
338
  build_env="$(mktemp "${TMPDIR:-/tmp}/mm-harness-android-build-env.XXXXXX")" || return 1
320
339
  chmod 600 "$build_env" || { rm -f "$build_env"; return 1; }
321
- trap 'rm -f "$build_env"' EXIT HUP INT TERM
340
+ shim_dir="$(mktemp -d "${TMPDIR:-/tmp}/mm-harness-build-shim.XXXXXX")" || { rm -f "$build_env"; return 1; }
341
+ trap 'rm -rf "$build_env" "$shim_dir"' EXIT HUP INT TERM
342
+ write_lsof_shim "$shim_dir"
322
343
  {
323
344
  printf 'export MM_HARNESS_BUILD_ANDROID_SERIAL=%q\n' "$serial"
324
345
  printf 'export MM_HARNESS_BUILD_ANDROID_EXPO_DEVICE=%q\n' "$expo_device"
325
346
  printf 'export MM_HARNESS_BUILD_WATCHER_PORT=%q\n' "$PORT"
347
+ printf 'export MM_HARNESS_METRO_PID_FILE=%q\n' "$(metro_pid_file || true)"
348
+ printf 'export PATH=%q:"$PATH"\n' "$shim_dir"
326
349
  cat <<'BUILD_ENV'
327
350
  mm_harness_restore_android_build_target() {
328
351
  export WATCHER_PORT="$MM_HARNESS_BUILD_WATCHER_PORT"
@@ -342,24 +365,9 @@ source() {
342
365
  mm_harness_restore_android_build_target
343
366
  return "$status"
344
367
  }
345
- # --no-bundler without --port: the harness owns Metro on WATCHER_PORT (see the
346
- # iOS build env for why).
347
- mm_harness_expo_build_args() {
348
- local arg skip=false
349
- MM_HARNESS_EXPO_ARGS=()
350
- for arg in "$@"; do
351
- if [ "$skip" = true ]; then skip=false; continue; fi
352
- case "$arg" in
353
- --port) skip=true; continue ;;
354
- --port=*) continue ;;
355
- esac
356
- MM_HARNESS_EXPO_ARGS+=("$arg")
357
- done
358
- }
359
368
  yarn() {
360
369
  if [ "${1:-}" = expo ] && [ "${2:-}" = run:android ]; then
361
- mm_harness_expo_build_args "$@"
362
- command yarn "${MM_HARNESS_EXPO_ARGS[@]}" "$MM_HARNESS_BUILD_ANDROID_EXPO_DEVICE" --no-bundler
370
+ command yarn "$@" "$MM_HARNESS_BUILD_ANDROID_EXPO_DEVICE"
363
371
  else
364
372
  command yarn "$@"
365
373
  fi
@@ -218,6 +218,12 @@ if metro_ready; then
218
218
  rm -f "$PID_FILE"
219
219
  elif metro_listener_valid; then
220
220
  printf 'Metro already running and valid on port %s\n' "$PORT" >&2
221
+ # A reused listener still needs its record: the native build answers
222
+ # Expo's port lookup from metro.pid.
223
+ if [ ! -f "$PID_FILE" ]; then
224
+ lsof -nP -iTCP:"$PORT" -sTCP:LISTEN -t 2>/dev/null | head -1 > "$PID_FILE" || true
225
+ [ -s "$PID_FILE" ] || rm -f "$PID_FILE"
226
+ fi
221
227
  exit 0
222
228
  else
223
229
  stop_metro_listener || exit 1
@@ -10,6 +10,7 @@ import { applyDeviceTargeting } from "./device-target.js";
10
10
  import { ADAPTER_DETECT_NEXT, checkoutBusyOut, EXIT, flag, parseFlags, resolveAdapter, scriptOverride, spawnScript, spawnScriptStreaming, str, targetOf, usageOut } from "./shared.js";
11
11
  const FIXTURES_BOOLEANS = /* @__PURE__ */ new Set(["dev", "force", "json"]);
12
12
  const FIXTURE_STREAM_TIMEOUT_MS = 12e4;
13
+ const MOBILE_SETUP_WALLET_TIMEOUT_MS = 36e4;
13
14
  async function handleFixtures(argv) {
14
15
  const { positional, options } = parseFlags(argv, FIXTURES_BOOLEANS);
15
16
  if (!positional[0]) return fixturesStatus(options);
@@ -246,8 +247,8 @@ async function handleFixturesLocked(argv) {
246
247
  }
247
248
  }
248
249
  }
249
- const configuredTimeout = Number(process.env.MM_HARNESS_FIXTURES_SET_TIMEOUT_MS ?? FIXTURE_STREAM_TIMEOUT_MS);
250
- const timeoutMs = Number.isFinite(configuredTimeout) && configuredTimeout > 0 ? configuredTimeout : FIXTURE_STREAM_TIMEOUT_MS;
250
+ const configuredTimeout = Number(process.env.MM_HARNESS_FIXTURES_SET_TIMEOUT_MS ?? MOBILE_SETUP_WALLET_TIMEOUT_MS);
251
+ const timeoutMs = Number.isFinite(configuredTimeout) && configuredTimeout > 0 ? configuredTimeout : MOBILE_SETUP_WALLET_TIMEOUT_MS;
251
252
  if (!resetError) {
252
253
  mobileSetupResult = await spawnScriptStreaming(
253
254
  setupWalletSh,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@deeeed/metamask-harness",
3
- "version": "0.51.1",
3
+ "version": "0.51.3",
4
4
  "type": "module",
5
5
  "bin": {
6
6
  "mm-harness": "bin/mm-harness"