npm package: @oleanderhq/sdk
Description: TypeScript SDK for oleander: query lake, list and launch Spark jobs
Latest version: 0.5.0

# oleander TypeScript SDK

Use the [oleander](https://oleander.dev) API from TypeScript: run lake queries, list Spark jobs, and launch Spark jobs.

## Install

```bash
npm install @oleanderhq/sdk
yarn add @oleanderhq/sdk
pnpm add @oleanderhq/sdk
```

## Get your API key

Create an API key in [oleander settings](https://oleander.dev/app/settings), or run `oleander configure` if you use the CLI. You can pass the key when creating the client or set the `OLEANDER_API_KEY` environment variable (Node only).

## Quick start

```ts
import { Oleander } from "@oleanderhq/sdk";

const oleander = new Oleander();
const list = await oleander.listSparkJobs();
console.log(list.artifacts);
```

## API

### Query (lake)

Run a SQL query against the oleander lake. The second parameter is optional; `save` defaults to `false`. Use `save: true` to persist results as a table.

```ts
const result = await oleander.query(
  "SELECT * FROM oleander.default.flowers LIMIT 10",
);
console.log(result.results?.columns, result.results?.rows);
console.log(result.row_count, result.execution_time);
if (result.saved_table_name) console.log("Saved to:", result.saved_table_name);
```

### List Spark jobs

List your Spark artifacts. Options: `limit` (default 20), `offset` (default 0).

```ts
const list = await oleander.listSparkJobs();
console.log(list.artifacts, list.hasMore);

const next = await oleander.listSparkJobs({ offset: 20 });
```

### Launch Spark job

Submit a Spark job. Required: `namespace`, `name`, `entrypoint`. `cluster` defaults to `"oleander"`.

```ts
const { runId } = await oleander.submitSparkJob({
  namespace: "my-namespace",
  name: "my-job-name",
  entrypoint: "my_script.py",
});
console.log("Run ID:", runId);
```

### Wait for a run to finish

Submit and poll until the run completes. Optional: `pollIntervalMs` (default 10000), `timeoutMs` (default 600000).

```ts
const { runId, state, run } = await oleander.submitSparkJobAndWait({
  namespace: "my-namespace",
  name: "my-job-name",
  entrypoint: "my_script.py",
});
console.log(runId, state); // COMPLETE | FAIL | ABORT
```

### Get run status

```ts
const run = await oleander.getRun(runId);
console.log(run.state, run.duration);
```

### Typed error handling

The SDK throws structured errors for HTTP failures:

- `OleanderHttpError` for any non-2xx response (`status`, `method`, `path`, `url`, `body`, `apiError`, `apiDetails`)
- `RunNotFoundError` (subclass of `OleanderHttpError`) when `getRun(runId)` returns 404

```ts
import { Oleander, RunNotFoundError, OleanderHttpError } from "@oleanderhq/sdk";

try {
  await oleander.getRun(runId);
} catch (err) {
  if (err instanceof RunNotFoundError) {
    // Eventual-consistency case after submitSparkJob
    console.log("Run is not visible yet:", err.runId);
  } else if (err instanceof OleanderHttpError) {
    console.log(err.status, err.path, err.apiError ?? err.apiDetails);
  } else {
    throw err;
  }
}
```

## Options

- **Constructor**: `new Oleander({ apiKey?, baseUrl? })`. Omit `apiKey` to use `OLEANDER_API_KEY`. Set `baseUrl` to use a different endpoint (e.g. `http://localhost:3000`).
- **Schemas**: The package exports Zod schemas (e.g. `optionsSchema`, `submitOptionsSchema`) if you want to validate config or options yourself.