npm package: @royalti/syynk
Description: TypeScript SDK for Syynk API - transcribe audio and export synchronized lyrics/subtitles
Author: Syynk
Latest version: 0.2.0

# @royalti/syynk

TypeScript SDK for the Syynk API - transcribe audio and export synchronized lyrics/subtitles.

## Installation

```bash
npm install @royalti/syynk
# or
yarn add @royalti/syynk
# or
pnpm add @royalti/syynk
```

## Quick Start

```typescript
import { SyynkClient } from '@royalti/syynk';

const client = new SyynkClient({
  apiKey: process.env.SYYNK_API_KEY,
});

// Transcribe audio from URL
const result = await client.transcribe({
  audioUrl: 'https://example.com/song.mp3',
  language: 'en',
});

// Export to LRC format
const lrc = await client.export({
  format: 'lrc',
  segments: result.segments,
  projectName: 'My Song',
});

console.log(lrc.content);
```

## Features

- Transcribe audio from URL or file upload
- Export to multiple formats: LRC, SRT, VTT, TTML, JSON, TXT
- Full TypeScript support
- Automatic retry with exponential backoff
- Rate limit handling
- Works in Node.js (18+) and browsers

## API Reference

### `SyynkClient`

Create a new client instance:

```typescript
const client = new SyynkClient({
  apiKey: 'your-api-key',
  baseUrl: 'https://syynk.to', // optional
  timeout: 30000, // optional, in milliseconds
  maxRetries: 3, // optional
});
```

### Methods

#### `transcribe(options)`

Transcribe audio from a URL.

```typescript
const result = await client.transcribe({
  audioUrl: 'https://example.com/song.mp3',
  language: 'en', // optional, auto-detected if not specified
  projectName: 'My Song', // optional
});

// Result contains:
// - projectId: string
// - editorUrl: string (URL to open in Syynk editor)
// - language: string
// - duration: number (seconds)
// - lyricsText: string (plain text lyrics)
// - segments: Segment[]
// - words: Word[]
```

#### `transcribeFile(file, options?)`

Transcribe audio from a file upload.

```typescript
// Node.js
import fs from 'fs';

const buffer = fs.readFileSync('song.mp3');
const result = await client.transcribeFile(buffer, {
  filename: 'song.mp3',
  language: 'en',
});

// Browser
const file = document.querySelector('input[type="file"]').files[0];
const result = await client.transcribeFile(file);
```

#### `export(options)`

Export segments to a specific format.

```typescript
const result = await client.export({
  format: 'lrc', // 'lrc' | 'srt' | 'vtt' | 'ttml' | 'json' | 'txt'
  segments: transcription.segments,
  words: transcription.words, // optional, for word-level timing
  projectName: 'My Song', // optional
});

// Result contains:
// - content: string
// - filename: string
// - mimeType: string
// - extension: string
```

#### `getFormats()`

Get information about available export formats.

```typescript
const formats = await client.getFormats();

// Returns:
// [
//   { id: 'lrc', name: 'LRC', supportsWordTiming: false, ... },
//   { id: 'ttml', name: 'TTML', supportsWordTiming: true, ... },
//   ...
// ]
```

#### `listProjects(options?)`

List your projects with optional filtering.

```typescript
const result = await client.listProjects({
  status: 'ready',
  type: 'lyricsync',
  limit: 20,
  offset: 0,
});

// Result contains:
// - projects: ProjectSummary[]
// - total: number
// - limit: number
// - offset: number
```

#### `getProject(id, options?)`

Get a single project with segments and optionally words.

```typescript
const result = await client.getProject('project-id', {
  includeWords: true, // default: true
});

// Result contains:
// - project: Project (id, name, type, status, editorUrl, audioUrl, etc.)
// - segments: Segment[]
// - words?: Word[] (if includeWords is true)
```

#### `getLyrics(id)`

Get plain text lyrics for a project.

```typescript
const result = await client.getLyrics('project-id');
console.log(result.lyrics);
// "First line of lyrics\nSecond line\n..."
```

#### `deleteProject(id)`

Delete a project and all its segments and words.

```typescript
await client.deleteProject('project-id');
console.log('Project deleted');
```

#### `getRateLimitInfo()`

Get the current rate limit status.

```typescript
const rateLimit = client.getRateLimitInfo();

if (rateLimit) {
  console.log(`${rateLimit.remaining}/${rateLimit.limit} requests remaining`);
  console.log(`Resets at ${new Date(rateLimit.reset * 1000)}`);
}
```

## Error Handling

The SDK provides typed errors for different failure scenarios:

```typescript
import {
  SyynkClient,
  AuthenticationError,
  RateLimitError,
  ValidationError,
  NotFoundError,
  ServerError,
  NetworkError,
  TimeoutError,
} from '@royalti/syynk';

try {
  const result = await client.transcribe({ audioUrl: 'invalid' });
} catch (error) {
  if (error instanceof AuthenticationError) {
    // Invalid or missing API key (401)
    console.log('Check your API key');
  } else if (error instanceof RateLimitError) {
    // Rate limit exceeded (429)
    console.log(`Retry after ${error.retryAfter} seconds`);
    console.log(`Reset time: ${error.getResetDate()}`);
  } else if (error instanceof ValidationError) {
    // Invalid request data (400)
    console.log(error.fieldErrors);
  } else if (error instanceof NotFoundError) {
    // Resource not found (404)
    console.log('Project not found');
  } else if (error instanceof ServerError) {
    // Server error (500+)
    console.log(`Request ID: ${error.requestId}`);
  } else if (error instanceof NetworkError) {
    // Connection failed
    console.log('Check your internet connection');
  } else if (error instanceof TimeoutError) {
    // Request timed out
    console.log(`Timed out after ${error.timeoutMs}ms`);
  }
}
```

### Type Guards

```typescript
import { isSyynkError, isRateLimitError, isRetryableError } from '@royalti/syynk';

if (isSyynkError(error)) {
  console.log(error.code, error.status);
}

if (isRateLimitError(error)) {
  console.log(error.retryAfter);
}

if (isRetryableError(error)) {
  // Error is rate limit, network, timeout, or server error
}
```

## Types

All types are exported for TypeScript users:

```typescript
import type {
  Segment,
  Word,
  Project,
  ProjectSummary,
  ProjectResult,
  LyricsResult,
  ExportFormat,
  TranscribeResult,
  ExportResult,
} from '@royalti/syynk';
```

## Export Formats

| Format | Extension | Word Timing | Use Case |
|--------|-----------|-------------|----------|
| LRC | `.lrc` | No | Karaoke players |
| SRT | `.srt` | No | Video subtitles (VLC, YouTube) |
| VTT | `.vtt` | No | HTML5 `<track>` element |
| TTML | `.ttml` | Yes | Professional broadcast |
| JSON | `.json` | Yes | Developer integration |
| TXT | `.txt` | No | Plain text lyrics |

## License

MIT