Files
2026-05-27 23:47:53 +01:00
..
2026-05-27 23:47:53 +01:00
2026-05-27 23:47:53 +01:00
2026-05-27 23:47:53 +01:00
2026-05-27 23:47:53 +01:00
2026-05-27 23:47:53 +01:00
2026-05-27 23:47:53 +01:00
2026-05-27 23:47:53 +01:00

@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.

Documentation tree

  • factory — Composition root for the @suaveplan/voice engine adapters that target ElevenLabs. One call, one shared transport, fiv…
    • create-elevenlabs-voice — Composition root for the @suaveplan/voice engine adapters that target ElevenLabs. One call, one shared transport, fiv…
  • models — ElevenLabs model catalog. Lists every model the API key has access to, along with capability flags (TTS / voice convers…
    • models — ElevenLabs model catalog. Lists every model the API key has access to, along with capability flags (TTS / voice convers…
  • sound-effects — ElevenLabs implementation of @suaveplan/voice's SoundEffectEngine interface. Posts a JSON body to `POST /v1/sound-g…
    • sound-effects — ElevenLabs implementation of @suaveplan/voice's SoundEffectEngine interface. Posts a JSON body to `POST /v1/sound-g…
  • speech-to-speech — ElevenLabs Speech-to-Speech (voice conversion) adapter. Given source audio and a target voiceId, produces audio that…
    • speech-to-speech — ElevenLabs Speech-to-Speech (voice conversion) adapter. Given source audio and a target voiceId, produces audio that…
  • stt — ElevenLabs implementation of @suaveplan/voice's TranscriptionEngine interface. Posts the audio as multipart form-da…
    • stt — ElevenLabs implementation of @suaveplan/voice's TranscriptionEngine interface. Posts the audio as multipart form-da…
  • tts — ElevenLabs implementation of @suaveplan/voice's VoiceSynthesizer interface. Posts to `/v1/text-to-speech/{voice_id}…
    • tts — ElevenLabs implementation of @suaveplan/voice's VoiceSynthesizer interface. Posts to `/v1/text-to-speech/{voice_id}…
  • voice-isolation — ElevenLabs implementation of @suaveplan/voice's VoiceIsolationEngine interface. Posts the audio as multipart form-d…
    • voice-isolation — ElevenLabs implementation of @suaveplan/voice's VoiceIsolationEngine interface. Posts the audio as multipart form-d…
  • voices — ElevenLabs implementation of @suaveplan/voice's VoiceRepository interface. Lists voices via GET /v1/voices and lo…
    • voices — ElevenLabs implementation of @suaveplan/voice's VoiceRepository interface. Lists voices via GET /v1/voices and lo…

Install

bun add @suaveplan/voice-elevenlabs @suaveplan/voice

Quick start

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:

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

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.