npm package: @kubbi.ai/sdk
Description: Official TypeScript SDK for the Kubbi API — send and receive ephemeral, encrypted payloads
Author: Kubbi
Latest version: 0.1.0

# @kubbi/sdk

Official TypeScript SDK for the [Kubbi](https://kubbi.ai) API — send and receive ephemeral, encrypted payloads between decoupled actors.

## Install

```bash
npm install @kubbi/sdk
```

## Quick Start

Create an API key at [dashboard.kubbi.ai](https://dashboard.kubbi.ai), then use it below.

### Send a kubbi

```typescript
import { KubbiClient } from '@kubbi/sdk';

const kubbi = new KubbiClient({ apiKey: 'kb_...' });

const { claimUrl } = await kubbi.send({
  content: { orderId: '123', status: 'approved' },
  contentType: 'application/json',
  ttlSeconds: 3600,
  maxRetrievals: 1,
});

// Pass claimUrl to the next actor (agent, service, webhook, etc.)
console.log(claimUrl);
```

### Receive a kubbi

```typescript
import { KubbiClient } from '@kubbi/sdk';

const result = await KubbiClient.claim('https://api.kubbi.ai/r/abc123');

console.log(result.content);      // { orderId: '123', status: 'approved' }
console.log(result.contentType);   // 'application/json'
```

## API Reference

### `KubbiClient`

The main client for producing and consuming kubbis.

#### Constructor

```typescript
const kubbi = new KubbiClient({
  apiKey: 'kb_...',                    // required
  baseUrl: 'https://api.kubbi.ai',     // optional (default)
  maxRetries: 2,                       // optional (default: 2)
  timeoutMs: 30000,                    // optional (default: 30000)
  debug: false,                        // optional (default: false)
});
```

#### `kubbi.send(options): Promise<SendResult>`

Create a kubbi and get a claim URL.

```typescript
const result = await kubbi.send({
  content: { key: 'value' },           // required — any JSON-serializable value or string
  contentType: 'application/json',     // required — 'text/plain' | 'application/json'
  ttlSeconds: 3600,                    // required — 60 to 86400
  maxRetrievals: 1,                    // optional — burn after N retrievals
  metadata: { source: 'billing' },     // optional — up to 1KB
});

// result: { id, claimUrl, claimToken, status, contentType, maxRetrievals, metadata, createdAt, expiresAt }
```

#### `kubbi.sendFiles(options): Promise<SendFilesResult>`

Create a multi-file kubbi package and get a claim URL.

```typescript
const result = await kubbi.sendFiles({
  files: [
    {
      name: 'config.json',
      content: JSON.stringify({ model: 'gpt-4' }),
      contentType: 'application/json',
      role: 'config',
    },
    {
      name: 'prompt.txt',
      content: 'Summarize the attached data.',
      contentType: 'text/plain',
      role: 'instructions',
    },
  ],
  ttlSeconds: 3600,
  maxRetrievals: 1,
  metadata: { source: 'pipeline' },
});

// result: { id, claimUrl, claimToken, status, fileCount, totalSizeBytes,
//           maxRetrievals, metadata, createdAt, expiresAt }
```

Each file entry accepts:

- `name` — filename (e.g. `'config.json'`)
- `content` — file content as a string, or base64-encoded for binary
- `contentType` — MIME type (e.g. `'application/json'`, `'image/png'`)
- `role` *(optional)* — `'instructions'` | `'data'` | `'context'` | `'config'` | `'attachment'`
- `encoding` *(optional)* — set to `'base64'` for binary content

#### `kubbi.get(kubbiId): Promise<KubbiDetail>`

Get details about a kubbi you created.

```typescript
const detail = await kubbi.get('kubbi-id-here');

// detail: { id, status, contentType, maxRetrievals, retrievalCount,
//           firstRetrievedAt, lastRetrievedAt, metadata, createdAt, expiresAt }
```

#### `kubbi.list(options?): Promise<ListKubbisResult>`

List kubbis created with this API key.

```typescript
const { kubbis, pagination } = await kubbi.list({ page: 1, limit: 20 });
```

#### `kubbi.delete(kubbiId): Promise<{ status: string }>`

Delete a kubbi you created. Wipes the encrypted payload.

```typescript
await kubbi.delete('kubbi-id-here');
```

#### `KubbiClient.inspect(claimUrlOrToken, options?): Promise<InspectResult>` (static)

Inspect a kubbi without consuming it. No API key required.

```typescript
// With a full claim URL:
const info = await KubbiClient.inspect('https://api.kubbi.ai/r/abc123');

// With just a claim token:
const info = await KubbiClient.inspect('abc123', {
  baseUrl: 'https://api.kubbi.ai',
});

// info: { status, contentType, maxRetrievals, retrievalCount, metadata, createdAt, expiresAt }
```

#### `KubbiClient.claim(claimUrlOrToken, options?): Promise<ClaimResult>` (static)

Retrieve a kubbi's content. No API key required. Counts as a retrieval.

```typescript
const result = await KubbiClient.claim('https://api.kubbi.ai/r/abc123');

// result: { content, contentType, metadata, createdAt, expiresAt }
```

## Error Handling

All API errors throw typed exceptions that extend `KubbiApiError`:

```typescript
import {
  KubbiApiError,
  KubbiNotFoundError,
  KubbiGoneError,
  KubbiValidationError,
  KubbiQuotaExceededError,
  KubbiRateLimitError,
  KubbiNetworkError,
} from '@kubbi/sdk';

try {
  const result = await KubbiClient.claim(claimUrl);
} catch (err) {
  if (err instanceof KubbiGoneError) {
    console.log('Kubbi already consumed or expired');
  } else if (err instanceof KubbiNotFoundError) {
    console.log('Kubbi not found');
  } else if (err instanceof KubbiNetworkError) {
    console.log('Network issue:', err.message);
  }
}
```

Every `KubbiApiError` has:
- `status` — HTTP status code (e.g. `404`, `410`, `429`)
- `code` — API error code (e.g. `'not_found'`, `'gone'`, `'quota_exceeded'`)
- `message` — Human-readable error message
- `messages` — Array of validation error messages (for `KubbiValidationError`)

## Retries

The SDK automatically retries on transient errors (502, 503, 504) and network failures with exponential backoff. Configure with `maxRetries` (default: 2).

## Security Notes

**Claim URL origin handling:** When a full URL is passed to `inspect()` or `claim()`, the SDK extracts the origin from the URL and directs HTTP requests to that host. If your application accepts claim URLs from untrusted input (e.g. user-supplied or agent-provided), validate the URL origin before passing it to the SDK, or use bare claim tokens with an explicit `baseUrl` instead.

```typescript
// Safe: use bare tokens with a known base URL
const result = await KubbiClient.claim('abc123', {
  baseUrl: 'https://api.kubbi.ai',
});
```

**Debug mode:** When `debug: true` is set, request URLs including claim tokens are logged to the console. Avoid enabling debug mode in production environments where logs may be persisted or forwarded.

## Requirements

- Node.js 18+ (uses native `fetch`)
- TypeScript 5.0+ (for type definitions)

## License

MIT