---
title: TypeScript
description: The TypeScript SDK.
---

[`@subako-ai/function-sdk`](https://www.npmjs.com/package/@subako-ai/function-sdk) runs TypeScript and JavaScript as a function package. Each `tool` becomes a function an agent can call.

Every JavaScript package shares one prebuilt runtime module. `build` bundles your code and compiles it to bytecode the runtime loads from the package's assets, so there is no WebAssembly toolchain to install: Node 20 or newer is all it needs.

## Start a package

```bash
git clone https://github.com/subako-ai/subako-function-template-typescript orders
```

Rename `my-function` in `package.json` and `subako-package.json`, and describe the package there. Or set up a project of your own:

```bash
npm install @subako-ai/function-sdk zod
```

```json tsconfig.json
{
  "compilerOptions": {
    "lib": ["ES2023"],
    "types": ["@subako-ai/function-sdk/env"],
    "strict": true
  }
}
```

The `env` types declare exactly the globals the runtime provides, so a DOM or Node API is a type error rather than a crash.

## Tools

```ts src/index.ts
import { serve, tool } from "@subako-ai/function-sdk";
import { z } from "zod";

const lookup = tool({
  name: "lookup",
  description: "Look an order up by its number.",
  input: z.object({ order: z.number().int().describe("the order's number, such as 1042") }),
  output: z.object({ status: z.string(), total_cents: z.number() }),
  run: async ({ order }) => {
    const response = await fetch(`https://api.acme.example/orders/${order}`);
    if (!response.ok) throw new Error(`the orders API answered ${response.status}`);
    return await response.json();
  },
});

serve([lookup]);
```

- `input` and `output` take any [Standard Schema](https://standardschema.dev) that also emits JSON Schema — zod 4, valibot, arktype — or a plain JSON Schema object, which describes but does not validate. The input must be an object.
- Input is validated before `run`; output is checked against `output` when it validates.
- A thrown error is a failed call the model reads. A returned object is sent as JSON; a string as text.
- `serve` takes every tool, once, from the entry point.

Prefer the official MCP TypeScript SDK? `serveMcp` from `@subako-ai/function-sdk/mcp` serves an `McpServer` instead.

## Files

```ts
import { fs } from "@subako-ai/function-sdk";

const csv = fs.readText("/volume/tmp/export.csv");
fs.mkdir("/volume/data/reports");
fs.writeText("/volume/data/reports/q3.md", summary);
```

`fs` also offers `readBytes`, `writeBytes`, `appendText`, `remove`, `stat`, `exists`, and `list`.

## HTTP

`fetch` goes through Subako, under the grant's network and credentials. It carries text bodies; for a volume file as the body, or a response saved to the volume, use `http.request`:

```ts
import { http } from "@subako-ai/function-sdk";

const saved = await http.request({
  url: "https://api.acme.example/exports/q3",
  saveTo: "/volume/tmp/q3.csv",
});
// saved.file: { path: "/volume/tmp/q3.csv", bytes: 48211 }
```

A failure rejects with an `HttpError` carrying a `kind` and a `message`.

## Images

```ts
import { answer } from "@subako-ai/function-sdk";

return answer({ path }).withImageFile(path);
```

## The runtime

The runtime is not Node and not a browser. Alongside the language itself it provides `console` (to stderr), timers, `TextEncoder` and `TextDecoder`, `crypto.getRandomValues` and `randomUUID`, `URL`, `Headers`, `Response`, `AbortController`, and `fetch` — and nothing else. Packages from npm that need only these bundle and run; ones that reach for Node's modules do not.

## Build

```bash
npx @subako-ai/function-sdk build   # writes dist/: module.wasm, subako-package.json, assets/
npx @subako-ai/function-sdk pack    # packs dist/ into <name>.tar.gz
```

`build` needs `subako-package.json` in the current directory, and takes the entry from `src/index.ts` unless you name another. Upload the `.tar.gz` in the console, or the `dist/` directory with `subako function create dist`.
