Initial Commit

This commit is contained in:
2026-05-27 23:47:53 +01:00
parent fbc70f96e6
commit 9b28db724f
18103 changed files with 1600554 additions and 0 deletions

View File

@@ -0,0 +1,109 @@
# `client`
REST + WebSocket transport for the ElevenLabs platform. `ElevenLabsClient`
exposes typed `fetchJson` / `fetchBinary` / `fetchStream` /
`fetchMultipartJson` / `fetchMultipartBinary` / `openSocket` methods, plus
internal retry-with-exponential-backoff that honours the `Retry-After`
header. Every adapter in the package (`tts`, `stt`, `voices`, …) composes
this single client so authentication, timeouts, retries, and event
emissions live in exactly one place.
<!-- begin:auto-docs -->
_(no submodules)_
<!-- end:auto-docs -->
## Purpose
ElevenLabs offers a sprawling REST + WebSocket API surface. Without a
shared transport, every adapter would duplicate the same error mapping,
header injection, retry policy, and timeout handling. `ElevenLabsClient`
solves that: it's the only piece of code in the package that calls
`fetch`, and the only piece that knows how to map HTTP status codes onto
typed errors. Adapters become thin domain remappers.
## Features
- Five typed request shapes — JSON in/out, JSON in / binary out, JSON in /
streaming out, multipart in / JSON out, multipart in / binary out.
- WebSocket support via `openSocket()` for ElevenLabs's streaming-input
TTS endpoints.
- Built-in retry: exponential backoff (`initialDelay * 2^attempt`) with
`Retry-After` honouring on 429 / 503 / 504 / network errors.
- Per-request `AbortSignal` plus a per-call `timeoutMs` race.
- Optional `LoggerLike` and `EventBusLike` for observability — emits
`request-start`, `request-end`, `retry-attempt`, `rate-limit-hit`.
- Caller-supplied `fetchImpl` and `webSocketImpl` for tests / edge runtimes.
## Usage: Basic Example
```ts
import { ElevenLabsClient } from "@suaveplan/third-party-elevenlabs";
const client = new ElevenLabsClient({ apiKey: process.env.ELEVENLABS_KEY! });
const res = await client.fetchJson<{ voice_id: string }>({
method: "GET",
path: "/v1/voices/abc",
feature: "voices",
operation: "get",
});
console.log(res.body.voice_id, res.metadata.requestId);
```
## Usage: Advanced Example
```ts
import { ElevenLabsClient } from "@suaveplan/third-party-elevenlabs";
const client = new ElevenLabsClient({
apiKey: process.env.ELEVENLABS_KEY!,
baseUrl: "https://eu.api.elevenlabs.io",
timeoutMs: 60_000,
maxRetries: 5,
initialRetryDelayMs: 250,
fetchImpl: customFetch,
events: myBus,
logger: myLogger,
});
const ctrl = new AbortController();
const stream = await client.fetchStream({
method: "POST",
path: "/v1/text-to-speech/voice-id/stream",
feature: "tts",
operation: "synthesize_stream",
body: { text: "hello" },
accept: "audio/mpeg",
signal: ctrl.signal,
});
for await (const chunk of stream.body) {
/* … */
}
```
## API Reference
- `new ElevenLabsClient(options: ElevenLabsClientOptions)` — constructor.
- `fetchJson<TBody>(req: JsonRequest): Promise<JsonResponse<TBody>>`
- `fetchBinary(req: BinaryRequest): Promise<BinaryResponse>`
- `fetchStream(req: StreamRequest): Promise<StreamResponse>`
- `fetchMultipartJson<TBody>(req: MultipartRequest): Promise<JsonResponse<TBody>>`
- `fetchMultipartBinary(req: MultipartRequest): Promise<BinaryResponse>`
- `openSocket(req: SocketRequest): ElevenLabsSocket` — wss connection with
`xi-api-key` injected as a query parameter.
Throws typed `ElevenLabsApiError` subclasses on non-2xx responses.
## Implementation Notes
- `xi-api-key` is sent as a request header for HTTP, but as a query
parameter for WebSocket (browsers can't set headers on the WS upgrade).
- Multipart values may be `Uint8Array | Blob | ReadableStream | URL`;
streams are buffered and URLs are fetched before upload — ElevenLabs
multipart endpoints require complete bodies.
- Retries fire only for `RATE_LIMIT.EXCEEDED`, `SERVER.TRANSIENT`,
`NETWORK.TIMEOUT`, and `NETWORK.UNREACHABLE` codes. Auth and validation
failures are not retried.
- The class delegates error mapping, multipart materialisation, retry
decision, and backoff math to `internals.ts` so the class itself stays
focused on transport orchestration.