Skip to main content
Node.js

TypeScript

Compile, type-check, execute, and evaluate TypeScript inside an AgentOS VM.

TypeScript is built into @rivet-dev/agentos/javascript; it is not a separate public package or subpath. The compiler and submitted source both execute inside the runtime’s isolated VM.

/**
 * TypeScript example.
 *
 * `@rivet-dev/agentos/javascript` runs the TypeScript compiler INSIDE the VM.
 * The compiler is projected into the VM and every compile/type-check happens
 * in the guest, so untrusted TypeScript never executes (or compiles) on the
 * host. Here we compile a typed snippet to JavaScript, run the emitted code in
 * the VM, and type-check a snippet that has a type error.
 */
import { JavaScriptRuntime } from "@rivet-dev/agentos/javascript";

// A typed snippet we want to compile and run inside the VM.
const typeScriptSource = `
interface Greeting {
  name: string;
  count: number;
}

const greeting: Greeting = { name: "agentos", count: 3 };
const lines: string[] = Array.from(
  { length: greeting.count },
  (_unused, index) => \`hello \${greeting.name} #\${index + 1}\`,
);

for (const line of lines) {
  console.log(line);
}
`;

// Step 1: compile TypeScript to JavaScript inside the VM.
const rt = await JavaScriptRuntime.create();
try {
	const compiled = await rt.typescript.compile(typeScriptSource, {
		compilerOptions: { module: "ESNext", target: "ES2022" },
	});

	if (!compiled.success) {
		const messages = compiled.diagnostics.map((d) => d.message);
		throw new Error(`TypeScript compile failed:\n${messages.join("\n")}`);
	}

	console.log("Compiled TypeScript to JavaScript inside the VM.");

	// Step 2: run the emitted JavaScript inside the VM.
	const result = await rt.execute(compiled.outputText ?? "");
	console.log("exitCode:", result.exitCode);
	console.log("guest stdout:\n" + result.stdout.trimEnd());

	// Step 3: type-check a snippet that has a type error inside the VM.
	const typeCheck = await rt.typescript.check(
		`const total: number = "not a number";`,
	);

	console.log("type check success:", typeCheck.success);
	for (const diagnostic of typeCheck.diagnostics) {
		console.log(
			`  ${diagnostic.category} TS${diagnostic.code} (line ${diagnostic.line}): ${diagnostic.message}`,
		);
	}

	if (typeCheck.success) {
		throw new Error("Expected the ill-typed snippet to fail type checking.");
	}

	console.log("OK: TypeScript compiled and type-checked inside the VM.");
} finally {
	await rt.dispose();
}

Execute or evaluate directly

The checked example above covers explicit compilation and diagnostics. For the convenience execution and evaluation methods, see the focused API example:

import { JavaScriptRuntime } from "@rivet-dev/agentos/javascript";

const javascript = await JavaScriptRuntime.create({
	cwd: "/workspace",
	env: { GREETING: "hello from the VM" },
});

try {
	const execution = await javascript.execute(`
		console.log(process.env.GREETING);
		console.error("stderr is captured separately");
	`);
	console.log(execution);

	const evaluation = await javascript.evaluate<{ sum: number; cwd: string }>(
		`({ sum: 2 + 40, cwd: process.cwd() })`,
	);
	console.log(evaluation);

	const typed = await javascript.typescript.evaluate<number>(
		`Promise.resolve(21 * 2 satisfies number)`,
	);
	console.log(typed);
} finally {
	await javascript.dispose();
}

Both methods return the same result shapes as their JavaScript counterparts. Compilation failures have success: false and formatted diagnostics in stderr; use check() or compile() when you need structured diagnostics.

Projects

Seed or mount a project into the VM, then call checkProject({ cwd, tsconfigPath }) or compileProject({ cwd, tsconfigPath }) on the same tools.

See Executing Code for the shared result and execution options.