Skip to content

Commit 8f9f2cb

Browse files
authored
fix(engine): defer repo-map's createRequire past module scope to unbreak the api Worker deploy (#4590)
* fix(engine): defer repo-map's createRequire past module scope to unbreak the api Worker deploy createRequire(import.meta.url) ran eagerly at module load. The barrel export in @jsonbored/gittensory-engine pulls this file into the gittensory-api Worker bundle (via find-opportunities -> gittensory-miner's opportunity-fanout/ranker), even though the Worker never calls buildRepoMap. import.meta.url is undefined in that bundle's startup context, so the eager call crashed wrangler deploy's validation step before any request could be served. Constructing require lazily, only when a language actually needs to be loaded, lets esbuild tree-shake the whole unused module out of the Worker bundle instead. * fix(miner): defer status.js's createRequire/moduleDir past module scope too Same landmine as the repo-map.ts Worker-deploy break: an eager createRequire(import.meta.url) and import.meta.dirname at module scope. Not currently reachable from any bundler context, but the pattern is exactly what broke the api Worker deploy, so close it here too before an import chain connects it.
1 parent 6fee937 commit 8f9f2cb

2 files changed

Lines changed: 29 additions & 11 deletions

File tree

packages/gittensory-engine/src/miner/repo-map.ts

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,15 @@ import { readFileSync } from "node:fs";
2020
import { createRequire } from "node:module";
2121
import Parser from "web-tree-sitter";
2222

23-
const require = createRequire(import.meta.url);
23+
// Lazy, not module-scope: this file is reachable from the Cloudflare Workers bundle (barrel-exported via
24+
// `@jsonbored/gittensory-engine`) even though nothing there ever calls `buildRepoMap`. `import.meta.url` is
25+
// undefined in that bundle's startup-validation context, so an eager `createRequire(import.meta.url)` at
26+
// module scope would crash the Worker's deploy before any request is served. Deferring construction to
27+
// first real use keeps this module import-safe everywhere while still working for its actual CLI callers.
28+
let cachedRequire: NodeJS.Require | null = null;
29+
function requireFromHere(): NodeJS.Require {
30+
return (cachedRequire ??= createRequire(import.meta.url));
31+
}
2432

2533
export type RepoMapSymbolKind = "function" | "class" | "method" | "interface" | "type";
2634

@@ -90,7 +98,7 @@ let parserInitialized: Promise<void> | null = null;
9098
async function defaultLoadRepoMapLanguage(languageName: string): Promise<Parser.Language> {
9199
parserInitialized ??= Parser.init();
92100
await parserInitialized;
93-
const wasmPath = require.resolve(`tree-sitter-wasms/out/tree-sitter-${languageName}.wasm`);
101+
const wasmPath = requireFromHere().resolve(`tree-sitter-wasms/out/tree-sitter-${languageName}.wasm`);
94102
return Parser.Language.load(readFileSync(wasmPath));
95103
}
96104

packages/gittensory-miner/lib/status.js

Lines changed: 19 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,18 @@ import { resolveMinerVersion } from "./version.js";
99
// this laptop set up correctly). Both are read-only and 100% local — no repo-scanning, no coding-agent invocation,
1010
// no GitHub writes, and no network calls of any kind. Later phases add the real discover/plan/manage loop.
1111

12-
const require = createRequire(import.meta.url);
13-
const moduleDir = import.meta.dirname;
12+
// Lazy, not module-scope: mirrors the gittensory-engine repo-map.ts fix -- this file is CLI-only today, but
13+
// an eager createRequire(import.meta.url)/import.meta.dirname at module scope would crash on import in any
14+
// bundler context where import.meta is unavailable (e.g. if a future import chain pulls this into a Worker
15+
// bundle, the way repo-map.ts was). Deferring construction to first real use keeps this import-safe.
16+
let cachedRequire = null;
17+
function requireFromHere() {
18+
return (cachedRequire ??= createRequire(import.meta.url));
19+
}
20+
let cachedModuleDir = null;
21+
function moduleDir() {
22+
return (cachedModuleDir ??= import.meta.dirname);
23+
}
1424

1525
const PACKAGE_NAME = "@jsonbored/gittensory-miner";
1626
const ENGINE_PACKAGE = "@jsonbored/gittensory-engine";
@@ -40,7 +50,7 @@ export function resolveMinerStateDir(env = process.env) {
4050
// be absent depending on build order, so the declared-dependency version is the reliable, always-available source.)
4151
function readEngineVersion() {
4252
try {
43-
return require("../package.json").dependencies?.[ENGINE_PACKAGE] ?? null;
53+
return requireFromHere()("../package.json").dependencies?.[ENGINE_PACKAGE] ?? null;
4454
} catch {
4555
return null;
4656
}
@@ -75,11 +85,11 @@ export function readInstalledEnginePackageVersionFromPaths(
7585
export function readInstalledEnginePackageVersion() {
7686
try {
7787
return readInstalledEnginePackageVersionFromPaths(
78-
require.resolve(ENGINE_PACKAGE),
79-
join(moduleDir, "../../gittensory-engine/package.json"),
88+
requireFromHere().resolve(ENGINE_PACKAGE),
89+
join(moduleDir(), "../../gittensory-engine/package.json"),
8090
);
8191
} catch {
82-
const workspacePkg = join(moduleDir, "../../gittensory-engine/package.json");
92+
const workspacePkg = join(moduleDir(), "../../gittensory-engine/package.json");
8393
if (existsSync(workspacePkg)) {
8494
try {
8595
return JSON.parse(readFileSync(workspacePkg, "utf8")).version ?? null;
@@ -114,8 +124,8 @@ export function readExpectedEnginePackageVersionFromPaths(
114124

115125
export function readExpectedEnginePackageVersion() {
116126
return readExpectedEnginePackageVersionFromPaths(
117-
join(moduleDir, "../../gittensory-engine/package.json"),
118-
join(moduleDir, "../expected-engine.version"),
127+
join(moduleDir(), "../../gittensory-engine/package.json"),
128+
join(moduleDir(), "../expected-engine.version"),
119129
);
120130
}
121131

@@ -170,7 +180,7 @@ function checkEngineVersionSkew() {
170180

171181
/** The minimum Node major version from the package's `engines.node` floor (e.g. ">=22.13.0" → 22). */
172182
function requiredNodeMajor() {
173-
const engines = require("../package.json").engines;
183+
const engines = requireFromHere()("../package.json").engines;
174184
const match = typeof engines?.node === "string" ? engines.node.match(/(\d+)/) : null;
175185
return match ? Number(match[1]) : 0;
176186
}

0 commit comments

Comments
 (0)