> ## Documentation Index
> Fetch the complete documentation index at: https://docs.mesa.dev/llms.txt
> Use this file to discover all available pages before exploring further.

# Overview

The Mesa TypeScript SDK is the ergonomic client for Mesa in Node.js and JavaScript runtimes. It wraps the generated `@mesadev/rest` client, resolves the default organization for you, verifies webhooks, and exposes a native virtual filesystem for repo I/O and shell execution.

Node.js 18 or newer is required.

## Installation

```bash theme={null}
npm install @mesadev/sdk
```

## Create a client

```ts theme={null}
import { Mesa } from '@mesadev/sdk';

const mesa = new Mesa({ privateKey: process.env.MESA_PRIVATE_KEY });

const repos = await mesa.repos.list({ limit: 50 });
console.log(`found ${repos.repos.length} repos`);
```

<Tip>
  Set `MESA_PRIVATE_KEY` in a trusted Node.js environment to omit `privateKey` from the constructor.
</Tip>

## Client options

```ts theme={null}
import { Mesa } from '@mesadev/sdk';

const mesa = new Mesa({
  privateKey: 'mesa_private_key_acme_...',
  apiUrl: 'https://api.mesa.dev/v1',
  fetch: globalThis.fetch,
  userAgent: 'my-app/1.0.0',
  webhookSecret: 'whsec_...',
});
```

<ParamField path="privateKey" type="string | undefined">
  Ed25519 private key. In Node.js, the SDK reads `MESA_PRIVATE_KEY` when no explicit credential is supplied.
</ParamField>

<ParamField path="auth" type="{ privateKey: string } | { accessToken: string } | undefined">
  A credential group holding either a private key or an existing access token. A client built from an access token forwards that token unchanged and cannot mint another one.
</ParamField>

<ParamField path="apiUrl" type="string">
  REST API base URL. Defaults to `https://api.mesa.dev/v1`. `http` and `https` are accepted. Trailing slashes are stripped.
</ParamField>

<ParamField path="fetch" type="typeof globalThis.fetch | undefined">
  Custom fetch implementation for REST requests.
</ParamField>

<ParamField path="userAgent" type="string | undefined">
  Appended to the SDK user agent. Node.js uses `User-Agent`; browser-like runtimes use `X-Mesa-User-Agent`.
</ParamField>

<ParamField path="webhookSecret" type="string | undefined">
  Signing secret used by `mesa.webhooks.receive(...)`.
</ParamField>

## Lifecycle

The TypeScript client does not hold an HTTP session and does not need to be closed. Reuse one `Mesa` instance where practical.

Private-key and API-key mounts sign one short-lived, layout-scoped access token locally and use it for the mount's whole lifetime, while a client built from an access token forwards that token unchanged. Private-key definitions default to a 15 minute `ttl` and can run up to 4 hours; API-key definitions default to 1 hour and can run up to 24 hours. Set `ttl` on the definition: `mesa.fs({ layout, ttl, authors }).mount()`.

## Organization resolution

Private-key and access-token clients read the organization from the credential. Resource methods always use that organization and do not accept an `org` value.

```ts theme={null}
console.log(mesa.org.slug);
await mesa.repos.list();
```

Use `mesa.org.get()` when you need organization metadata from the API.

## Resource namespaces

| Namespace             | Purpose                                                                                                                                                  |
| --------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `mesa.repos`          | Create, read, update, delete, sync upstreams, and read upstream sync history on repositories.                                                            |
| `mesa.content`        | Read files, symlinks, and directory listings without mounting.                                                                                           |
| `mesa.changes`        | Create, patch, and inspect Mesa changes.                                                                                                                 |
| `mesa.diffs`          | Inspect diffs and conflicts between changes.                                                                                                             |
| `mesa.bookmarks`      | Manage branch-like bookmark refs.                                                                                                                        |
| `mesa.apiKeys`        | Create, list, and revoke Mesa API keys (deprecated).                                                                                                     |
| `mesa.tokens`         | Sign short-lived, scoped access tokens locally from a private key or compatible API key.                                                                 |
| `mesa.webhookTargets` | Manage outbound webhook targets.                                                                                                                         |
| `mesa.webhooks`       | Verify incoming webhook requests and dispatch typed handlers.                                                                                            |
| `mesa.fs`             | Define a layout and mount it as a virtual filesystem, or mint its scoped token. Call `mesa.fs({ layout, authors?, ttl? })` then `.mount()` / `.token()`. |
| `mesa.org`            | Read the credential's organization slug with `mesa.org.slug`, or fetch organization metadata with `mesa.org.get()`.                                      |

Bulk repository tag updates are available through `mesa.raw`.

