@stim-cli/core 1.26.0 → 1.28.0

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.
@@ -3,12 +3,12 @@ import { projectNodeBin } from "./toolchain.mjs";
3
3
  import fs, { existsSync, lstatSync, mkdirSync, readFileSync, readdirSync, realpathSync, renameSync, rmSync, rmdirSync, statSync, unlinkSync, utimesSync, writeFileSync } from "node:fs";
4
4
  import os from "node:os";
5
5
  import path, { basename, dirname, isAbsolute, join, normalize, relative, sep } from "node:path";
6
- import { createHash, randomBytes, randomUUID, timingSafeEqual } from "node:crypto";
6
+ import { createHash, randomBytes, randomUUID } from "node:crypto";
7
7
  import { setTimeout as setTimeout$1 } from "node:timers/promises";
8
8
  import { AsyncLocalStorage } from "node:async_hooks";
9
9
  import { mkdir, rm } from "node:fs/promises";
10
10
  import { spawnSync } from "node:child_process";
11
- import { connect, createServer, isIP } from "node:net";
11
+ import { createServer } from "node:net";
12
12
  //#region dir-lock.ts
13
13
  const DEFAULT_LOCK_WAIT_MS = 12e3;
14
14
  const DEFAULT_LOCK_POLL_MS = 25;
