npm package: @opentusk/sdk
Description: TypeScript SDK for the OpenTusk decentralized storage platform
Latest version: 0.8.2

# @opentusk/sdk

TypeScript SDK for the OpenTusk decentralized storage platform. Zero external dependencies — uses native `fetch`.

## Installation

```bash
npm install @opentusk/sdk
```

## Quick Start

```typescript
import { OpenTuskClient } from '@opentusk/sdk';

const client = new OpenTuskClient({
  apiKey: 'otk_your_api_key',
});
```

## Vaults

```typescript
// Create a vault
const vault = await client.vaults.create({
  name: 'My Vault',
  description: 'Project files',
  visibility: 'public',
});

// List vaults
const vaults = await client.vaults.list();

// Update a vault
await client.vaults.update(vault.id, { name: 'Renamed Vault' });

// Delete (use force: true if vault has files)
await client.vaults.delete(vault.id, { force: true });
```

## File Upload

### One-liner upload

```typescript
import { readFile } from 'fs/promises';

const data = await readFile('./photo.jpg');
const file = await client.files.upload({
  name: 'photo.jpg',
  mimeType: 'image/jpeg',
  vaultId: vault.id,
  data,
});
console.log(file.id, file.status); // "hot"
```

### Manual 3-step upload

```typescript
// 1. Get presigned URL
const { fileId, uploadUrl } = await client.files.requestUpload({
  name: 'doc.pdf',
  mimeType: 'application/pdf',
  sizeBytes: buffer.byteLength,
  vaultId: vault.id,
});

// 2. PUT to presigned URL
await fetch(uploadUrl, {
  method: 'PUT',
  body: buffer,
  headers: { 'Content-Type': 'application/pdf' },
});

// 3. Confirm
const file = await client.files.confirmUpload(fileId);
```

## Polling for Walrus Sync

```typescript
// Wait for file to be synced to Walrus (promise)
const status = await client.files.waitForStatus(file.id, ['synced'], {
  interval: 3000, // poll every 3s (default: 2s)
  timeout: 120000, // give up after 2min (default: 60s)
});

// Or use async iterator for progress updates
for await (const status of client.files.pollStatus(file.id, ['synced'])) {
  console.log(`Status: ${status.status}`);
}
```

## Download

```typescript
const { downloadUrl, encryption } = await client.files.getDownloadUrl(file.id);

if (downloadUrl) {
  const response = await fetch(downloadUrl);
  // If encrypted, decrypt client-side using encryption.wrappedKey / encryption.iv
}
```

## List Files

```typescript
const { files, nextCursor } = await client.files.list({
  vaultId: vault.id,
  limit: 25,
  sortBy: 'createdAt',
  order: 'desc',
});
```

## Webhooks

```typescript
// Create a webhook
const webhook = await client.webhooks.create({
  url: 'https://example.com/webhook',
  events: ['file.synced', 'file.error'],
});
console.log(webhook.secret); // Save this — only shown once

// Send a test delivery
const delivery = await client.webhooks.test(webhook.id);

// List deliveries
const deliveries = await client.webhooks.listDeliveries(webhook.id, { limit: 10 });

// Update
await client.webhooks.update(webhook.id, { active: false });

// Delete
await client.webhooks.delete(webhook.id);
```

## Public Access (No Auth)

```typescript
// Build public URLs (synchronous)
const fileUrl = client.public.getFileUrl(fileId);
const blobUrl = client.public.getBlobUrl(walrusBlobId);

// List files in a public vault
const { vault, files } = await client.public.listVaultFiles(userId, 'my-vault');
```

## Account & API Keys

```typescript
// Get account info
const account = await client.account.get();
console.log(account.planTier, account.storageUsedFormatted);

// Create an API key
const newKey = await client.apiKeys.create({
  name: 'CI/CD',
  scopes: ['files:write'],
  expiresInDays: 90,
});

// List & revoke
const keys = await client.apiKeys.list();
await client.apiKeys.revoke(keys[0].id);
```

## Trash

```typescript
const trash = await client.trash.list();
await client.trash.restore(trash.files[0].id);
await client.trash.delete(trash.vaults[0].id);
await client.trash.empty();
```

## Error Handling

```typescript
import { OpenTuskError, OpenTuskTimeoutError } from '@opentusk/sdk';

try {
  await client.vaults.get('non-existent');
} catch (err) {
  if (err instanceof OpenTuskError) {
    console.error(err.statusCode, err.message);
  }
  if (err instanceof OpenTuskTimeoutError) {
    console.error('Polling timed out');
  }
}
```

## Configuration

```typescript
const client = new OpenTuskClient({
  apiKey: 'otk_...',
  baseUrl: 'http://localhost:8000', // Override for local dev
  headers: { 'X-Custom': 'value' }, // Extra headers
  fetch: customFetchFn,             // Custom fetch implementation
});
```