@orkestrel/probe 0.0.11 → 0.0.12

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.
@@ -4,7 +4,7 @@ import { createHash, randomUUID } from "node:crypto";
4
4
  import { basename, dirname, extname, isAbsolute, join, relative, resolve, sep } from "node:path";
5
5
  import { fileURLToPath, pathToFileURL } from "node:url";
6
6
  import { attempt, compileGuard, compileSchema, isArray, isRecord, schemaToParameters } from "@orkestrel/contract";
7
- import { CLAIM_SHAPE, LINT_DEADLINE, PROBE_DEADLINE, PROBE_KEYS, ProbeError, computeReceipt, createDestroyedError, formatCheck, formatReceipt, formatSpecification, formatVerdict, isClaim, isDraft, isProbeError, isVerdict, matchesSpecification } from "../core/index.js";
7
+ import { CLAIM_SHAPE, LINT_DEADLINE, PROBE_DEADLINE, PROBE_KEYS, PROBE_SPECIFICATIONS, ProbeError, RUNTIME_PLUGIN, computeReceipt, createDestroyedError, formatCheck, formatReceipt, formatSpecification, formatVerdict, isClaim, isDraft, isProbeError, isVerdict, matchesSpecification } from "../core/index.js";
8
8
  import { Emitter } from "@orkestrel/emitter";
9
9
  import { createQueue } from "@orkestrel/queue";
10
10
  import { createTimeout } from "@orkestrel/timeout";
@@ -37,6 +37,64 @@ function normalizePath(path) {
37
37
  return path.replaceAll("\\", "/");
38
38
  }
