# Execute & Evaluate

## Evaluate an expression

`evaluate` runs **one expression** and returns its JSON-serializable value.

secure-exec/examples/quickstart/src/index.ts:

```ts
import { evaluate } from "secure-exec";

// Each call runs in a fresh VM that is disposed when the call finishes.
const sum = await evaluate<number>("1 + 2");
console.log(sum.outcome === "succeeded" ? sum.value : sum.error); // 3
```

The expression may be a promise, which is awaited. Returning `undefined`, a
function, a symbol, or a circular value fails instead of silently losing the
value.

Several statements go in a function:

secure-exec/examples/quickstart/src/index.ts:

```ts
// `evaluate` takes one expression, so several statements go in a function.
const report = await evaluate<{ count: number; max: number }>(`
	(() => {
		const values = [3, 9, 4];
		return { count: values.length, max: Math.max(...values) };
	})()
`);
console.log(report.outcome === "succeeded" ? report.value : report.error);
```

## Execute a module

`execute` runs source as an ES module, so `import` and top-level `await` work.
It returns captured output instead of a value.

secure-exec/examples/quickstart/src/module.ts:

```ts
// `execute` runs a whole ES module for its side effects. Capture output to read
// it back.
const run = await execute(
	`
	import { platform } from "node:os";
	console.log("running on", platform());
	`,
	{ output: { capture: "all" } },
);
console.log(run.stdout?.trim()); // running on linux
```

## Run a file

`executeFile` runs a JavaScript file that is already in the VM, by its guest
path. Mount a host directory to run a script in a one-shot call. On a
[VM](/secure-exec/docs/vms), write the file with `vm.filesystem` first.
`secure-exec/typescript` has the same function for TypeScript files.

secure-exec/examples/mounts/src/index.ts:

```ts
// `executeFile` runs a file that is already in the VM. With a mount, that works
// in a one-shot call: the script lives on the host and runs inside the VM.
const report = await executeFile("/mnt/data/report.mjs", {
	mounts: [hostDirMount("/mnt/data", hostData)],
	output: { capture: "all" },
});
console.log(report.stdout?.trim()); // report: hello from the host
```

A file resolves its imports from its own directory, the same as in Node.js, so a
file under `/workspace` finds packages installed there.

## Pass data in

secure-exec/examples/quickstart/src/index.ts:

```ts
// `inputs` hands host values to the code as real objects, so data is never
// interpolated into source.
const total = await evaluate<number>(
	"inputs.prices.reduce((a, b) => a + b, 0)",
	{ inputs: { prices: [5, 10, 27] } },
);
console.log(total.outcome === "succeeded" ? total.value : total.error); // 42
```

## TypeScript

`secure-exec/typescript` has the same `execute`, `evaluate`, and `executeFile`
functions for TypeScript source. They strip types rather than check them, and a
separate `check` type-checks without running anything. That is useful for
validating model-generated code before you execute it.

See [TypeScript](/secure-exec/docs/typescript).

## Results

Both functions resolve to a result with an `outcome`.

| `outcome` | Meaning |
|---|---|
| `succeeded` | The code finished. `evaluate` results carry `value`. |
| `failed` | The code threw or exited non-zero. |
| `timed_out` | `timeoutMs` elapsed. |
| `cancelled` | The `signal` you passed was aborted. |

secure-exec/examples/quickstart/src/index.ts:

```ts
// Guest errors are returned, not thrown. Capture stderr to see the stack.
const failed = await evaluate(`JSON.parse("not json")`, {
	output: { capture: "stderr" },
});
if (failed.outcome !== "succeeded") {
	console.log(failed.outcome, failed.stderr?.split("\n")[0]); // failed SyntaxError: ...
}
```

## Guest failures are returned

Anything the guest code does wrong comes back as a result, never as an
exception, so untrusted code can never crash your process.

secure-exec/examples/quickstart/src/errors.ts:

```ts
// What the guest code does wrong is returned as a result, never thrown.
const failed = await evaluate(`null.length`, { output: { capture: "stderr" } });
console.log(failed.outcome); // failed
if (failed.outcome !== "succeeded") {
	console.log(failed.error.code); // execution_failed
	console.log(failed.stderr?.split("\n")[0]); // TypeError: Cannot read properties of null ...
}
```

| `outcome` | `error.code` | Cause |
|---|---|---|
| `failed` | `execution_failed` | The code threw, or exited non-zero |
| `failed` | `evaluation_serialization_failed` | `evaluate` produced a value that is not JSON |
| `timed_out` | | `timeoutMs` elapsed |
| `cancelled` | | The `signal` you passed was aborted |

The guest's own message and stack trace arrive on `stderr`. Capture it with
`output: { capture: "stderr" }` when you want to show it to a user or a model.

## Host mistakes are thrown

A call rejects only when the host asked for something that cannot run.

secure-exec/examples/quickstart/src/errors.ts:

```ts
// What the host asks for wrong is thrown, as a typed error with a stable code.
const vm = await createVm();
const context = await vm.createContext();
const slow = context.evaluate(
	"new Promise((resolve) => setTimeout(resolve, 500))",
);
try {
	await context.evaluate("1 + 1"); // The context is still busy with `slow`.
} catch (error) {
	if (error instanceof SidecarRejectedError) {
		console.log(error.detail.code); // execution_busy
	}
}
await slow;
await vm.dispose();
```

| Error | When |
|---|---|
| `SidecarRejectedError` | The sidecar refused the request. `error.detail.code` says why |
| `SidecarProcessExited` | The sidecar process died |
| `SidecarSilenceTimeout` | The sidecar stopped responding |
| `KernelError` | A host-side filesystem or process operation failed, with a POSIX-style `code` |
| `TypeError` / validation error | An option is missing or malformed |

Common `detail.code` values on `SidecarRejectedError`:

| Code | Meaning |
|---|---|
| `execution_busy` | The context is already running a call |
| `context_not_found` | The context was disposed, or its VM was |

Errors that hit a limit name the limit and the option that raises it. See
[Resource Limits](/secure-exec/docs/resource-limits).

## Options

| Option | Purpose |
|---|---|
| `inputs` | JSON values the code reads from `inputs` |
| `timeoutMs` | Stop the code after this long. Set it for any code you did not write |
| `signal` | An `AbortSignal` that cancels the call |
| `output`, `onStdout`, `onStderr` | [Capture or stream output](/secure-exec/docs/output-capture) |
| `env`, `cwd`, `args`, `stdin` | The process environment the code sees. The working directory defaults to `/workspace` |
| `filePath` | The path the code reports in stack traces and resolves imports from |

The top-level functions also take [VM options](/secure-exec/docs/permissions),
such as `permissions`, `limits`, and `mounts`, because each call creates its own
VM. To keep anything between calls, create a [VM](/secure-exec/docs/vms) and
call the same methods on `vm.javascript`.
