@muhkoo/connect 0.13.0-alpha.0 → 0.13.1-alpha.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.
@@ -3235,7 +3235,7 @@ function base64UrlDecode(s) {
3235
3235
  * expect (and isn't serving a stale cached bundle). Keep this in sync with
3236
3236
  * `package.json` `version`.
3237
3237
  */
3238
- const VERSION = "0.13.0-alpha.0";
3238
+ const VERSION = "0.13.1-alpha.0";
3239
3239
 
3240
3240
  /**
3241
3241
  * `HttpClient` — the one place the unified {@link Client} talks to the
@@ -11914,6 +11914,32 @@ function escapeLiteral(s) {
11914
11914
  * repeat.
11915
11915
  */
11916
11916
  const MAX_DEPTH = 64;
11917
+ /**
11918
+ * How many directories `walk` lists at once.
11919
+ *
11920
+ * Enough to hide per-request latency on a wide tree; low enough that a big
11921
+ * project does not open a request per directory. Browsers cap concurrency per
11922
+ * origin anyway, so a larger number mostly moves the queue.
11923
+ */
11924
+ const WALK_CONCURRENCY = 8;
11925
+ /**
11926
+ * `Promise.all` with a ceiling, preserving input order.
11927
+ *
11928
+ * Results are written back BY INDEX rather than pushed as they settle, so the
11929
+ * output order matches the input regardless of which finishes first — which is
11930
+ * what lets `walk` parallelise without changing what it returns.
11931
+ */
11932
+ async function mapLimit(items, limit, fn) {
11933
+ if (items.length <= 1)
11934
+ return items.length ? [await fn(items[0])] : [];
11935
+ const out = new Array(items.length);
11936
+ let next = 0;
11937
+ await Promise.all(Array.from({ length: Math.min(limit, items.length) }, async () => {
11938
+ for (let i = next++; i < items.length; i = next++)
11939
+ out[i] = await fn(items[i]);
11940
+ }));
11941
+ return out;
11942
+ }
11917
11943
  const DEFAULT_HISTORY_LIMIT = 20;
11918
11944
  class VfsNamespace {
11919
11945
  deps;
@@ -12072,34 +12098,40 @@ class VfsNamespace {
12072
12098
  * one fetch per directory. Fine for a project, wrong as a default.
12073
12099
  */
12074
12100
  async walk(path = ".") {
12075
- const out = [];
12076
- // Guard against a tree that is not one.
12077
- //
12078
- // `visit` recurses on a PATH, re-resolved from the root each time, so a
12079
- // record whose entry points back at an ancestor - or, before names were
12080
- // validated, an entry simply named ".." - recurses forever and grows
12081
- // `out` without bound. Nothing in the format prevents that, and `mount`
12082
- // calls this on every sync pass.
12101
+ /**
12102
+ * Sibling directories are listed CONCURRENTLY.
12103
+ *
12104
+ * Each `list` is a round trip for one directory record, and walking them
12105
+ * one after another cost the sum of those latencies: measured against a
12106
+ * real project, the walk alone was 1–2.1s before a single file had been
12107
+ * read. Directories are independent, so there was never a reason to
12108
+ * queue them.
12109
+ *
12110
+ * Order is preserved exactly. Each entry maps to its own slice of the
12111
+ * result and the slices are concatenated in listing order, so the output
12112
+ * is identical to the depth-first version — callers and tests that
12113
+ * depend on it are unaffected, and only the timing changes.
12114
+ */
12083
12115
  const seen = new Set();
12084
12116
  const visit = async (dirPath, depth) => {
12085
12117
  if (depth > MAX_DEPTH) {
12086
12118
  this.warn(`stopping at ${dirPath}: deeper than ${MAX_DEPTH} levels`);
12087
- return;
12119
+ return [];
12088
12120
  }
12121
+ // Claimed BEFORE the first await, so two concurrent visits to the
12122
+ // same directory cannot both get past this. A record whose entry
12123
+ // points back at an ancestor would otherwise recurse forever, and
12124
+ // nothing in the format prevents one.
12089
12125
  if (seen.has(dirPath)) {
12090
12126
  this.warn(`stopping at ${dirPath}: already visited (the tree contains a cycle)`);
12091
- return;
12127
+ return [];
12092
12128
  }
12093
12129
  seen.add(dirPath);
12094
- for (const entry of await this.list(dirPath)) {
12095
- if (entry.kind === "dir")
12096
- await visit(entry.path, depth + 1);
12097
- else
12098
- out.push(entry.path);
12099
- }
12130
+ const entries = await this.list(dirPath);
12131
+ const slices = await mapLimit(entries, WALK_CONCURRENCY, async (entry) => entry.kind === "dir" ? visit(entry.path, depth + 1) : [entry.path]);
12132
+ return slices.flat();
12100
12133
  };
12101
- await visit(this.resolve(path), 0);
12102
- return out;
12134
+ return visit(this.resolve(path), 0);
12103
12135
  }
12104
12136
  async readFile(path) {
12105
12137
  const entry = await this.expectFile(path);