1import { spawnSync } from "node:child_process";
2
3export interface Runtime {
4 readonly name: "bun" | "node";
5 readonly argv: (entry: string) => Array<string>;
6 readonly available: boolean;
7}
8
9const hasBin = (bin: string): boolean => {
10 try {
11 // `which` doesn't exist on Windows; `where` is the equivalent.
12 const probe = process.platform === "win32" ? "where" : "which";
13 const r = spawnSync(probe, [bin], { encoding: "utf-8" });
14 return r.status === 0 && Boolean(r.stdout?.trim());
15 } catch {
16 return false;
17 }
18};
19
20const canTransformTypes =
21 spawnSync("node", ["-p", 'process.features.typescript === "transform"'], {
22 encoding: "utf-8",
23 }).stdout.trim() === "true";
24const transformTypesFlags = canTransformTypes
25 ? ["--experimental-transform-types", "--no-warnings=ExperimentalWarning"]
26 : [];
27
28export const runtimes = (): Array<Runtime> => [
29 {
30 name: "bun",
31 argv: (entry) => ["bun", "run", entry],
32 available: hasBin("bun"),
33 },
34 {
35 name: "node",
36 argv: (entry) => ["node", ...transformTypesFlags, entry],
37 // Node 26 removed transform-types and its built-in strip-only loader
38 // cannot execute parameter properties used by Alchemy's source graph.
39 // Published JS remains supported; only these source-level fixtures skip.
40 available: hasBin("node") && canTransformTypes,
41 },
42];