@royalti/syynk 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md ADDED
@@ -0,0 +1,279 @@
1
+ # @royalti/syynk
2
+
3
+ TypeScript SDK for the Syynk API - transcribe audio and export synchronized lyrics/subtitles.
4
+
5
+ ## Installation
6
+
7
+ ```bash
8
+ npm install @royalti/syynk
9
+ # or
10
+ yarn add @royalti/syynk
11
+ # or
12
+ pnpm add @royalti/syynk
13
+ ```
14
+
15
+ ## Quick Start
16
+
17
+ ```typescript
18
+ import { SyynkClient } from '@royalti/syynk';
19
+
20
+ const client = new SyynkClient({
21
+ apiKey: process.env.SYYNK_API_KEY,
22
+ });
23
+
24
+ // Transcribe audio from URL
25
+ const result = await client.transcribe({
26
+ audioUrl: 'https://example.com/song.mp3',
27
+ language: 'en',
28
+ });
29
+
30
+ // Export to LRC format
31
+ const lrc = await client.export({
32
+ format: 'lrc',
33
+ segments: result.segments,
34
+ projectName: 'My Song',
35
+ });
36
+
37
+ console.log(lrc.content);
38
+ ```
39
+
40
+ ## Features
41
+
42
+ - Transcribe audio from URL or file upload
43
+ - Export to multiple formats: LRC, SRT, VTT, TTML, JSON, TXT
44
+ - Full TypeScript support
45
+ - Automatic retry with exponential backoff
46
+ - Rate limit handling
47
+ - Works in Node.js (18+) and browsers
48
+
49
+ ## API Reference
50
+
51
+ ### `SyynkClient`
52
+
53
+ Create a new client instance:
54
+
55
+ ```typescript
56
+ const client = new SyynkClient({
57
+ apiKey: 'your-api-key',
58
+ baseUrl: 'https://syynk.to', // optional
59
+ timeout: 30000, // optional, in milliseconds
60
+ maxRetries: 3, // optional
61
+ });
62
+ ```
63
+
64
+ ### Methods
65
+
66
+ #### `transcribe(options)`
67
+
68
+ Transcribe audio from a URL.
69
+
70
+ ```typescript
71
+ const result = await client.transcribe({
72
+ audioUrl: 'https://example.com/song.mp3',
73
+ language: 'en', // optional, auto-detected if not specified
74
+ projectName: 'My Song', // optional
75
+ });
76
+
77
+ // Result contains:
78
+ // - projectId: string
79
+ // - language: string
80
+ // - duration: number (seconds)
81
+ // - segments: Segment[]
82
+ // - words: Word[]
83
+ ```
84
+
85
+ #### `transcribeFile(file, options?)`
86
+
87
+ Transcribe audio from a file upload.
88
+
89
+ ```typescript
90
+ // Node.js
91
+ import fs from 'fs';
92
+
93
+ const buffer = fs.readFileSync('song.mp3');
94
+ const result = await client.transcribeFile(buffer, {
95
+ filename: 'song.mp3',
96
+ language: 'en',
97
+ });
98
+
99
+ // Browser
100
+ const file = document.querySelector('input[type="file"]').files[0];
101
+ const result = await client.transcribeFile(file);
102
+ ```
103
+
104
+ #### `export(options)`
105
+
106
+ Export segments to a specific format.
107
+
108
+ ```typescript
109
+ const result = await client.export({
110
+ format: 'lrc', // 'lrc' | 'srt' | 'vtt' | 'ttml' | 'json' | 'txt'
111
+ segments: transcription.segments,
112
+ words: transcription.words, // optional, for word-level timing
113
+ projectName: 'My Song', // optional
114
+ });
115
+
116
+ // Result contains:
117
+ // - content: string
118
+ // - filename: string
119
+ // - mimeType: string
120
+ // - extension: string
121
+ ```
122
+
123
+ #### `getFormats()`
124
+
125
+ Get information about available export formats.
126
+
127
+ ```typescript
128
+ const formats = await client.getFormats();
129
+
130
+ // Returns:
131
+ // [
132
+ // { id: 'lrc', name: 'LRC', supportsWordTiming: false, ... },
133
+ // { id: 'ttml', name: 'TTML', supportsWordTiming: true, ... },
134
+ // ...
135
+ // ]
136
+ ```
137
+
138
+ #### `listProjects(options?)`
139
+
140
+ List your projects with optional filtering.
141
+
142
+ ```typescript
143
+ const result = await client.listProjects({
144
+ status: 'ready',
145
+ type: 'lyricsync',
146
+ limit: 20,
147
+ offset: 0,
148
+ });
149
+
150
+ // Result contains:
151
+ // - projects: Project[]
152
+ // - total: number
153
+ // - hasMore: boolean
154
+ ```
155
+
156
+ #### `getProject(id, options?)`
157
+
158
+ Get a single project with segments and words.
159
+
160
+ ```typescript
161
+ const project = await client.getProject('project-id', {
162
+ includeWords: true,
163
+ includeSegments: true,
164
+ });
165
+ ```
166
+
167
+ #### `deleteProject(id)`
168
+
169
+ Delete a project.
170
+
171
+ ```typescript
172
+ await client.deleteProject('project-id');
173
+ ```
174
+
175
+ #### `getRateLimitInfo()`
176
+
177
+ Get the current rate limit status.
178
+
179
+ ```typescript
180
+ const rateLimit = client.getRateLimitInfo();
181
+
182
+ if (rateLimit) {
183
+ console.log(`${rateLimit.remaining}/${rateLimit.limit} requests remaining`);
184
+ console.log(`Resets at ${new Date(rateLimit.reset * 1000)}`);
185
+ }
186
+ ```
187
+
188
+ ## Error Handling
189
+
190
+ The SDK provides typed errors for different failure scenarios:
191
+
192
+ ```typescript
193
+ import {
194
+ SyynkClient,
195
+ AuthenticationError,
196
+ RateLimitError,
197
+ ValidationError,
198
+ NotFoundError,
199
+ ServerError,
200
+ NetworkError,
201
+ TimeoutError,
202
+ } from '@royalti/syynk';
203
+
204
+ try {
205
+ const result = await client.transcribe({ audioUrl: 'invalid' });
206
+ } catch (error) {
207
+ if (error instanceof AuthenticationError) {
208
+ // Invalid or missing API key (401)
209
+ console.log('Check your API key');
210
+ } else if (error instanceof RateLimitError) {
211
+ // Rate limit exceeded (429)
212
+ console.log(`Retry after ${error.retryAfter} seconds`);
213
+ console.log(`Reset time: ${error.getResetDate()}`);
214
+ } else if (error instanceof ValidationError) {
215
+ // Invalid request data (400)
216
+ console.log(error.fieldErrors);
217
+ } else if (error instanceof NotFoundError) {
218
+ // Resource not found (404)
219
+ console.log('Project not found');
220
+ } else if (error instanceof ServerError) {
221
+ // Server error (500+)
222
+ console.log(`Request ID: ${error.requestId}`);
223
+ } else if (error instanceof NetworkError) {
224
+ // Connection failed
225
+ console.log('Check your internet connection');
226
+ } else if (error instanceof TimeoutError) {
227
+ // Request timed out
228
+ console.log(`Timed out after ${error.timeoutMs}ms`);
229
+ }
230
+ }
231
+ ```
232
+
233
+ ### Type Guards
234
+
235
+ ```typescript
236
+ import { isSyynkError, isRateLimitError, isRetryableError } from '@royalti/syynk';
237
+
238
+ if (isSyynkError(error)) {
239
+ console.log(error.code, error.status);
240
+ }
241
+
242
+ if (isRateLimitError(error)) {
243
+ console.log(error.retryAfter);
244
+ }
245
+
246
+ if (isRetryableError(error)) {
247
+ // Error is rate limit, network, timeout, or server error
248
+ }
249
+ ```
250
+
251
+ ## Types
252
+
253
+ All types are exported for TypeScript users:
254
+
255
+ ```typescript
256
+ import type {
257
+ Segment,
258
+ Word,
259
+ Project,
260
+ ExportFormat,
261
+ TranscribeResult,
262
+ ExportResult,
263
+ } from '@royalti/syynk';
264
+ ```
265
+
266
+ ## Export Formats
267
+
268
+ | Format | Extension | Word Timing | Use Case |
269
+ |--------|-----------|-------------|----------|
270
+ | LRC | `.lrc` | No | Karaoke players |
271
+ | SRT | `.srt` | No | Video subtitles (VLC, YouTube) |
272
+ | VTT | `.vtt` | No | HTML5 `<track>` element |
273
+ | TTML | `.ttml` | Yes | Professional broadcast |
274
+ | JSON | `.json` | Yes | Developer integration |
275
+ | TXT | `.txt` | No | Plain text lyrics |
276
+
277
+ ## License
278
+
279
+ MIT