first commit

This commit is contained in:
2026-05-29 08:20:56 +01:00
commit 949299f58d
6368 changed files with 527176 additions and 0 deletions

View File

@@ -0,0 +1,143 @@
# @suaveplan/voice-elevenlabs - ElevenLabs domain adapter for @suaveplan/voice: TTS, STT, voice repository, sound effects, and voice isolation engines implemented by delegating to @suaveplan/third-party-elevenlabs.
ElevenLabs domain adapter for the `@suaveplan/voice` interface family.
This package implements every `@suaveplan/voice` engine contract —
`VoiceSynthesizer`, `TranscriptionEngine`, `VoiceRepository`,
`SoundEffectEngine`, `VoiceIsolationEngine` — by delegating to the typed
HTTP/WebSocket transport in `@suaveplan/third-party-elevenlabs`. It owns
DTO ↔ domain mapping, ElevenLabs-specific error remapping into the
`VOICE.*` namespace, multipart/stream plumbing for the voice surface,
and a composite factory that wires every engine against a shared
transport.
<!-- begin:auto-docs -->
## Documentation tree
- [factory](./src/factory/create-elevenlabs-voice.md) — Composition root for the `@suaveplan/voice` engine adapters that target ElevenLabs. One call, one shared transport, fiv…
- [create-elevenlabs-voice](./src/factory/create-elevenlabs-voice.md) — Composition root for the `@suaveplan/voice` engine adapters that target ElevenLabs. One call, one shared transport, fiv…
- [models](./src/models/models.md) — ElevenLabs model catalog. Lists every model the API key has access to, along with capability flags (TTS / voice convers…
- [models](./src/models/models.md) — ElevenLabs model catalog. Lists every model the API key has access to, along with capability flags (TTS / voice convers…
- [sound-effects](./src/sound-effects/sound-effects.md) — ElevenLabs implementation of `@suaveplan/voice`'s `SoundEffectEngine` interface. Posts a JSON body to `POST /v1/sound-g…
- [sound-effects](./src/sound-effects/sound-effects.md) — ElevenLabs implementation of `@suaveplan/voice`'s `SoundEffectEngine` interface. Posts a JSON body to `POST /v1/sound-g…
- [speech-to-speech](./src/speech-to-speech/speech-to-speech.md) — ElevenLabs Speech-to-Speech (voice conversion) adapter. Given source audio and a target `voiceId`, produces audio that…
- [speech-to-speech](./src/speech-to-speech/speech-to-speech.md) — ElevenLabs Speech-to-Speech (voice conversion) adapter. Given source audio and a target `voiceId`, produces audio that…
- [stt](./src/stt/stt.md) — ElevenLabs implementation of `@suaveplan/voice`'s `TranscriptionEngine` interface. Posts the audio as multipart form-da…
- [stt](./src/stt/stt.md) — ElevenLabs implementation of `@suaveplan/voice`'s `TranscriptionEngine` interface. Posts the audio as multipart form-da…
- [tts](./src/tts/tts.md) — ElevenLabs implementation of `@suaveplan/voice`'s `VoiceSynthesizer` interface. Posts to `/v1/text-to-speech/{voice_id}…
- [tts](./src/tts/tts.md) — ElevenLabs implementation of `@suaveplan/voice`'s `VoiceSynthesizer` interface. Posts to `/v1/text-to-speech/{voice_id}…
- [voice-isolation](./src/voice-isolation/voice-isolation.md) — ElevenLabs implementation of `@suaveplan/voice`'s `VoiceIsolationEngine` interface. Posts the audio as multipart form-d…
- [voice-isolation](./src/voice-isolation/voice-isolation.md) — ElevenLabs implementation of `@suaveplan/voice`'s `VoiceIsolationEngine` interface. Posts the audio as multipart form-d…
- [voices](./src/voices/voices.md) — ElevenLabs implementation of `@suaveplan/voice`'s `VoiceRepository` interface. Lists voices via `GET /v1/voices` and lo…
- [voices](./src/voices/voices.md) — ElevenLabs implementation of `@suaveplan/voice`'s `VoiceRepository` interface. Lists voices via `GET /v1/voices` and lo…
<!-- end:auto-docs -->
## Install
```sh
bun add @suaveplan/voice-elevenlabs @suaveplan/voice
```
## Quick start
```ts
import { createElevenLabsVoice } from "@suaveplan/voice-elevenlabs";
const { tts, voices } = createElevenLabsVoice({
apiKey: process.env.ELEVENLABS_KEY!,
});
const all = await voices.list();
const result = await tts.synthesize({
text: "hello",
voiceId: all.voices[0]!.id,
});
```
## Modules
| Subpath | Engine | `@suaveplan/voice` contract |
| --- | --- | --- |
| `./tts/tts` | `ElevenLabsVoiceSynthesizer` | `VoiceSynthesizer` |
| `./stt/stt` | `ElevenLabsTranscriptionEngine` | `TranscriptionEngine` |
| `./voices/voices` | `ElevenLabsVoiceRepository` | `VoiceRepository` |
| `./sound-effects/sound-effects` | `ElevenLabsSoundEffectEngine` | `SoundEffectEngine` |
| `./voice-isolation/voice-isolation` | `ElevenLabsVoiceIsolationEngine` | `VoiceIsolationEngine` |
| `./factory/create-elevenlabs-voice` | `createElevenLabsVoice` | bundle factory |
## Composing with other ElevenLabs surfaces
The factory accepts a pre-constructed `ElevenLabsClient` from
`@suaveplan/third-party-elevenlabs` so the same transport (with its
retry, rate-limit, OTel, base URL, and event-bus configuration) can be
shared with ElevenLabs-specific surfaces that are *not* part of the
voice domain — for example the model catalogue or the
speech-to-speech (voice-conversion) endpoint:
```ts
import {
ElevenLabsClient,
ElevenLabsModelCatalog,
ElevenLabsSpeechToSpeech,
} from "@suaveplan/third-party-elevenlabs";
import { createElevenLabsVoice } from "@suaveplan/voice-elevenlabs";
const client = new ElevenLabsClient({
apiKey: process.env.ELEVENLABS_KEY!,
baseUrl: "https://eu.api.elevenlabs.io",
});
const voice = createElevenLabsVoice({ client });
const models = new ElevenLabsModelCatalog(client);
const s2s = new ElevenLabsSpeechToSpeech(client);
```
## Error remapping
Every `ElevenLabsApiError` subclass raised by the underlying transport
is remapped into a `VoiceError` from `@suaveplan/voice`, preserving the
original via `.cause`. The full table is documented inline at the call
sites; a representative subset:
| Third-party error | Voice domain error |
| --- | --- |
| `UnauthorizedError`, `ForbiddenError` | `ProviderNotConfiguredError` |
| `RequestNotFoundError` (from `voices.get`) | resolves to `null` (no throw) |
| `RequestValidationFailedError`, `RequestInvalidError` | `VoiceValidationError` |
| `RateLimitExceededError`, `RateLimitQuotaExhaustedError` | `ProviderRateLimitedError` (with `retryAfterMs`) |
| `ServerTransientError` / `ServerUnavailableError` (TTS) | `TtsSynthesisFailedError` |
| `ServerTransientError` (STT) | `SttTranscriptionFailedError` |
| `StreamInterruptedError` | `TtsStreamInterruptedError` |
| `ResponseUnsupportedFormatError` | `AudioFormatUnsupportedError` |
`voices.get(voiceId)` follows the `VoiceRepository` null-on-not-found
contract: any upstream 404 is mapped to `null` rather than thrown.
## Architecture
```
@suaveplan/voice abstract engine interfaces
▲
│ implements
│
@suaveplan/voice-elevenlabs domain adapter (this package)
│
│ delegates HTTP / WebSocket / multipart
▼
@suaveplan/third-party-elevenlabs typed transport, retry, OTel,
rate-limit headers, raw DTOs
```
Future ElevenLabs surfaces (music, dubbing, conversational AI) compose
against the same `@suaveplan/third-party-elevenlabs` client; they do not
fan out from this package. This keeps each surface's domain-mapping
concerns isolated.
## Verification
```sh
bunx turbo lint typecheck test --filter=@suaveplan/voice-elevenlabs
bunx turbo test:coverage --filter=@suaveplan/voice-elevenlabs
```
Coverage gate: 100/100/100/100 statements/branches/functions/lines.