## Response objects

High-level SDK methods return response data directly. They do not return generated HTTP wrapper objects.

```ts theme={null}
const repos = await mesa.repos.list();
for (const repo of repos.repos) {
  console.log(repo.name, repo.head_change_id);
}
```

Generated response aliases such as `GetRepoResponse` live in `@mesadev/rest`.

## Common types

Import SDK-owned types from `@mesadev/sdk`.

```ts theme={null}
import type { FsLayoutDefinition, FsMountRuntimeOptions, MesaOptions, WebhookEvent } from '@mesadev/sdk';
import { repo } from '@mesadev/sdk';
```

| Type                    | Purpose                                                                                                     |
| ----------------------- | ----------------------------------------------------------------------------------------------------------- |
| `MesaOptions`           | Constructor options for `new Mesa(...)`.                                                                    |
| `FsMountRuntimeOptions` | Runtime options for `definition.mount(...)` (`cache`, `telemetry`).                                         |
| `FsLayoutDefinition`    | Layout bundled with its `layout()`, `mount()`, and `token()` operations, returned by `mesa.fs({ layout })`. |
| `LayoutSpec` / `Layout` | Raw path map passed to `mesa.fs(...)`, and the prepared layout the definition exposes.                      |
| `Repo` / `RepoOptions`  | One layout repository declaration, produced by `repo(...)`.                                                 |
| `MesaFileSystem`        | Native filesystem implementation returned by `mesa.fs({ layout }).mount()`.                                 |
| `ChangeInfo`            | Change metadata returned by mounted filesystem change operations.                                           |
| `ExecResult`            | Output from `fs.bash().exec(...)`, re-exported from `just-bash`.                                            |
| `WebhookEvent`          | Discriminated union of webhook event payloads.                                                              |

High-level REST method input types are inferred from the method signatures. If you need named REST schema types, import them from `@mesadev/rest`.

## Error model

SDK-owned setup and webhook errors extend `MesaError` and expose a stable `code` field.

| Exception                      | Code                          | Meaning                                                                            |
| ------------------------------ | ----------------------------- | ---------------------------------------------------------------------------------- |
| `MissingCredentialError`       | `MISSING_CREDENTIAL`          | No credential was provided or available in the environment.                        |
| `InvalidApiUrlError`           | `INVALID_API_URL`             | `apiUrl` is malformed or uses a protocol other than `http` or `https`.             |
| `InvalidOptionsError`          | `INVALID_OPTIONS`             | Local options are invalid, such as an empty layout or missing private-key authors. |
| `OrgResolutionError`           | `ORG_RESOLUTION_FAILED`       | The SDK could not resolve the default organization through `/whoami`.              |
| `MissingWebhookSecretError`    | `MISSING_WEBHOOK_SECRET`      | `mesa.webhooks.receive(...)` was called without a constructor `webhookSecret`.     |
| `MesaWebhookVerificationError` | `WEBHOOK_VERIFICATION_FAILED` | Webhook signature, timestamp, JSON parsing, or payload validation failed.          |

API operations throw Mesa API error payloads directly when the server returns an error response. These payloads are not `MesaError` instances.

## Raw generated client

`mesa.raw` exposes generated REST operations with authentication, base URL, fetch, and user-agent already wired in. Use it when the high-level SDK does not expose an operation or option yet.

```ts theme={null}
const repo = await mesa.raw.getRepo({
  path: { org: 'acme', repo: 'app' },
});
```

Raw calls use the generated REST request shape (`path`, `query`, `body`) and return response data directly.

## Complete example

```ts theme={null}
import { Buffer } from 'node:buffer';
import { Mesa, repo } from '@mesadev/sdk';

const mesa = new Mesa({ privateKey: process.env.MESA_PRIVATE_KEY });

const created = await mesa.repos.create({ name: 'demo' });

const change = await mesa.changes.create({
  repo: created.name,
  base_change_id: created.head_change_id,
  message: 'Add README',
  authors: [{ name: 'Docs Bot', email: 'docs@example.com' }],
  files: [
    {
      path: 'README.md',
      content: Buffer.from('# Demo\n').toString('base64'),
    },
  ],
});

await mesa.bookmarks.move({
  repo: created.name,
  bookmark: created.default_bookmark,
  change_id: change.id,
});

const fs = await mesa
  .fs({
    layout: { '/workspace': repo(created.name, { mode: 'rw' }) },
    authors: [{ name: 'Docs Bot', email: 'docs@example.com' }],
  })
  .mount();
const data = await fs.readFileBuffer('/workspace/README.md');
console.log(Buffer.from(data).toString('utf8'));
```
