Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 21 additions & 5 deletions config/navigation.json
Original file line number Diff line number Diff line change
Expand Up @@ -431,6 +431,27 @@
}
]
},
{
"item": "API Reference",
"icon": "code",
"openapi": "https://app.kosli.com/api/v2/openapi.json"
},
{
"item": "SDKs",
"icon": "puzzle-piece",
"groups": [
{
"group": "TypeScript",
"icon": "js",
"pages": [
"typescript-sdk/index",
"typescript-sdk/retries-and-timeouts",
"typescript-sdk/pagination",
"typescript-sdk/error-handling"
]
}
]
},
{
"item": "Template Reference",
"icon": "file-code",
Expand All @@ -457,11 +478,6 @@
}
]
},
{
"item": "API Reference",
"icon": "code",
"openapi": "https://app.kosli.com/api/v2/openapi.json"
},
{
"item": "Helm Reference",
"icon": "layer-group",
Expand Down
101 changes: 101 additions & 0 deletions typescript-sdk/error-handling.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
---
title: Error handling
description: How to catch and inspect errors thrown by the Kosli TypeScript SDK.
---

All HTTP errors from the SDK are instances of `KosliError` or one of its subclasses. Network-level failures throw one of the client error classes listed below.

## KosliError

`KosliError` is the base class for any non-2xx HTTP response. It exposes:

| Property | Type | Description |
|----------|------|-------------|
| `message` | `string` | Error message |
| `statusCode` | `number` | HTTP status code (e.g. `404`, `403`) |
| `headers` | `Headers` | Response headers |
| `body` | `string` | Raw response body (may be empty) |
| `rawResponse` | `Response` | The full HTTP response object |
| `data$` | varies | Structured error data for specific error types (see below) |

## HTTP error classes

These named subclasses cover the most common API errors:

| Class | Status | Description |
|-------|--------|-------------|
| `BadRequestError` | `400` | Invalid request |
| `UnauthorizedError` | `401` | Permission denied or not authenticated |
| `NotFoundError` | `404` | Resource not found |
| `RateLimitedError` | `429` | Rate limit exceeded |

```typescript
import { Kosli } from "@kosli/sdk";
import * as errors from "@kosli/sdk/models/errors";

const kosli = new Kosli({
httpBearer: process.env["KOSLI_API_KEY"] ?? "",
});

try {
const trail = await kosli.trails.get({}, {
org: "my-org",
flowName: "my-flow",
trailName: "my-trail",
});
} catch (error) {
if (error instanceof errors.NotFoundError) {
console.error("Trail not found");
} else if (error instanceof errors.UnauthorizedError) {
console.error("Access denied:", error.data$.message);
} else if (error instanceof errors.RateLimitedError) {
console.error("Rate limit hit - back off and retry");
} else if (error instanceof errors.KosliError) {
console.error(`HTTP ${error.statusCode}: ${error.message}`);
}
}
```

## Network errors

These errors are thrown when the request cannot be completed at the transport level:

| Class | Description |
|-------|-------------|
| `ConnectionError` | The HTTP client could not reach the server |
| `RequestTimeoutError` | The request was aborted by an `AbortSignal` timeout |
| `RequestAbortedError` | The request was cancelled by the caller |
| `InvalidRequestError` | The request could not be constructed (invalid input) |
| `UnexpectedClientError` | An unrecognised error occurred in the HTTP client |

Network errors do not have a `statusCode` - handle them separately from `KosliError`:

```typescript
import * as errors from "@kosli/sdk/models/errors";

try {
const result = await kosli.trails.list({}, { org: "my-org", flowName: "my-flow" });
} catch (error) {
if (error instanceof errors.ConnectionError) {
console.error("Could not connect to Kosli - check your network");
} else if (error instanceof errors.RequestTimeoutError) {
console.error("Request timed out");
} else if (error instanceof errors.KosliError) {
console.error(`API error ${error.statusCode}: ${error.message}`);
} else {
throw error;
}
}
```

## Other errors

A small number of operations can throw additional error types for specific conditions:

| Class | Status | Description |
|-------|--------|-------------|
| `ConflictResponseModelError` | `409` | Conflict (e.g. resource already exists) |
| `RequestEntityTooLargeResponseModelError` | `413` | Request body too large |
| `ResponseValidationError` | - | Response from server did not match the expected schema; inspect `error.rawValue` or call `error.pretty()` |

Check the method's documentation to see which errors apply to a specific operation.
Comment on lines +93 to +101

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Improvement: These additional error types aren't shown in the import * as errors from "@kosli/sdk/models/errors" examples above. A brief note confirming they come from the same import path would save readers from guessing.

178 changes: 178 additions & 0 deletions typescript-sdk/index.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,178 @@
---
title: Overview
description: Use the Kosli TypeScript SDK to interact with the Kosli API from Node.js, Bun, Deno, and browser environments.
---

<Warning>
**Early access.** The TypeScript SDK is an unsupported work in progress and may change or be removed without notice. It is provided for evaluation only - do not use it in production.
</Warning>

The `@kosli/sdk` package provides a type-safe TypeScript client for the Kosli API. It supports Node.js, Bun, Deno, and all modern browsers.

## Installation

Install using your preferred package manager:

<CodeGroup>
```bash npm
npm add @kosli/sdk
```

```bash pnpm
pnpm add @kosli/sdk
```

```bash bun
bun add @kosli/sdk
```

```bash yarn
yarn add @kosli/sdk
```
</CodeGroup>

<Note>
The package is published as an ES Module (ESM) only. CommonJS projects must use dynamic import:

```typescript
const { Kosli } = await import("@kosli/sdk");
```
</Note>

## Quick start

```typescript
import { Kosli } from "@kosli/sdk";

const kosli = new Kosli({
httpBearer: process.env["KOSLI_API_KEY"] ?? "",
});

const trails = await kosli.trails.list({}, {
org: "my-org",
flowName: "my-flow",
});

console.log(trails);
```

## Authentication

Set your API key when constructing the client. This applies it to all requests:

```typescript
import { Kosli } from "@kosli/sdk";

const kosli = new Kosli({
httpBearer: process.env["KOSLI_API_KEY"] ?? "",
});
```

Some operations accept the API key at the call site instead. Use this when you need per-request credentials:

```typescript
const result = await kosli.trails.list(
{ httpBearer: process.env["KOSLI_API_KEY"] ?? "" }, // security
{ org: "my-org", flowName: "my-flow" }, // request params
);
```

See [personal API keys](/user/personal_api_keys) and [service accounts](/administration/authentication/service_accounts) for how to create API keys.

## Server selection

By default the SDK targets the EU region. Pass `server: "us"` to use the US region:

```typescript
const kosli = new Kosli({
httpBearer: process.env["KOSLI_API_KEY"] ?? "",
server: "us",
});
```

| Name | URL | Region |
|------|-----|--------|
| `"eu"` | `https://app.kosli.com/api/v2` | EU (default) |
| `"us"` | `https://app.us.kosli.com/api/v2` | US |

To point at a custom URL (e.g. a proxy or local instance), use `serverURL` instead:

```typescript
const kosli = new Kosli({
httpBearer: process.env["KOSLI_API_KEY"] ?? "",
serverURL: "https://app.kosli.com/api/v2",
});
```

## Available resources

The client exposes the following resource groups:

| Resource | Description |
|----------|-------------|
| `kosli.actions` | Environment and flow actions |
| `kosli.allowlists` | Artifact allowlists |
| `kosli.approvals` | Approvals |
| `kosli.artifacts` | Artifact reporting and lookup |
| `kosli.attestations` | Attestations (custom, JUnit, Jira, Snyk, Sonar, pull request) |
| `kosli.builds` | Builds |
| `kosli.customAttestationTypes` | Custom attestation type management |
| `kosli.deployments` | Deployments |
| `kosli.environments` | Environment management and reporting |
| `kosli.flows` | Flow management |
| `kosli.organizations` | Organization settings and notifications |
| `kosli.policies` | Policy management |
| `kosli.repos` | Repository live artifact lookup |
| `kosli.schemas` | Policy and template schemas |
| `kosli.search` | Artifact search by SHA or fingerprint |
| `kosli.serviceAccounts` | Service account API key management |
| `kosli.snapshots` | Environment snapshots |
| `kosli.tags` | Tag management |
| `kosli.trails` | Trail management |
| `kosli.user` | User settings |

## Standalone functions

All methods are also available as individually importable functions, which allows bundlers to tree-shake unused code:

```typescript
import { KosliCore } from "@kosli/sdk/core.js";
import { trailsList } from "@kosli/sdk/funcs/trails-list.js";

const kosli = new KosliCore({
httpBearer: process.env["KOSLI_API_KEY"] ?? "",
});

const result = await trailsList(kosli, {}, {
org: "my-org",
flowName: "my-flow",
});
```

## Supported runtimes

The SDK requires ECMAScript 2020 or later and the Web Fetch API. Supported environments:

- **Browsers**: Chrome, Safari, Edge, Firefox (evergreen)
- **Node.js**: active and maintenance LTS releases (v18, v20+)
- **Bun**: v1 and above
- **Deno**: v1.39+

For TypeScript projects, add `"lib": ["es2020", "dom", "dom.iterable"]` to your `tsconfig.json` to get full type support for async iterables, streams, and fetch-related APIs.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggestion: This reads as though users should set lib to exactly these three entries. Consider phrasing as "ensure your lib array includes at least…" so users with existing entries (e.g. "es2021", "webworker") don't accidentally drop them.

Suggested change
For TypeScript projects, add `"lib": ["es2020", "dom", "dom.iterable"]` to your `tsconfig.json` to get full type support for async iterables, streams, and fetch-related APIs.
For TypeScript projects, ensure your `tsconfig.json` `lib` array includes at least `"es2020"`, `"dom"`, and `"dom.iterable"` for full type support for async iterables, streams, and fetch-related APIs.


## Debugging

Pass a logger to emit debug output for all requests and responses:

```typescript
const kosli = new Kosli({
httpBearer: process.env["KOSLI_API_KEY"] ?? "",
debugLogger: console,
});
```

Alternatively, set the environment variable `KOSLI_DEBUG=true`.

<Warning>
Debug logging prints headers including your API key in plain text. Use it only during local development.
</Warning>
Loading