Skip to content

Commit 249b2f6

Browse files
committed
fix(web): name the four Node builtins the browser bundle now destructures
The Docker leg failed on `vite build`, and this one is genuinely this branch's. @nodetool-ai/runtime now depends on @nodetool-ai/storage, which drags @openclaw/fs-safe into the browser graph; it destructures readSync and closeSync from node:fs, and the stub that replaces node:fs in the web bundle did not export them. Two more surfaced behind the first: createHmac from node:crypto, and request plus createRequire from the shared empty stub that covers node:http, node:https and node:module. A named import binds at bundle time, so empty.js's default Proxy cannot satisfy one — every name a workspace bundle destructures needs a real export. Each addition keeps the file's existing shape: throw on use, because browser-tagged code must never reach these. Also adds mkdtemp to the fs-promises stub. It was not an error, only an IMPORT_IS_UNDEFINED warning from claude-agent-provider.ts, but the binding resolved to undefined rather than to a named error. Enumerated the missing exports from the build rather than fixing them one crash at a time, and proved the check catches this: removing readSync alone puts the build back to "not exported by fs-stub.js". web build: exit 0, no MISSING_EXPORT, no IMPORT_IS_UNDEFINED. npm run lint: 0 errors. No test covered this. `npm run build` for web is not in the four mandatory post-change checks, and only the Docker leg runs it on a PR.
1 parent f0adde1 commit 249b2f6

4 files changed

Lines changed: 24 additions & 2 deletions

File tree

web/vite-node-stubs/crypto-stub.js

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,10 +15,14 @@ export function createHash() {
1515
throw new Error("node:crypto.createHash not available in browser");
1616
}
1717

18+
export function createHmac() {
19+
throw new Error("node:crypto.createHmac not available in browser");
20+
}
21+
1822
export function randomBytes(n) {
1923
const buf = new Uint8Array(n);
2024
globalThis.crypto.getRandomValues(buf);
2125
return buf;
2226
}
2327

24-
export default { randomUUID, createHash, randomBytes };
28+
export default { randomUUID, createHash, createHmac, randomBytes };

web/vite-node-stubs/empty.js

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,3 +10,15 @@ const handler = {
1010
}
1111
};
1212
export default new Proxy({}, handler);
13+
14+
// A named import binds at bundle time and the Proxy above cannot satisfy it,
15+
// so every named import a workspace bundle destructures from one of these
16+
// builtins needs a real export here. `request` is `node:http`/`node:https`.
17+
export function request() {
18+
throw new Error("Browser stub: node:http.request not supported");
19+
}
20+
21+
/** `node:module`. A bundle that reaches for CJS resolution has no browser path. */
22+
export function createRequire() {
23+
throw new Error("Browser stub: node:module.createRequire not supported");
24+
}

web/vite-node-stubs/fs-promises-stub.js

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ export const readlink = makeThrower("readlink");
2929
export const utimes = makeThrower("utimes");
3030
export const truncate = makeThrower("truncate");
3131
export const rmdir = makeThrower("rmdir");
32+
export const mkdtemp = makeThrower("mkdtemp");
3233

3334
export default {
3435
readFile,
@@ -49,5 +50,6 @@ export default {
4950
readlink,
5051
utimes,
5152
truncate,
52-
rmdir
53+
rmdir,
54+
mkdtemp
5355
};

web/vite-node-stubs/fs-stub.js

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,8 @@ export const accessSync = notInBrowser("accessSync");
1818
export const writeFileSync = notInBrowser("writeFileSync");
1919
export const openSync = notInBrowser("openSync");
2020
export const writeSync = notInBrowser("writeSync");
21+
export const readSync = notInBrowser("readSync");
22+
export const closeSync = notInBrowser("closeSync");
2123
export const createReadStream = notInBrowser("createReadStream");
2224
export const createWriteStream = notInBrowser("createWriteStream");
2325
export const cpSync = notInBrowser("cpSync");
@@ -58,6 +60,8 @@ export default {
5860
writeFileSync,
5961
openSync,
6062
writeSync,
63+
readSync,
64+
closeSync,
6165
createReadStream,
6266
createWriteStream,
6367
cpSync,

0 commit comments

Comments
 (0)