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

# TypeScript SDK

> Use the run.cloud API from Node.js, CI, and agent runtimes.

`@run-cloud/sdk` is the API-key client for iOS simulator sessions, Android
emulator sessions, microVM sandboxes, snapshots, account state, and reusable
app assets. It requires Node.js 20 or newer.

See the [latest SDK reference](/sdk/latest) for the complete class, method,
option, and response-type index.

## Install

```bash theme={null}
npm install @run-cloud/sdk
```

## Authenticate

Create an API key in the [run.cloud dashboard](/dashboard), then expose it to
the process that runs your application:

```bash theme={null}
export RUN_CLOUD_API_KEY="rc_live_..."
```

The client reads `RUN_CLOUD_API_KEY` automatically. You can also pass the key
directly when your application loads secrets another way:

```ts theme={null}
import { writeFile } from "node:fs/promises";
import { Client } from "@run-cloud/sdk";

const cloud = new Client({ apiKey: process.env.MY_RUN_CLOUD_KEY });
```

Set `RUN_CLOUD_API_URL` or pass `apiUrl` to use a non-default API host. Do not
put API keys in source code, browser bundles, logs, or committed environment
files.

## Run the complete example

The runnable example checks account access, creates iOS and Android sessions,
opens a URL on each platform, and releases both sessions even when the run is
interrupted or fails:

```bash theme={null}
git clone --depth 1 https://github.com/newly-app/run-cloud-examples.git
cd run-cloud-examples/sdk-ios-android
npm install
npm run demo -- --platform both --open
```

See
[newly-app/run-cloud-examples/sdk-ios-android](https://github.com/newly-app/run-cloud-examples/tree/main/sdk-ios-android)
for platform, codec, duration, and JSON-output options.

## Create and release sessions

Use the platform client when the platform is known. Always release metered
sessions in `finally` so a failed test does not leave them running:

```ts theme={null}
import { Client } from "@run-cloud/sdk";

const cloud = new Client();
const session = await cloud.ios.create({
  displayName: "iOS smoke",
  labels: { suite: "onboarding" },
  inactivityTimeout: "60s",
  hardTimeout: "10m",
});

try {
  await cloud.ios.openUrl(session.id, "https://run.cloud");
  await new Promise((resolve) => setTimeout(resolve, 3000));
  const screenshot = await cloud.ios.screenshot(session.id);
  await writeFile("run-cloud.png", screenshot);
  console.log(`Captured run-cloud.png (${screenshot.byteLength} bytes)`);
} finally {
  await cloud.ios.delete(session.id);
}
```

`cloud.ios` and `cloud.android` both provide:

| Method             | Purpose                                                              |
| ------------------ | -------------------------------------------------------------------- |
| `create(options)`  | Create a metered simulator or emulator session.                      |
| `list({ all })`    | List active sessions, or include released sessions with `all: true`. |
| `get(id)`          | Read the latest session state.                                       |
| `openUrl(id, url)` | Open an HTTP URL or app deep link.                                   |
| `delete(id)`       | Release the session and stop future metering.                        |

The iOS client also provides:

* `screenshot(id)`, which returns PNG bytes as a `Uint8Array`.
* `uploadVideo(id, video, options)`, which accepts an MP4 or QuickTime `Blob`
  and imports it into Photos. The uploaded file remains in `cloud.assets` for
  reuse or deletion.
* `uploadMicrophoneAudio(id, audio, options)`, which accepts AAC, M4A, MP3,
  MP4-audio, or WAV and loops it through the foreground app's microphone input.
  Pass `bundleId` when the intended app is not currently in front.

These methods are not currently available on `cloud.android`.

```ts theme={null}
import { readFile } from "node:fs/promises";

const video = new Blob([await readFile("./proof.mp4")], { type: "video/mp4" });
const imported = await cloud.ios.uploadVideo(session.id, video, {
  filename: "proof.mp4",
});
console.log(`Imported ${imported.filename} (${imported.byteSize} bytes)`);
```

```ts theme={null}
const audio = new Blob([await readFile("./spoken.wav")], { type: "audio/wav" });
const injected = await cloud.ios.uploadMicrophoneAudio(session.id, audio, {
  filename: "spoken.wav",
  bundleId: "com.example.AudioRecorder",
});
console.log(`Injecting ${injected.filename} into ${injected.bundleId}`);
```

## Use the generic simulator client

Use `cloud.simulators` when the platform is selected at runtime. Pass the
session platform back to methods that operate on an existing session:

```ts theme={null}
const session = await cloud.simulators.create({
  platform: "android",
  displayName: "Android smoke",
  codec: "auto",
});

try {
  await cloud.simulators.openUrl(session.id, "myapp://settings", {
    platform: session.platform,
  });
} finally {
  await cloud.simulators.delete(session.id, {
    platform: session.platform,
  });
}
```

`cloud.simulators.list()` returns every platform unless `platform` is supplied. Other generic
simulator lifecycle methods default to iOS when `platform` is omitted.

## Check account state

Use `account()` before starting a larger test matrix when you want to surface
access or organization information early:

```ts theme={null}
const account = await cloud.account();
console.log(account.orgs);
```

## Upload and reuse assets

Upload an artifact once, then reference its id from one or more sessions:

```ts theme={null}
import { readFile } from "node:fs/promises";

const archive = await readFile("./MyApp.tar.gz");
const asset = await cloud.assets.upload(new Blob([new Uint8Array(archive)]), {
  name: "ios-smoke",
  filename: "MyApp.tar.gz",
});

const session = await cloud.ios.create({ installAssets: [asset.id] });
```

`cloud.assets` provides `upload`, `list`, and `delete`. Artifact contents must
match the target platform: iOS needs a simulator-compatible build, while
Android needs an Android-compatible artifact such as an APK.

## Handle API errors

Non-successful responses throw `RunCloudError` with the HTTP status and the API
detail:

```ts theme={null}
import { Client, RunCloudError } from "@run-cloud/sdk";

try {
  await new Client().ios.create();
} catch (error) {
  if (error instanceof RunCloudError) {
    console.error(error.status, error.detail);
  }
  throw error;
}
```
