@touchtechclub/simbox 0.4.9 → 0.4.10

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 (2) hide show
  1. package/dist/cli.js +55 -9
  2. package/package.json +1 -1
package/dist/cli.js CHANGED
@@ -623,6 +623,22 @@ function remoteArgs(args, info, stateDir) {
623
623
  result.push("--state-dir", stateDir, "--daemon-base-url", daemonBaseUrl(info.tunnelUrl), "--daemon-transport", "http");
624
624
  return [...result, ...tail];
625
625
  }
626
+ var REPLAY_SAFE = new Set([
627
+ "devices",
628
+ "snapshot",
629
+ "screenshot",
630
+ "fold",
631
+ "session",
632
+ "appstate",
633
+ "apps",
634
+ "get",
635
+ "is"
636
+ ]);
637
+ var TRANSPORT_ERROR = /Remote daemon is unavailable|Daemon request timed out|Failed to read daemon response|fetch failed|ECONNRESET|socket hang up/;
638
+ function shouldReplay(args, code, output) {
639
+ return code !== 0 && REPLAY_SAFE.has(args[0] ?? "") && TRANSPORT_ERROR.test(output);
640
+ }
641
+ var REPLAY_ATTEMPTS = 3;
626
642
  function hasFlag(args, flag) {
627
643
  const end = args.indexOf("--");
628
644
  return (end < 0 ? args : args.slice(0, end)).some((arg) => arg === flag || arg.startsWith(`${flag}=`));
@@ -661,26 +677,56 @@ async function cmdExec(args) {
661
677
  info = await waitForRemote(initial);
662
678
  }
663
679
  writeCachedRun(info);
680
+ const replaySafe = REPLAY_SAFE.has(args[0]);
681
+ let connected = info;
682
+ let result = await runRemote(bin, args, connected, replaySafe);
683
+ for (let attempt = 1;attempt < REPLAY_ATTEMPTS; attempt++) {
684
+ if (!shouldReplay(args, result.code, result.output))
685
+ break;
686
+ process.stderr.write(`Tunnel dropped during \`${args[0]}\`; retrying (${attempt}/${REPLAY_ATTEMPTS - 1}).
687
+ `);
688
+ await sleep(attempt * 5000);
689
+ if (!await probeRemote(connected)) {
690
+ const refreshed = await refreshRemote();
691
+ if (!refreshed)
692
+ break;
693
+ connected = await waitForRemote(refreshed);
694
+ writeCachedRun(connected);
695
+ }
696
+ result = await runRemote(bin, args, connected, replaySafe);
697
+ }
698
+ if (replaySafe) {
699
+ process.stdout.write(result.stdout);
700
+ process.stderr.write(result.stderr);
701
+ }
702
+ const code = result.code;
703
+ if (code === 0 && !args.some((arg) => ["help", "--help", "-h", "--version", "version"].includes(arg)))
704
+ registerDevice(connected, { args });
705
+ if (code !== 0 && !replaySafe) {
706
+ process.stderr.write("Simbox did not retry the device command (it may already have executed). Use `simbox exec session list` to inspect it; the next command refreshes the tunnel automatically.\n");
707
+ }
708
+ process.exitCode = code;
709
+ }
710
+ async function runRemote(bin, args, info, capture) {
664
711
  const env = {
665
712
  ...process.env,
666
713
  AGENT_DEVICE_DAEMON_AUTH_TOKEN: info.daemonToken
667
714
  };
668
715
  delete env.AGENT_DEVICE_REMOTE_CONFIG;
669
716
  delete env.AGENT_DEVICE_DAEMON_BASE_URL;
717
+ let stdout = "";
718
+ let stderr = "";
670
719
  const code = await new Promise((resolve, reject) => {
671
720
  const child = spawn(bin, remoteArgs(args, info, join4(configDir(), "agent-device")), {
672
- stdio: "inherit",
721
+ stdio: capture ? ["inherit", "pipe", "pipe"] : "inherit",
673
722
  env
674
723
  });
724
+ child.stdout?.on("data", (chunk) => stdout += chunk.toString());
725
+ child.stderr?.on("data", (chunk) => stderr += chunk.toString());
675
726
  child.on("error", reject);
676
- child.on("exit", (status) => resolve(status ?? 1));
727
+ child.on("close", (status) => resolve(status ?? 1));
677
728
  });
678
- if (code === 0 && !args.some((arg) => ["help", "--help", "-h", "--version", "version"].includes(arg)))
679
- registerDevice(info, { args });
680
- if (code !== 0) {
681
- process.stderr.write("Simbox did not retry the device command (it may already have executed). Use `simbox exec session list` to inspect it; the next command refreshes the tunnel automatically.\n");
682
- }
683
- process.exitCode = code;
729
+ return { code, output: stdout + stderr, stdout, stderr };
684
730
  }
685
731
 
686
732
  // src/commands.ts
@@ -765,7 +811,7 @@ function printRepoConnected(repo) {
765
811
  }
766
812
  console.log(`Run ${pc3.cyan("simbox sim")} to boot a simulator.`);
767
813
  }
768
- var SIM_TIMEOUT_MS = 12 * 60 * 1000;
814
+ var SIM_TIMEOUT_MS = 25 * 60 * 1000;
769
815
  var SIM_POLL_MS = 3000;
770
816
  async function cmdSim(opts) {
771
817
  const json = opts.json === true;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@touchtechclub/simbox",
3
- "version": "0.4.9",
3
+ "version": "0.4.10",
4
4
  "description": "On-demand iOS simulators & Android emulators on your own GitHub Actions minutes.",
5
5
  "repository": {
6
6
  "type": "git",