39
39
  /**
40
+ * Reads the condition code a native fault carries.
41
+ *
42
+ * @remarks
43
+ * A caller catches `unknown`, so every reading of a caught value's own property calls into code
44
+ * this package does not own: a proxy whose `has` trap throws and a value whose `code` getter throws
45
+ * both arrive here. The read is guarded, so a fault that refuses inspection reports no code rather
46
+ * than raising a second fault over the first. A `code` the host reports as anything other than a
47
+ * string is no code this package compares against, so it reports none either.
48
+ *
49
+ * One reading serves every site that classifies a native fault, so a host condition is admitted the
50
+ * same way wherever it is read.
51
+ *
52
+ * @param error - The caught value to read
53
+ * @returns The fault's `code` when it carries a string one; `undefined` otherwise
54
+ *
55
+ * @example
56
+ * ```ts
57
+ * readFaultCode(Object.assign(new Error('no such file'), { code: 'ENOENT' })) // 'ENOENT'
58
+ * readFaultCode(new Error('the runtime stage was destroyed')) // undefined
59
+ * readFaultCode('ENOENT') // undefined
60
+ * ```
61
+ */
62
+ function readFaultCode(error) {
63
+ if (typeof error !== "object" || error === null) return void 0;
64
+ const fault = error;
65
+ const reading = attempt(() => "code" in fault ? fault.code : void 0);
66
+ if (!reading.success) return void 0;
67
+ return typeof reading.value === "string" ? reading.value : void 0;
68
+ }
69
+ /**
70
+ * Reports whether one path resolves outside the root it is read against.
71
+ *
72
+ * @remarks
73
+ * Containment decides which paths a claim may reach and which absolute paths a digest may rewrite,
74
+ * so one reading serves every site that asks the question. A target resolving to the root itself is
75
+ * contained, and each caller decides on its own what that empty relative path means for it.
76
+ *
77
+ * The test reads the relative path rather than a string prefix of the root, so a sibling directory
78
+ * whose name begins with the root's own text is outside rather than beneath it. An absolute
79
+ * relative path is the answer a host returns for two paths on different volumes, which no root
80
+ * contains.
81
+ *
82
+ * @param root - The root the target is read against
83
+ * @param target - The path to test, absolute or root-relative
84
+ * @returns True if the target resolves outside the root; false otherwise
85
+ *
86
+ * @example
87
+ * ```ts
88
+ * escapesRoot('/srv/checkout', 'src/core/greeting.ts') // false
89
+ * escapesRoot('/srv/checkout', '../secrets.env') // true
90
+ * escapesRoot('/srv/checkout', '/srv/checkout-backup/secrets.env') // true
91
+ * ```
92
+ */
93
+ function escapesRoot(root, target) {
94
+ const path = relative(resolve(root), resolve(root, target));
95
+ return path === ".." || path.startsWith(`..${sep}`) || isAbsolute(path);
96
+ }
97
+ /**
40
98
  * Resolves a path inside a target workspace and rejects traversal outside it.
41
99
  *
42
100
  * @remarks
@@ -64,7 +122,7 @@ function resolveWorkspaceFile(workspace, target, mutate = false) {
64
122
  const root = resolve(workspace);
65
123
  const file = resolve(root, target);
66
124
  const path = relative(root, file);
67
- if (path === "" || path === ".." || path.startsWith(`..${sep}`) || isAbsolute(path)) throw new ProbeError(`Path escapes the workspace: ${target}`, {
125
+ if (path === "" || escapesRoot(root, file)) throw new ProbeError(`Path escapes the workspace: ${target}`, {
68
126
  origin: "claimant",
69
127
  code: "refused",
70
128
  context: { path: target }
@@ -77,18 +135,16 @@ function resolveWorkspaceFile(workspace, target, mutate = false) {
77
135
  descendant = resolve(descendant, segment);
78
136
  const outcome = attempt(() => lstatSync(descendant));
79
137
  if (!outcome.success) {
80
- const error = outcome.error;
81
- if (typeof error === "object" && error !== null && "code" in error && (error.code === "ENOENT" || error.code === "ENOTDIR")) break;
82
- throw error;
138
+ const code = readFaultCode(outcome.error);
139
+ if (code === "ENOENT" || code === "ENOTDIR") break;
140
+ throw outcome.error;
83
141
  }
84
142
  if (outcome.value.isSymbolicLink()) throw new ProbeError(`Path crosses a symbolic link: ${target}`, {
85
143
  origin: "workspace",
86
144
  code: "refused",
87
145
  context: { path: target }
88
146
  });
89
- const resolved = realpathSync(descendant);
90
- const remainder = relative(canonical, resolved);
91
- if (remainder === ".." || remainder.startsWith(`..${sep}`) || isAbsolute(remainder)) throw new ProbeError(`Path escapes the workspace: ${target}`, {
147
+ if (escapesRoot(canonical, realpathSync(descendant))) throw new ProbeError(`Path escapes the workspace: ${target}`, {
92
148
  origin: "claimant",
93
149
  code: "refused",
94
150
  context: { path: target }
@@ -96,7 +152,8 @@ function resolveWorkspaceFile(workspace, target, mutate = false) {
96
152
  }
97
153
  } catch (error) {
98
154
  if (error instanceof ProbeError) throw error;
99
- const claimant = typeof error === "object" && error !== null && "code" in error && (error.code === "ENAMETOOLONG" || error.code === "ERR_INVALID_ARG_VALUE");
155
+ const code = readFaultCode(error);
156
+ const claimant = code === "ENAMETOOLONG" || code === "ERR_INVALID_ARG_VALUE";
100
157
  throw new ProbeError(`The workspace path cannot be inspected: ${target}`, {
101
158
  origin: claimant ? "claimant" : "workspace",
102
159
  code: claimant ? "refused" : "malformed",
@@ -176,7 +233,7 @@ function overwriteFile(file, text) {
176
233
  *
177
234
  * @param file - The path whose creation failed
178
235
  * @param error - The fault the failed operation raised
179
- * @returns True when the fault means the host refuses this name; false otherwise
236
+ * @returns True if the fault means the host refuses this name; false otherwise
180
237
  *
181
238
  * @example
182
239
  * ```ts
@@ -189,11 +246,7 @@ function overwriteFile(file, text) {
189
246
  * ```
190
247
  */