@@ -578,14 +578,16 @@ const LOCKFILES = [
578
578
  */
579
579
  function dependencyLockfile(root, project = ".") {
580
580
  let dir = normalize(project);
581
+ if (isAbsolute(dir)) return null;
581
582
  while (true) {
582
583
  const file = LOCKFILES.find((name) => existsSync(join(root, dir, name)));
583
584
  if (file) return {
584
585
  dir,
585
586
  file
586
587
  };
587
- if (dir === ".") return null;
588
- dir = dirname(dir);
588
+ const parent = dirname(dir);
589
+ if (dir === "." || parent === dir) return null;
590
+ dir = parent;
589
591
  }
590
592
  }
591
593
  /**
@@ -627,25 +629,69 @@ function reusableDependencies(area, project, lockfile, env = process.env) {
627
629
  }
628
630
  //#endregion
629
631
  //#region metro-bridge.ts
630
- function port(value) {
631
- if (!Number.isInteger(value) || value < 1 || value > 65535) throw new Error("Invalid Metro bridge port.");
632
- }
633
- function credential(secret) {
634
- if (!/^[a-f0-9]{64}$/.test(secret)) throw new Error("A Metro bridge needs a 256-bit secret.");
635
- return Buffer.from(`${secret}\n`, "ascii");
632
+ const METRO_LINK_LIMIT = 16;
633
+ const METRO_LINK_WAIT_MS = 1e4;
634
+ function createMetroLinks() {
635
+ const idle = [];
636
+ const waiting = [];
637
+ let closed = false;
638
+ return {
639
+ add: (link) => {
640
+ if (closed) return false;
641
+ const waiter = waiting.shift();
642
+ if (waiter) {
643
+ waiter(link);
644
+ return true;
645
+ }
646
+ if (idle.length >= METRO_LINK_LIMIT) idle.shift()?.close();
647
+ idle.push(link);
648
+ return true;
649
+ },
650
+ remove: (link) => {
651
+ const index = idle.indexOf(link);
652
+ if (index >= 0) idle.splice(index, 1);
653
+ },
654
+ take: (waitMs) => {
655
+ const link = idle.pop();
656
+ if (link || closed) return Promise.resolve(link ?? null);
657
+ return new Promise((resolve) => {
658
+ const waiter = (taken) => {
659
+ clearTimeout(timer);
660
+ resolve(taken);
661
+ };
662
+ const timer = setTimeout(() => {
663
+ waiting.splice(waiting.indexOf(waiter), 1);
664
+ resolve(null);
665
+ }, waitMs);
666
+ waiting.push(waiter);
667
+ });
668
+ },
669
+ close: () => {
670
+ closed = true;
671
+ for (const link of idle.splice(0)) link.close();
672
+ for (const waiter of waiting.splice(0)) waiter(null);
673
+ }
674
+ };
636
675
  }
637
- function trackedServer(accept) {
676
+ /** Bind this endpoint only to worker loopback; each accepted connection rides one link its client opened. */
677
+ function createMetroBridge(links, waitMs = METRO_LINK_WAIT_MS) {
638
678
  const sockets = /* @__PURE__ */ new Set();
639
679
  let closing;
640
- const track = (socket) => {
680
+ const server = createServer((socket) => {
681
+ if (closing || sockets.size >= 128) return void socket.destroy();
641
682
  sockets.add(socket);
642
683
  socket.once("close", () => sockets.delete(socket));
643
684
  socket.on("error", () => socket.destroy());
644
- };
645
- const server = createServer((socket) => {
646
- if (closing || sockets.size >= 128) return void socket.destroy();
647
- track(socket);
648
- accept(socket, track);
685
+ socket.pause();
686
+ (async () => {
687
+ const deadline = Date.now() + waitMs;
688
+ for (;;) {
689
+ const link = await links.take(Math.max(0, deadline - Date.now()));
690
+ if (!link) return void socket.destroy();
691
+ if (socket.destroyed) return void (links.add(link) || link.close());
692
+ if (link.open(socket)) return;
693
+ }
694
+ })();
649
695
  });
650
696
  return {
651
697
  server,
@@ -659,63 +705,6 @@ function trackedServer(accept) {
659
705
  }
660
706
  };
661
707
  }
662
- function forward(source, target) {
663
- source.once("close", () => target.destroy());
664
- target.once("close", () => source.destroy());
665
- source.pipe(target).pipe(source);
666
- }
667
- /** Bind this gateway only to the client's own Tailscale address; `peer` is the pinned worker's literal address. */
668
- function createMetroGateway({ metroPort, peer, secret }) {
669
- port(metroPort);
670
- if (!isIP(peer)) throw new Error("The Metro gateway requires a pinned peer address.");
671
- const expected = credential(secret);
672
- return trackedServer((socket, track) => {
673
- if (socket.remoteAddress?.replace(/^::ffff:/, "") !== peer) return void socket.destroy();
674
- const deadline = setTimeout(() => socket.destroy(), 5e3);
675
- socket.once("close", () => clearTimeout(deadline));
676
- let prefix = Buffer.alloc(0);
677
- const authenticate = (chunk) => {
678
- const needed = expected.length - prefix.length;
679
- prefix = Buffer.concat([prefix, chunk.subarray(0, needed)]);
680
- if (prefix.length < expected.length) return;
681
- socket.removeListener("data", authenticate);
682
- socket.pause();
683
- if (!timingSafeEqual(prefix, expected)) return void socket.destroy();
684
- clearTimeout(deadline);
685
- const upstream = connect({
686
- host: "127.0.0.1",
687
- port: metroPort
688
- });
689
- track(upstream);
690
- if (chunk.length > needed) socket.unshift(chunk.subarray(needed));
691
- forward(socket, upstream);
692
- };
693
- socket.on("data", authenticate);
694
- });
695
- }
696
- /** Bind this endpoint only to worker loopback; `peer` comes from the approved client's authenticated connection. */
697
- function createMetroBridge({ gatewayPort, peer, secret }) {
698
- port(gatewayPort);
699
- if (!isIP(peer)) throw new Error("The Metro bridge requires an authenticated peer address.");
700
- const prefix = credential(secret);
701
- return trackedServer((socket, track) => {
702
- socket.pause();
703
- const upstream = connect({
704
- host: peer,
705
- port: gatewayPort,
706
- timeout: 5e3
707
- });
708
- track(upstream);
709
- upstream.once("timeout", () => upstream.destroy());
710
- upstream.once("close", () => socket.destroy());
711
- upstream.once("connect", () => {
712
- upstream.setTimeout(0);
713
- upstream.write(prefix);
714
- forward(socket, upstream);
715
- });
716
- socket.once("close", () => upstream.destroy());
717
- });
718
- }
719
708
  //#endregion
720
709
  //#region react-native-artifact.ts
721
710
  const text$1 = (value) => typeof value === "string" && value.length > 0 && value.length <= 256 && !/[\0\r\n]/.test(value);
@@ -1096,4 +1085,4 @@ function matchesCache(cache, match) {
1096
1085
  return match.layout === void 0 || cache.layout === match.layout;
1097
1086
  }
1098
1087
  //#endregion
1099
- export { withDirLockAsync as $, createMetroGateway as A, unitLines as B, workspaceName as C, reactNativeArtifactIdentity as D, swiftpmArtifactQuery as E, storeArtifactAsync as F, ambientWrite as G, validMacosResourceDestination as H, artifactIn as I, readJsonFile as J, withAmbientContext as K, resolveArtifact as L, dependencyLockfile as M, reusableDependencies as N, reactNativeArtifactQuery as O, compiledHelper as P, withDirLock as Q, storeArtifact as R, workspaceLogDir as S, workspaceStateDir as T, ambientContext as U, unitWords as V, ambientEnv as W, readStateFile as X, readJsonObject as Y, withStateReadCache as Z, rotatedLogPath as _, buildCacheRoot as a, updateCacheManifest as b, cacheNameSegment as c, ensurePrivateDir as d, withDirLockTransaction as et, hostSimulatorArch as f, rotateLog as g, registerCache as h, buildCacheKey as i, dependencyInstall as j, createMetroBridge as k, cachePathSetting as l, readCacheManifest as m, METRO_NAMED_CACHE_LAYOUT as n, cacheDirRefusal as o, metroCacheRoot as p, isJsonObject as q, STORE_ROOT_TAG as r, cacheManifestLockPath as s, LOG_ROTATE_BYTES as t, configDir as u, sharedStoreRoot as v, workspaceSlug as w, workspaceId as x, tagSharedStore as y, quoteUnitWord as z };
1088
+ export { withDirLockAsync as $, createMetroLinks as A, unitLines as B, workspaceName as C, reactNativeArtifactIdentity as D, swiftpmArtifactQuery as E, storeArtifactAsync as F, ambientWrite as G, validMacosResourceDestination as H, artifactIn as I, readJsonFile as J, withAmbientContext as K, resolveArtifact as L, dependencyLockfile as M, reusableDependencies as N, reactNativeArtifactQuery as O, compiledHelper as P, withDirLock as Q, storeArtifact as R, workspaceLogDir as S, workspaceStateDir as T, ambientContext as U, unitWords as V, ambientEnv as W, readStateFile as X, readJsonObject as Y, withStateReadCache as Z, rotatedLogPath as _, buildCacheRoot as a, updateCacheManifest as b, cacheNameSegment as c, ensurePrivateDir as d, withDirLockTransaction as et, hostSimulatorArch as f, rotateLog as g, registerCache as h, buildCacheKey as i, dependencyInstall as j, createMetroBridge as k, cachePathSetting as l, readCacheManifest as m, METRO_NAMED_CACHE_LAYOUT as n, cacheDirRefusal as o, metroCacheRoot as p, isJsonObject as q, STORE_ROOT_TAG as r, cacheManifestLockPath as s, LOG_ROTATE_BYTES as t, configDir as u, sharedStoreRoot as v, workspaceSlug as w, workspaceId as x, tagSharedStore as y, quoteUnitWord as z };