Skip to content

Commit 1a2d787

Browse files
committed
feat: update all doc examples to use ESM instead of CJS
Convert sandbox code in permissions, module-loading, filesystem, virtual-filesystem, child-processes, plugin-systems, ai-agent-code-exec, dev-servers, and node runtime docs from require/module.exports to import/export with .mjs filePath.
1 parent e160a13 commit 1a2d787

10 files changed

Lines changed: 65 additions & 71 deletions

File tree

README.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -64,9 +64,9 @@ const { text } = await generateText({
6464
stopWhen: stepCountIs(5),
6565
tools: {
6666
execute: tool({
67-
description: "Run JavaScript in a secure sandbox. Assign the result to module.exports to return data.",
67+
description: "Run JavaScript in a secure sandbox. Use export to return data.",
6868
inputSchema: z.object({ code: z.string() }),
69-
execute: async ({ code }) => runtime.run(code),
69+
execute: async ({ code }) => runtime.run(code, "/entry.mjs"),
7070
}),
7171
},
7272
});

docs/features/child-processes.mdx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,7 @@ const runtime = new NodeRuntime({
6868

6969
try {
7070
const result = await runtime.exec(`
71-
const { spawnSync } = require("node:child_process");
71+
import { spawnSync } from "node:child_process";
7272
7373
const child = spawnSync("node", ["--version"], {
7474
encoding: "utf8",
@@ -81,7 +81,7 @@ try {
8181
if (child.status !== 0 || !output.startsWith("v")) {
8282
throw new Error("Unexpected child process exit code: " + child.status);
8383
}
84-
`);
84+
`, { filePath: "/entry.mjs" });
8585

8686
if (result.code !== 0) {
8787
throw new Error(`Unexpected execution result: ${JSON.stringify(result)}`);

docs/features/filesystem.mdx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -32,10 +32,10 @@ const runtime = new NodeRuntime({
3232

3333
try {
3434
const result = await runtime.exec(`
35-
const fs = require("node:fs");
35+
import fs from "node:fs";
3636
fs.mkdirSync("/workspace", { recursive: true });
3737
fs.writeFileSync("/workspace/hello.txt", "hello from the sandbox");
38-
`);
38+
`, { filePath: "/entry.mjs" });
3939

4040
if (result.code !== 0) {
4141
throw new Error(`Unexpected execution result: ${JSON.stringify(result)}`);

docs/features/module-loading.mdx

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ icon: "cubes"
99
Runnable example for module resolution and loading.
1010
</Card>
1111

12-
Sandboxed code can `require()` and `import` modules through secure-exec's module resolution system.
12+
Sandboxed code can `import` and `require()` modules through secure-exec's module resolution system.
1313

1414
## Runnable example
1515

@@ -36,10 +36,10 @@ const runtime = new NodeRuntime({
3636
try {
3737
const result = await runtime.run<{ version: string }>(
3838
`
39-
const typescript = require("/root/node_modules/typescript/lib/typescript.js");
40-
module.exports = { version: typescript.version };
39+
import typescript from "/root/node_modules/typescript/lib/typescript.js";
40+
export const version = typescript.version;
4141
`,
42-
"/app/example.js",
42+
"/app/example.mjs",
4343
);
4444

4545
if (result.code !== 0 || typeof result.exports?.version !== "string") {
@@ -66,7 +66,7 @@ Node runtime executions expose a read-only dependency overlay at `/app/node_modu
6666

6767
```ts
6868
// Inside the sandbox, this resolves from the host's node_modules
69-
const lodash = require("lodash");
69+
import lodash from "lodash";
7070
```
7171

7272
Key constraints:

docs/features/permissions.mdx

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ const result = await runtime.run<{
3737
blocked: boolean;
3838
}>(
3939
`
40-
const fs = require("node:fs");
40+
import fs from "node:fs";
4141
4242
fs.mkdirSync("/workspace", { recursive: true });
4343
fs.writeFileSync("/workspace/message.txt", "hello from permissions");
@@ -49,11 +49,10 @@ const result = await runtime.run<{
4949
blocked = error && error.code === "EACCES";
5050
}
5151
52-
module.exports = {
53-
message: fs.readFileSync("/workspace/message.txt", "utf8"),
54-
blocked,
55-
};
52+
export const message = fs.readFileSync("/workspace/message.txt", "utf8");
53+
export { blocked };
5654
`,
55+
"/entry.mjs",
5756
);
5857

5958
console.log(

docs/features/virtual-filesystem.mdx

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -148,8 +148,9 @@ class ReadOnlyMapFS implements VirtualFileSystem {
148148
```ts
149149
const fs = new ReadOnlyMapFS({
150150
"/config.json": JSON.stringify({ greeting: "hello" }),
151-
"/src/index.js": `
152-
const config = JSON.parse(require("fs").readFileSync("/config.json", "utf8"));
151+
"/src/index.mjs": `
152+
import { readFileSync } from "node:fs";
153+
const config = JSON.parse(readFileSync("/config.json", "utf8"));
153154
console.log(config.greeting);
154155
`,
155156
});
@@ -163,9 +164,10 @@ const runtime = new NodeRuntime({
163164
});
164165

165166
const result = await runtime.exec(`
166-
const config = JSON.parse(require("fs").readFileSync("/config.json", "utf8"));
167+
import { readFileSync } from "node:fs";
168+
const config = JSON.parse(readFileSync("/config.json", "utf8"));
167169
console.log(config.greeting);
168-
`);
170+
`, { filePath: "/entry.mjs" });
169171

170172
// Output captured via onStdio callback — see Output Capture docs
171173
runtime.dispose();

docs/runtimes/node.mdx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -246,8 +246,8 @@ const runtime = new NodeRuntime({
246246
});
247247

248248
const execution = await runtime.run<{ answer: number }>(
249-
"module.exports = require('./dist/index.js');",
250-
"/root/entry.js",
249+
"export { default as answer } from './dist/index.js';",
250+
"/root/entry.mjs",
251251
);
252252

253253
console.log(execution.exports); // { answer: 42 }

docs/use-cases/ai-agent-code-exec.mdx

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ Give your agent a code-execution tool with explicit CPU and memory limits. The a
1212

1313
## Run generated JavaScript
1414

15-
The agent writes JavaScript, assigns a return value to `module.exports`, and gets it back.
15+
The agent writes JavaScript, uses `export` to return values, and the host gets them back.
1616

1717
```ts JavaScript Execution
1818
import { generateText, stepCountIs, tool } from "ai";
@@ -38,9 +38,9 @@ const { text } = await generateText({
3838
stopWhen: stepCountIs(5),
3939
tools: {
4040
execute: tool({
41-
description: "Run JavaScript in a secure sandbox. Assign the result to module.exports to return data.",
41+
description: "Run JavaScript in a secure sandbox. Use export to return data.",
4242
inputSchema: z.object({ code: z.string() }),
43-
execute: async ({ code }) => runtime.run(code),
43+
execute: async ({ code }) => runtime.run(code, "/entry.mjs"),
4444
}),
4545
},
4646
});
@@ -87,7 +87,7 @@ const ts = createTypeScriptTools({
8787
const { text } = await generateText({
8888
model: anthropic("claude-sonnet-4-6"),
8989
prompt:
90-
"Write TypeScript that calculates the first 20 fibonacci numbers. Assign the result to module.exports.",
90+
"Write TypeScript that calculates the first 20 fibonacci numbers. Use export to return the result.",
9191
stopWhen: stepCountIs(5),
9292
tools: {
9393
execute_typescript: tool({
@@ -99,7 +99,7 @@ const { text } = await generateText({
9999
sourceText: code,
100100
filePath: "/root/generated.ts",
101101
compilerOptions: {
102-
module: "commonjs",
102+
module: "esnext",
103103
target: "es2022",
104104
},
105105
});
@@ -116,7 +116,7 @@ const { text } = await generateText({
116116
sourceText: code,
117117
filePath: "/root/generated.ts",
118118
compilerOptions: {
119-
module: "commonjs",
119+
module: "esnext",
120120
target: "es2022",
121121
},
122122
});
@@ -131,7 +131,7 @@ const { text } = await generateText({
131131

132132
const execution = await runtime.run<Record<string, unknown>>(
133133
compiled.outputText,
134-
"/root/generated.js"
134+
"/root/generated.mjs"
135135
);
136136

137137
if (execution.code !== 0) {

docs/use-cases/dev-servers.mdx

Lines changed: 14 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -38,27 +38,23 @@ const runtime = new NodeRuntime({
3838
});
3939

4040
const execPromise = runtime.exec(`
41-
(async () => {
42-
const { Hono } = require("hono");
43-
const { serve } = require("@hono/node-server");
44-
45-
const app = new Hono();
46-
app.get("/", (c) => c.text("hello from sandboxed hono"));
47-
app.get("/health", (c) => c.json({ ok: true }));
48-
49-
serve({
50-
fetch: app.fetch,
51-
port: ${port},
52-
hostname: "${host}",
53-
});
41+
import { Hono } from "hono";
42+
import { serve } from "@hono/node-server";
43+
44+
const app = new Hono();
45+
app.get("/", (c) => c.text("hello from sandboxed hono"));
46+
app.get("/health", (c) => c.json({ ok: true }));
5447
55-
console.log("server:listening:${port}");
56-
await new Promise(() => {});
57-
})().catch((error) => {
58-
console.error(error);
59-
process.exitCode = 1;
48+
serve({
49+
fetch: app.fetch,
50+
port: ${port},
51+
hostname: "${host}",
6052
});
53+
54+
console.log("server:listening:${port}");
55+
await new Promise(() => {});
6156
`, {
57+
filePath: "/app/server.mjs",
6258
onStdio: (event) => logs.push(`[${event.channel}] ${event.message}`),
6359
});
6460

docs/use-cases/plugin-systems.mdx

Lines changed: 21 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -26,22 +26,21 @@ import {
2626
const filesystem = createInMemoryFileSystem();
2727
await filesystem.mkdir("/plugins");
2828
await filesystem.writeFile(
29-
"/plugins/title-case.js",
29+
"/plugins/title-case.mjs",
3030
`
31-
module.exports = {
32-
manifest: {
33-
name: "title-case",
34-
version: "1.0.0",
35-
},
36-
transform(input, options = {}) {
37-
const words = String(input)
38-
.split(/\\s+/)
39-
.filter(Boolean)
40-
.map((word) => word.charAt(0).toUpperCase() + word.slice(1).toLowerCase());
41-
42-
return (options.prefix ?? "") + words.join(" ");
43-
},
31+
export const manifest = {
32+
name: "title-case",
33+
version: "1.0.0",
4434
};
35+
36+
export function transform(input, options = {}) {
37+
const words = String(input)
38+
.split(/\\s+/)
39+
.filter(Boolean)
40+
.map((word) => word.charAt(0).toUpperCase() + word.slice(1).toLowerCase());
41+
42+
return (options.prefix ?? "") + words.join(" ");
43+
}
4544
`
4645
);
4746

@@ -62,16 +61,14 @@ const result = await runtime.run<{
6261
manifest: { name: string; version: string };
6362
output: string;
6463
}>(`
65-
const plugin = require("/plugins/title-case.js");
66-
67-
module.exports = {
68-
manifest: plugin.manifest,
69-
output: plugin.transform(
70-
${JSON.stringify(input)},
71-
${JSON.stringify(options)}
72-
),
73-
};
74-
`, "/root/run-plugin.js");
64+
import { manifest, transform } from "/plugins/title-case.mjs";
65+
66+
export { manifest };
67+
export const output = transform(
68+
${JSON.stringify(input)},
69+
${JSON.stringify(options)}
70+
);
71+
`, "/root/run-plugin.mjs");
7572

7673
console.log(result.exports?.manifest.name); // "title-case"
7774
console.log(result.exports?.output); // "Plugin says: Hello From Plugin Land"

0 commit comments

Comments
 (0)