@stim-cli/core 1.27.0 → 1.29.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;
@@ -629,25 +629,69 @@ function reusableDependencies(area, project, lockfile, env = process.env) {
629
629
  }
630
630
  //#endregion
631
631
  //#region metro-bridge.ts
632
- function port(value) {
633
- if (!Number.isInteger(value) || value < 1 || value > 65535) throw new Error("Invalid Metro bridge port.");
634
- }
635
- function credential(secret) {
636
- if (!/^[a-f0-9]{64}$/.test(secret)) throw new Error("A Metro bridge needs a 256-bit secret.");
637
- 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
+ };
638
675
  }
639
- 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) {
640
678
  const sockets = /* @__PURE__ */ new Set();
641
679
  let closing;
642
- const track = (socket) => {
680
+ const server = createServer((socket) => {
681
+ if (closing || sockets.size >= 128) return void socket.destroy();
643
682
  sockets.add(socket);
644
683
  socket.once("close", () => sockets.delete(socket));
645
684
  socket.on("error", () => socket.destroy());
646
- };
647
- const server = createServer((socket) => {
648
- if (closing || sockets.size >= 128) return void socket.destroy();
649
- track(socket);
650
- 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
+ })();
651
695
  });
652
696
  return {
653
697
  server,
@@ -661,63 +705,6 @@ function trackedServer(accept) {
661
705
  }
662
706
  };
663
707
  }
664
- function forward(source, target) {
665
- source.once("close", () => target.destroy());
666
- target.once("close", () => source.destroy());
667
- source.pipe(target).pipe(source);
668
- }
669
- /** Bind this gateway only to the client's own Tailscale address; `peer` is the pinned worker's literal address. */
670
- function createMetroGateway({ metroPort, peer, secret }) {
671
- port(metroPort);
672
- if (!isIP(peer)) throw new Error("The Metro gateway requires a pinned peer address.");
673
- const expected = credential(secret);
674
- return trackedServer((socket, track) => {
675
- if (socket.remoteAddress?.replace(/^::ffff:/, "") !== peer) return void socket.destroy();
676
- const deadline = setTimeout(() => socket.destroy(), 5e3);
677
- socket.once("close", () => clearTimeout(deadline));
678
- let prefix = Buffer.alloc(0);
679
- const authenticate = (chunk) => {
680
- const needed = expected.length - prefix.length;
681
- prefix = Buffer.concat([prefix, chunk.subarray(0, needed)]);
682
- if (prefix.length < expected.length) return;
683
- socket.removeListener("data", authenticate);
684
- socket.pause();
685
- if (!timingSafeEqual(prefix, expected)) return void socket.destroy();
686
- clearTimeout(deadline);
687
- const upstream = connect({
688
- host: "127.0.0.1",
689
- port: metroPort
690
- });
691
- track(upstream);
692
- if (chunk.length > needed) socket.unshift(chunk.subarray(needed));
693
- forward(socket, upstream);
694
- };
695
- socket.on("data", authenticate);
696
- });
697
- }
698
- /** Bind this endpoint only to worker loopback; `peer` comes from the approved client's authenticated connection. */
699
- function createMetroBridge({ gatewayPort, peer, secret }) {
700
- port(gatewayPort);
701
- if (!isIP(peer)) throw new Error("The Metro bridge requires an authenticated peer address.");
702
- const prefix = credential(secret);
703
- return trackedServer((socket, track) => {
704
- socket.pause();
705
- const upstream = connect({
706
- host: peer,
707
- port: gatewayPort,
708
- timeout: 5e3
709
- });
710
- track(upstream);
711
- upstream.once("timeout", () => upstream.destroy());
712
- upstream.once("close", () => socket.destroy());
713
- upstream.once("connect", () => {
714
- upstream.setTimeout(0);
715
- upstream.write(prefix);
716
- forward(socket, upstream);
717
- });
718
- socket.once("close", () => upstream.destroy());
719
- });
720
- }
721
708
  //#endregion
722
709
  //#region react-native-artifact.ts
723
710
  const text$1 = (value) => typeof value === "string" && value.length > 0 && value.length <= 256 && !/[\0\r\n]/.test(value);
@@ -1098,4 +1085,4 @@ function matchesCache(cache, match) {
1098
1085
  return match.layout === void 0 || cache.layout === match.layout;
1099
1086
  }
1100
1087
  //#endregion
1101
- 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 };