191
248
  function isRefusedName(file, error) {
192
- if (typeof error !== "object" || error === null) return false;
193
- const fault = error;
194
- const reading = attempt(() => "code" in fault ? fault.code : void 0);
195
- if (!reading.success) return false;
196
- const code = reading.value;
249
+ const code = readFaultCode(error);
197
250
  if (code === "ENAMETOOLONG") return true;
198
251
  if (code === "ERR_INVALID_ARG_VALUE") return file.includes("\0");
199
252
  if (code !== "ENOENT") return false;
@@ -288,7 +341,7 @@ function resolveWorkspaceModule(workspace, specifier) {
288
341
  const outcome = attempt(() => createRequire(resolve(workspace, "package.json")).resolve(specifier));
289
342
  if (outcome.success) return outcome.value;
290
343
  const error = outcome.error;
291
- const missing = typeof error === "object" && error !== null && "code" in error && error.code === "MODULE_NOT_FOUND";
344
+ const missing = readFaultCode(error) === "MODULE_NOT_FOUND";
292
345
  throw new ProbeError(`The workspace cannot resolve ${specifier}`, {
293
346
  origin: "workspace",
294
347
  code: missing ? "missing" : "malformed",
@@ -303,7 +356,7 @@ function loadWorkspaceModule(workspace, specifier) {
303
356
  });
304
357
  if (outcome.success) return outcome.value;
305
358
  const error = outcome.error;
306
- const missing = typeof error === "object" && error !== null && "code" in error && error.code === "MODULE_NOT_FOUND";
359
+ const missing = readFaultCode(error) === "MODULE_NOT_FOUND";
307
360
  throw new ProbeError(`The workspace cannot load ${specifier}`, {
308
361
  origin: "workspace",
309
362
  code: missing ? "missing" : "malformed",
@@ -341,7 +394,8 @@ function readWorkspaceManifest(workspace, name) {
341
394
  const reading = attempt(() => readFileSync(path, "utf8"));
342
395
  if (!reading.success) {
343
396
  const error = reading.error;
344
- const missing = typeof error === "object" && error !== null && "code" in error && (error.code === "ENOENT" || error.code === "ENOTDIR");
397
+ const code = readFaultCode(error);
398
+ const missing = code === "ENOENT" || code === "ENOTDIR";
345
399
  throw new ProbeError(`${name} does not publish a readable manifest`, {
346
400
  origin: "workspace",
347
401
  code: missing ? "missing" : "malformed",
@@ -485,23 +539,24 @@ function inferDocumentLanguage(path) {
485
539
  return "typescript";
486
540
  }
487
541
  /**
488
- * Creates a fresh sibling identity while preserving a test's resolution directory.
542
+ * Builds the fresh sibling path a revision's file is written at, preserving the test's resolution
543
+ * directory.
489
544
  *
490
545
  * @param workspace - The target workspace root
491
546
  * @param path - The workspace-relative test path
492
547
  * @param revision - The fresh revision identity
493
- * @returns An absolute sibling file path
548
+ * @returns The absolute sibling path
494
549
  *
495
550
  * @example
496
551
  * ```ts
497
552
  * relativeWorkspaceFile(
498
553
  * '/srv/checkout',
499
- * createRevisionFile('/srv/checkout', 'tmp/probe/greeting.test.ts', '4821-9f0c'),
554
+ * buildRevisionPath('/srv/checkout', 'tmp/probe/greeting.test.ts', '4821-9f0c'),
500
555
  * )
501
556
  * // 'tmp/probe/greeting.test.probe-4821-9f0c.ts'
502
557
  * ```
503
558
  */
504
- function createRevisionFile(workspace, path, revision) {
559
+ function buildRevisionPath(workspace, path, revision) {
505
560
  const file = resolveWorkspaceFile(workspace, path);
506
561
  const extension = extname(file);
507
562
  return `${extension === "" ? file : file.slice(0, -extension.length)}.probe-${revision}${extension}`;
@@ -510,7 +565,7 @@ function createRevisionFile(workspace, path, revision) {
510
565
  * Reports whether a path is a workspace module Vitest can cache.
511
566
  *
512
567
  * @param path - The candidate file path
513
- * @returns True for script, TypeScript, Vue, and JSON modules; false otherwise
568
+ * @returns True if the path is a script, TypeScript, Vue, or JSON module; false otherwise
514
569
  *
515
570
  * @example
516
571
  * ```ts
@@ -637,7 +692,7 @@ function normalizeValue(workspace, value) {
637
692
  if (!isAbsolute(value)) return value;
638
693
  const path = relative(root, resolve(value));
639
694
  if (path === "") return ".";
640
- if (path === ".." || path.startsWith(`..${sep}`) || isAbsolute(path)) return value;
695
+ if (escapesRoot(root, value)) return value;
641
696
  return normalizePath(path);
642
697
  }
643
698
  if (isArray(value)) return value.map((entry) => normalizeValue(workspace, entry));
@@ -823,11 +878,11 @@ var Overlay = class {
823
878
  };
824
879
  //#endregion
825
880
  //#region package.json
826
- var version = "0.0.11";
881
+ var version = "0.0.12";
827
882
  var peerDependencies = {
828
- "oxlint": "^1.77.0",
829
- "typescript": "^6.0.0",
830
- "vitest": "^4.1.0"
883
+ "oxlint": "^1.80.0",
884
+ "typescript": "^6.0.3",
885
+ "vitest": "^4.1.11"
831
886
  };
832
887
  //#endregion
833
888
  //#region src/server/stages/LintStage.ts
@@ -877,7 +932,6 @@ var LintStage = class {
877
932
  #closing;
878
933
  #progress = 0;
879
934
  #revision = 0;
880
- #destroyed = false;
881
935
  /**
882
936
  * Starts warming the target workspace's Oxlint language server.
883
937
  *
@@ -899,12 +953,11 @@ var LintStage = class {
899
953
  }
900
954
  destroy() {
901
955
  if (this.#closing !== void 0) return this.#closing;
902
- this.#destroyed = true;
903
956
  this.#closing = guardStage(this.stage, this.#destroy());
904
957
  return this.#closing;
905
958
  }
906
959
  async #inspect(subject, options) {
907
- if (this.#destroyed) throw createDestroyedError("lint stage");
960
+ if (this.#closing !== void 0) throw createDestroyedError("lint stage");
908
961
  if (options === void 0) throw new ProbeError("The lint stage inspects only under a bound its caller supplies", {
909
962
  origin: "claimant",
910
963
  code: "refused",
@@ -912,7 +965,7 @@ var LintStage = class {
912
965
  });
913
966
  const started = performance.now();
914
967
  const client = await this.#warmed();
915
- if (this.#destroyed) throw createDestroyedError("lint stage");
968
+ if (this.#closing !== void 0) throw createDestroyedError("lint stage");
916
969
  const issues = [];
917
970
  for (const draft of [...subject.files, subject.test]) issues.push(...await this.#document(client, draft, options.signal));
918
971
  return {
@@ -997,7 +1050,7 @@ var LintStage = class {
997
1050
  });
998
1051
  }
999
1052
  #translate(error, path) {
1000
- if (this.#destroyed) return createDestroyedError("lint stage");
1053
+ if (this.#closing !== void 0) return createDestroyedError("lint stage");
1001
1054
  const ending = this.#ending;
1002
1055
  if (ending !== void 0) return this.#fault(`The Oxlint language server exited with ${ending}`, error, path);
1003
1056
  if (error instanceof Error) return error;
@@ -1052,6 +1105,11 @@ var LintStage = class {
1052
1105
  * The runtime overlay leaves bare specifier resolution to Vite: it replaces a bare import only
1053
1106
  * after Vite resolves that import to a covered file. The type stage overlays the declared test
1054
1107
  * path, while this stage executes a generated sibling and overlays only the candidate files.
1108
+ * This stage mints its overlay with the default exact-match sensitivity, because it declares no
1109
+ * file-name case sensitivity to Vite. A covered path whose spelling an importer wrote differs from
1110
+ * the recorded candidate path is therefore served by whatever answers first, and `#misses` reports
1111
+ * it as `The workspace configuration served this module before the runtime overlay` with origin
1112
+ * `workspace` rather than leaving it answered silently.
1055
1113
  *
1056
1114
  * Vite retains one unresolved URL for every specification path, so the stage replaces its whole
1057
1115
  * Vitest service after 64 specifications rather than deleting from each map that service owns. Any
@@ -1100,7 +1158,6 @@ var RuntimeStage = class {
1100
1158
  #specifications = 0;
1101
1159
  #closing;
1102
1160
  #progress = 0;
1103
- #destroyed = false;
1104
1161
  /**
1105
1162
  * Starts warming the target workspace's Vitest service.
1106
1163
  *
@@ -1122,16 +1179,15 @@ var RuntimeStage = class {
1122
1179
  }
1123
1180
  destroy() {
1124
1181
  if (this.#closing !== void 0) return this.#closing;
1125
- this.#destroyed = true;
1126
1182
  this.#closing = guardStage(this.stage, this.#destroy());
1127
1183
  return this.#closing;
1128
1184
  }
1129
1185
  async #inspect(subject) {
1130
- if (this.#destroyed) throw createDestroyedError("runtime stage");
1186
+ if (this.#closing !== void 0) throw createDestroyedError("runtime stage");
1131
1187
  const started = performance.now();
1132
1188
  const exitCode = process.exitCode;
1133
1189
  const vitest = await this.#runner();
1134
- if (this.#destroyed) throw createDestroyedError("runtime stage");
1190
+ if (this.#closing !== void 0) throw createDestroyedError("runtime stage");
1135
1191
  const project = this.#project(vitest, subject.test.path);
1136
1192
  if ("message" in project) return {
1137
1193
  stage: this.stage,
@@ -1273,7 +1329,7 @@ var RuntimeStage = class {
1273
1329
  return {
1274
1330
  ...config,
1275
1331
  plugins: [...config.plugins ?? [], {
1276
- name: "orkestrel-runtime-overlay",
1332
+ name: RUNTIME_PLUGIN,
1277
1333
  enforce: "pre",
1278
1334
  resolveId: this.#resolve.bind(this),
1279
1335
  load: this.#load.bind(this)
@@ -1315,7 +1371,7 @@ var RuntimeStage = class {
1315
1371
  let generated;
1316
1372
  const outcome = attempt(() => {
1317
1373
  const revision = `${process.pid}-${randomUUID()}`;
1318
- const file = createRevisionFile(this.#workspace, test.path, revision);
1374
+ const file = buildRevisionPath(this.#workspace, test.path, revision);
1319
1375
  generated = file;
1320
1376
  const target = relative(this.#workspace, file);
1321
1377
  resolveWorkspaceFile(this.#workspace, target, true);
@@ -1373,7 +1429,7 @@ var RuntimeStage = class {
1373
1429
  path
1374
1430
  }
1375
1431
  });
1376
- if (!project.vite.config.plugins.some((plugin) => plugin.name === "orkestrel-runtime-overlay")) return {
1432
+ if (!project.vite.config.plugins.some((plugin) => plugin.name === RUNTIME_PLUGIN)) return {
1377
1433
  origin: "workspace",
1378
1434
  path,
1379
1435
  message: `The runtime stage cannot instrument the string-declared Vitest project ${name} because its configuration carries no runtime overlay plugin`
@@ -1462,14 +1518,14 @@ var RuntimeStage = class {
1462
1518
  }
1463
1519
  #runner() {
1464
1520
  const current = this.#vitest;
1465
- if (current !== void 0 && this.#specifications < 64) return current;
1521
+ if (current !== void 0 && this.#specifications < PROBE_SPECIFICATIONS) return current;
1466
1522
  if (current !== void 0) return this.#store(this.#replace(current));
1467
1523
  const runner = loadWorkspaceModule(this.#workspace, "vitest/node");
1468
- return this.#store(this.#specifications < 64 ? this.#warm(runner.createVitest) : this.#replace(void 0, runner.createVitest));
1524
+ return this.#store(this.#specifications < PROBE_SPECIFICATIONS ? this.#warm(runner.createVitest) : this.#replace(void 0, runner.createVitest));
1469
1525
  }
1470
1526
  async #replace(current, create) {
1471
1527
  if (current !== void 0) await (await current).close();
1472
- if (this.#destroyed) throw createDestroyedError("runtime stage");
1528
+ if (this.#closing !== void 0) throw createDestroyedError("runtime stage");
1473
1529
  const runner = create ?? loadWorkspaceModule(this.#workspace, "vitest/node").createVitest;
1474
1530
  const replacement = await this.#warm(runner);
1475
1531
  this.#specifications = 0;
@@ -1547,7 +1603,7 @@ var RuntimeStage = class {
1547
1603
  process.kill(id, 0);
1548
1604
  return true;
1549
1605
  } catch (error) {
1550
- return error instanceof Error && "code" in error && error.code === "EPERM";
1606
+ return readFaultCode(error) === "EPERM";
1551
1607
  }
1552
1608
  }
1553
1609
  *#walk() {
@@ -1720,7 +1776,6 @@ var TypeStage = class {
1720
1776
  #recycled;
1721
1777
  #closing;
1722
1778
  #progress = 0;
1723
- #destroyed = false;
1724
1779
  /**
1725
1780
  * Starts warming the target workspace's TypeScript service.
1726
1781
  *
@@ -1774,15 +1829,14 @@ var TypeStage = class {
1774
1829
  }
1775
1830
  destroy() {
1776
1831
  if (this.#closing !== void 0) return this.#closing;
1777
- this.#destroyed = true;
1778
1832
  this.#closing = guardStage(this.stage, this.#destroy());
1779
1833
  return this.#closing;
1780
1834
  }
1781
1835
  async #inspect(subject, project) {
1782
- if (this.#destroyed) throw createDestroyedError("type stage");
1836
+ if (this.#closing !== void 0) throw createDestroyedError("type stage");
1783
1837
  const started = performance.now();
1784
1838
  const typescript = await this.#typescript;
1785
- if (this.#destroyed) throw createDestroyedError("type stage");
1839
+ if (this.#closing !== void 0) throw createDestroyedError("type stage");
1786
1840
  const selections = subject.files.map((draft) => ({
1787
1841
  draft,
1788
1842
  path: resolveWorkspaceFile(this.#workspace, draft.path)
@@ -1826,9 +1880,9 @@ var TypeStage = class {
1826
1880
  }
1827
1881
  }
1828
1882
  async #resolve(project) {
1829
- if (this.#destroyed) throw createDestroyedError("type stage");
1883
+ if (this.#closing !== void 0) throw createDestroyedError("type stage");
1830
1884
  const typescript = await this.#typescript;
1831
- if (this.#destroyed) throw createDestroyedError("type stage");
1885
+ if (this.#closing !== void 0) throw createDestroyedError("type stage");
1832
1886
  const resolved = resolveWorkspaceFile(this.#workspace, project);
1833
1887
  this.#progress += 1;
1834
1888
  this.#service(typescript, project);
@@ -1871,7 +1925,7 @@ var TypeStage = class {
1871
1925
  }
1872
1926
  async #unblock() {
1873
1927
  await setTimeout(0);
1874
- if (this.#destroyed) throw createDestroyedError("type stage");
1928
+ if (this.#closing !== void 0) throw createDestroyedError("type stage");
1875
1929
  }
1876
1930
  #record(draft, overlay) {
1877
1931
  overlay.set(resolveWorkspaceFile(this.#workspace, draft.path), draft.text);
@@ -2059,7 +2113,6 @@ var Probe = class {
2059
2113
  #typeTail = Promise.resolve();
2060
2114
  #arming;
2061
2115
  #closing;
2062
- #destroyed = false;
2063
2116
  /**
2064
2117
  * Resolves the target toolchain and starts warming the resident stages.
2065
2118
  *
@@ -2109,7 +2162,7 @@ var Probe = class {
2109
2162
  this.#support();
2110
2163
  this.#admit(claim);
2111
2164
  await this.#ready();
2112
- if (this.#destroyed) throw createDestroyedError("probe");
2165
+ if (this.#closing !== void 0) throw createDestroyedError("probe");
2113
2166
  const started = performance.now();
2114
2167
  const id = randomUUID();
2115
2168
  const project = await this.#resolve(claim);
@@ -2143,7 +2196,6 @@ var Probe = class {
2143
2196
  }
2144
2197
  destroy() {
2145
2198
  if (this.#closing !== void 0) return this.#closing;
2146
- this.#destroyed = true;
2147
2199
  this.#closing = this.#destroy();
2148
2200
  return this.#closing;
2149
2201
  }
@@ -2153,7 +2205,7 @@ var Probe = class {
2153
2205
  await attempt;
2154
2206
  return;
2155
2207
  } catch (error) {
2156
- if (this.#destroyed) throw error;
2208
+ if (this.#closing !== void 0) throw error;
2157
2209
  }
2158
2210
  if (this.#arming === attempt) {
2159
2211
  this.#arming = this.#arm();
@@ -2205,8 +2257,8 @@ var Probe = class {
2205
2257
  }
2206
2258
  async #boot(created) {
2207
2259
  const revision = `${process.pid}-${randomUUID()}`;
2208
- const typeDependency = createRevisionFile(this.#workspace, "tmp/probe/arm-type.ts", revision);
2209
- const runtimeDependency = createRevisionFile(this.#workspace, "tmp/probe/arm-runtime.ts", revision);
2260
+ const typeDependency = buildRevisionPath(this.#workspace, "tmp/probe/arm-type.ts", revision);
2261
+ const runtimeDependency = buildRevisionPath(this.#workspace, "tmp/probe/arm-runtime.ts", revision);
2210
2262
  const typeModule = basename(typeDependency, ".ts");
2211
2263
  const runtimeModule = basename(runtimeDependency, ".ts");
2212
2264
  const typeTest = {
@@ -2347,7 +2399,7 @@ var Probe = class {
2347
2399
  }
2348
2400
  }
2349
2401
  async #recycle(stage) {
2350
- if (this.#destroyed) return false;
2402
+ if (this.#closing !== void 0) return false;
2351
2403
  const timeout = createTimeout({ ms: this.#deadline });
2352
2404
  timeout.start();
2353
2405
  try {
@@ -2355,7 +2407,7 @@ var Probe = class {
2355
2407
  } catch {} finally {
2356
2408
  timeout.clear();
2357
2409
  }
2358
- if (this.#destroyed) return false;
2410
+ if (this.#closing !== void 0) return false;
2359
2411
  if (stage === this.#type) {
2360
2412
  this.#type = new TypeStage(this.#workspace);
2361
2413
  return true;
@@ -2413,13 +2465,17 @@ var Probe = class {
2413
2465
  }
2414
2466
  async #destroy() {
2415
2467
  try {
2416
- await this.#arming;
2417
- } catch {}
2418
- await Promise.all([
2419
- this.#destroyStage(this.#type),
2420
- this.#destroyStage(this.#lint),
2421
- this.#destroyStage(this.#runtime)
2422
- ]);
2468
+ try {
2469
+ await this.#arming;
2470
+ } catch {}
2471
+ await Promise.all([
2472
+ this.#destroyStage(this.#type),
2473
+ this.#destroyStage(this.#lint),
2474
+ this.#destroyStage(this.#runtime)
2475
+ ]);
2476
+ } finally {
2477
+ this.#emitter.destroy();
2478
+ }
2423
2479
  }
2424
2480
  async #destroyStage(stage) {
2425
2481
  try {
@@ -2636,6 +2692,6 @@ var ProbeServer = class {
2636
2692
  }
2637
2693
  };
2638
2694
  //#endregion
2639
- export { LintStage, Overlay, Probe, ProbeServer, RuntimeStage, TypeStage, captureListeners, computeDigest, createRevisionFile, describeUnknown, findRefusedPaths, guardStage, inferDocumentLanguage, inferTestProject, inferTypeProject, isRefusedName, loadWorkspaceModule, matchesWorkspaceModule, normalizePath, normalizeValue, overwriteFile, readWorkspaceManifest, relativeWorkspaceFile, relativeWorkspaceMessage, releaseListeners, resolveWorkspaceBinary, resolveWorkspaceFile, resolveWorkspaceModule };
2695
+ export { LintStage, Overlay, Probe, ProbeServer, RuntimeStage, TypeStage, buildRevisionPath, captureListeners, computeDigest, describeUnknown, escapesRoot, findRefusedPaths, guardStage, inferDocumentLanguage, inferTestProject, inferTypeProject, isRefusedName, loadWorkspaceModule, matchesWorkspaceModule, normalizePath, normalizeValue, overwriteFile, readFaultCode, readWorkspaceManifest, relativeWorkspaceFile, relativeWorkspaceMessage, releaseListeners, resolveWorkspaceBinary, resolveWorkspaceFile, resolveWorkspaceModule };
2640
2696
 
2641
2697
  //# sourceMappingURL=index.js.map