Skip to content

Commit 8203dc0

Browse files
committed
fix(producer): use TypeScript compiler API for declarations, avoiding Windows junction EPERM
Spawning tsc as a child process (even via 'bun x tsc') fails on Windows because Node.js realpathSync returns EPERM when stat-ing NTFS junctions created by Bun in packages/producer/node_modules/typescript. Use the TypeScript compiler API (import ts from 'typescript') directly inside build.mjs instead. Since build.mjs runs under Bun, all module resolution and file I/O goes through Bun's junction-aware layer.
1 parent 97472fd commit 8203dc0

1 file changed

Lines changed: 34 additions & 8 deletions

File tree

packages/producer/build.mjs

Lines changed: 34 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
*/
77

88
import { build } from "esbuild";
9-
import { mkdirSync, rmSync, readFileSync } from "fs";
9+
import { mkdirSync, rmSync, readFileSync, copyFileSync, existsSync } from "fs";
1010
import { resolve, dirname } from "path";
1111
import { fileURLToPath } from "url";
1212

@@ -65,7 +65,6 @@ await Promise.all([
6565
]);
6666

6767
// Copy core runtime artifacts so the producer can find them at dist/
68-
import { copyFileSync, existsSync } from "fs";
6968
const coreDistDir = resolve(scriptDir, "../core/dist");
7069
try {
7170
const manifestSrc = resolve(coreDistDir, "hyperframe.manifest.json");
@@ -80,12 +79,39 @@ try {
8079
console.warn("[Build] Warning: Could not copy runtime artifacts:", e.message);
8180
}
8281

83-
// Generate .d.ts declarations (esbuild doesn't emit them).
84-
// Use "bun x tsc" so Bun's module resolver handles node_modules junctions
85-
// on Windows instead of Node.js's realpathSync (which returns EPERM).
86-
import { execSync } from "child_process";
87-
execSync("bun x tsc --emitDeclarationOnly --declaration --declarationMap", {
88-
stdio: "inherit",
82+
// Generate .d.ts declarations via the TypeScript compiler API (imported directly
83+
// so Bun's junction-aware module resolver is used instead of spawning a Node.js
84+
// child process, which fails on Windows with EPERM when stat-ing junctions).
85+
import ts from "typescript";
86+
87+
const configPath = ts.findConfigFile(scriptDir, ts.sys.fileExists, "tsconfig.json");
88+
if (!configPath) throw new Error("tsconfig.json not found");
89+
90+
const { config, error } = ts.readConfigFile(configPath, ts.sys.readFile);
91+
if (error) throw new Error(ts.formatDiagnostic(error, ts.createCompilerHost({})));
92+
93+
const { options, fileNames, errors } = ts.parseJsonConfigFileContent(
94+
config,
95+
ts.sys,
96+
dirname(configPath),
97+
);
98+
if (errors.length) {
99+
throw new Error(ts.formatDiagnostics(errors, ts.createCompilerHost(options)));
100+
}
101+
102+
const program = ts.createProgram(fileNames, {
103+
...options,
104+
declaration: true,
105+
declarationMap: true,
106+
emitDeclarationOnly: true,
107+
noEmit: false,
89108
});
90109

110+
const { diagnostics, emitSkipped } = program.emit();
111+
const allDiags = [...ts.getPreEmitDiagnostics(program), ...diagnostics];
112+
if (allDiags.length) {
113+
console.error(ts.formatDiagnosticsWithColorAndContext(allDiags, ts.createCompilerHost(options)));
114+
}
115+
if (emitSkipped) process.exit(1);
116+
91117
console.log("[Build] Complete: dist/index.js, dist/public-server.js, *.d.ts");

0 commit comments

Comments
 (0)