first commit
This commit is contained in:
148
docs/media/audio/third-party-elevenlabs/src/errors/errors.md
Normal file
148
docs/media/audio/third-party-elevenlabs/src/errors/errors.md
Normal file
@@ -0,0 +1,148 @@
|
||||
# `errors`
|
||||
|
||||
Stable error class hierarchy and code registry for
|
||||
`@suaveplan/third-party-elevenlabs`. Every non-2xx HTTP response and every
|
||||
transport-level failure maps to one of 17 typed `ElevenLabsApiError`
|
||||
subclasses under namespace `THIRD_PARTY_ELEVENLABS.*`.
|
||||
|
||||
<!-- begin:auto-docs -->
|
||||
_(no submodules)_
|
||||
<!-- end:auto-docs -->
|
||||
|
||||
## Purpose
|
||||
|
||||
The ElevenLabs API surface is large and surfaces failures across HTTP status
|
||||
codes, malformed JSON bodies, transport timeouts, and WebSocket protocol
|
||||
errors. Without a stable error hierarchy, every consumer of this client
|
||||
would have to learn the upstream's quirks. This module defines the
|
||||
canonical 17-code surface so callers can branch on `error.code` or
|
||||
`error instanceof RateLimitExceededError` without touching the wire.
|
||||
|
||||
The mapping is total and disjoint over the `[400, 600)` HTTP range, every
|
||||
documented network failure mode, every JSON / Zod parse failure, and the
|
||||
two WebSocket failure modes (handshake / protocol). Every error preserves
|
||||
the original cause via the cause-chain on `SuaveplanError`.
|
||||
|
||||
## Features
|
||||
|
||||
- 17 error codes registered via `defineCodes('THIRD_PARTY_ELEVENLABS', ...)`.
|
||||
- 17 typed subclasses, one per code, with sensible default messages.
|
||||
- Convenience options surface common transport context:
|
||||
- `RateLimitExceededError({ retryAfterMs })` — retries planning.
|
||||
- `RequestValidationFailedError({ body })` — preserved 422 body.
|
||||
- `WebSocketConnectionFailedError({ code })` — close code.
|
||||
- `NetworkTimeoutError({ timeoutMs })` — observed limit.
|
||||
- Every HTTP error accepts `{ endpoint, statusCode, requestId }`.
|
||||
- Caller-supplied `context` is shallow-merged on top of derived context so
|
||||
adapter packages can layer their own attribution (e.g. `tenantId`).
|
||||
|
||||
## Usage: Basic Example
|
||||
|
||||
```ts
|
||||
import {
|
||||
ElevenLabsApiError,
|
||||
RateLimitExceededError,
|
||||
} from "@suaveplan/third-party-elevenlabs/errors/errors";
|
||||
|
||||
try {
|
||||
await client.fetchJson(req, schema);
|
||||
} catch (err) {
|
||||
if (err instanceof RateLimitExceededError) {
|
||||
console.log(`retry after ${err.context?.retryAfterMs ?? "unknown"} ms`);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Usage: Advanced Example
|
||||
|
||||
Branch on every documented failure mode and re-throw with adapter context:
|
||||
|
||||
```ts
|
||||
import {
|
||||
ElevenLabsApiError,
|
||||
ELEVENLABS_CODES,
|
||||
} from "@suaveplan/third-party-elevenlabs/errors/errors";
|
||||
|
||||
function handleFailure(err: unknown): never {
|
||||
if (!(err instanceof ElevenLabsApiError)) throw err;
|
||||
switch (err.code) {
|
||||
case ELEVENLABS_CODES["AUTH.UNAUTHORIZED"]:
|
||||
case ELEVENLABS_CODES["AUTH.FORBIDDEN"]:
|
||||
throw new ProviderNotConfiguredError({ cause: err });
|
||||
case ELEVENLABS_CODES["RATE_LIMIT.EXCEEDED"]:
|
||||
case ELEVENLABS_CODES["RATE_LIMIT.QUOTA_EXHAUSTED"]:
|
||||
throw new ProviderRateLimitedError({
|
||||
retryAfterMs: err.context?.retryAfterMs as number | undefined,
|
||||
cause: err,
|
||||
});
|
||||
default:
|
||||
throw new TtsSynthesisFailedError({ cause: err });
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## API Reference
|
||||
|
||||
- `ELEVENLABS_CODES` — frozen record `{ "<reason>":
|
||||
"THIRD_PARTY_ELEVENLABS.<reason>" }`.
|
||||
- `ElevenLabsErrorCode` — TypeScript union of every code value.
|
||||
- `ElevenLabsApiError` — abstract base extending `SuaveplanError`.
|
||||
|
||||
Auth + request errors:
|
||||
|
||||
- `UnauthorizedError({ endpoint?, statusCode?, requestId?, ...base })` —
|
||||
`AUTH.UNAUTHORIZED` (HTTP 401).
|
||||
- `ForbiddenError(...)` — `AUTH.FORBIDDEN` (HTTP 403).
|
||||
- `RequestInvalidError(...)` — `REQUEST.INVALID` (other 4xx).
|
||||
- `RequestValidationFailedError({ body?, ...request })` —
|
||||
`REQUEST.VALIDATION_FAILED` (HTTP 422); body preserved verbatim.
|
||||
- `RequestNotFoundError(...)` — `REQUEST.NOT_FOUND` (HTTP 404).
|
||||
|
||||
Rate limit:
|
||||
|
||||
- `RateLimitExceededError({ retryAfterMs?, ...request })` —
|
||||
`RATE_LIMIT.EXCEEDED` (HTTP 429).
|
||||
- `RateLimitQuotaExhaustedError(...)` — `RATE_LIMIT.QUOTA_EXHAUSTED`.
|
||||
|
||||
Server:
|
||||
|
||||
- `ServerTransientError(...)` — `SERVER.TRANSIENT` (retryable 5xx).
|
||||
- `ServerUnavailableError(...)` — `SERVER.UNAVAILABLE` (non-retryable / circuit-open).
|
||||
|
||||
Network:
|
||||
|
||||
- `NetworkTimeoutError({ endpoint?, timeoutMs?, ...base })` —
|
||||
`NETWORK.TIMEOUT`.
|
||||
- `NetworkAbortedError({ endpoint?, ...base })` — `NETWORK.ABORTED`.
|
||||
- `NetworkUnreachableError({ endpoint?, ...base })` — `NETWORK.UNREACHABLE`.
|
||||
|
||||
Response / stream:
|
||||
|
||||
- `ResponseMalformedError({ endpoint?, bodyPreview?, ...base })` —
|
||||
`RESPONSE.MALFORMED`.
|
||||
- `ResponseUnsupportedFormatError({ contentType?, ...base })` —
|
||||
`RESPONSE.UNSUPPORTED_FORMAT`.
|
||||
- `StreamInterruptedError(...)` — `STREAM.INTERRUPTED`.
|
||||
|
||||
WebSocket:
|
||||
|
||||
- `WebSocketConnectionFailedError({ code?, ...base })` —
|
||||
`WEBSOCKET.CONNECTION_FAILED`.
|
||||
- `WebSocketProtocolError({ code?, ...base })` — `WEBSOCKET.PROTOCOL`.
|
||||
|
||||
Every constructor accepts `{ message?, cause?, context?, traceId? }`.
|
||||
|
||||
## Implementation Notes
|
||||
|
||||
- The 17 codes partition `[400, 600)` HTTP statuses plus three networking
|
||||
modes plus three response / stream modes plus two WebSocket modes. The
|
||||
client never throws a generic `ElevenLabsApiError` — every thrown error
|
||||
is one of the typed subclasses.
|
||||
- `RequestValidationFailedError.body` should be the **parsed** JSON body
|
||||
(truncated to a reasonable bound by the client — currently 4 KB; see
|
||||
`client.ts`). Never put raw network buffers here.
|
||||
- `bodyPreview` on `ResponseMalformedError` is a short string (≤ 256
|
||||
bytes) suitable for logs. Adapters should not re-serialise the full body
|
||||
into context.
|
||||
- All subclasses default to a stable English message. Localisation flows
|
||||
through `MessageResolver` on `@suaveplan/error`.
|
||||
Reference in New Issue
Block a user