@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.
@@ -0,0 +1,571 @@
1
+ /**
2
+ * @fileoverview Type definitions for the Syynk SDK
3
+ *
4
+ * These types mirror the Syynk API responses and provide type safety
5
+ * for SDK consumers.
6
+ */
7
+ /**
8
+ * Configuration options for the SyynkClient
9
+ */
10
+ interface SyynkClientOptions {
11
+ /** API key for authentication */
12
+ apiKey: string;
13
+ /** Base URL for the API (default: https://syynk.to) */
14
+ baseUrl?: string;
15
+ /** Request timeout in milliseconds (default: 30000) */
16
+ timeout?: number;
17
+ /** Maximum number of retries for rate-limited requests (default: 3) */
18
+ maxRetries?: number;
19
+ }
20
+ /**
21
+ * Options for transcribing audio from a URL
22
+ */
23
+ interface TranscribeOptions {
24
+ /** URL of the audio file to transcribe */
25
+ audioUrl: string;
26
+ /** ISO 639-1 language code (e.g., 'en', 'es', 'ja'). Auto-detected if not specified */
27
+ language?: string;
28
+ /** Optional name for the project */
29
+ projectName?: string;
30
+ }
31
+ /**
32
+ * Options for transcribing audio from a file upload
33
+ */
34
+ interface TranscribeFileOptions {
35
+ /** ISO 639-1 language code (e.g., 'en', 'es', 'ja'). Auto-detected if not specified */
36
+ language?: string;
37
+ /** Custom filename (defaults to 'audio' with detected extension) */
38
+ filename?: string;
39
+ /** Optional name for the project */
40
+ projectName?: string;
41
+ }
42
+ /**
43
+ * Result of a transcription operation
44
+ */
45
+ interface TranscribeResult {
46
+ /** Unique identifier for the created project */
47
+ projectId: string;
48
+ /** Detected or specified language code */
49
+ language: string;
50
+ /** Audio duration in seconds */
51
+ duration: number;
52
+ /** Transcribed segments with line-level timestamps */
53
+ segments: Segment[];
54
+ /** Individual words with word-level timestamps */
55
+ words: Word[];
56
+ }
57
+ /**
58
+ * A segment represents a line of lyrics or a subtitle block
59
+ * with start and end timestamps
60
+ */
61
+ interface Segment {
62
+ /** Unique segment identifier */
63
+ id: string;
64
+ /** Start time in seconds */
65
+ startTime: number;
66
+ /** End time in seconds */
67
+ endTime: number;
68
+ /** Text content of the segment */
69
+ text: string;
70
+ /** Order within the project (0-indexed) */
71
+ sortOrder: number;
72
+ /** Optional speaker identifier for multi-speaker content */
73
+ speakerId?: string | null;
74
+ /** Transcription confidence score (0-1) */
75
+ confidence?: number | null;
76
+ }
77
+ /**
78
+ * A word with precise timestamp within a segment
79
+ */
80
+ interface Word {
81
+ /** Unique word identifier */
82
+ id: string;
83
+ /** ID of the parent segment */
84
+ segmentId: string;
85
+ /** Start time in seconds */
86
+ startTime: number;
87
+ /** End time in seconds */
88
+ endTime: number;
89
+ /** The word text */
90
+ word: string;
91
+ /** Order within the segment (0-indexed) */
92
+ sortOrder: number;
93
+ /** Transcription confidence score (0-1) */
94
+ confidence?: number | null;
95
+ }
96
+ /**
97
+ * Supported export format identifiers
98
+ */
99
+ type ExportFormat = 'lrc' | 'srt' | 'vtt' | 'ttml' | 'json' | 'txt';
100
+ /**
101
+ * Options for exporting segments to a specific format
102
+ */
103
+ interface ExportOptions {
104
+ /** Target export format */
105
+ format: ExportFormat;
106
+ /** Segments to export */
107
+ segments: Segment[];
108
+ /** Optional words for word-level timing (supported by TTML and JSON) */
109
+ words?: Word[];
110
+ /** Project name for metadata (appears in file headers) */
111
+ projectName?: string;
112
+ }
113
+ /**
114
+ * Result of an export operation
115
+ */
116
+ interface ExportResult {
117
+ /** The formatted content as a string */
118
+ content: string;
119
+ /** Suggested filename for download */
120
+ filename: string;
121
+ /** MIME type for the content */
122
+ mimeType: string;
123
+ /** File extension (without dot) */
124
+ extension: string;
125
+ }
126
+ /**
127
+ * Information about a supported export format
128
+ */
129
+ interface FormatInfo {
130
+ /** Format identifier */
131
+ id: ExportFormat;
132
+ /** Human-readable format name */
133
+ name: string;
134
+ /** Description of the format and its use cases */
135
+ description: string;
136
+ /** File extension (without dot) */
137
+ extension: string;
138
+ /** MIME type */
139
+ mimeType: string;
140
+ /** Whether this format supports word-level timing */
141
+ supportsWordTiming: boolean;
142
+ }
143
+ /**
144
+ * Project type identifier
145
+ */
146
+ type ProjectType = 'lyricsync' | 'subsync';
147
+ /**
148
+ * Project status
149
+ */
150
+ type ProjectStatus = 'draft' | 'processing' | 'ready' | 'error';
151
+ /**
152
+ * Options for listing projects
153
+ */
154
+ interface ListProjectsOptions {
155
+ /** Maximum number of projects to return (default: 20, max: 100) */
156
+ limit?: number;
157
+ /** Number of projects to skip for pagination */
158
+ offset?: number;
159
+ /** Filter by project status */
160
+ status?: ProjectStatus;
161
+ /** Filter by project type */
162
+ type?: ProjectType;
163
+ }
164
+ /**
165
+ * Paginated result for project listing
166
+ */
167
+ interface ProjectsResult {
168
+ /** Array of projects */
169
+ projects: Project[];
170
+ /** Total count of projects matching filters */
171
+ total: number;
172
+ /** Current limit */
173
+ limit: number;
174
+ /** Current offset */
175
+ offset: number;
176
+ /** Whether there are more results */
177
+ hasMore: boolean;
178
+ }
179
+ /**
180
+ * Options for getting a single project
181
+ */
182
+ interface GetProjectOptions {
183
+ /** Include word-level timing data (default: true) */
184
+ includeWords?: boolean;
185
+ /** Include segments (default: true) */
186
+ includeSegments?: boolean;
187
+ }
188
+ /**
189
+ * A Syynk project containing synchronized content
190
+ */
191
+ interface Project {
192
+ /** Unique project identifier */
193
+ id: string;
194
+ /** Project name/title */
195
+ name: string | null;
196
+ /** Project type */
197
+ type: ProjectType;
198
+ /** Current status */
199
+ status: ProjectStatus;
200
+ /** Audio/video duration in seconds */
201
+ durationSeconds: number | null;
202
+ /** URL to the audio file (if stored) */
203
+ audioUrl: string | null;
204
+ /** URL to the video file (for subsync projects) */
205
+ videoUrl: string | null;
206
+ /** Error message if status is 'error' */
207
+ errorMessage?: string | null;
208
+ /** ISO 8601 creation timestamp */
209
+ createdAt: string;
210
+ /** ISO 8601 last update timestamp */
211
+ updatedAt: string;
212
+ }
213
+ /**
214
+ * Full project result including segments and words
215
+ */
216
+ interface ProjectResult extends Project {
217
+ /** Project segments (included by default) */
218
+ segments: Segment[];
219
+ /** Project words (included by default) */
220
+ words: Word[];
221
+ }
222
+ /**
223
+ * Rate limit information from API response headers
224
+ */
225
+ interface RateLimitInfo {
226
+ /** Maximum requests allowed in the window */
227
+ limit: number;
228
+ /** Remaining requests in the current window */
229
+ remaining: number;
230
+ /** Unix timestamp when the rate limit resets */
231
+ reset: number;
232
+ }
233
+ /**
234
+ * Standard API response envelope
235
+ */
236
+ interface ApiResponse<T> {
237
+ /** Response data */
238
+ data: T;
239
+ /** Optional metadata */
240
+ meta?: {
241
+ /** Rate limit information */
242
+ rateLimit?: RateLimitInfo;
243
+ };
244
+ }
245
+ /**
246
+ * API error response
247
+ */
248
+ interface ApiErrorResponse {
249
+ /** Error information */
250
+ error: {
251
+ /** Error code */
252
+ code: string;
253
+ /** Human-readable error message */
254
+ message: string;
255
+ /** Additional error details */
256
+ details?: unknown;
257
+ };
258
+ }
259
+
260
+ /**
261
+ * @fileoverview Syynk API client implementation
262
+ *
263
+ * Provides a type-safe client for interacting with the Syynk API.
264
+ * Includes automatic retry with exponential backoff for rate-limited requests.
265
+ */
266
+
267
+ /**
268
+ * Syynk API client for transcription and export operations
269
+ *
270
+ * @example
271
+ * ```typescript
272
+ * import { SyynkClient } from '@syynk/sdk';
273
+ *
274
+ * const client = new SyynkClient({ apiKey: 'your-api-key' });
275
+ *
276
+ * // Transcribe audio from URL
277
+ * const result = await client.transcribe({
278
+ * audioUrl: 'https://example.com/song.mp3',
279
+ * language: 'en',
280
+ * });
281
+ *
282
+ * // Export to LRC format
283
+ * const lrc = await client.export({
284
+ * format: 'lrc',
285
+ * segments: result.segments,
286
+ * });
287
+ * ```
288
+ */
289
+ declare class SyynkClient {
290
+ private readonly apiKey;
291
+ private readonly baseUrl;
292
+ private readonly timeout;
293
+ private readonly maxRetries;
294
+ /** Last rate limit info received from the API */
295
+ private lastRateLimitInfo;
296
+ /**
297
+ * Create a new Syynk API client
298
+ *
299
+ * @param options - Client configuration options
300
+ * @throws {Error} If apiKey is not provided
301
+ */
302
+ constructor(options: SyynkClientOptions);
303
+ /**
304
+ * Get the current rate limit information
305
+ *
306
+ * @returns The last rate limit info received, or null if no requests have been made
307
+ */
308
+ getRateLimitInfo(): RateLimitInfo | null;
309
+ /**
310
+ * Transcribe audio from a URL
311
+ *
312
+ * @param options - Transcription options
313
+ * @returns Transcription result with segments and words
314
+ *
315
+ * @example
316
+ * ```typescript
317
+ * const result = await client.transcribe({
318
+ * audioUrl: 'https://example.com/song.mp3',
319
+ * language: 'en',
320
+ * });
321
+ * console.log(`Transcribed ${result.segments.length} segments`);
322
+ * ```
323
+ */
324
+ transcribe(options: TranscribeOptions): Promise<TranscribeResult>;
325
+ /**
326
+ * Transcribe audio from a file upload
327
+ *
328
+ * Works in both Node.js and browser environments.
329
+ *
330
+ * @param file - Audio file as Blob/File (browser) or ArrayBuffer/Uint8Array (Node.js Buffer works as it extends Uint8Array)
331
+ * @param options - Optional transcription options
332
+ * @returns Transcription result with segments and words
333
+ *
334
+ * @example
335
+ * ```typescript
336
+ * // Browser
337
+ * const file = document.querySelector('input[type="file"]').files[0];
338
+ * const result = await client.transcribeFile(file);
339
+ *
340
+ * // Node.js
341
+ * const buffer = fs.readFileSync('song.mp3');
342
+ * const result = await client.transcribeFile(buffer, { filename: 'song.mp3' });
343
+ * ```
344
+ */
345
+ transcribeFile(file: Blob | ArrayBuffer | Uint8Array, options?: TranscribeFileOptions): Promise<TranscribeResult>;
346
+ /**
347
+ * Export segments to a specific format
348
+ *
349
+ * @param options - Export options including format and segments
350
+ * @returns Export result with content and metadata
351
+ *
352
+ * @example
353
+ * ```typescript
354
+ * const result = await client.export({
355
+ * format: 'lrc',
356
+ * segments: transcription.segments,
357
+ * projectName: 'My Song',
358
+ * });
359
+ *
360
+ * // Save the file
361
+ * fs.writeFileSync(`output.${result.extension}`, result.content);
362
+ * ```
363
+ */
364
+ export(options: ExportOptions): Promise<ExportResult>;
365
+ /**
366
+ * Get information about all available export formats
367
+ *
368
+ * @returns Array of format information objects
369
+ *
370
+ * @example
371
+ * ```typescript
372
+ * const formats = await client.getFormats();
373
+ * const wordTimingFormats = formats.filter(f => f.supportsWordTiming);
374
+ * ```
375
+ */
376
+ getFormats(): Promise<FormatInfo[]>;
377
+ /**
378
+ * List projects with optional filtering and pagination
379
+ *
380
+ * @param options - Listing options
381
+ * @returns Paginated list of projects
382
+ *
383
+ * @example
384
+ * ```typescript
385
+ * const result = await client.listProjects({
386
+ * status: 'ready',
387
+ * limit: 10,
388
+ * });
389
+ * console.log(`Found ${result.total} projects`);
390
+ * ```
391
+ */
392
+ listProjects(options?: ListProjectsOptions): Promise<ProjectsResult>;
393
+ /**
394
+ * Get a single project by ID
395
+ *
396
+ * @param id - Project ID
397
+ * @param options - Options for including segments/words
398
+ * @returns Project with segments and words
399
+ *
400
+ * @example
401
+ * ```typescript
402
+ * const project = await client.getProject('project-id', {
403
+ * includeWords: true,
404
+ * });
405
+ * console.log(`Project has ${project.segments.length} segments`);
406
+ * ```
407
+ */
408
+ getProject(id: string, options?: GetProjectOptions): Promise<ProjectResult>;
409
+ /**
410
+ * Delete a project by ID
411
+ *
412
+ * @param id - Project ID
413
+ *
414
+ * @example
415
+ * ```typescript
416
+ * await client.deleteProject('project-id');
417
+ * ```
418
+ */
419
+ deleteProject(id: string): Promise<void>;
420
+ /**
421
+ * Make an authenticated API request with automatic retry
422
+ *
423
+ * @param path - API path (starting with /)
424
+ * @param options - Fetch request options
425
+ * @returns Parsed response data
426
+ */
427
+ private request;
428
+ /**
429
+ * Parse rate limit headers from response
430
+ */
431
+ private parseRateLimitHeaders;
432
+ /**
433
+ * Handle error responses and convert to typed errors
434
+ */
435
+ private handleErrorResponse;
436
+ /**
437
+ * Calculate retry delay with exponential backoff
438
+ */
439
+ private calculateRetryDelay;
440
+ /**
441
+ * Sleep for the specified duration
442
+ */
443
+ private sleep;
444
+ }
445
+
446
+ /**
447
+ * @fileoverview Custom error classes for the Syynk SDK
448
+ *
449
+ * Provides typed errors for different API failure scenarios.
450
+ */
451
+ /**
452
+ * Base error class for all Syynk SDK errors
453
+ */
454
+ declare class SyynkError extends Error {
455
+ /** Error code for programmatic handling */
456
+ readonly code: string;
457
+ /** HTTP status code */
458
+ readonly status: number;
459
+ /** Additional error details from the API */
460
+ readonly details?: unknown;
461
+ constructor(message: string, code: string, status: number, details?: unknown);
462
+ /**
463
+ * Convert error to a plain object for serialization
464
+ */
465
+ toJSON(): Record<string, unknown>;
466
+ }
467
+ /**
468
+ * Authentication error (401)
469
+ *
470
+ * Thrown when the API key is missing, invalid, or expired.
471
+ */
472
+ declare class AuthenticationError extends SyynkError {
473
+ constructor(message?: string, details?: unknown);
474
+ }
475
+ /**
476
+ * Authorization error (403)
477
+ *
478
+ * Thrown when the API key doesn't have permission for the requested operation.
479
+ */
480
+ declare class AuthorizationError extends SyynkError {
481
+ constructor(message?: string, details?: unknown);
482
+ }
483
+ /**
484
+ * Rate limit error (429)
485
+ *
486
+ * Thrown when the API rate limit has been exceeded.
487
+ * Includes information about when the limit resets.
488
+ */
489
+ declare class RateLimitError extends SyynkError {
490
+ /** Unix timestamp when the rate limit resets */
491
+ readonly resetAt: number;
492
+ /** Seconds until the rate limit resets */
493
+ readonly retryAfter: number;
494
+ constructor(message: string | undefined, resetAt: number, details?: unknown);
495
+ /**
496
+ * Get the Date object for when the rate limit resets
497
+ */
498
+ getResetDate(): Date;
499
+ toJSON(): Record<string, unknown>;
500
+ }
501
+ /**
502
+ * Validation error (400)
503
+ *
504
+ * Thrown when the request contains invalid data.
505
+ */
506
+ declare class ValidationError extends SyynkError {
507
+ /** Field-level validation errors */
508
+ readonly fieldErrors?: Record<string, string[]>;
509
+ constructor(message?: string, details?: unknown, fieldErrors?: Record<string, string[]>);
510
+ toJSON(): Record<string, unknown>;
511
+ }
512
+ /**
513
+ * Not found error (404)
514
+ *
515
+ * Thrown when the requested resource doesn't exist.
516
+ */
517
+ declare class NotFoundError extends SyynkError {
518
+ /** Type of resource that wasn't found */
519
+ readonly resourceType?: string;
520
+ /** ID of the resource that wasn't found */
521
+ readonly resourceId?: string;
522
+ constructor(message?: string, resourceType?: string, resourceId?: string, details?: unknown);
523
+ toJSON(): Record<string, unknown>;
524
+ }
525
+ /**
526
+ * Server error (500+)
527
+ *
528
+ * Thrown when the server encounters an internal error.
529
+ */
530
+ declare class ServerError extends SyynkError {
531
+ /** Request ID for debugging */
532
+ readonly requestId?: string;
533
+ constructor(message?: string, status?: number, requestId?: string, details?: unknown);
534
+ toJSON(): Record<string, unknown>;
535
+ }
536
+ /**
537
+ * Network error
538
+ *
539
+ * Thrown when a network request fails (connection refused, timeout, etc.)
540
+ */
541
+ declare class NetworkError extends SyynkError {
542
+ /** The original error that caused this network error */
543
+ readonly cause?: Error;
544
+ constructor(message?: string, cause?: Error);
545
+ toJSON(): Record<string, unknown>;
546
+ }
547
+ /**
548
+ * Timeout error
549
+ *
550
+ * Thrown when a request times out.
551
+ */
552
+ declare class TimeoutError extends SyynkError {
553
+ /** The timeout duration in milliseconds */
554
+ readonly timeoutMs: number;
555
+ constructor(message: string | undefined, timeoutMs: number);
556
+ toJSON(): Record<string, unknown>;
557
+ }
558
+ /**
559
+ * Type guard to check if an error is a SyynkError
560
+ */
561
+ declare function isSyynkError(error: unknown): error is SyynkError;
562
+ /**
563
+ * Type guard to check if an error is a rate limit error
564
+ */
565
+ declare function isRateLimitError(error: unknown): error is RateLimitError;
566
+ /**
567
+ * Type guard to check if an error is retryable
568
+ */
569
+ declare function isRetryableError(error: unknown): boolean;
570
+
571
+ export { type ApiErrorResponse, type ApiResponse, AuthenticationError, AuthorizationError, type ExportFormat, type ExportOptions, type ExportResult, type FormatInfo, type GetProjectOptions, type ListProjectsOptions, NetworkError, NotFoundError, type Project, type ProjectResult, type ProjectStatus, type ProjectType, type ProjectsResult, RateLimitError, type RateLimitInfo, type Segment, ServerError, SyynkClient, type SyynkClientOptions, SyynkError, TimeoutError, type TranscribeFileOptions, type TranscribeOptions, type TranscribeResult, ValidationError, type Word, isRateLimitError, isRetryableError, isSyynkError };