@effect-uai/elevenlabs 0.17.0 → 0.19.0-dev-20261109183959

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.
Files changed (59) hide show
  1. package/dist/ElevenLabsMusicGenerator.d.mts +1 -1
  2. package/dist/ElevenLabsMusicGenerator.mjs +1 -1
  3. package/dist/ElevenLabsMusicGenerator.mjs.map +1 -1
  4. package/dist/ElevenLabsMusicGenerator.test.mjs +3 -3
  5. package/dist/ElevenLabsMusicGenerator.test.mjs.map +1 -1
  6. package/dist/ElevenLabsSynthesizer.d.mts +2 -2
  7. package/dist/ElevenLabsSynthesizer.mjs +2 -2
  8. package/dist/ElevenLabsSynthesizer.mjs.map +1 -1
  9. package/dist/ElevenLabsTranscriber.d.mts +2 -2
  10. package/dist/ElevenLabsTranscriber.mjs +2 -2
  11. package/dist/ElevenLabsTranscriber.mjs.map +1 -1
  12. package/dist/ElevenLabsTranscriber.test.mjs +4 -4
  13. package/dist/ElevenLabsTranscriber.test.mjs.map +1 -1
  14. package/dist/codec.d.mts +1 -1
  15. package/dist/codec.d.mts.map +1 -1
  16. package/dist/codec.mjs +3 -2
  17. package/dist/codec.mjs.map +1 -1
  18. package/dist/codec.test.mjs +4 -3
  19. package/dist/codec.test.mjs.map +1 -1
  20. package/dist/dist-BFhPS-q4.mjs +190 -0
  21. package/dist/dist-BFhPS-q4.mjs.map +1 -0
  22. package/dist/dist-DHer1cql.mjs +1533 -0
  23. package/dist/dist-DHer1cql.mjs.map +1 -0
  24. package/dist/dist-DkEvSNwD.mjs +7 -0
  25. package/dist/dist-DkEvSNwD.mjs.map +1 -0
  26. package/dist/{test.DNmyFkvJ-N3QqMRwZ.mjs → index.C4tKZ0yW-DjxCdpW_.mjs} +9524 -5893
  27. package/dist/index.C4tKZ0yW-DjxCdpW_.mjs.map +1 -0
  28. package/dist/realtimeStt.d.mts +2 -2
  29. package/dist/realtimeStt.d.mts.map +1 -1
  30. package/dist/realtimeStt.mjs +19 -15
  31. package/dist/realtimeStt.mjs.map +1 -1
  32. package/dist/realtimeStt.test.d.mts +1 -0
  33. package/dist/realtimeStt.test.mjs +80 -0
  34. package/dist/realtimeStt.test.mjs.map +1 -0
  35. package/dist/realtimeTts.d.mts +1 -1
  36. package/dist/realtimeTts.d.mts.map +1 -1
  37. package/dist/realtimeTts.mjs +20 -18
  38. package/dist/realtimeTts.mjs.map +1 -1
  39. package/dist/realtimeTts.test.d.mts +1 -0
  40. package/dist/realtimeTts.test.mjs +59 -0
  41. package/dist/realtimeTts.test.mjs.map +1 -0
  42. package/dist/region.test.mjs +1 -1
  43. package/package.json +5 -5
  44. package/src/ElevenLabsMusicGenerator.test.ts +1 -1
  45. package/src/ElevenLabsMusicGenerator.ts +1 -1
  46. package/src/ElevenLabsSynthesizer.ts +2 -2
  47. package/src/ElevenLabsTranscriber.test.ts +2 -2
  48. package/src/ElevenLabsTranscriber.ts +2 -2
  49. package/src/codec.test.ts +3 -2
  50. package/src/codec.ts +4 -3
  51. package/src/realtimeStt.test.ts +92 -0
  52. package/src/realtimeStt.ts +28 -38
  53. package/src/realtimeTts.test.ts +72 -0
  54. package/src/realtimeTts.ts +38 -39
  55. package/dist/dist-C0AvqZTC.mjs +0 -145
  56. package/dist/dist-C0AvqZTC.mjs.map +0 -1
  57. package/dist/magic-string.es-CUAnjKYC.mjs +0 -1014
  58. package/dist/magic-string.es-CUAnjKYC.mjs.map +0 -1
  59. package/dist/test.DNmyFkvJ-N3QqMRwZ.mjs.map +0 -1
@@ -2,7 +2,7 @@ import { ElevenLabsMusicModel } from "./models.mjs";
2
2
  import { t as ElevenLabsCompositionPlan } from "./musicCodec-DjmvNC4W.mjs";
3
3
  import { ElevenLabsRegion } from "./region.mjs";
4
4
  import { Context, Duration, Effect, Layer, Redacted, Stream } from "effect";
5
- import { HttpClient } from "effect/unstable/http";
5
+ import { HttpClient } from "effect/http";
6
6
  import { CommonGenerateMusicRequest, CommonStreamGenerateMusicRequest, GenerateResult, MusicSessionInput, MusicStreamEvent } from "@effect-uai/core/Music";
7
7
  import { MusicGenerator } from "@effect-uai/core/MusicGenerator";
8
8
  import * as AiError from "@effect-uai/core/AiError";
@@ -3,7 +3,7 @@ import { defaultFormat, formatToOutputSlug } from "./codec.mjs";
3
3
  import { decodeCompositionPlan, warnDroppedPromptModeHints, wireCompositionPlan } from "./musicCodec.mjs";
4
4
  import { resolveHost } from "./region.mjs";
5
5
  import { Context, Duration, Effect, Layer, Redacted, Stream } from "effect";
6
- import { HttpClient, HttpClientRequest } from "effect/unstable/http";
6
+ import { HttpClient, HttpClientRequest } from "effect/http";
7
7
  import { singleVariant } from "@effect-uai/core/Music";
8
8
  import { MusicGenerator } from "@effect-uai/core/MusicGenerator";
9
9
  import * as AiError from "@effect-uai/core/AiError";
@@ -1 +1 @@
1
- {"version":3,"file":"ElevenLabsMusicGenerator.mjs","names":[],"sources":["../src/ElevenLabsMusicGenerator.ts"],"sourcesContent":["import { Context, Duration, Effect, Layer, Redacted, Stream } from \"effect\"\nimport { HttpClient, HttpClientRequest } from \"effect/unstable/http\"\nimport * as AiError from \"@effect-uai/core/AiError\"\nimport type { AudioChunk, AudioFormat } from \"@effect-uai/core/Audio\"\nimport type {\n CommonGenerateMusicRequest,\n CommonStreamGenerateMusicRequest,\n GenerateResult,\n MusicResult,\n MusicSessionInput,\n MusicStreamEvent,\n} from \"@effect-uai/core/Music\"\nimport { singleVariant } from \"@effect-uai/core/Music\"\nimport { MusicGenerator, type MusicGeneratorService } from \"@effect-uai/core/MusicGenerator\"\nimport { defaultFormat, formatToOutputSlug } from \"./codec.js\"\nimport type { ElevenLabsMusicModel } from \"./models.js\"\nimport {\n decodeCompositionPlan,\n type ElevenLabsCompositionPlan,\n warnDroppedPromptModeHints,\n wireCompositionPlan,\n} from \"./musicCodec.js\"\nimport { type ElevenLabsRegion, resolveHost } from \"./region.js\"\n\n// ---------------------------------------------------------------------------\n// Public types\n// ---------------------------------------------------------------------------\n\n/**\n * ElevenLabs-typed music request. Narrows `model` to\n * `ElevenLabsMusicModel` and adds provider-specific extras:\n *\n * - `compositionPlan` — switch from prompt mode to plan mode. Mutually\n * exclusive with `prompt` on the wire.\n * - `forceInstrumental` — skip vocals. ElevenLabs has no `instrumental`\n * on the cross-provider Common request (the field was removed in\n * v0.7 because it has wildly different semantics per provider); the\n * typed surface restores it.\n * - `signWithC2pa` — opt-in C2PA Content Credentials, MP3 output only.\n * - `respectSectionsDurations` — composition-plan mode only. False\n * trades section-duration accuracy for quality + latency.\n *\n * Setting `compositionPlan` with a non-empty `prompt`, or with\n * `duration`, fails `InvalidRequest` at the codec layer.\n */\nexport type ElevenLabsMusicGenerateRequest = Omit<CommonGenerateMusicRequest, \"model\"> & {\n readonly model?: ElevenLabsMusicModel\n readonly compositionPlan?: ElevenLabsCompositionPlan\n readonly forceInstrumental?: boolean\n readonly signWithC2pa?: boolean\n readonly respectSectionsDurations?: boolean\n}\n\nexport type CreateCompositionPlanRequest = {\n readonly prompt: string\n readonly duration?: Duration.Duration\n readonly sourceCompositionPlan?: ElevenLabsCompositionPlan\n readonly model?: ElevenLabsMusicModel\n}\n\nexport type ElevenLabsMusicGeneratorService = {\n readonly generate: (\n request: ElevenLabsMusicGenerateRequest,\n ) => Effect.Effect<GenerateResult, AiError.AiError>\n readonly streamGeneration: (\n request: ElevenLabsMusicGenerateRequest,\n ) => Stream.Stream<AudioChunk, AiError.AiError>\n readonly streamGenerationFrom: <E, R>(\n input: Stream.Stream<MusicSessionInput, E, R>,\n request: CommonStreamGenerateMusicRequest,\n ) => Stream.Stream<MusicStreamEvent, AiError.AiError | E, R>\n /**\n * Free endpoint (rate-limited, no credit cost): turn a prompt into a\n * structured `MusicPrompt` plan. Feed the result back into\n * `generate` / `streamGeneration` via `compositionPlan`.\n */\n readonly createCompositionPlan: (\n request: CreateCompositionPlanRequest,\n ) => Effect.Effect<ElevenLabsCompositionPlan, AiError.AiError>\n}\n\nexport class ElevenLabsMusicGenerator extends Context.Service<\n ElevenLabsMusicGenerator,\n ElevenLabsMusicGeneratorService\n>()(\"@betalyra/effect-uai/providers/elevenlabs/ElevenLabsMusicGenerator\") {}\n\nexport type Config = {\n readonly apiKey: Redacted.Redacted\n readonly baseUrl?: string\n readonly region?: ElevenLabsRegion\n}\n\nconst DEFAULT_MODEL: ElevenLabsMusicModel = \"music_v1\"\n\n// ---------------------------------------------------------------------------\n// HTTP errors (music namespace; reuses the same status taxonomy)\n// ---------------------------------------------------------------------------\n\nconst musicTransportFailure = (cause: unknown): AiError.AiError =>\n new AiError.Unavailable({ provider: \"elevenlabs-music\", raw: cause })\n\nconst musicHttpStatusError = (status: number, body: string): AiError.AiError => {\n if (status === 429) return new AiError.RateLimited({ provider: \"elevenlabs-music\", raw: body })\n if (status === 408 || status === 504)\n return new AiError.Timeout({ provider: \"elevenlabs-music\", raw: body })\n if (status === 401)\n return new AiError.AuthFailed({ provider: \"elevenlabs-music\", subtype: \"auth\", raw: body })\n if (status === 403)\n return new AiError.AuthFailed({\n provider: \"elevenlabs-music\",\n subtype: \"permission\",\n raw: body,\n })\n if (status === 402)\n return new AiError.AuthFailed({\n provider: \"elevenlabs-music\",\n subtype: \"billing\",\n raw: body,\n })\n if (status >= 500)\n return new AiError.Unavailable({ provider: \"elevenlabs-music\", status, raw: body })\n return new AiError.InvalidRequest({ provider: \"elevenlabs-music\", raw: body })\n}\n\n// ---------------------------------------------------------------------------\n// Wire body\n// ---------------------------------------------------------------------------\n\n/**\n * Build the JSON body for `/v1/music` (sync + stream share the body).\n *\n * Mutual exclusion: `compositionPlan` and prompt-mode fields cannot\n * coexist. When `compositionPlan` is set, `prompt` must be empty and\n * `duration` must be unset (section durations live on the plan).\n */\nconst buildBody = (request: ElevenLabsMusicGenerateRequest) =>\n Effect.gen(function* () {\n const model = request.model ?? DEFAULT_MODEL\n if (request.compositionPlan !== undefined) {\n if (request.prompt.length > 0) {\n return yield* Effect.fail(\n new AiError.InvalidRequest({\n provider: \"elevenlabs-music\",\n param: \"prompt\",\n raw: \"`prompt` and `compositionPlan` are mutually exclusive. Pass one or the other (compositionPlan carries its own per-section lyrics and styles).\",\n }),\n )\n }\n if (request.duration !== undefined) {\n return yield* Effect.fail(\n new AiError.InvalidRequest({\n provider: \"elevenlabs-music\",\n param: \"duration\",\n raw: \"`duration` is ignored when `compositionPlan` is set; section durations live on the plan. Remove `duration`.\",\n }),\n )\n }\n return {\n composition_plan: wireCompositionPlan(request.compositionPlan),\n model_id: model,\n ...(request.seed !== undefined && { seed: request.seed }),\n ...(request.forceInstrumental !== undefined && {\n force_instrumental: request.forceInstrumental,\n }),\n ...(request.respectSectionsDurations !== undefined && {\n respect_sections_durations: request.respectSectionsDurations,\n }),\n ...(request.signWithC2pa !== undefined && { sign_with_c2pa: request.signWithC2pa }),\n }\n }\n yield* warnDroppedPromptModeHints(request as CommonGenerateMusicRequest)\n return {\n prompt: request.prompt,\n model_id: model,\n ...(request.duration !== undefined && {\n music_length_ms: Duration.toMillis(request.duration),\n }),\n ...(request.seed !== undefined && { seed: request.seed }),\n ...(request.forceInstrumental !== undefined && {\n force_instrumental: request.forceInstrumental,\n }),\n ...(request.signWithC2pa !== undefined && { sign_with_c2pa: request.signWithC2pa }),\n }\n })\n\nconst buildMusicHttpRequest = (\n cfg: Config,\n request: ElevenLabsMusicGenerateRequest,\n path: \"\" | \"/stream\",\n) =>\n Effect.gen(function* () {\n const format: AudioFormat = request.outputFormat ?? defaultFormat\n const slug = yield* formatToOutputSlug(format)\n const body = yield* buildBody(request)\n const url = `${resolveHost(cfg)}/music${path}?output_format=${slug}`\n const httpRequest = HttpClientRequest.post(url).pipe(\n HttpClientRequest.setHeader(\"xi-api-key\", Redacted.value(cfg.apiKey)),\n HttpClientRequest.bodyJsonUnsafe(body),\n )\n return { httpRequest, format }\n })\n\n// ---------------------------------------------------------------------------\n// Service implementation\n// ---------------------------------------------------------------------------\n\nconst generateImpl =\n (cfg: Config) =>\n (\n request: ElevenLabsMusicGenerateRequest,\n ): Effect.Effect<GenerateResult, AiError.AiError, HttpClient.HttpClient> =>\n Effect.gen(function* () {\n const client = yield* HttpClient.HttpClient\n const { httpRequest, format } = yield* buildMusicHttpRequest(cfg, request, \"\")\n const response = yield* client\n .execute(httpRequest)\n .pipe(Effect.mapError(musicTransportFailure))\n if (response.status >= 400) {\n const text = yield* response.text.pipe(Effect.orElseSucceed(() => \"\"))\n return yield* Effect.fail(musicHttpStatusError(response.status, text))\n }\n const buffer = yield* response.arrayBuffer.pipe(Effect.mapError(musicTransportFailure))\n const bytes = new Uint8Array(buffer)\n const songId = response.headers[\"song_id\"] ?? response.headers[\"x-song-id\"]\n const result: MusicResult = {\n audio: { format, bytes },\n provider: \"elevenlabs-music\",\n ...(typeof songId === \"string\" && { songId }),\n ...(request.signWithC2pa === true && { watermark: \"c2pa\" as const }),\n }\n return singleVariant(result)\n })\n\nconst streamGenerationImpl =\n (cfg: Config) =>\n (\n request: ElevenLabsMusicGenerateRequest,\n ): Stream.Stream<AudioChunk, AiError.AiError, HttpClient.HttpClient> =>\n Stream.unwrap(\n Effect.gen(function* () {\n const client = yield* HttpClient.HttpClient\n const { httpRequest } = yield* buildMusicHttpRequest(cfg, request, \"/stream\")\n const response = yield* client\n .execute(httpRequest)\n .pipe(Effect.mapError(musicTransportFailure))\n if (response.status >= 400) {\n const text = yield* response.text.pipe(Effect.orElseSucceed(() => \"\"))\n return Stream.fail(musicHttpStatusError(response.status, text))\n }\n return response.stream.pipe(\n Stream.mapError(musicTransportFailure),\n Stream.map((bytes): AudioChunk => ({ bytes })),\n )\n }),\n )\n\n/**\n * ElevenLabs music has no bidirectional session at the wire level.\n * Layer does not register `MusicInteractiveSession`, so callers using\n * `MusicGenerator.streamGenerationFrom` get a compile-time error\n * before this runtime fallback fires.\n */\nconst streamGenerationFromUnsupported = <E, R>(\n _input: Stream.Stream<MusicSessionInput, E, R>,\n _request: CommonStreamGenerateMusicRequest,\n): Stream.Stream<MusicStreamEvent, AiError.AiError | E, R> =>\n Stream.fail(\n new AiError.Unsupported({\n provider: \"elevenlabs-music\",\n capability: \"streamGenerationFrom\",\n reason:\n \"ElevenLabs music has no bidirectional session. Use `streamGeneration` for chunked output, or `createCompositionPlan` + `generate` for structured plans.\",\n }),\n )\n\nconst createCompositionPlanImpl =\n (cfg: Config) =>\n (\n request: CreateCompositionPlanRequest,\n ): Effect.Effect<ElevenLabsCompositionPlan, AiError.AiError, HttpClient.HttpClient> =>\n Effect.gen(function* () {\n const client = yield* HttpClient.HttpClient\n const body = {\n prompt: request.prompt,\n model_id: request.model ?? DEFAULT_MODEL,\n ...(request.duration !== undefined && {\n music_length_ms: Duration.toMillis(request.duration),\n }),\n ...(request.sourceCompositionPlan !== undefined && {\n source_composition_plan: wireCompositionPlan(request.sourceCompositionPlan),\n }),\n }\n const httpRequest = HttpClientRequest.post(`${resolveHost(cfg)}/music/plan`).pipe(\n HttpClientRequest.setHeader(\"xi-api-key\", Redacted.value(cfg.apiKey)),\n HttpClientRequest.bodyJsonUnsafe(body),\n )\n const response = yield* client\n .execute(httpRequest)\n .pipe(Effect.mapError(musicTransportFailure))\n if (response.status >= 400) {\n const text = yield* response.text.pipe(Effect.orElseSucceed(() => \"\"))\n return yield* Effect.fail(musicHttpStatusError(response.status, text))\n }\n const json = yield* response.json.pipe(Effect.mapError(musicTransportFailure))\n return decodeCompositionPlan(json)\n })\n\n// ---------------------------------------------------------------------------\n// Constructors\n// ---------------------------------------------------------------------------\n\nexport const make = (\n cfg: Config,\n): Effect.Effect<ElevenLabsMusicGeneratorService, never, HttpClient.HttpClient> =>\n Effect.map(HttpClient.HttpClient, (client) => ({\n generate: (request) =>\n generateImpl(cfg)(request).pipe(Effect.provideService(HttpClient.HttpClient, client)),\n streamGeneration: (request) =>\n streamGenerationImpl(cfg)(request).pipe(Stream.provideService(HttpClient.HttpClient, client)),\n streamGenerationFrom: streamGenerationFromUnsupported,\n createCompositionPlan: (request) =>\n createCompositionPlanImpl(cfg)(request).pipe(\n Effect.provideService(HttpClient.HttpClient, client),\n ),\n }))\n\n/**\n * Layer that registers the provider-specific `ElevenLabsMusicGenerator`\n * tag and the generic `MusicGenerator` tag.\n *\n * Does NOT register `MusicInteractiveSession`. ElevenLabs music has no\n * bidirectional wire endpoint; `streamGenerationFrom` against this\n * Layer alone fails to typecheck.\n */\nexport const layer = (\n cfg: Config,\n): Layer.Layer<ElevenLabsMusicGenerator | MusicGenerator, never, HttpClient.HttpClient> =>\n Layer.merge(\n Layer.effect(ElevenLabsMusicGenerator, make(cfg)),\n Layer.effect(\n MusicGenerator,\n Effect.map(make(cfg), (s): MusicGeneratorService => ({\n generate: (req: CommonGenerateMusicRequest) =>\n s.generate({ ...req, model: req.model as ElevenLabsMusicModel }),\n streamGeneration: (req: CommonStreamGenerateMusicRequest) =>\n s.streamGeneration({ ...req, model: req.model as ElevenLabsMusicModel }),\n streamGenerationFrom: s.streamGenerationFrom,\n })),\n ),\n )\n"],"mappings":"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"}
1
+ {"version":3,"file":"ElevenLabsMusicGenerator.mjs","names":[],"sources":["../src/ElevenLabsMusicGenerator.ts"],"sourcesContent":["import { Context, Duration, Effect, Layer, Redacted, Stream } from \"effect\"\nimport { HttpClient, HttpClientRequest } from \"effect/http\"\nimport * as AiError from \"@effect-uai/core/AiError\"\nimport type { AudioChunk, AudioFormat } from \"@effect-uai/core/Audio\"\nimport type {\n CommonGenerateMusicRequest,\n CommonStreamGenerateMusicRequest,\n GenerateResult,\n MusicResult,\n MusicSessionInput,\n MusicStreamEvent,\n} from \"@effect-uai/core/Music\"\nimport { singleVariant } from \"@effect-uai/core/Music\"\nimport { MusicGenerator, type MusicGeneratorService } from \"@effect-uai/core/MusicGenerator\"\nimport { defaultFormat, formatToOutputSlug } from \"./codec.js\"\nimport type { ElevenLabsMusicModel } from \"./models.js\"\nimport {\n decodeCompositionPlan,\n type ElevenLabsCompositionPlan,\n warnDroppedPromptModeHints,\n wireCompositionPlan,\n} from \"./musicCodec.js\"\nimport { type ElevenLabsRegion, resolveHost } from \"./region.js\"\n\n// ---------------------------------------------------------------------------\n// Public types\n// ---------------------------------------------------------------------------\n\n/**\n * ElevenLabs-typed music request. Narrows `model` to\n * `ElevenLabsMusicModel` and adds provider-specific extras:\n *\n * - `compositionPlan` — switch from prompt mode to plan mode. Mutually\n * exclusive with `prompt` on the wire.\n * - `forceInstrumental` — skip vocals. ElevenLabs has no `instrumental`\n * on the cross-provider Common request (the field was removed in\n * v0.7 because it has wildly different semantics per provider); the\n * typed surface restores it.\n * - `signWithC2pa` — opt-in C2PA Content Credentials, MP3 output only.\n * - `respectSectionsDurations` — composition-plan mode only. False\n * trades section-duration accuracy for quality + latency.\n *\n * Setting `compositionPlan` with a non-empty `prompt`, or with\n * `duration`, fails `InvalidRequest` at the codec layer.\n */\nexport type ElevenLabsMusicGenerateRequest = Omit<CommonGenerateMusicRequest, \"model\"> & {\n readonly model?: ElevenLabsMusicModel\n readonly compositionPlan?: ElevenLabsCompositionPlan\n readonly forceInstrumental?: boolean\n readonly signWithC2pa?: boolean\n readonly respectSectionsDurations?: boolean\n}\n\nexport type CreateCompositionPlanRequest = {\n readonly prompt: string\n readonly duration?: Duration.Duration\n readonly sourceCompositionPlan?: ElevenLabsCompositionPlan\n readonly model?: ElevenLabsMusicModel\n}\n\nexport type ElevenLabsMusicGeneratorService = {\n readonly generate: (\n request: ElevenLabsMusicGenerateRequest,\n ) => Effect.Effect<GenerateResult, AiError.AiError>\n readonly streamGeneration: (\n request: ElevenLabsMusicGenerateRequest,\n ) => Stream.Stream<AudioChunk, AiError.AiError>\n readonly streamGenerationFrom: <E, R>(\n input: Stream.Stream<MusicSessionInput, E, R>,\n request: CommonStreamGenerateMusicRequest,\n ) => Stream.Stream<MusicStreamEvent, AiError.AiError | E, R>\n /**\n * Free endpoint (rate-limited, no credit cost): turn a prompt into a\n * structured `MusicPrompt` plan. Feed the result back into\n * `generate` / `streamGeneration` via `compositionPlan`.\n */\n readonly createCompositionPlan: (\n request: CreateCompositionPlanRequest,\n ) => Effect.Effect<ElevenLabsCompositionPlan, AiError.AiError>\n}\n\nexport class ElevenLabsMusicGenerator extends Context.Service<\n ElevenLabsMusicGenerator,\n ElevenLabsMusicGeneratorService\n>()(\"@betalyra/effect-uai/providers/elevenlabs/ElevenLabsMusicGenerator\") {}\n\nexport type Config = {\n readonly apiKey: Redacted.Redacted\n readonly baseUrl?: string\n readonly region?: ElevenLabsRegion\n}\n\nconst DEFAULT_MODEL: ElevenLabsMusicModel = \"music_v1\"\n\n// ---------------------------------------------------------------------------\n// HTTP errors (music namespace; reuses the same status taxonomy)\n// ---------------------------------------------------------------------------\n\nconst musicTransportFailure = (cause: unknown): AiError.AiError =>\n new AiError.Unavailable({ provider: \"elevenlabs-music\", raw: cause })\n\nconst musicHttpStatusError = (status: number, body: string): AiError.AiError => {\n if (status === 429) return new AiError.RateLimited({ provider: \"elevenlabs-music\", raw: body })\n if (status === 408 || status === 504)\n return new AiError.Timeout({ provider: \"elevenlabs-music\", raw: body })\n if (status === 401)\n return new AiError.AuthFailed({ provider: \"elevenlabs-music\", subtype: \"auth\", raw: body })\n if (status === 403)\n return new AiError.AuthFailed({\n provider: \"elevenlabs-music\",\n subtype: \"permission\",\n raw: body,\n })\n if (status === 402)\n return new AiError.AuthFailed({\n provider: \"elevenlabs-music\",\n subtype: \"billing\",\n raw: body,\n })\n if (status >= 500)\n return new AiError.Unavailable({ provider: \"elevenlabs-music\", status, raw: body })\n return new AiError.InvalidRequest({ provider: \"elevenlabs-music\", raw: body })\n}\n\n// ---------------------------------------------------------------------------\n// Wire body\n// ---------------------------------------------------------------------------\n\n/**\n * Build the JSON body for `/v1/music` (sync + stream share the body).\n *\n * Mutual exclusion: `compositionPlan` and prompt-mode fields cannot\n * coexist. When `compositionPlan` is set, `prompt` must be empty and\n * `duration` must be unset (section durations live on the plan).\n */\nconst buildBody = (request: ElevenLabsMusicGenerateRequest) =>\n Effect.gen(function* () {\n const model = request.model ?? DEFAULT_MODEL\n if (request.compositionPlan !== undefined) {\n if (request.prompt.length > 0) {\n return yield* Effect.fail(\n new AiError.InvalidRequest({\n provider: \"elevenlabs-music\",\n param: \"prompt\",\n raw: \"`prompt` and `compositionPlan` are mutually exclusive. Pass one or the other (compositionPlan carries its own per-section lyrics and styles).\",\n }),\n )\n }\n if (request.duration !== undefined) {\n return yield* Effect.fail(\n new AiError.InvalidRequest({\n provider: \"elevenlabs-music\",\n param: \"duration\",\n raw: \"`duration` is ignored when `compositionPlan` is set; section durations live on the plan. Remove `duration`.\",\n }),\n )\n }\n return {\n composition_plan: wireCompositionPlan(request.compositionPlan),\n model_id: model,\n ...(request.seed !== undefined && { seed: request.seed }),\n ...(request.forceInstrumental !== undefined && {\n force_instrumental: request.forceInstrumental,\n }),\n ...(request.respectSectionsDurations !== undefined && {\n respect_sections_durations: request.respectSectionsDurations,\n }),\n ...(request.signWithC2pa !== undefined && { sign_with_c2pa: request.signWithC2pa }),\n }\n }\n yield* warnDroppedPromptModeHints(request as CommonGenerateMusicRequest)\n return {\n prompt: request.prompt,\n model_id: model,\n ...(request.duration !== undefined && {\n music_length_ms: Duration.toMillis(request.duration),\n }),\n ...(request.seed !== undefined && { seed: request.seed }),\n ...(request.forceInstrumental !== undefined && {\n force_instrumental: request.forceInstrumental,\n }),\n ...(request.signWithC2pa !== undefined && { sign_with_c2pa: request.signWithC2pa }),\n }\n })\n\nconst buildMusicHttpRequest = (\n cfg: Config,\n request: ElevenLabsMusicGenerateRequest,\n path: \"\" | \"/stream\",\n) =>\n Effect.gen(function* () {\n const format: AudioFormat = request.outputFormat ?? defaultFormat\n const slug = yield* formatToOutputSlug(format)\n const body = yield* buildBody(request)\n const url = `${resolveHost(cfg)}/music${path}?output_format=${slug}`\n const httpRequest = HttpClientRequest.post(url).pipe(\n HttpClientRequest.setHeader(\"xi-api-key\", Redacted.value(cfg.apiKey)),\n HttpClientRequest.bodyJsonUnsafe(body),\n )\n return { httpRequest, format }\n })\n\n// ---------------------------------------------------------------------------\n// Service implementation\n// ---------------------------------------------------------------------------\n\nconst generateImpl =\n (cfg: Config) =>\n (\n request: ElevenLabsMusicGenerateRequest,\n ): Effect.Effect<GenerateResult, AiError.AiError, HttpClient.HttpClient> =>\n Effect.gen(function* () {\n const client = yield* HttpClient.HttpClient\n const { httpRequest, format } = yield* buildMusicHttpRequest(cfg, request, \"\")\n const response = yield* client\n .execute(httpRequest)\n .pipe(Effect.mapError(musicTransportFailure))\n if (response.status >= 400) {\n const text = yield* response.text.pipe(Effect.orElseSucceed(() => \"\"))\n return yield* Effect.fail(musicHttpStatusError(response.status, text))\n }\n const buffer = yield* response.arrayBuffer.pipe(Effect.mapError(musicTransportFailure))\n const bytes = new Uint8Array(buffer)\n const songId = response.headers[\"song_id\"] ?? response.headers[\"x-song-id\"]\n const result: MusicResult = {\n audio: { format, bytes },\n provider: \"elevenlabs-music\",\n ...(typeof songId === \"string\" && { songId }),\n ...(request.signWithC2pa === true && { watermark: \"c2pa\" as const }),\n }\n return singleVariant(result)\n })\n\nconst streamGenerationImpl =\n (cfg: Config) =>\n (\n request: ElevenLabsMusicGenerateRequest,\n ): Stream.Stream<AudioChunk, AiError.AiError, HttpClient.HttpClient> =>\n Stream.unwrap(\n Effect.gen(function* () {\n const client = yield* HttpClient.HttpClient\n const { httpRequest } = yield* buildMusicHttpRequest(cfg, request, \"/stream\")\n const response = yield* client\n .execute(httpRequest)\n .pipe(Effect.mapError(musicTransportFailure))\n if (response.status >= 400) {\n const text = yield* response.text.pipe(Effect.orElseSucceed(() => \"\"))\n return Stream.fail(musicHttpStatusError(response.status, text))\n }\n return response.stream.pipe(\n Stream.mapError(musicTransportFailure),\n Stream.map((bytes): AudioChunk => ({ bytes })),\n )\n }),\n )\n\n/**\n * ElevenLabs music has no bidirectional session at the wire level.\n * Layer does not register `MusicInteractiveSession`, so callers using\n * `MusicGenerator.streamGenerationFrom` get a compile-time error\n * before this runtime fallback fires.\n */\nconst streamGenerationFromUnsupported = <E, R>(\n _input: Stream.Stream<MusicSessionInput, E, R>,\n _request: CommonStreamGenerateMusicRequest,\n): Stream.Stream<MusicStreamEvent, AiError.AiError | E, R> =>\n Stream.fail(\n new AiError.Unsupported({\n provider: \"elevenlabs-music\",\n capability: \"streamGenerationFrom\",\n reason:\n \"ElevenLabs music has no bidirectional session. Use `streamGeneration` for chunked output, or `createCompositionPlan` + `generate` for structured plans.\",\n }),\n )\n\nconst createCompositionPlanImpl =\n (cfg: Config) =>\n (\n request: CreateCompositionPlanRequest,\n ): Effect.Effect<ElevenLabsCompositionPlan, AiError.AiError, HttpClient.HttpClient> =>\n Effect.gen(function* () {\n const client = yield* HttpClient.HttpClient\n const body = {\n prompt: request.prompt,\n model_id: request.model ?? DEFAULT_MODEL,\n ...(request.duration !== undefined && {\n music_length_ms: Duration.toMillis(request.duration),\n }),\n ...(request.sourceCompositionPlan !== undefined && {\n source_composition_plan: wireCompositionPlan(request.sourceCompositionPlan),\n }),\n }\n const httpRequest = HttpClientRequest.post(`${resolveHost(cfg)}/music/plan`).pipe(\n HttpClientRequest.setHeader(\"xi-api-key\", Redacted.value(cfg.apiKey)),\n HttpClientRequest.bodyJsonUnsafe(body),\n )\n const response = yield* client\n .execute(httpRequest)\n .pipe(Effect.mapError(musicTransportFailure))\n if (response.status >= 400) {\n const text = yield* response.text.pipe(Effect.orElseSucceed(() => \"\"))\n return yield* Effect.fail(musicHttpStatusError(response.status, text))\n }\n const json = yield* response.json.pipe(Effect.mapError(musicTransportFailure))\n return decodeCompositionPlan(json)\n })\n\n// ---------------------------------------------------------------------------\n// Constructors\n// ---------------------------------------------------------------------------\n\nexport const make = (\n cfg: Config,\n): Effect.Effect<ElevenLabsMusicGeneratorService, never, HttpClient.HttpClient> =>\n Effect.map(HttpClient.HttpClient, (client) => ({\n generate: (request) =>\n generateImpl(cfg)(request).pipe(Effect.provideService(HttpClient.HttpClient, client)),\n streamGeneration: (request) =>\n streamGenerationImpl(cfg)(request).pipe(Stream.provideService(HttpClient.HttpClient, client)),\n streamGenerationFrom: streamGenerationFromUnsupported,\n createCompositionPlan: (request) =>\n createCompositionPlanImpl(cfg)(request).pipe(\n Effect.provideService(HttpClient.HttpClient, client),\n ),\n }))\n\n/**\n * Layer that registers the provider-specific `ElevenLabsMusicGenerator`\n * tag and the generic `MusicGenerator` tag.\n *\n * Does NOT register `MusicInteractiveSession`. ElevenLabs music has no\n * bidirectional wire endpoint; `streamGenerationFrom` against this\n * Layer alone fails to typecheck.\n */\nexport const layer = (\n cfg: Config,\n): Layer.Layer<ElevenLabsMusicGenerator | MusicGenerator, never, HttpClient.HttpClient> =>\n Layer.merge(\n Layer.effect(ElevenLabsMusicGenerator, make(cfg)),\n Layer.effect(\n MusicGenerator,\n Effect.map(make(cfg), (s): MusicGeneratorService => ({\n generate: (req: CommonGenerateMusicRequest) =>\n s.generate({ ...req, model: req.model as ElevenLabsMusicModel }),\n streamGeneration: (req: CommonStreamGenerateMusicRequest) =>\n s.streamGeneration({ ...req, model: req.model as ElevenLabsMusicModel }),\n streamGenerationFrom: s.streamGenerationFrom,\n })),\n ),\n )\n"],"mappings":"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"}
@@ -1,8 +1,8 @@
1
- import { n as describe, r as it, t as globalExpect } from "./test.DNmyFkvJ-N3QqMRwZ.mjs";
2
- import { t as import_dist } from "./dist-C0AvqZTC.mjs";
1
+ import { c as it, n as globalExpect, s as describe } from "./index.C4tKZ0yW-DjxCdpW_.mjs";
2
+ import { t as import_dist } from "./dist-DkEvSNwD.mjs";
3
3
  import { ElevenLabsMusicGenerator, layer } from "./ElevenLabsMusicGenerator.mjs";
4
4
  import { Duration, Effect, Layer, Redacted, Stream } from "effect";
5
- import { FetchHttpClient } from "effect/unstable/http";
5
+ import { FetchHttpClient } from "effect/http";
6
6
  import { promptsInput } from "@effect-uai/core/Music";
7
7
  import * as MusicGenerator$1 from "@effect-uai/core/MusicGenerator";
8
8
  //#region src/ElevenLabsMusicGenerator.test.ts
@@ -1 +1 @@
1
- {"version":3,"file":"ElevenLabsMusicGenerator.test.mjs","names":["ElevenLabsMusicGenerator.layer","MusicGenerator"],"sources":["../src/ElevenLabsMusicGenerator.test.ts"],"sourcesContent":["import { Duration, Effect, Layer, Redacted, Stream } from \"effect\"\nimport { FetchHttpClient } from \"effect/unstable/http\"\nimport { describe, expect, expectTypeOf, it } from \"vitest\"\nimport type * as AiError from \"@effect-uai/core/AiError\"\nimport type { GenerateResult } from \"@effect-uai/core/Music\"\nimport { promptsInput } from \"@effect-uai/core/Music\"\nimport * as MusicGenerator from \"@effect-uai/core/MusicGenerator\"\nimport * as ElevenLabsMusicGenerator from \"./ElevenLabsMusicGenerator.js\"\n\nconst cfg: ElevenLabsMusicGenerator.Config = { apiKey: Redacted.make(\"test-key\") }\nconst live = Layer.provide(ElevenLabsMusicGenerator.layer(cfg), FetchHttpClient.layer)\n\ndescribe(\"ElevenLabsMusicGenerator capability guards (runtime)\", () => {\n it(\"streamGenerationFrom returns an Unsupported stream\", async () => {\n const program = ElevenLabsMusicGenerator.ElevenLabsMusicGenerator.use((s) =>\n Stream.runDrain(\n s.streamGenerationFrom(Stream.fromIterable([promptsInput([{ text: \"x\" }])]), {\n model: \"music_v1\",\n prompt: \"\",\n }),\n ),\n )\n const exit = await Effect.runPromiseExit(program.pipe(Effect.provide(live)))\n expect(exit._tag).toBe(\"Failure\")\n if (exit._tag === \"Failure\") {\n expect(JSON.stringify(exit.cause)).toContain(\"Unsupported\")\n expect(JSON.stringify(exit.cause)).toContain(\"streamGenerationFrom\")\n }\n })\n})\n\ndescribe(\"ElevenLabsMusicGenerator Layer (compile-time)\", () => {\n it(\"leaves `MusicInteractiveSession` unsatisfied via the generic surface\", () => {\n const inputs = Stream.fromIterable([promptsInput([{ text: \"techno\" }])])\n const events = inputs.pipe(\n MusicGenerator.streamGenerationFrom({ model: \"music_v1\", prompt: \"\" }),\n )\n const provided = Stream.runDrain(events).pipe(Effect.provide(live))\n expectTypeOf(provided).toEqualTypeOf<\n Effect.Effect<void, AiError.AiError, MusicGenerator.MusicInteractiveSession>\n >()\n })\n\n it(\"sync `generate` returns GenerateResult and requires no marker\", () => {\n const gen = MusicGenerator.generate({ model: \"music_v1\", prompt: \"house\" }).pipe(\n Effect.provide(live),\n )\n expectTypeOf(gen).toEqualTypeOf<Effect.Effect<GenerateResult, AiError.AiError, never>>()\n })\n\n it(\"typed request accepts compositionPlan, forceInstrumental, signWithC2pa\", () => {\n const _req: ElevenLabsMusicGenerator.ElevenLabsMusicGenerateRequest = {\n model: \"music_v1\",\n prompt: \"\",\n compositionPlan: {\n positiveGlobalStyles: [\"lo-fi\", \"warm\"],\n negativeGlobalStyles: [\"distorted\"],\n sections: [\n {\n sectionName: \"Intro\",\n positiveLocalStyles: [\"piano\"],\n negativeLocalStyles: [],\n duration: Duration.seconds(15),\n lines: [],\n },\n ],\n },\n forceInstrumental: true,\n signWithC2pa: true,\n }\n expect(_req).toBeDefined()\n })\n})\n\ndescribe(\"ElevenLabsMusicGenerator codec validation (runtime, no HTTP)\", () => {\n it(\"rejects compositionPlan + non-empty prompt\", async () => {\n const program = ElevenLabsMusicGenerator.ElevenLabsMusicGenerator.use((s) =>\n s.generate({\n model: \"music_v1\",\n prompt: \"house\",\n compositionPlan: {\n positiveGlobalStyles: [],\n negativeGlobalStyles: [],\n sections: [],\n },\n }),\n )\n const exit = await Effect.runPromiseExit(program.pipe(Effect.provide(live)))\n expect(exit._tag).toBe(\"Failure\")\n if (exit._tag === \"Failure\") {\n expect(JSON.stringify(exit.cause)).toContain(\"InvalidRequest\")\n expect(JSON.stringify(exit.cause)).toContain(\"mutually exclusive\")\n }\n })\n\n it(\"rejects compositionPlan + duration\", async () => {\n const program = ElevenLabsMusicGenerator.ElevenLabsMusicGenerator.use((s) =>\n s.generate({\n model: \"music_v1\",\n prompt: \"\",\n duration: Duration.seconds(30),\n compositionPlan: {\n positiveGlobalStyles: [],\n negativeGlobalStyles: [],\n sections: [],\n },\n }),\n )\n const exit = await Effect.runPromiseExit(program.pipe(Effect.provide(live)))\n expect(exit._tag).toBe(\"Failure\")\n if (exit._tag === \"Failure\") {\n expect(JSON.stringify(exit.cause)).toContain(\"InvalidRequest\")\n expect(JSON.stringify(exit.cause)).toContain(\"`duration` is ignored\")\n }\n })\n})\n"],"mappings":";;;;;;;;AASA,MAAM,MAAuC,EAAE,QAAQ,SAAS,KAAK,UAAU,EAAE;AACjF,MAAM,OAAO,MAAM,QAAQA,MAA+B,GAAG,GAAG,gBAAgB,KAAK;AAErF,SAAS,8DAA8D;CACrE,GAAG,sDAAsD,YAAY;EACnE,MAAM,UAAA,yBAA4D,KAAK,MACrE,OAAO,SACL,EAAE,qBAAqB,OAAO,aAAa,CAAC,aAAa,CAAC,EAAE,MAAM,IAAI,CAAC,CAAC,CAAC,CAAC,GAAG;GAC3E,OAAO;GACP,QAAQ;EACV,CAAC,CACH,CACF;EACA,MAAM,OAAO,MAAM,OAAO,eAAe,QAAQ,KAAK,OAAO,QAAQ,IAAI,CAAC,CAAC;EAC3E,aAAO,KAAK,IAAI,CAAC,CAAC,KAAK,SAAS;EAChC,IAAI,KAAK,SAAS,WAAW;GAC3B,aAAO,KAAK,UAAU,KAAK,KAAK,CAAC,CAAC,CAAC,UAAU,aAAa;GAC1D,aAAO,KAAK,UAAU,KAAK,KAAK,CAAC,CAAC,CAAC,UAAU,sBAAsB;EACrE;CACF,CAAC;AACH,CAAC;AAED,SAAS,uDAAuD;CAC9D,GAAG,8EAA8E;EAE/E,MAAM,SADS,OAAO,aAAa,CAAC,aAAa,CAAC,EAAE,MAAM,SAAS,CAAC,CAAC,CAAC,CAClD,CAAC,CAAC,KACpBC,iBAAe,qBAAqB;GAAE,OAAO;GAAY,QAAQ;EAAG,CAAC,CACvE;EACA,MAAM,WAAW,OAAO,SAAS,MAAM,CAAC,CAAC,KAAK,OAAO,QAAQ,IAAI,CAAC;EAClE,CAAA,GAAA,YAAA,aAAA,CAAa,QAAQ,CAAC,CAAC,cAErB;CACJ,CAAC;CAED,GAAG,uEAAuE;EACxE,MAAM,MAAMA,iBAAe,SAAS;GAAE,OAAO;GAAY,QAAQ;EAAQ,CAAC,CAAC,CAAC,KAC1E,OAAO,QAAQ,IAAI,CACrB;EACA,CAAA,GAAA,YAAA,aAAA,CAAa,GAAG,CAAC,CAAC,cAAqE;CACzF,CAAC;CAED,GAAG,gFAAgF;EACjF,MAAM,OAAgE;GACpE,OAAO;GACP,QAAQ;GACR,iBAAiB;IACf,sBAAsB,CAAC,SAAS,MAAM;IACtC,sBAAsB,CAAC,WAAW;IAClC,UAAU,CACR;KACE,aAAa;KACb,qBAAqB,CAAC,OAAO;KAC7B,qBAAqB,CAAC;KACtB,UAAU,SAAS,QAAQ,EAAE;KAC7B,OAAO,CAAC;IACV,CACF;GACF;GACA,mBAAmB;GACnB,cAAc;EAChB;EACA,aAAO,IAAI,CAAC,CAAC,YAAY;CAC3B,CAAC;AACH,CAAC;AAED,SAAS,sEAAsE;CAC7E,GAAG,8CAA8C,YAAY;EAC3D,MAAM,UAAA,yBAA4D,KAAK,MACrE,EAAE,SAAS;GACT,OAAO;GACP,QAAQ;GACR,iBAAiB;IACf,sBAAsB,CAAC;IACvB,sBAAsB,CAAC;IACvB,UAAU,CAAC;GACb;EACF,CAAC,CACH;EACA,MAAM,OAAO,MAAM,OAAO,eAAe,QAAQ,KAAK,OAAO,QAAQ,IAAI,CAAC,CAAC;EAC3E,aAAO,KAAK,IAAI,CAAC,CAAC,KAAK,SAAS;EAChC,IAAI,KAAK,SAAS,WAAW;GAC3B,aAAO,KAAK,UAAU,KAAK,KAAK,CAAC,CAAC,CAAC,UAAU,gBAAgB;GAC7D,aAAO,KAAK,UAAU,KAAK,KAAK,CAAC,CAAC,CAAC,UAAU,oBAAoB;EACnE;CACF,CAAC;CAED,GAAG,sCAAsC,YAAY;EACnD,MAAM,UAAA,yBAA4D,KAAK,MACrE,EAAE,SAAS;GACT,OAAO;GACP,QAAQ;GACR,UAAU,SAAS,QAAQ,EAAE;GAC7B,iBAAiB;IACf,sBAAsB,CAAC;IACvB,sBAAsB,CAAC;IACvB,UAAU,CAAC;GACb;EACF,CAAC,CACH;EACA,MAAM,OAAO,MAAM,OAAO,eAAe,QAAQ,KAAK,OAAO,QAAQ,IAAI,CAAC,CAAC;EAC3E,aAAO,KAAK,IAAI,CAAC,CAAC,KAAK,SAAS;EAChC,IAAI,KAAK,SAAS,WAAW;GAC3B,aAAO,KAAK,UAAU,KAAK,KAAK,CAAC,CAAC,CAAC,UAAU,gBAAgB;GAC7D,aAAO,KAAK,UAAU,KAAK,KAAK,CAAC,CAAC,CAAC,UAAU,uBAAuB;EACtE;CACF,CAAC;AACH,CAAC"}
1
+ {"version":3,"file":"ElevenLabsMusicGenerator.test.mjs","names":["ElevenLabsMusicGenerator.layer","MusicGenerator"],"sources":["../src/ElevenLabsMusicGenerator.test.ts"],"sourcesContent":["import { Duration, Effect, Layer, Redacted, Stream } from \"effect\"\nimport { FetchHttpClient } from \"effect/http\"\nimport { describe, expect, expectTypeOf, it } from \"vitest\"\nimport type * as AiError from \"@effect-uai/core/AiError\"\nimport type { GenerateResult } from \"@effect-uai/core/Music\"\nimport { promptsInput } from \"@effect-uai/core/Music\"\nimport * as MusicGenerator from \"@effect-uai/core/MusicGenerator\"\nimport * as ElevenLabsMusicGenerator from \"./ElevenLabsMusicGenerator.js\"\n\nconst cfg: ElevenLabsMusicGenerator.Config = { apiKey: Redacted.make(\"test-key\") }\nconst live = Layer.provide(ElevenLabsMusicGenerator.layer(cfg), FetchHttpClient.layer)\n\ndescribe(\"ElevenLabsMusicGenerator capability guards (runtime)\", () => {\n it(\"streamGenerationFrom returns an Unsupported stream\", async () => {\n const program = ElevenLabsMusicGenerator.ElevenLabsMusicGenerator.use((s) =>\n Stream.runDrain(\n s.streamGenerationFrom(Stream.fromIterable([promptsInput([{ text: \"x\" }])]), {\n model: \"music_v1\",\n prompt: \"\",\n }),\n ),\n )\n const exit = await Effect.runPromiseExit(program.pipe(Effect.provide(live)))\n expect(exit._tag).toBe(\"Failure\")\n if (exit._tag === \"Failure\") {\n expect(JSON.stringify(exit.cause)).toContain(\"Unsupported\")\n expect(JSON.stringify(exit.cause)).toContain(\"streamGenerationFrom\")\n }\n })\n})\n\ndescribe(\"ElevenLabsMusicGenerator Layer (compile-time)\", () => {\n it(\"leaves `MusicInteractiveSession` unsatisfied via the generic surface\", () => {\n const inputs = Stream.fromIterable([promptsInput([{ text: \"techno\" }])])\n const events = inputs.pipe(\n MusicGenerator.streamGenerationFrom({ model: \"music_v1\", prompt: \"\" }),\n )\n const provided = Stream.runDrain(events).pipe(Effect.provide(live))\n expectTypeOf(provided).toEqualTypeOf<\n Effect.Effect<void, AiError.AiError, MusicGenerator.MusicInteractiveSession>\n >()\n })\n\n it(\"sync `generate` returns GenerateResult and requires no marker\", () => {\n const gen = MusicGenerator.generate({ model: \"music_v1\", prompt: \"house\" }).pipe(\n Effect.provide(live),\n )\n expectTypeOf(gen).toEqualTypeOf<Effect.Effect<GenerateResult, AiError.AiError, never>>()\n })\n\n it(\"typed request accepts compositionPlan, forceInstrumental, signWithC2pa\", () => {\n const _req: ElevenLabsMusicGenerator.ElevenLabsMusicGenerateRequest = {\n model: \"music_v1\",\n prompt: \"\",\n compositionPlan: {\n positiveGlobalStyles: [\"lo-fi\", \"warm\"],\n negativeGlobalStyles: [\"distorted\"],\n sections: [\n {\n sectionName: \"Intro\",\n positiveLocalStyles: [\"piano\"],\n negativeLocalStyles: [],\n duration: Duration.seconds(15),\n lines: [],\n },\n ],\n },\n forceInstrumental: true,\n signWithC2pa: true,\n }\n expect(_req).toBeDefined()\n })\n})\n\ndescribe(\"ElevenLabsMusicGenerator codec validation (runtime, no HTTP)\", () => {\n it(\"rejects compositionPlan + non-empty prompt\", async () => {\n const program = ElevenLabsMusicGenerator.ElevenLabsMusicGenerator.use((s) =>\n s.generate({\n model: \"music_v1\",\n prompt: \"house\",\n compositionPlan: {\n positiveGlobalStyles: [],\n negativeGlobalStyles: [],\n sections: [],\n },\n }),\n )\n const exit = await Effect.runPromiseExit(program.pipe(Effect.provide(live)))\n expect(exit._tag).toBe(\"Failure\")\n if (exit._tag === \"Failure\") {\n expect(JSON.stringify(exit.cause)).toContain(\"InvalidRequest\")\n expect(JSON.stringify(exit.cause)).toContain(\"mutually exclusive\")\n }\n })\n\n it(\"rejects compositionPlan + duration\", async () => {\n const program = ElevenLabsMusicGenerator.ElevenLabsMusicGenerator.use((s) =>\n s.generate({\n model: \"music_v1\",\n prompt: \"\",\n duration: Duration.seconds(30),\n compositionPlan: {\n positiveGlobalStyles: [],\n negativeGlobalStyles: [],\n sections: [],\n },\n }),\n )\n const exit = await Effect.runPromiseExit(program.pipe(Effect.provide(live)))\n expect(exit._tag).toBe(\"Failure\")\n if (exit._tag === \"Failure\") {\n expect(JSON.stringify(exit.cause)).toContain(\"InvalidRequest\")\n expect(JSON.stringify(exit.cause)).toContain(\"`duration` is ignored\")\n }\n })\n})\n"],"mappings":"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"}
@@ -2,9 +2,9 @@ import { ElevenLabsTtsModel, ElevenLabsVoiceId } from "./models.mjs";
2
2
  import { ElevenLabsRegion } from "./region.mjs";
3
3
  import { PronunciationDictionaryLocator, VoiceSettings } from "./codec.mjs";
4
4
  import { Context, Effect, Layer, Redacted, Stream } from "effect";
5
- import { HttpClient } from "effect/unstable/http";
5
+ import { HttpClient } from "effect/http";
6
6
  import * as AiError from "@effect-uai/core/AiError";
7
- import * as Socket from "effect/unstable/socket/Socket";
7
+ import * as Socket from "effect/socket/Socket";
8
8
  import { CommonStreamSynthesizeRequest, CommonSynthesizeDialogueRequest, CommonSynthesizeRequest, MultiSpeakerTts, SpeechSynthesizer, SpeechSynthesizerService, TtsIncrementalText } from "@effect-uai/core/SpeechSynthesizer";
9
9
  import { AudioBlob, AudioChunk } from "@effect-uai/core/Audio";
10
10
  declare namespace ElevenLabsSynthesizer_d_exports {
@@ -3,8 +3,8 @@ import { defaultFormat, formatToOutputSlug, httpStatusError, rejectInlinePronunc
3
3
  import { resolveHost } from "./region.mjs";
4
4
  import { streamSynthesis } from "./realtimeTts.mjs";
5
5
  import { Context, Effect, Layer, Redacted, Stream } from "effect";
6
- import { HttpClient, HttpClientRequest } from "effect/unstable/http";
7
- import * as Socket from "effect/unstable/socket/Socket";
6
+ import { HttpClient, HttpClientRequest } from "effect/http";
7
+ import * as Socket from "effect/socket/Socket";
8
8
  import { MultiSpeakerTts, SpeechSynthesizer, TtsIncrementalText } from "@effect-uai/core/SpeechSynthesizer";
9
9
  //#region src/ElevenLabsSynthesizer.ts
10
10
  var ElevenLabsSynthesizer_exports = /* @__PURE__ */ __exportAll({
@@ -1 +1 @@
1
- {"version":3,"file":"ElevenLabsSynthesizer.mjs","names":["realtimeStream"],"sources":["../src/ElevenLabsSynthesizer.ts"],"sourcesContent":["import { Context, Effect, Layer, Redacted, Stream } from \"effect\"\nimport { HttpClient, HttpClientRequest } from \"effect/unstable/http\"\nimport * as Socket from \"effect/unstable/socket/Socket\"\nimport type * as AiError from \"@effect-uai/core/AiError\"\nimport type { AudioBlob, AudioChunk } from \"@effect-uai/core/Audio\"\nimport {\n type CommonStreamSynthesizeRequest,\n type CommonSynthesizeDialogueRequest,\n type CommonSynthesizeRequest,\n MultiSpeakerTts,\n SpeechSynthesizer,\n type SpeechSynthesizerService,\n TtsIncrementalText,\n} from \"@effect-uai/core/SpeechSynthesizer\"\nimport {\n defaultFormat,\n formatToOutputSlug,\n httpStatusError,\n type PronunciationDictionaryLocator,\n rejectInlinePronunciations,\n transportFailure,\n type VoiceSettings,\n wirePronunciationLocators,\n wireVoiceSettings,\n} from \"./codec.js\"\nimport type { ElevenLabsTtsModel, ElevenLabsVoiceId } from \"./models.js\"\nimport { streamSynthesis as realtimeStream } from \"./realtimeTts.js\"\nimport { type ElevenLabsRegion, resolveHost } from \"./region.js\"\n\n// ---------------------------------------------------------------------------\n// Public types\n// ---------------------------------------------------------------------------\n\n/**\n * ElevenLabs-typed synthesize request. `voiceSettings` exposes the\n * provider's prosody/timbre controls; `seed` makes generation\n * deterministic; `previousText` / `nextText` thread context across\n * sequential calls for natural prosody.\n *\n * `pronunciationDictionaryLocators` references pre-provisioned\n * pronunciation dictionaries by ID. Inline `pronunciations` (IPA) on\n * the Common request are not supported by ElevenLabs and fail\n * `Unsupported`; use a dictionary for phonetic control.\n */\nexport type ElevenLabsSynthesizeRequest = Omit<CommonSynthesizeRequest, \"model\" | \"voiceId\"> & {\n readonly model: ElevenLabsTtsModel\n readonly voiceId: ElevenLabsVoiceId\n readonly voiceSettings?: VoiceSettings\n readonly seed?: number\n readonly previousText?: string\n readonly nextText?: string\n readonly pronunciationDictionaryLocators?: ReadonlyArray<PronunciationDictionaryLocator>\n}\n\nexport type ElevenLabsSynthesizerService = {\n readonly synthesize: (r: ElevenLabsSynthesizeRequest) => Effect.Effect<AudioBlob, AiError.AiError>\n readonly streamSynthesis: (\n r: ElevenLabsSynthesizeRequest,\n ) => Stream.Stream<AudioChunk, AiError.AiError>\n readonly streamSynthesisFrom: SpeechSynthesizerService[\"streamSynthesisFrom\"]\n readonly synthesizeDialogue: SpeechSynthesizerService[\"synthesizeDialogue\"]\n readonly streamSynthesizeDialogue: SpeechSynthesizerService[\"streamSynthesizeDialogue\"]\n}\n\nexport class ElevenLabsSynthesizer extends Context.Service<\n ElevenLabsSynthesizer,\n ElevenLabsSynthesizerService\n>()(\"@betalyra/effect-uai/providers/elevenlabs/ElevenLabsSynthesizer\") {}\n\nexport type Config = {\n readonly apiKey: Redacted.Redacted\n readonly baseUrl?: string\n readonly region?: ElevenLabsRegion\n}\n\n// ---------------------------------------------------------------------------\n// Codec — request → JSON body\n// ---------------------------------------------------------------------------\n\nconst buildBody = (r: ElevenLabsSynthesizeRequest) => ({\n text: r.text,\n model_id: r.model,\n ...(r.languageCode !== undefined && { language_code: r.languageCode }),\n ...(r.seed !== undefined && { seed: r.seed }),\n ...(r.previousText !== undefined && { previous_text: r.previousText }),\n ...(r.nextText !== undefined && { next_text: r.nextText }),\n ...wirePronunciationLocators(r.pronunciationDictionaryLocators),\n ...(r.voiceSettings !== undefined && { voice_settings: wireVoiceSettings(r.voiceSettings) }),\n})\n\n// ---------------------------------------------------------------------------\n// Dialogue — POST /v1/text-to-dialogue (+ /stream variant)\n// ---------------------------------------------------------------------------\n\nconst DEFAULT_DIALOGUE_MODEL = \"eleven_v3\"\n\nconst buildDialogueBody = (r: CommonSynthesizeDialogueRequest) => ({\n inputs: r.turns.map((t) => ({\n voice_id: t.voiceId,\n text: t.text,\n })),\n model_id: r.model ?? DEFAULT_DIALOGUE_MODEL,\n ...(r.languageCode !== undefined && { language_code: r.languageCode }),\n})\n\nconst buildDialogueHttpRequest = (\n cfg: Config,\n r: CommonSynthesizeDialogueRequest,\n path: \"\" | \"/stream\",\n) =>\n Effect.gen(function* () {\n const format = r.outputFormat ?? defaultFormat\n const slug = yield* formatToOutputSlug(format)\n const url = `${resolveHost(cfg)}/text-to-dialogue${path}?output_format=${slug}`\n const httpRequest = HttpClientRequest.post(url).pipe(\n HttpClientRequest.setHeader(\"xi-api-key\", Redacted.value(cfg.apiKey)),\n HttpClientRequest.bodyJsonUnsafe(buildDialogueBody(r)),\n )\n return { httpRequest, format }\n })\n\nconst synthesizeDialogueImpl = (cfg: Config) => (request: CommonSynthesizeDialogueRequest) =>\n Effect.gen(function* () {\n yield* rejectInlinePronunciations(request.pronunciations)\n const client = yield* HttpClient.HttpClient\n const { httpRequest, format } = yield* buildDialogueHttpRequest(cfg, request, \"\")\n const response = yield* client.execute(httpRequest).pipe(Effect.mapError(transportFailure))\n if (response.status >= 400) {\n const text = yield* response.text.pipe(Effect.orElseSucceed(() => \"\"))\n return yield* Effect.fail(httpStatusError(response.status, text))\n }\n const bytes = yield* response.arrayBuffer.pipe(Effect.mapError(transportFailure))\n return { format, bytes: new Uint8Array(bytes) } satisfies AudioBlob\n })\n\nconst streamSynthesizeDialogueImpl = (cfg: Config) => (request: CommonSynthesizeDialogueRequest) =>\n Stream.unwrap(\n Effect.gen(function* () {\n yield* rejectInlinePronunciations(request.pronunciations)\n const client = yield* HttpClient.HttpClient\n const { httpRequest } = yield* buildDialogueHttpRequest(cfg, request, \"/stream\")\n const response = yield* client.execute(httpRequest).pipe(Effect.mapError(transportFailure))\n if (response.status >= 400) {\n const text = yield* response.text.pipe(Effect.orElseSucceed(() => \"\"))\n return Stream.fail(httpStatusError(response.status, text))\n }\n return response.stream.pipe(\n Stream.mapError(transportFailure),\n Stream.map((bytes): AudioChunk => ({ bytes })),\n )\n }),\n )\n\n// ---------------------------------------------------------------------------\n// HTTP plumbing (sync + chunked-HTTP streaming)\n// ---------------------------------------------------------------------------\n\nconst buildHttpRequest = (cfg: Config, r: ElevenLabsSynthesizeRequest, path: \"\" | \"/stream\") =>\n Effect.gen(function* () {\n const format = r.outputFormat ?? defaultFormat\n const slug = yield* formatToOutputSlug(format)\n const url = `${resolveHost(cfg)}/text-to-speech/${r.voiceId}${path}?output_format=${slug}`\n const httpRequest = HttpClientRequest.post(url).pipe(\n HttpClientRequest.setHeader(\"xi-api-key\", Redacted.value(cfg.apiKey)),\n HttpClientRequest.bodyJsonUnsafe(buildBody(r)),\n )\n return { httpRequest, format }\n })\n\nconst synthesizeImpl = (cfg: Config) => (request: ElevenLabsSynthesizeRequest) =>\n Effect.gen(function* () {\n yield* rejectInlinePronunciations(request.pronunciations)\n const client = yield* HttpClient.HttpClient\n const { httpRequest, format } = yield* buildHttpRequest(cfg, request, \"\")\n const response = yield* client.execute(httpRequest).pipe(Effect.mapError(transportFailure))\n if (response.status >= 400) {\n const text = yield* response.text.pipe(Effect.orElseSucceed(() => \"\"))\n return yield* Effect.fail(httpStatusError(response.status, text))\n }\n const bytes = yield* response.arrayBuffer.pipe(Effect.mapError(transportFailure))\n return { format, bytes: new Uint8Array(bytes) } satisfies AudioBlob\n })\n\nconst streamSynthesisImpl = (cfg: Config) => (request: ElevenLabsSynthesizeRequest) =>\n Stream.unwrap(\n Effect.gen(function* () {\n yield* rejectInlinePronunciations(request.pronunciations)\n const client = yield* HttpClient.HttpClient\n const { httpRequest } = yield* buildHttpRequest(cfg, request, \"/stream\")\n const response = yield* client.execute(httpRequest).pipe(Effect.mapError(transportFailure))\n if (response.status >= 400) {\n const text = yield* response.text.pipe(Effect.orElseSucceed(() => \"\"))\n return Stream.fail(httpStatusError(response.status, text))\n }\n return response.stream.pipe(\n Stream.mapError(transportFailure),\n Stream.map((bytes): AudioChunk => ({ bytes })),\n )\n }),\n )\n\n// ---------------------------------------------------------------------------\n// Constructors\n// ---------------------------------------------------------------------------\n\nexport const make = (cfg: Config) =>\n Effect.gen(function* () {\n const client = yield* HttpClient.HttpClient\n const ctor = yield* Socket.WebSocketConstructor\n return {\n synthesize: (r) =>\n synthesizeImpl(cfg)(r).pipe(Effect.provideService(HttpClient.HttpClient, client)),\n streamSynthesis: (r) =>\n streamSynthesisImpl(cfg)(r).pipe(Stream.provideService(HttpClient.HttpClient, client)),\n streamSynthesisFrom: (textIn, request) =>\n realtimeStream(cfg)(textIn, request as ElevenLabsSynthesizeRequest).pipe(\n Stream.provideService(Socket.WebSocketConstructor, ctor),\n ),\n synthesizeDialogue: (request) =>\n synthesizeDialogueImpl(cfg)(request).pipe(\n Effect.provideService(HttpClient.HttpClient, client),\n ),\n streamSynthesizeDialogue: (request) =>\n streamSynthesizeDialogueImpl(cfg)(request).pipe(\n Stream.provideService(HttpClient.HttpClient, client),\n ),\n } satisfies ElevenLabsSynthesizerService\n })\n\n/**\n * Layer registers `ElevenLabsSynthesizer`, the generic\n * `SpeechSynthesizer`, the `TtsIncrementalText` marker (incremental\n * text-in via `/stream-input` WebSocket), **and `MultiSpeakerTts`** —\n * multi-speaker dialogue is wired to `POST /v1/text-to-dialogue`\n * (sync) and `/v1/text-to-dialogue/stream` (chunked). Provide\n * `Socket.layerWebSocketConstructorGlobal` and an `HttpClient` Layer\n * at the call site.\n */\nexport const layer = (cfg: Config) =>\n Layer.mergeAll(\n Layer.effect(ElevenLabsSynthesizer, make(cfg)),\n Layer.effect(\n SpeechSynthesizer,\n Effect.map(make(cfg), (s): SpeechSynthesizerService => ({\n synthesize: (req: CommonSynthesizeRequest) =>\n s.synthesize(req as ElevenLabsSynthesizeRequest),\n streamSynthesis: (req: CommonSynthesizeRequest) =>\n s.streamSynthesis(req as ElevenLabsSynthesizeRequest),\n streamSynthesisFrom: (textIn, req: CommonStreamSynthesizeRequest) =>\n s.streamSynthesisFrom(textIn, req),\n synthesizeDialogue: s.synthesizeDialogue,\n streamSynthesizeDialogue: s.streamSynthesizeDialogue,\n })),\n ),\n Layer.succeed(TtsIncrementalText, undefined),\n Layer.succeed(MultiSpeakerTts, undefined),\n )\n"],"mappings":"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"}
1
+ {"version":3,"file":"ElevenLabsSynthesizer.mjs","names":["realtimeStream"],"sources":["../src/ElevenLabsSynthesizer.ts"],"sourcesContent":["import { Context, Effect, Layer, Redacted, Stream } from \"effect\"\nimport { HttpClient, HttpClientRequest } from \"effect/http\"\nimport * as Socket from \"effect/socket/Socket\"\nimport type * as AiError from \"@effect-uai/core/AiError\"\nimport type { AudioBlob, AudioChunk } from \"@effect-uai/core/Audio\"\nimport {\n type CommonStreamSynthesizeRequest,\n type CommonSynthesizeDialogueRequest,\n type CommonSynthesizeRequest,\n MultiSpeakerTts,\n SpeechSynthesizer,\n type SpeechSynthesizerService,\n TtsIncrementalText,\n} from \"@effect-uai/core/SpeechSynthesizer\"\nimport {\n defaultFormat,\n formatToOutputSlug,\n httpStatusError,\n type PronunciationDictionaryLocator,\n rejectInlinePronunciations,\n transportFailure,\n type VoiceSettings,\n wirePronunciationLocators,\n wireVoiceSettings,\n} from \"./codec.js\"\nimport type { ElevenLabsTtsModel, ElevenLabsVoiceId } from \"./models.js\"\nimport { streamSynthesis as realtimeStream } from \"./realtimeTts.js\"\nimport { type ElevenLabsRegion, resolveHost } from \"./region.js\"\n\n// ---------------------------------------------------------------------------\n// Public types\n// ---------------------------------------------------------------------------\n\n/**\n * ElevenLabs-typed synthesize request. `voiceSettings` exposes the\n * provider's prosody/timbre controls; `seed` makes generation\n * deterministic; `previousText` / `nextText` thread context across\n * sequential calls for natural prosody.\n *\n * `pronunciationDictionaryLocators` references pre-provisioned\n * pronunciation dictionaries by ID. Inline `pronunciations` (IPA) on\n * the Common request are not supported by ElevenLabs and fail\n * `Unsupported`; use a dictionary for phonetic control.\n */\nexport type ElevenLabsSynthesizeRequest = Omit<CommonSynthesizeRequest, \"model\" | \"voiceId\"> & {\n readonly model: ElevenLabsTtsModel\n readonly voiceId: ElevenLabsVoiceId\n readonly voiceSettings?: VoiceSettings\n readonly seed?: number\n readonly previousText?: string\n readonly nextText?: string\n readonly pronunciationDictionaryLocators?: ReadonlyArray<PronunciationDictionaryLocator>\n}\n\nexport type ElevenLabsSynthesizerService = {\n readonly synthesize: (r: ElevenLabsSynthesizeRequest) => Effect.Effect<AudioBlob, AiError.AiError>\n readonly streamSynthesis: (\n r: ElevenLabsSynthesizeRequest,\n ) => Stream.Stream<AudioChunk, AiError.AiError>\n readonly streamSynthesisFrom: SpeechSynthesizerService[\"streamSynthesisFrom\"]\n readonly synthesizeDialogue: SpeechSynthesizerService[\"synthesizeDialogue\"]\n readonly streamSynthesizeDialogue: SpeechSynthesizerService[\"streamSynthesizeDialogue\"]\n}\n\nexport class ElevenLabsSynthesizer extends Context.Service<\n ElevenLabsSynthesizer,\n ElevenLabsSynthesizerService\n>()(\"@betalyra/effect-uai/providers/elevenlabs/ElevenLabsSynthesizer\") {}\n\nexport type Config = {\n readonly apiKey: Redacted.Redacted\n readonly baseUrl?: string\n readonly region?: ElevenLabsRegion\n}\n\n// ---------------------------------------------------------------------------\n// Codec — request → JSON body\n// ---------------------------------------------------------------------------\n\nconst buildBody = (r: ElevenLabsSynthesizeRequest) => ({\n text: r.text,\n model_id: r.model,\n ...(r.languageCode !== undefined && { language_code: r.languageCode }),\n ...(r.seed !== undefined && { seed: r.seed }),\n ...(r.previousText !== undefined && { previous_text: r.previousText }),\n ...(r.nextText !== undefined && { next_text: r.nextText }),\n ...wirePronunciationLocators(r.pronunciationDictionaryLocators),\n ...(r.voiceSettings !== undefined && { voice_settings: wireVoiceSettings(r.voiceSettings) }),\n})\n\n// ---------------------------------------------------------------------------\n// Dialogue — POST /v1/text-to-dialogue (+ /stream variant)\n// ---------------------------------------------------------------------------\n\nconst DEFAULT_DIALOGUE_MODEL = \"eleven_v3\"\n\nconst buildDialogueBody = (r: CommonSynthesizeDialogueRequest) => ({\n inputs: r.turns.map((t) => ({\n voice_id: t.voiceId,\n text: t.text,\n })),\n model_id: r.model ?? DEFAULT_DIALOGUE_MODEL,\n ...(r.languageCode !== undefined && { language_code: r.languageCode }),\n})\n\nconst buildDialogueHttpRequest = (\n cfg: Config,\n r: CommonSynthesizeDialogueRequest,\n path: \"\" | \"/stream\",\n) =>\n Effect.gen(function* () {\n const format = r.outputFormat ?? defaultFormat\n const slug = yield* formatToOutputSlug(format)\n const url = `${resolveHost(cfg)}/text-to-dialogue${path}?output_format=${slug}`\n const httpRequest = HttpClientRequest.post(url).pipe(\n HttpClientRequest.setHeader(\"xi-api-key\", Redacted.value(cfg.apiKey)),\n HttpClientRequest.bodyJsonUnsafe(buildDialogueBody(r)),\n )\n return { httpRequest, format }\n })\n\nconst synthesizeDialogueImpl = (cfg: Config) => (request: CommonSynthesizeDialogueRequest) =>\n Effect.gen(function* () {\n yield* rejectInlinePronunciations(request.pronunciations)\n const client = yield* HttpClient.HttpClient\n const { httpRequest, format } = yield* buildDialogueHttpRequest(cfg, request, \"\")\n const response = yield* client.execute(httpRequest).pipe(Effect.mapError(transportFailure))\n if (response.status >= 400) {\n const text = yield* response.text.pipe(Effect.orElseSucceed(() => \"\"))\n return yield* Effect.fail(httpStatusError(response.status, text))\n }\n const bytes = yield* response.arrayBuffer.pipe(Effect.mapError(transportFailure))\n return { format, bytes: new Uint8Array(bytes) } satisfies AudioBlob\n })\n\nconst streamSynthesizeDialogueImpl = (cfg: Config) => (request: CommonSynthesizeDialogueRequest) =>\n Stream.unwrap(\n Effect.gen(function* () {\n yield* rejectInlinePronunciations(request.pronunciations)\n const client = yield* HttpClient.HttpClient\n const { httpRequest } = yield* buildDialogueHttpRequest(cfg, request, \"/stream\")\n const response = yield* client.execute(httpRequest).pipe(Effect.mapError(transportFailure))\n if (response.status >= 400) {\n const text = yield* response.text.pipe(Effect.orElseSucceed(() => \"\"))\n return Stream.fail(httpStatusError(response.status, text))\n }\n return response.stream.pipe(\n Stream.mapError(transportFailure),\n Stream.map((bytes): AudioChunk => ({ bytes })),\n )\n }),\n )\n\n// ---------------------------------------------------------------------------\n// HTTP plumbing (sync + chunked-HTTP streaming)\n// ---------------------------------------------------------------------------\n\nconst buildHttpRequest = (cfg: Config, r: ElevenLabsSynthesizeRequest, path: \"\" | \"/stream\") =>\n Effect.gen(function* () {\n const format = r.outputFormat ?? defaultFormat\n const slug = yield* formatToOutputSlug(format)\n const url = `${resolveHost(cfg)}/text-to-speech/${r.voiceId}${path}?output_format=${slug}`\n const httpRequest = HttpClientRequest.post(url).pipe(\n HttpClientRequest.setHeader(\"xi-api-key\", Redacted.value(cfg.apiKey)),\n HttpClientRequest.bodyJsonUnsafe(buildBody(r)),\n )\n return { httpRequest, format }\n })\n\nconst synthesizeImpl = (cfg: Config) => (request: ElevenLabsSynthesizeRequest) =>\n Effect.gen(function* () {\n yield* rejectInlinePronunciations(request.pronunciations)\n const client = yield* HttpClient.HttpClient\n const { httpRequest, format } = yield* buildHttpRequest(cfg, request, \"\")\n const response = yield* client.execute(httpRequest).pipe(Effect.mapError(transportFailure))\n if (response.status >= 400) {\n const text = yield* response.text.pipe(Effect.orElseSucceed(() => \"\"))\n return yield* Effect.fail(httpStatusError(response.status, text))\n }\n const bytes = yield* response.arrayBuffer.pipe(Effect.mapError(transportFailure))\n return { format, bytes: new Uint8Array(bytes) } satisfies AudioBlob\n })\n\nconst streamSynthesisImpl = (cfg: Config) => (request: ElevenLabsSynthesizeRequest) =>\n Stream.unwrap(\n Effect.gen(function* () {\n yield* rejectInlinePronunciations(request.pronunciations)\n const client = yield* HttpClient.HttpClient\n const { httpRequest } = yield* buildHttpRequest(cfg, request, \"/stream\")\n const response = yield* client.execute(httpRequest).pipe(Effect.mapError(transportFailure))\n if (response.status >= 400) {\n const text = yield* response.text.pipe(Effect.orElseSucceed(() => \"\"))\n return Stream.fail(httpStatusError(response.status, text))\n }\n return response.stream.pipe(\n Stream.mapError(transportFailure),\n Stream.map((bytes): AudioChunk => ({ bytes })),\n )\n }),\n )\n\n// ---------------------------------------------------------------------------\n// Constructors\n// ---------------------------------------------------------------------------\n\nexport const make = (cfg: Config) =>\n Effect.gen(function* () {\n const client = yield* HttpClient.HttpClient\n const ctor = yield* Socket.WebSocketConstructor\n return {\n synthesize: (r) =>\n synthesizeImpl(cfg)(r).pipe(Effect.provideService(HttpClient.HttpClient, client)),\n streamSynthesis: (r) =>\n streamSynthesisImpl(cfg)(r).pipe(Stream.provideService(HttpClient.HttpClient, client)),\n streamSynthesisFrom: (textIn, request) =>\n realtimeStream(cfg)(textIn, request as ElevenLabsSynthesizeRequest).pipe(\n Stream.provideService(Socket.WebSocketConstructor, ctor),\n ),\n synthesizeDialogue: (request) =>\n synthesizeDialogueImpl(cfg)(request).pipe(\n Effect.provideService(HttpClient.HttpClient, client),\n ),\n streamSynthesizeDialogue: (request) =>\n streamSynthesizeDialogueImpl(cfg)(request).pipe(\n Stream.provideService(HttpClient.HttpClient, client),\n ),\n } satisfies ElevenLabsSynthesizerService\n })\n\n/**\n * Layer registers `ElevenLabsSynthesizer`, the generic\n * `SpeechSynthesizer`, the `TtsIncrementalText` marker (incremental\n * text-in via `/stream-input` WebSocket), **and `MultiSpeakerTts`** —\n * multi-speaker dialogue is wired to `POST /v1/text-to-dialogue`\n * (sync) and `/v1/text-to-dialogue/stream` (chunked). Provide\n * `Socket.layerWebSocketConstructorGlobal` and an `HttpClient` Layer\n * at the call site.\n */\nexport const layer = (cfg: Config) =>\n Layer.mergeAll(\n Layer.effect(ElevenLabsSynthesizer, make(cfg)),\n Layer.effect(\n SpeechSynthesizer,\n Effect.map(make(cfg), (s): SpeechSynthesizerService => ({\n synthesize: (req: CommonSynthesizeRequest) =>\n s.synthesize(req as ElevenLabsSynthesizeRequest),\n streamSynthesis: (req: CommonSynthesizeRequest) =>\n s.streamSynthesis(req as ElevenLabsSynthesizeRequest),\n streamSynthesisFrom: (textIn, req: CommonStreamSynthesizeRequest) =>\n s.streamSynthesisFrom(textIn, req),\n synthesizeDialogue: s.synthesizeDialogue,\n streamSynthesizeDialogue: s.streamSynthesizeDialogue,\n })),\n ),\n Layer.succeed(TtsIncrementalText, undefined),\n Layer.succeed(MultiSpeakerTts, undefined),\n )\n"],"mappings":"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"}
@@ -1,9 +1,9 @@
1
1
  import { ElevenLabsSttModel } from "./models.mjs";
2
2
  import { ElevenLabsRegion } from "./region.mjs";
3
3
  import { Context, Effect, Layer, Redacted, Schema, Stream } from "effect";
4
- import { HttpClient } from "effect/unstable/http";
4
+ import { HttpClient } from "effect/http";
5
5
  import * as AiError from "@effect-uai/core/AiError";
6
- import * as Socket from "effect/unstable/socket/Socket";
6
+ import * as Socket from "effect/socket/Socket";
7
7
  import { CommonTranscribeRequest, SttStreaming, Transcriber, TranscriberService } from "@effect-uai/core/Transcriber";
8
8
  import { TranscriptResult, WordTimestamp } from "@effect-uai/core/Transcript";
9
9
  declare namespace ElevenLabsTranscriber_d_exports {
@@ -3,10 +3,10 @@ import { audioToBlob, bodyMultipart, defaultFileName, httpStatusError, transport
3
3
  import { resolveHost } from "./region.mjs";
4
4
  import { streamTranscription } from "./realtimeStt.mjs";
5
5
  import { Context, Effect, Layer, Redacted, Schema, Stream } from "effect";
6
- import { HttpClient, HttpClientRequest } from "effect/unstable/http";
6
+ import { HttpClient, HttpClientRequest } from "effect/http";
7
7
  import * as AiError from "@effect-uai/core/AiError";
8
8
  import * as Capabilities from "@effect-uai/core/Capabilities";
9
- import * as Socket from "effect/unstable/socket/Socket";
9
+ import * as Socket from "effect/socket/Socket";
10
10
  import { SttStreaming, Transcriber } from "@effect-uai/core/Transcriber";
11
11
  //#region src/ElevenLabsTranscriber.ts
12
12
  var ElevenLabsTranscriber_exports = /* @__PURE__ */ __exportAll({
@@ -1 +1 @@
1
- {"version":3,"file":"ElevenLabsTranscriber.mjs","names":[],"sources":["../src/ElevenLabsTranscriber.ts"],"sourcesContent":["import { Context, Effect, Layer, Redacted, Schema, Stream } from \"effect\"\nimport { HttpClient, HttpClientRequest } from \"effect/unstable/http\"\nimport * as Socket from \"effect/unstable/socket/Socket\"\nimport * as AiError from \"@effect-uai/core/AiError\"\nimport * as Capabilities from \"@effect-uai/core/Capabilities\"\nimport type { TranscriptResult, WordTimestamp } from \"@effect-uai/core/Transcript\"\nimport {\n type CommonTranscribeRequest,\n SttStreaming,\n Transcriber,\n type TranscriberService,\n} from \"@effect-uai/core/Transcriber\"\nimport {\n audioToBlob,\n bodyMultipart,\n defaultFileName,\n httpStatusError,\n transportFailure,\n} from \"./codec.js\"\nimport type { ElevenLabsSttModel } from \"./models.js\"\nimport { streamTranscription } from \"./realtimeStt.js\"\nimport { type ElevenLabsRegion, resolveHost } from \"./region.js\"\n\n// ---------------------------------------------------------------------------\n// Public types\n// ---------------------------------------------------------------------------\n\n/**\n * ElevenLabs-typed transcribe request. `model` narrows to\n * `ElevenLabsSttModel`. `numSpeakers` hints diarization. `audioEvents`\n * surfaces `(laughter)` / `(music)` tags inline in `text` (provider\n * default: true). `fileName` overrides the multipart upload's\n * `filename`; ElevenLabs uses the extension to detect format.\n */\nexport type ElevenLabsTranscribeRequest = Omit<CommonTranscribeRequest, \"model\"> & {\n readonly model: ElevenLabsSttModel\n readonly numSpeakers?: number\n readonly audioEvents?: boolean\n readonly fileName?: string\n}\n\nexport type ElevenLabsTranscriberService = {\n readonly transcribe: (\n r: ElevenLabsTranscribeRequest,\n ) => Effect.Effect<TranscriptResult, AiError.AiError>\n readonly streamTranscriptionFrom: TranscriberService[\"streamTranscriptionFrom\"]\n}\n\nexport class ElevenLabsTranscriber extends Context.Service<\n ElevenLabsTranscriber,\n ElevenLabsTranscriberService\n>()(\"@betalyra/effect-uai/providers/elevenlabs/ElevenLabsTranscriber\") {}\n\nexport type Config = {\n readonly apiKey: Redacted.Redacted\n readonly baseUrl?: string\n readonly region?: ElevenLabsRegion\n}\n\n// ---------------------------------------------------------------------------\n// Response schema\n// ---------------------------------------------------------------------------\n\nconst Word = Schema.Struct({\n text: Schema.String,\n start: Schema.optional(Schema.Number),\n end: Schema.optional(Schema.Number),\n type: Schema.optional(Schema.String),\n speaker_id: Schema.optional(Schema.String),\n logprob: Schema.optional(Schema.Number),\n})\n\nconst Wire = Schema.Struct({\n text: Schema.String,\n language_code: Schema.optional(Schema.String),\n language_probability: Schema.optional(Schema.Number),\n words: Schema.optional(Schema.Array(Word)),\n transcription_id: Schema.optional(Schema.String),\n})\nconst decodeWire = Schema.decodeUnknownEffect(Wire)\n\nconst toWordTimestamp = (w: typeof Word.Type): WordTimestamp | undefined =>\n w.start === undefined || w.end === undefined\n ? undefined\n : {\n text: w.text,\n startSeconds: w.start,\n endSeconds: w.end,\n ...(w.logprob !== undefined && { confidence: Math.exp(w.logprob) }),\n ...(w.speaker_id !== undefined && { speakerId: w.speaker_id }),\n }\n\n// ---------------------------------------------------------------------------\n// Multipart body\n// ---------------------------------------------------------------------------\n\nconst buildForm = (request: ElevenLabsTranscribeRequest) =>\n Effect.gen(function* () {\n const blob = yield* audioToBlob(request.audio)\n const fileName = request.fileName ?? defaultFileName(request.audio.mimeType ?? \"\")\n const form = new FormData()\n form.set(\"model_id\", request.model)\n form.set(\"file\", blob, fileName)\n if (request.language !== undefined) form.set(\"language_code\", request.language)\n if (request.diarization !== undefined)\n form.set(\"diarize\", request.diarization ? \"true\" : \"false\")\n if (request.wordTimestamps === true) form.set(\"timestamps_granularity\", \"word\")\n if (request.numSpeakers !== undefined) form.set(\"num_speakers\", String(request.numSpeakers))\n if (request.audioEvents !== undefined)\n form.set(\"tag_audio_events\", request.audioEvents ? \"true\" : \"false\")\n // Vocab biasing → Scribe `keyterms` (≤1000 terms, ≤50 chars). Each\n // term is a repeated form field (`keyterms=a&keyterms=b`), matching\n // the ElevenLabs SDK. Scribe has no free-form prompt field.\n for (const term of request.biasingTerms ?? []) form.append(\"keyterms\", term)\n yield* Capabilities.warnDroppedWhen(request.prompt, {\n provider: \"elevenlabs\",\n capability: \"prompt\",\n field: \"prompt\",\n reason: \"ElevenLabs Scribe has no free-form prompt field; bias via `biasingTerms`.\",\n })\n return form\n })\n\n// ---------------------------------------------------------------------------\n// HTTP plumbing\n// ---------------------------------------------------------------------------\n\nconst transcribeImpl = (cfg: Config) => (request: ElevenLabsTranscribeRequest) =>\n Effect.gen(function* () {\n const client = yield* HttpClient.HttpClient\n const withBody = yield* Effect.flatMap(buildForm(request), bodyMultipart)\n const httpRequest = HttpClientRequest.post(`${resolveHost(cfg)}/speech-to-text`).pipe(\n HttpClientRequest.setHeader(\"xi-api-key\", Redacted.value(cfg.apiKey)),\n withBody,\n )\n const response = yield* client.execute(httpRequest).pipe(Effect.mapError(transportFailure))\n if (response.status >= 400) {\n const text = yield* response.text.pipe(Effect.orElseSucceed(() => \"\"))\n return yield* Effect.fail(httpStatusError(response.status, text))\n }\n const json = yield* response.json.pipe(Effect.mapError(transportFailure))\n const wire = yield* decodeWire(json).pipe(\n Effect.mapError(\n (cause) => new AiError.GenerationFailed({ provider: \"elevenlabs\", raw: cause }),\n ),\n )\n const words = wire.words\n ?.map(toWordTimestamp)\n .filter((w): w is WordTimestamp => w !== undefined)\n return {\n text: wire.text,\n ...(wire.language_code !== undefined && { languageCode: wire.language_code }),\n ...(words !== undefined && words.length > 0 && { words }),\n raw: json,\n } satisfies TranscriptResult\n })\n\n// ---------------------------------------------------------------------------\n// Constructors\n// ---------------------------------------------------------------------------\n\nexport const make = (cfg: Config) =>\n Effect.gen(function* () {\n const client = yield* HttpClient.HttpClient\n const ctor = yield* Socket.WebSocketConstructor\n return {\n transcribe: (r) =>\n transcribeImpl(cfg)(r).pipe(Effect.provideService(HttpClient.HttpClient, client)),\n streamTranscriptionFrom: (audioIn, request) =>\n streamTranscription(cfg)(audioIn, request).pipe(\n Stream.provideService(HttpClient.HttpClient, client),\n Stream.provideService(Socket.WebSocketConstructor, ctor),\n ),\n } satisfies ElevenLabsTranscriberService\n })\n\n/**\n * Layer registers `ElevenLabsTranscriber`, the generic `Transcriber`,\n * **and the `SttStreaming` capability marker** — `streamTranscriptionFrom`\n * is wired to the realtime WebSocket. Provide\n * `Socket.layerWebSocketConstructorGlobal` (or a custom constructor) +\n * an `HttpClient` Layer at the call site.\n */\nexport const layer = (cfg: Config) =>\n Layer.mergeAll(\n Layer.effect(ElevenLabsTranscriber, make(cfg)),\n Layer.effect(\n Transcriber,\n Effect.map(make(cfg), (s): TranscriberService => ({\n transcribe: (req: CommonTranscribeRequest) =>\n s.transcribe(req as ElevenLabsTranscribeRequest),\n streamTranscriptionFrom: s.streamTranscriptionFrom,\n })),\n ),\n Layer.succeed(SttStreaming, undefined),\n )\n"],"mappings":"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"}
1
+ {"version":3,"file":"ElevenLabsTranscriber.mjs","names":[],"sources":["../src/ElevenLabsTranscriber.ts"],"sourcesContent":["import { Context, Effect, Layer, Redacted, Schema, Stream } from \"effect\"\nimport { HttpClient, HttpClientRequest } from \"effect/http\"\nimport * as Socket from \"effect/socket/Socket\"\nimport * as AiError from \"@effect-uai/core/AiError\"\nimport * as Capabilities from \"@effect-uai/core/Capabilities\"\nimport type { TranscriptResult, WordTimestamp } from \"@effect-uai/core/Transcript\"\nimport {\n type CommonTranscribeRequest,\n SttStreaming,\n Transcriber,\n type TranscriberService,\n} from \"@effect-uai/core/Transcriber\"\nimport {\n audioToBlob,\n bodyMultipart,\n defaultFileName,\n httpStatusError,\n transportFailure,\n} from \"./codec.js\"\nimport type { ElevenLabsSttModel } from \"./models.js\"\nimport { streamTranscription } from \"./realtimeStt.js\"\nimport { type ElevenLabsRegion, resolveHost } from \"./region.js\"\n\n// ---------------------------------------------------------------------------\n// Public types\n// ---------------------------------------------------------------------------\n\n/**\n * ElevenLabs-typed transcribe request. `model` narrows to\n * `ElevenLabsSttModel`. `numSpeakers` hints diarization. `audioEvents`\n * surfaces `(laughter)` / `(music)` tags inline in `text` (provider\n * default: true). `fileName` overrides the multipart upload's\n * `filename`; ElevenLabs uses the extension to detect format.\n */\nexport type ElevenLabsTranscribeRequest = Omit<CommonTranscribeRequest, \"model\"> & {\n readonly model: ElevenLabsSttModel\n readonly numSpeakers?: number\n readonly audioEvents?: boolean\n readonly fileName?: string\n}\n\nexport type ElevenLabsTranscriberService = {\n readonly transcribe: (\n r: ElevenLabsTranscribeRequest,\n ) => Effect.Effect<TranscriptResult, AiError.AiError>\n readonly streamTranscriptionFrom: TranscriberService[\"streamTranscriptionFrom\"]\n}\n\nexport class ElevenLabsTranscriber extends Context.Service<\n ElevenLabsTranscriber,\n ElevenLabsTranscriberService\n>()(\"@betalyra/effect-uai/providers/elevenlabs/ElevenLabsTranscriber\") {}\n\nexport type Config = {\n readonly apiKey: Redacted.Redacted\n readonly baseUrl?: string\n readonly region?: ElevenLabsRegion\n}\n\n// ---------------------------------------------------------------------------\n// Response schema\n// ---------------------------------------------------------------------------\n\nconst Word = Schema.Struct({\n text: Schema.String,\n start: Schema.optional(Schema.Number),\n end: Schema.optional(Schema.Number),\n type: Schema.optional(Schema.String),\n speaker_id: Schema.optional(Schema.String),\n logprob: Schema.optional(Schema.Number),\n})\n\nconst Wire = Schema.Struct({\n text: Schema.String,\n language_code: Schema.optional(Schema.String),\n language_probability: Schema.optional(Schema.Number),\n words: Schema.optional(Schema.Array(Word)),\n transcription_id: Schema.optional(Schema.String),\n})\nconst decodeWire = Schema.decodeUnknownEffect(Wire)\n\nconst toWordTimestamp = (w: typeof Word.Type): WordTimestamp | undefined =>\n w.start === undefined || w.end === undefined\n ? undefined\n : {\n text: w.text,\n startSeconds: w.start,\n endSeconds: w.end,\n ...(w.logprob !== undefined && { confidence: Math.exp(w.logprob) }),\n ...(w.speaker_id !== undefined && { speakerId: w.speaker_id }),\n }\n\n// ---------------------------------------------------------------------------\n// Multipart body\n// ---------------------------------------------------------------------------\n\nconst buildForm = (request: ElevenLabsTranscribeRequest) =>\n Effect.gen(function* () {\n const blob = yield* audioToBlob(request.audio)\n const fileName = request.fileName ?? defaultFileName(request.audio.mimeType ?? \"\")\n const form = new FormData()\n form.set(\"model_id\", request.model)\n form.set(\"file\", blob, fileName)\n if (request.language !== undefined) form.set(\"language_code\", request.language)\n if (request.diarization !== undefined)\n form.set(\"diarize\", request.diarization ? \"true\" : \"false\")\n if (request.wordTimestamps === true) form.set(\"timestamps_granularity\", \"word\")\n if (request.numSpeakers !== undefined) form.set(\"num_speakers\", String(request.numSpeakers))\n if (request.audioEvents !== undefined)\n form.set(\"tag_audio_events\", request.audioEvents ? \"true\" : \"false\")\n // Vocab biasing → Scribe `keyterms` (≤1000 terms, ≤50 chars). Each\n // term is a repeated form field (`keyterms=a&keyterms=b`), matching\n // the ElevenLabs SDK. Scribe has no free-form prompt field.\n for (const term of request.biasingTerms ?? []) form.append(\"keyterms\", term)\n yield* Capabilities.warnDroppedWhen(request.prompt, {\n provider: \"elevenlabs\",\n capability: \"prompt\",\n field: \"prompt\",\n reason: \"ElevenLabs Scribe has no free-form prompt field; bias via `biasingTerms`.\",\n })\n return form\n })\n\n// ---------------------------------------------------------------------------\n// HTTP plumbing\n// ---------------------------------------------------------------------------\n\nconst transcribeImpl = (cfg: Config) => (request: ElevenLabsTranscribeRequest) =>\n Effect.gen(function* () {\n const client = yield* HttpClient.HttpClient\n const withBody = yield* Effect.flatMap(buildForm(request), bodyMultipart)\n const httpRequest = HttpClientRequest.post(`${resolveHost(cfg)}/speech-to-text`).pipe(\n HttpClientRequest.setHeader(\"xi-api-key\", Redacted.value(cfg.apiKey)),\n withBody,\n )\n const response = yield* client.execute(httpRequest).pipe(Effect.mapError(transportFailure))\n if (response.status >= 400) {\n const text = yield* response.text.pipe(Effect.orElseSucceed(() => \"\"))\n return yield* Effect.fail(httpStatusError(response.status, text))\n }\n const json = yield* response.json.pipe(Effect.mapError(transportFailure))\n const wire = yield* decodeWire(json).pipe(\n Effect.mapError(\n (cause) => new AiError.GenerationFailed({ provider: \"elevenlabs\", raw: cause }),\n ),\n )\n const words = wire.words\n ?.map(toWordTimestamp)\n .filter((w): w is WordTimestamp => w !== undefined)\n return {\n text: wire.text,\n ...(wire.language_code !== undefined && { languageCode: wire.language_code }),\n ...(words !== undefined && words.length > 0 && { words }),\n raw: json,\n } satisfies TranscriptResult\n })\n\n// ---------------------------------------------------------------------------\n// Constructors\n// ---------------------------------------------------------------------------\n\nexport const make = (cfg: Config) =>\n Effect.gen(function* () {\n const client = yield* HttpClient.HttpClient\n const ctor = yield* Socket.WebSocketConstructor\n return {\n transcribe: (r) =>\n transcribeImpl(cfg)(r).pipe(Effect.provideService(HttpClient.HttpClient, client)),\n streamTranscriptionFrom: (audioIn, request) =>\n streamTranscription(cfg)(audioIn, request).pipe(\n Stream.provideService(HttpClient.HttpClient, client),\n Stream.provideService(Socket.WebSocketConstructor, ctor),\n ),\n } satisfies ElevenLabsTranscriberService\n })\n\n/**\n * Layer registers `ElevenLabsTranscriber`, the generic `Transcriber`,\n * **and the `SttStreaming` capability marker** — `streamTranscriptionFrom`\n * is wired to the realtime WebSocket. Provide\n * `Socket.layerWebSocketConstructorGlobal` (or a custom constructor) +\n * an `HttpClient` Layer at the call site.\n */\nexport const layer = (cfg: Config) =>\n Layer.mergeAll(\n Layer.effect(ElevenLabsTranscriber, make(cfg)),\n Layer.effect(\n Transcriber,\n Effect.map(make(cfg), (s): TranscriberService => ({\n transcribe: (req: CommonTranscribeRequest) =>\n s.transcribe(req as ElevenLabsTranscribeRequest),\n streamTranscriptionFrom: s.streamTranscriptionFrom,\n })),\n ),\n Layer.succeed(SttStreaming, undefined),\n )\n"],"mappings":"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"}
@@ -1,9 +1,9 @@
1
- import { n as describe, r as it, t as globalExpect } from "./test.DNmyFkvJ-N3QqMRwZ.mjs";
2
- import { t as import_dist } from "./dist-C0AvqZTC.mjs";
1
+ import { c as it, n as globalExpect, s as describe } from "./index.C4tKZ0yW-DjxCdpW_.mjs";
2
+ import { t as import_dist } from "./dist-DkEvSNwD.mjs";
3
3
  import { ElevenLabsTranscriber, layer } from "./ElevenLabsTranscriber.mjs";
4
4
  import { Effect, Layer, Redacted, Stream } from "effect";
5
- import { FetchHttpClient } from "effect/unstable/http";
6
- import * as Socket from "effect/unstable/socket/Socket";
5
+ import { FetchHttpClient } from "effect/http";
6
+ import * as Socket from "effect/socket/Socket";
7
7
  import * as Transcriber$1 from "@effect-uai/core/Transcriber";
8
8
  //#region src/ElevenLabsTranscriber.test.ts
9
9
  const cfg = { apiKey: Redacted.make("test-key") };
@@ -1 +1 @@
1
- {"version":3,"file":"ElevenLabsTranscriber.test.mjs","names":["ElevenLabsTranscriber.layer","Transcriber"],"sources":["../src/ElevenLabsTranscriber.test.ts"],"sourcesContent":["import { Effect, Layer, Redacted, Stream } from \"effect\"\nimport { FetchHttpClient } from \"effect/unstable/http\"\nimport * as Socket from \"effect/unstable/socket/Socket\"\nimport { describe, expect, expectTypeOf, it } from \"vitest\"\nimport type * as AiError from \"@effect-uai/core/AiError\"\nimport type { TranscriptResult } from \"@effect-uai/core/Transcript\"\nimport * as Transcriber from \"@effect-uai/core/Transcriber\"\nimport * as ElevenLabsTranscriber from \"./ElevenLabsTranscriber.js\"\n\nconst cfg: ElevenLabsTranscriber.Config = { apiKey: Redacted.make(\"test-key\") }\n// FetchHttpClient + globalThis.WebSocket are required for `make`, but these\n// tests only exercise the codec + compile-time / runtime branches — no real\n// HTTP or WS connection is opened.\nconst live = ElevenLabsTranscriber.layer(cfg).pipe(\n Layer.provide(FetchHttpClient.layer),\n Layer.provide(Socket.layerWebSocketConstructorGlobal),\n)\n\nconst dummyAudio = {\n _tag: \"bytes\" as const,\n bytes: new Uint8Array([0, 1, 2, 3]),\n mimeType: \"audio/wav\" as const,\n}\n\ndescribe(\"ElevenLabsTranscriber input format guard (runtime)\", () => {\n it(\"fails Unsupported for unsupported raw encodings\", async () => {\n const program = ElevenLabsTranscriber.ElevenLabsTranscriber.use((s) =>\n Stream.runDrain(\n s.streamTranscriptionFrom(Stream.fromIterable([new Uint8Array([0])]), {\n model: \"scribe_v2_realtime\",\n inputFormat: { container: \"mp3\", encoding: \"mp3\", sampleRate: 44100 },\n }),\n ),\n )\n const exit = await Effect.runPromiseExit(program.pipe(Effect.provide(live)))\n expect(exit._tag).toBe(\"Failure\")\n if (exit._tag === \"Failure\") {\n expect(JSON.stringify(exit.cause)).toContain(\"Unsupported\")\n expect(JSON.stringify(exit.cause)).toContain(\"inputFormat\")\n }\n })\n})\n\ndescribe(\"ElevenLabsTranscriber Layer (compile-time)\", () => {\n it(\"registers `SttStreaming` — `streamTranscriptionFrom` clears R to never\", () => {\n const audio: Stream.Stream<Uint8Array> = Stream.fromIterable([new Uint8Array([0])])\n const events = audio.pipe(\n Transcriber.streamTranscriptionFrom({\n model: \"scribe_v2_realtime\",\n inputFormat: { container: \"raw\", encoding: \"pcm_s16le\", sampleRate: 16000 },\n }),\n )\n const provided = Stream.runDrain(events).pipe(Effect.provide(live))\n expectTypeOf(provided).toEqualTypeOf<Effect.Effect<void, AiError.AiError, never>>()\n })\n\n it(\"sync `transcribe` requires no marker\", () => {\n const t = Transcriber.transcribe({ audio: dummyAudio, model: \"scribe_v2\" }).pipe(\n Effect.provide(live),\n )\n expectTypeOf(t).toEqualTypeOf<Effect.Effect<TranscriptResult, AiError.AiError, never>>()\n })\n})\n"],"mappings":";;;;;;;;AASA,MAAM,MAAoC,EAAE,QAAQ,SAAS,KAAK,UAAU,EAAE;AAI9E,MAAM,OAAOA,MAA4B,GAAG,CAAC,CAAC,KAC5C,MAAM,QAAQ,gBAAgB,KAAK,GACnC,MAAM,QAAQ,OAAO,+BAA+B,CACtD;AAEA,MAAM,aAAa;CACjB,MAAM;CACN,OAAO,IAAI,WAAW;EAAC;EAAG;EAAG;EAAG;CAAC,CAAC;CAClC,UAAU;AACZ;AAEA,SAAS,4DAA4D;CACnE,GAAG,mDAAmD,YAAY;EAChE,MAAM,UAAA,sBAAsD,KAAK,MAC/D,OAAO,SACL,EAAE,wBAAwB,OAAO,aAAa,CAAC,IAAI,WAAW,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG;GACpE,OAAO;GACP,aAAa;IAAE,WAAW;IAAO,UAAU;IAAO,YAAY;GAAM;EACtE,CAAC,CACH,CACF;EACA,MAAM,OAAO,MAAM,OAAO,eAAe,QAAQ,KAAK,OAAO,QAAQ,IAAI,CAAC,CAAC;EAC3E,aAAO,KAAK,IAAI,CAAC,CAAC,KAAK,SAAS;EAChC,IAAI,KAAK,SAAS,WAAW;GAC3B,aAAO,KAAK,UAAU,KAAK,KAAK,CAAC,CAAC,CAAC,UAAU,aAAa;GAC1D,aAAO,KAAK,UAAU,KAAK,KAAK,CAAC,CAAC,CAAC,UAAU,aAAa;EAC5D;CACF,CAAC;AACH,CAAC;AAED,SAAS,oDAAoD;CAC3D,GAAG,gFAAgF;EAEjF,MAAM,SADmC,OAAO,aAAa,CAAC,IAAI,WAAW,CAAC,CAAC,CAAC,CAAC,CAC9D,CAAC,CAAC,KACnBC,cAAY,wBAAwB;GAClC,OAAO;GACP,aAAa;IAAE,WAAW;IAAO,UAAU;IAAa,YAAY;GAAM;EAC5E,CAAC,CACH;EACA,MAAM,WAAW,OAAO,SAAS,MAAM,CAAC,CAAC,KAAK,OAAO,QAAQ,IAAI,CAAC;EAClE,CAAA,GAAA,YAAA,aAAA,CAAa,QAAQ,CAAC,CAAC,cAA2D;CACpF,CAAC;CAED,GAAG,8CAA8C;EAC/C,MAAM,IAAIA,cAAY,WAAW;GAAE,OAAO;GAAY,OAAO;EAAY,CAAC,CAAC,CAAC,KAC1E,OAAO,QAAQ,IAAI,CACrB;EACA,CAAA,GAAA,YAAA,aAAA,CAAa,CAAC,CAAC,CAAC,cAAuE;CACzF,CAAC;AACH,CAAC"}
1
+ {"version":3,"file":"ElevenLabsTranscriber.test.mjs","names":["ElevenLabsTranscriber.layer","Transcriber"],"sources":["../src/ElevenLabsTranscriber.test.ts"],"sourcesContent":["import { Effect, Layer, Redacted, Stream } from \"effect\"\nimport { FetchHttpClient } from \"effect/http\"\nimport * as Socket from \"effect/socket/Socket\"\nimport { describe, expect, expectTypeOf, it } from \"vitest\"\nimport type * as AiError from \"@effect-uai/core/AiError\"\nimport type { TranscriptResult } from \"@effect-uai/core/Transcript\"\nimport * as Transcriber from \"@effect-uai/core/Transcriber\"\nimport * as ElevenLabsTranscriber from \"./ElevenLabsTranscriber.js\"\n\nconst cfg: ElevenLabsTranscriber.Config = { apiKey: Redacted.make(\"test-key\") }\n// FetchHttpClient + globalThis.WebSocket are required for `make`, but these\n// tests only exercise the codec + compile-time / runtime branches — no real\n// HTTP or WS connection is opened.\nconst live = ElevenLabsTranscriber.layer(cfg).pipe(\n Layer.provide(FetchHttpClient.layer),\n Layer.provide(Socket.layerWebSocketConstructorGlobal),\n)\n\nconst dummyAudio = {\n _tag: \"bytes\" as const,\n bytes: new Uint8Array([0, 1, 2, 3]),\n mimeType: \"audio/wav\" as const,\n}\n\ndescribe(\"ElevenLabsTranscriber input format guard (runtime)\", () => {\n it(\"fails Unsupported for unsupported raw encodings\", async () => {\n const program = ElevenLabsTranscriber.ElevenLabsTranscriber.use((s) =>\n Stream.runDrain(\n s.streamTranscriptionFrom(Stream.fromIterable([new Uint8Array([0])]), {\n model: \"scribe_v2_realtime\",\n inputFormat: { container: \"mp3\", encoding: \"mp3\", sampleRate: 44100 },\n }),\n ),\n )\n const exit = await Effect.runPromiseExit(program.pipe(Effect.provide(live)))\n expect(exit._tag).toBe(\"Failure\")\n if (exit._tag === \"Failure\") {\n expect(JSON.stringify(exit.cause)).toContain(\"Unsupported\")\n expect(JSON.stringify(exit.cause)).toContain(\"inputFormat\")\n }\n })\n})\n\ndescribe(\"ElevenLabsTranscriber Layer (compile-time)\", () => {\n it(\"registers `SttStreaming` — `streamTranscriptionFrom` clears R to never\", () => {\n const audio: Stream.Stream<Uint8Array> = Stream.fromIterable([new Uint8Array([0])])\n const events = audio.pipe(\n Transcriber.streamTranscriptionFrom({\n model: \"scribe_v2_realtime\",\n inputFormat: { container: \"raw\", encoding: \"pcm_s16le\", sampleRate: 16000 },\n }),\n )\n const provided = Stream.runDrain(events).pipe(Effect.provide(live))\n expectTypeOf(provided).toEqualTypeOf<Effect.Effect<void, AiError.AiError, never>>()\n })\n\n it(\"sync `transcribe` requires no marker\", () => {\n const t = Transcriber.transcribe({ audio: dummyAudio, model: \"scribe_v2\" }).pipe(\n Effect.provide(live),\n )\n expectTypeOf(t).toEqualTypeOf<Effect.Effect<TranscriptResult, AiError.AiError, never>>()\n })\n})\n"],"mappings":";;;;;;;;AASA,MAAM,MAAoC,EAAE,QAAQ,SAAS,KAAK,UAAU,EAAE;AAI9E,MAAM,OAAOA,MAA4B,GAAG,CAAC,CAAC,KAC5C,MAAM,QAAQ,gBAAgB,KAAK,GACnC,MAAM,QAAQ,OAAO,+BAA+B,CACtD;AAEA,MAAM,aAAa;CACjB,MAAM;CACN,OAAO,IAAI,WAAW;EAAC;EAAG;EAAG;EAAG;CAAC,CAAC;CAClC,UAAU;AACZ;AAEA,SAAS,4DAA4D;CACnE,GAAG,mDAAmD,YAAY;EAChE,MAAM,UAAA,sBAAsD,KAAK,MAC/D,OAAO,SACL,EAAE,wBAAwB,OAAO,aAAa,CAAC,IAAI,WAAW,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG;GACpE,OAAO;GACP,aAAa;IAAE,WAAW;IAAO,UAAU;IAAO,YAAY;GAAM;EACtE,CAAC,CACH,CACF;EACA,MAAM,OAAO,MAAM,OAAO,eAAe,QAAQ,KAAK,OAAO,QAAQ,IAAI,CAAC,CAAC;EAC3E,aAAO,KAAK,IAAI,CAAC,CAAC,KAAK,SAAS;EAChC,IAAI,KAAK,SAAS,WAAW;GAC3B,aAAO,KAAK,UAAU,KAAK,KAAK,CAAC,CAAC,CAAC,UAAU,aAAa;GAC1D,aAAO,KAAK,UAAU,KAAK,KAAK,CAAC,CAAC,CAAC,UAAU,aAAa;EAC5D;CACF,CAAC;AACH,CAAC;AAED,SAAS,oDAAoD;CAC3D,GAAG,gFAAgF;EAEjF,MAAM,SADmC,OAAO,aAAa,CAAC,IAAI,WAAW,CAAC,CAAC,CAAC,CAAC,CAC9D,CAAC,CAAC,KACnBC,cAAY,wBAAwB;GAClC,OAAO;GACP,aAAa;IAAE,WAAW;IAAO,UAAU;IAAa,YAAY;GAAM;EAC5E,CAAC,CACH;EACA,MAAM,WAAW,OAAO,SAAS,MAAM,CAAC,CAAC,KAAK,OAAO,QAAQ,IAAI,CAAC;EAClE,CAAA,GAAA,YAAA,aAAA,CAAa,QAAQ,CAAC,CAAC,cAA2D;CACpF,CAAC;CAED,GAAG,8CAA8C;EAC/C,MAAM,IAAIA,cAAY,WAAW;GAAE,OAAO;GAAY,OAAO;EAAY,CAAC,CAAC,CAAC,KAC1E,OAAO,QAAQ,IAAI,CACrB;EACA,CAAA,GAAA,YAAA,aAAA,CAAa,CAAC,CAAC,CAAC,cAAuE;CACzF,CAAC;AACH,CAAC"}
package/dist/codec.d.mts CHANGED
@@ -1,5 +1,5 @@
1
1
  import { Effect } from "effect";
2
- import { HttpClientRequest } from "effect/unstable/http";
2
+ import { HttpClientRequest } from "effect/http";
3
3
  import * as AiError from "@effect-uai/core/AiError";
4
4
  import { CustomPronunciation } from "@effect-uai/core/SpeechSynthesizer";
5
5
  import { AudioFormat, AudioSource } from "@effect-uai/core/Audio";
@@ -1 +1 @@
1
- {"version":3,"file":"codec.d.mts","names":[],"sources":["../src/codec.ts"],"mappings":";;;;;;;;KAWY;WACD;WACA;WACA;WACA;WACA;;cAGE,oBAAiB,GAAO;;;;;;;;;;;;KAoBzB;WACD;WACA;;cAGE,4BAAyB,UAC1B,cAAc;;;;;;;;;;;;cAiBb,6BAA0B,gBACrB,cAAc,qCAC7B,OAAO,aAAa,QAAQ;;;;;;;;;;;;cA2BlB,qBAAqB,QAAQ,gBAAgB,OAAO,eAAe,QAAQ;;cAgC3E,eAAe;cA6Bf,cAAc,OAAO,gBAAgB,OAAO,OAAO,MAAM,QAAQ;cA2BjE,kBAAe;cAYf,kBAAkB,gBAAgB,iBAAiB,QAAQ;cAyC3D,mBAAgB,mBAAqB,QAAQ;;cAI7C,gBAAa,MAClB,aACL,OAAO,QACP,SAAS,kBAAkB,sBAAsB,kBAAkB,mBACpE,QAAQ"}
1
+ {"version":3,"file":"codec.d.mts","names":[],"sources":["../src/codec.ts"],"mappings":";;;;;;;;KAYY;WACD;WACA;WACA;WACA;WACA;;cAGE,oBAAiB,GAAO;;;;;;;;;;;;KAoBzB;WACD;WACA;;cAGE,4BAAyB,UAC1B,cAAc;;;;;;;;;;;;cAiBb,6BAA0B,gBACrB,cAAc,qCAC7B,OAAO,aAAa,QAAQ;;;;;;;;;;;;cA2BlB,qBAAqB,QAAQ,gBAAgB,OAAO,eAAe,QAAQ;;cAgC3E,eAAe;cA6Bf,cAAc,OAAO,gBAAgB,OAAO,OAAO,MAAM,QAAQ;cA2BjE,kBAAe;cAYf,kBAAkB,gBAAgB,iBAAiB,QAAQ;cAyC3D,mBAAgB,mBAAqB,QAAQ;;cAI7C,gBAAa,MAClB,aACL,OAAO,QACP,SAAS,kBAAkB,sBAAsB,kBAAkB,mBACpE,QAAQ"}
package/dist/codec.mjs CHANGED
@@ -1,6 +1,7 @@
1
1
  import { n as __exportAll } from "./rolldown-runtime-EAsCxrDo.mjs";
2
- import { Array, Effect, Encoding, Match, Option, Result } from "effect";
2
+ import { Array, Effect, Match, Option, Result } from "effect";
3
3
  import * as AiError from "@effect-uai/core/AiError";
4
+ import { Base64 } from "effect/encoding";
4
5
  import * as Multipart from "@effect-uai/core/Multipart";
5
6
  //#region src/codec.ts
6
7
  var codec_exports = /* @__PURE__ */ __exportAll({
@@ -74,7 +75,7 @@ const urlNotSupported = new AiError.InvalidRequest({
74
75
  param: "audio",
75
76
  raw: "ElevenLabs accepts URLs via the `cloud_storage_url` field, not the `file` field. Fetch the URL yourself and pass `{ _tag: \"bytes\", bytes, mimeType }` to use the inline path."
76
77
  });
77
- const decodeBase64ToBytes = (b64) => Result.match(Encoding.decodeBase64(b64), {
78
+ const decodeBase64ToBytes = (b64) => Result.match(Base64.decode(b64), {
78
79
  onSuccess: Effect.succeed,
79
80
  onFailure: (cause) => Effect.fail(new AiError.InvalidRequest({
80
81
  provider: "elevenlabs",
@@ -1 +1 @@
1
- {"version":3,"file":"codec.mjs","names":["Arr"],"sources":["../src/codec.ts"],"sourcesContent":["import { Array as Arr, Effect, Encoding, Match, Option, Result } from \"effect\"\nimport { HttpClientRequest } from \"effect/unstable/http\"\nimport * as AiError from \"@effect-uai/core/AiError\"\nimport type { AudioFormat, AudioSource } from \"@effect-uai/core/Audio\"\nimport * as Multipart from \"@effect-uai/core/Multipart\"\nimport type { CustomPronunciation } from \"@effect-uai/core/SpeechSynthesizer\"\n\n// ---------------------------------------------------------------------------\n// Shared TTS voice-settings shape (sync + streaming use the same fields)\n// ---------------------------------------------------------------------------\n\nexport type VoiceSettings = {\n readonly stability?: number\n readonly similarityBoost?: number\n readonly style?: number\n readonly useSpeakerBoost?: boolean\n readonly speed?: number\n}\n\nexport const wireVoiceSettings = (v: VoiceSettings | undefined) =>\n v === undefined\n ? undefined\n : {\n ...(v.stability !== undefined && { stability: v.stability }),\n ...(v.similarityBoost !== undefined && { similarity_boost: v.similarityBoost }),\n ...(v.style !== undefined && { style: v.style }),\n ...(v.useSpeakerBoost !== undefined && { use_speaker_boost: v.useSpeakerBoost }),\n ...(v.speed !== undefined && { speed: v.speed }),\n }\n\n// ---------------------------------------------------------------------------\n// Pronunciation: dictionary locators (supported) vs inline IPA (rejected)\n// ---------------------------------------------------------------------------\n\n/**\n * Reference to a pre-provisioned ElevenLabs pronunciation dictionary.\n * The caller provisions and versions the dictionary out-of-band\n * (dashboard or the pronunciation-dictionary API); we only reference it.\n */\nexport type PronunciationDictionaryLocator = {\n readonly dictionaryId: string\n readonly versionId: string\n}\n\nexport const wirePronunciationLocators = (\n locators: ReadonlyArray<PronunciationDictionaryLocator> | undefined,\n) =>\n locators === undefined || locators.length === 0\n ? undefined\n : {\n pronunciation_dictionary_locators: locators.map((l) => ({\n pronunciation_dictionary_id: l.dictionaryId,\n version_id: l.versionId,\n })),\n }\n\n/**\n * ElevenLabs has no stateless inline IPA path (legacy `<phoneme>` SSML\n * is dropped; modern phonetics live in pre-uploaded dictionaries).\n * Inline `pronunciations` are load-bearing (bucket 1), so reject rather\n * than silently mispronounce. Use `pronunciationDictionaryLocators`.\n */\nexport const rejectInlinePronunciations = (\n pronunciations: ReadonlyArray<CustomPronunciation> | undefined,\n): Effect.Effect<void, AiError.AiError> =>\n pronunciations !== undefined && pronunciations.length > 0\n ? Effect.fail(\n new AiError.Unsupported({\n provider: \"elevenlabs\",\n capability: \"pronunciations\",\n reason:\n \"ElevenLabs has no stateless inline IPA path. Provision a pronunciation dictionary and pass `pronunciationDictionaryLocators`, or use a provider with inline phonemes (Inworld, Google).\",\n }),\n )\n : Effect.void\n\n// ---------------------------------------------------------------------------\n// AudioFormat → ElevenLabs `output_format` query value\n// ---------------------------------------------------------------------------\n\n/**\n * ElevenLabs encodes container + sample rate + bitrate in a single\n * dot-less slug (`mp3_44100_128`, `pcm_16000`, `wav_48000`, `ulaw_8000`,\n * `opus_48000_128`, etc.). This helper inverts the common cases of our\n * `AudioFormat` shape into that slug.\n *\n * Only the formats that map cleanly are produced. Anything we can't\n * encode (mismatched bitrate, unsupported sample rate combination)\n * fails `Unsupported` with the requested format echoed so the user can\n * fix it.\n */\nexport const formatToOutputSlug: (format: AudioFormat) => Effect.Effect<string, AiError.AiError> = (\n format,\n) =>\n Match.value(format).pipe(\n Match.when({ container: \"mp3\" }, (f) =>\n Effect.succeed(`mp3_${f.sampleRate}_${f.bitRate ?? 128}`),\n ),\n Match.when({ container: \"opus\" }, (f) =>\n Effect.succeed(`opus_${f.sampleRate}_${f.bitRate ?? 128}`),\n ),\n Match.when({ container: \"wav\" }, (f) => Effect.succeed(`wav_${f.sampleRate}`)),\n Match.when({ container: \"raw\", encoding: \"pcm_s16le\" }, (f) =>\n Effect.succeed(`pcm_${f.sampleRate}`),\n ),\n Match.when({ container: \"raw\", encoding: \"pcm_mulaw\" }, (f) =>\n Effect.succeed(`ulaw_${f.sampleRate}`),\n ),\n Match.when({ container: \"raw\", encoding: \"pcm_alaw\" }, (f) =>\n Effect.succeed(`alaw_${f.sampleRate}`),\n ),\n Match.orElse((f) =>\n Effect.fail(\n new AiError.Unsupported({\n provider: \"elevenlabs\",\n capability: \"outputFormat\",\n reason: `Cannot encode ${JSON.stringify(f)} as ElevenLabs output_format. Supported: mp3 + (22050|44100), opus 48000, wav 48000, pcm/ulaw/alaw at any sample rate.`,\n }),\n ),\n ),\n )\n\n/** Default output: 128 kbps MP3 at 44.1 kHz. */\nexport const defaultFormat: AudioFormat = {\n container: \"mp3\",\n encoding: \"mp3\",\n sampleRate: 44100,\n bitRate: 128,\n}\n\n// ---------------------------------------------------------------------------\n// AudioSource → Blob (STT multipart upload)\n// ---------------------------------------------------------------------------\n\nconst urlNotSupported: AiError.AiError = new AiError.InvalidRequest({\n provider: \"elevenlabs\",\n param: \"audio\",\n raw: 'ElevenLabs accepts URLs via the `cloud_storage_url` field, not the `file` field. Fetch the URL yourself and pass `{ _tag: \"bytes\", bytes, mimeType }` to use the inline path.',\n})\n\nconst decodeBase64ToBytes = (b64: string): Effect.Effect<Uint8Array, AiError.AiError> =>\n Result.match(Encoding.decodeBase64(b64), {\n onSuccess: Effect.succeed,\n onFailure: (cause) =>\n Effect.fail(\n new AiError.InvalidRequest({ provider: \"elevenlabs\", param: \"audio\", raw: cause }),\n ),\n })\n\nconst bytesToBlob = (bytes: Uint8Array, mimeType: string): Blob =>\n new Blob([bytes as Uint8Array<ArrayBuffer>], { type: mimeType })\n\nexport const audioToBlob: (audio: AudioSource) => Effect.Effect<Blob, AiError.AiError> =\n Match.type<AudioSource>().pipe(\n Match.tag(\"bytes\", (a) => Effect.succeed(bytesToBlob(a.bytes, a.mimeType))),\n Match.tag(\"base64\", (a) =>\n decodeBase64ToBytes(a.base64).pipe(Effect.map((bytes) => bytesToBlob(bytes, a.mimeType))),\n ),\n Match.tag(\"url\", () => Effect.fail(urlNotSupported)),\n Match.exhaustive,\n )\n\n// ---------------------------------------------------------------------------\n// MIME → file extension (for the multipart `filename` field)\n// ---------------------------------------------------------------------------\n\nconst EXTENSION_BY_MIME: ReadonlyArray<readonly [string, string]> = [\n [\"mpeg\", \"mp3\"],\n [\"mp3\", \"mp3\"],\n [\"wav\", \"wav\"],\n [\"ogg\", \"ogg\"],\n [\"opus\", \"ogg\"],\n [\"flac\", \"flac\"],\n [\"aac\", \"aac\"],\n [\"mp4\", \"m4a\"],\n [\"m4a\", \"m4a\"],\n [\"webm\", \"webm\"],\n]\n\nexport const defaultFileName = (mimeType: string): string =>\n Arr.findFirst(EXTENSION_BY_MIME, ([pattern]) => mimeType.includes(pattern)).pipe(\n Option.match({\n onNone: () => \"audio\",\n onSome: ([, ext]) => `audio.${ext}`,\n }),\n )\n\n// ---------------------------------------------------------------------------\n// HTTP errors\n// ---------------------------------------------------------------------------\n\nexport const httpStatusError: (status: number, body: string) => AiError.AiError = (status, body) =>\n Match.value(status).pipe(\n Match.when(\n 429,\n (): AiError.AiError => new AiError.RateLimited({ provider: \"elevenlabs\", raw: body }),\n ),\n Match.whenOr(\n 408,\n 504,\n (): AiError.AiError => new AiError.Timeout({ provider: \"elevenlabs\", raw: body }),\n ),\n Match.when(\n 401,\n (): AiError.AiError =>\n new AiError.AuthFailed({ provider: \"elevenlabs\", subtype: \"auth\", raw: body }),\n ),\n Match.when(\n 403,\n (): AiError.AiError =>\n new AiError.AuthFailed({ provider: \"elevenlabs\", subtype: \"permission\", raw: body }),\n ),\n Match.when(\n 402,\n (): AiError.AiError =>\n new AiError.AuthFailed({ provider: \"elevenlabs\", subtype: \"billing\", raw: body }),\n ),\n Match.when(\n 413,\n (): AiError.AiError =>\n new AiError.ContextLengthExceeded({ provider: \"elevenlabs\", raw: body }),\n ),\n Match.when(\n (n) => n >= 500,\n (n): AiError.AiError =>\n new AiError.Unavailable({ provider: \"elevenlabs\", status: n, raw: body }),\n ),\n Match.orElse(\n (): AiError.AiError => new AiError.InvalidRequest({ provider: \"elevenlabs\", raw: body }),\n ),\n )\n\nexport const transportFailure = (cause: unknown): AiError.AiError =>\n new AiError.Unavailable({ provider: \"elevenlabs\", raw: cause })\n\n/** Core's helper, with our transport error. Never pass `FormData` to the client. */\nexport const bodyMultipart = (\n form: FormData,\n): Effect.Effect<\n (request: HttpClientRequest.HttpClientRequest) => HttpClientRequest.HttpClientRequest,\n AiError.AiError\n> => Multipart.bodyMultipart(form).pipe(Effect.mapError(transportFailure))\n"],"mappings":"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"}
1
+ {"version":3,"file":"codec.mjs","names":["Arr"],"sources":["../src/codec.ts"],"sourcesContent":["import { Array as Arr, Effect, Match, Option, Result } from \"effect\"\nimport { Base64 } from \"effect/encoding\"\nimport { HttpClientRequest } from \"effect/http\"\nimport * as AiError from \"@effect-uai/core/AiError\"\nimport type { AudioFormat, AudioSource } from \"@effect-uai/core/Audio\"\nimport * as Multipart from \"@effect-uai/core/Multipart\"\nimport type { CustomPronunciation } from \"@effect-uai/core/SpeechSynthesizer\"\n\n// ---------------------------------------------------------------------------\n// Shared TTS voice-settings shape (sync + streaming use the same fields)\n// ---------------------------------------------------------------------------\n\nexport type VoiceSettings = {\n readonly stability?: number\n readonly similarityBoost?: number\n readonly style?: number\n readonly useSpeakerBoost?: boolean\n readonly speed?: number\n}\n\nexport const wireVoiceSettings = (v: VoiceSettings | undefined) =>\n v === undefined\n ? undefined\n : {\n ...(v.stability !== undefined && { stability: v.stability }),\n ...(v.similarityBoost !== undefined && { similarity_boost: v.similarityBoost }),\n ...(v.style !== undefined && { style: v.style }),\n ...(v.useSpeakerBoost !== undefined && { use_speaker_boost: v.useSpeakerBoost }),\n ...(v.speed !== undefined && { speed: v.speed }),\n }\n\n// ---------------------------------------------------------------------------\n// Pronunciation: dictionary locators (supported) vs inline IPA (rejected)\n// ---------------------------------------------------------------------------\n\n/**\n * Reference to a pre-provisioned ElevenLabs pronunciation dictionary.\n * The caller provisions and versions the dictionary out-of-band\n * (dashboard or the pronunciation-dictionary API); we only reference it.\n */\nexport type PronunciationDictionaryLocator = {\n readonly dictionaryId: string\n readonly versionId: string\n}\n\nexport const wirePronunciationLocators = (\n locators: ReadonlyArray<PronunciationDictionaryLocator> | undefined,\n) =>\n locators === undefined || locators.length === 0\n ? undefined\n : {\n pronunciation_dictionary_locators: locators.map((l) => ({\n pronunciation_dictionary_id: l.dictionaryId,\n version_id: l.versionId,\n })),\n }\n\n/**\n * ElevenLabs has no stateless inline IPA path (legacy `<phoneme>` SSML\n * is dropped; modern phonetics live in pre-uploaded dictionaries).\n * Inline `pronunciations` are load-bearing (bucket 1), so reject rather\n * than silently mispronounce. Use `pronunciationDictionaryLocators`.\n */\nexport const rejectInlinePronunciations = (\n pronunciations: ReadonlyArray<CustomPronunciation> | undefined,\n): Effect.Effect<void, AiError.AiError> =>\n pronunciations !== undefined && pronunciations.length > 0\n ? Effect.fail(\n new AiError.Unsupported({\n provider: \"elevenlabs\",\n capability: \"pronunciations\",\n reason:\n \"ElevenLabs has no stateless inline IPA path. Provision a pronunciation dictionary and pass `pronunciationDictionaryLocators`, or use a provider with inline phonemes (Inworld, Google).\",\n }),\n )\n : Effect.void\n\n// ---------------------------------------------------------------------------\n// AudioFormat → ElevenLabs `output_format` query value\n// ---------------------------------------------------------------------------\n\n/**\n * ElevenLabs encodes container + sample rate + bitrate in a single\n * dot-less slug (`mp3_44100_128`, `pcm_16000`, `wav_48000`, `ulaw_8000`,\n * `opus_48000_128`, etc.). This helper inverts the common cases of our\n * `AudioFormat` shape into that slug.\n *\n * Only the formats that map cleanly are produced. Anything we can't\n * encode (mismatched bitrate, unsupported sample rate combination)\n * fails `Unsupported` with the requested format echoed so the user can\n * fix it.\n */\nexport const formatToOutputSlug: (format: AudioFormat) => Effect.Effect<string, AiError.AiError> = (\n format,\n) =>\n Match.value(format).pipe(\n Match.when({ container: \"mp3\" }, (f) =>\n Effect.succeed(`mp3_${f.sampleRate}_${f.bitRate ?? 128}`),\n ),\n Match.when({ container: \"opus\" }, (f) =>\n Effect.succeed(`opus_${f.sampleRate}_${f.bitRate ?? 128}`),\n ),\n Match.when({ container: \"wav\" }, (f) => Effect.succeed(`wav_${f.sampleRate}`)),\n Match.when({ container: \"raw\", encoding: \"pcm_s16le\" }, (f) =>\n Effect.succeed(`pcm_${f.sampleRate}`),\n ),\n Match.when({ container: \"raw\", encoding: \"pcm_mulaw\" }, (f) =>\n Effect.succeed(`ulaw_${f.sampleRate}`),\n ),\n Match.when({ container: \"raw\", encoding: \"pcm_alaw\" }, (f) =>\n Effect.succeed(`alaw_${f.sampleRate}`),\n ),\n Match.orElse((f) =>\n Effect.fail(\n new AiError.Unsupported({\n provider: \"elevenlabs\",\n capability: \"outputFormat\",\n reason: `Cannot encode ${JSON.stringify(f)} as ElevenLabs output_format. Supported: mp3 + (22050|44100), opus 48000, wav 48000, pcm/ulaw/alaw at any sample rate.`,\n }),\n ),\n ),\n )\n\n/** Default output: 128 kbps MP3 at 44.1 kHz. */\nexport const defaultFormat: AudioFormat = {\n container: \"mp3\",\n encoding: \"mp3\",\n sampleRate: 44100,\n bitRate: 128,\n}\n\n// ---------------------------------------------------------------------------\n// AudioSource → Blob (STT multipart upload)\n// ---------------------------------------------------------------------------\n\nconst urlNotSupported: AiError.AiError = new AiError.InvalidRequest({\n provider: \"elevenlabs\",\n param: \"audio\",\n raw: 'ElevenLabs accepts URLs via the `cloud_storage_url` field, not the `file` field. Fetch the URL yourself and pass `{ _tag: \"bytes\", bytes, mimeType }` to use the inline path.',\n})\n\nconst decodeBase64ToBytes = (b64: string): Effect.Effect<Uint8Array, AiError.AiError> =>\n Result.match(Base64.decode(b64), {\n onSuccess: Effect.succeed,\n onFailure: (cause) =>\n Effect.fail(\n new AiError.InvalidRequest({ provider: \"elevenlabs\", param: \"audio\", raw: cause }),\n ),\n })\n\nconst bytesToBlob = (bytes: Uint8Array, mimeType: string): Blob =>\n new Blob([bytes as Uint8Array<ArrayBuffer>], { type: mimeType })\n\nexport const audioToBlob: (audio: AudioSource) => Effect.Effect<Blob, AiError.AiError> =\n Match.type<AudioSource>().pipe(\n Match.tag(\"bytes\", (a) => Effect.succeed(bytesToBlob(a.bytes, a.mimeType))),\n Match.tag(\"base64\", (a) =>\n decodeBase64ToBytes(a.base64).pipe(Effect.map((bytes) => bytesToBlob(bytes, a.mimeType))),\n ),\n Match.tag(\"url\", () => Effect.fail(urlNotSupported)),\n Match.exhaustive,\n )\n\n// ---------------------------------------------------------------------------\n// MIME → file extension (for the multipart `filename` field)\n// ---------------------------------------------------------------------------\n\nconst EXTENSION_BY_MIME: ReadonlyArray<readonly [string, string]> = [\n [\"mpeg\", \"mp3\"],\n [\"mp3\", \"mp3\"],\n [\"wav\", \"wav\"],\n [\"ogg\", \"ogg\"],\n [\"opus\", \"ogg\"],\n [\"flac\", \"flac\"],\n [\"aac\", \"aac\"],\n [\"mp4\", \"m4a\"],\n [\"m4a\", \"m4a\"],\n [\"webm\", \"webm\"],\n]\n\nexport const defaultFileName = (mimeType: string): string =>\n Arr.findFirst(EXTENSION_BY_MIME, ([pattern]) => mimeType.includes(pattern)).pipe(\n Option.match({\n onNone: () => \"audio\",\n onSome: ([, ext]) => `audio.${ext}`,\n }),\n )\n\n// ---------------------------------------------------------------------------\n// HTTP errors\n// ---------------------------------------------------------------------------\n\nexport const httpStatusError: (status: number, body: string) => AiError.AiError = (status, body) =>\n Match.value(status).pipe(\n Match.when(\n 429,\n (): AiError.AiError => new AiError.RateLimited({ provider: \"elevenlabs\", raw: body }),\n ),\n Match.whenOr(\n 408,\n 504,\n (): AiError.AiError => new AiError.Timeout({ provider: \"elevenlabs\", raw: body }),\n ),\n Match.when(\n 401,\n (): AiError.AiError =>\n new AiError.AuthFailed({ provider: \"elevenlabs\", subtype: \"auth\", raw: body }),\n ),\n Match.when(\n 403,\n (): AiError.AiError =>\n new AiError.AuthFailed({ provider: \"elevenlabs\", subtype: \"permission\", raw: body }),\n ),\n Match.when(\n 402,\n (): AiError.AiError =>\n new AiError.AuthFailed({ provider: \"elevenlabs\", subtype: \"billing\", raw: body }),\n ),\n Match.when(\n 413,\n (): AiError.AiError =>\n new AiError.ContextLengthExceeded({ provider: \"elevenlabs\", raw: body }),\n ),\n Match.when(\n (n) => n >= 500,\n (n): AiError.AiError =>\n new AiError.Unavailable({ provider: \"elevenlabs\", status: n, raw: body }),\n ),\n Match.orElse(\n (): AiError.AiError => new AiError.InvalidRequest({ provider: \"elevenlabs\", raw: body }),\n ),\n )\n\nexport const transportFailure = (cause: unknown): AiError.AiError =>\n new AiError.Unavailable({ provider: \"elevenlabs\", raw: cause })\n\n/** Core's helper, with our transport error. Never pass `FormData` to the client. */\nexport const bodyMultipart = (\n form: FormData,\n): Effect.Effect<\n (request: HttpClientRequest.HttpClientRequest) => HttpClientRequest.HttpClientRequest,\n AiError.AiError\n> => Multipart.bodyMultipart(form).pipe(Effect.mapError(transportFailure))\n"],"mappings":"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"}
@@ -1,6 +1,7 @@
1
- import { n as describe, r as it, t as globalExpect } from "./test.DNmyFkvJ-N3QqMRwZ.mjs";
1
+ import { c as it, n as globalExpect, s as describe } from "./index.C4tKZ0yW-DjxCdpW_.mjs";
2
2
  import { audioToBlob, defaultFileName, formatToOutputSlug, httpStatusError } from "./codec.mjs";
3
- import { Effect, Encoding } from "effect";
3
+ import { Effect } from "effect";
4
+ import { Base64 } from "effect/encoding";
4
5
  //#region src/codec.test.ts
5
6
  describe("formatToOutputSlug", () => {
6
7
  it("encodes mp3 with default bitrate when omitted", async () => {
@@ -90,7 +91,7 @@ describe("audioToBlob", () => {
90
91
  ]);
91
92
  const source = {
92
93
  _tag: "base64",
93
- base64: Encoding.encodeBase64(original),
94
+ base64: Base64.encode(original),
94
95
  mimeType: "audio/mpeg"
95
96
  };
96
97
  const blob = await Effect.runPromise(audioToBlob(source));
@@ -1 +1 @@
1
- {"version":3,"file":"codec.test.mjs","names":["expect"],"sources":["../src/codec.test.ts"],"sourcesContent":["import { Effect, Encoding } from \"effect\"\nimport { describe, expect, it } from \"vitest\"\nimport type { AudioSource } from \"@effect-uai/core/Audio\"\nimport { audioToBlob, defaultFileName, formatToOutputSlug, httpStatusError } from \"./codec.js\"\n\ndescribe(\"formatToOutputSlug\", () => {\n it(\"encodes mp3 with default bitrate when omitted\", async () => {\n const slug = await Effect.runPromise(\n formatToOutputSlug({ container: \"mp3\", encoding: \"mp3\", sampleRate: 44100 }),\n )\n expect(slug).toBe(\"mp3_44100_128\")\n })\n\n it(\"honours an explicit mp3 bitrate\", async () => {\n const slug = await Effect.runPromise(\n formatToOutputSlug({ container: \"mp3\", encoding: \"mp3\", sampleRate: 22050, bitRate: 32 }),\n )\n expect(slug).toBe(\"mp3_22050_32\")\n })\n\n it(\"encodes raw pcm_s16le as `pcm_<sampleRate>`\", async () => {\n const slug = await Effect.runPromise(\n formatToOutputSlug({ container: \"raw\", encoding: \"pcm_s16le\", sampleRate: 16000 }),\n )\n expect(slug).toBe(\"pcm_16000\")\n })\n\n it(\"encodes mu-law as `ulaw_<sampleRate>`\", async () => {\n const slug = await Effect.runPromise(\n formatToOutputSlug({ container: \"raw\", encoding: \"pcm_mulaw\", sampleRate: 8000 }),\n )\n expect(slug).toBe(\"ulaw_8000\")\n })\n\n it(\"encodes opus with default bitrate\", async () => {\n const slug = await Effect.runPromise(\n formatToOutputSlug({ container: \"opus\", encoding: \"opus\", sampleRate: 48000 }),\n )\n expect(slug).toBe(\"opus_48000_128\")\n })\n\n it(\"encodes wav as `wav_<sampleRate>`\", async () => {\n const slug = await Effect.runPromise(\n formatToOutputSlug({ container: \"wav\", encoding: \"pcm_s16le\", sampleRate: 48000 }),\n )\n expect(slug).toBe(\"wav_48000\")\n })\n\n it(\"fails Unsupported for flac / aac / webm / ogg\", async () => {\n const exit = await Effect.runPromiseExit(\n formatToOutputSlug({ container: \"flac\", encoding: \"flac\", sampleRate: 44100 }),\n )\n expect(exit._tag).toBe(\"Failure\")\n if (exit._tag === \"Failure\") {\n expect(JSON.stringify(exit.cause)).toContain(\"Unsupported\")\n expect(JSON.stringify(exit.cause)).toContain(\"outputFormat\")\n }\n })\n})\n\ndescribe(\"audioToBlob\", () => {\n it(\"wraps bytes into a Blob with the right MIME type\", async () => {\n const source: AudioSource = {\n _tag: \"bytes\",\n bytes: new Uint8Array([1, 2, 3, 4]),\n mimeType: \"audio/wav\",\n }\n const blob = await Effect.runPromise(audioToBlob(source))\n expect(blob.type).toBe(\"audio/wav\")\n expect(blob.size).toBe(4)\n })\n\n it(\"decodes a base64 source into bytes\", async () => {\n const original = new Uint8Array([0xde, 0xad, 0xbe, 0xef])\n const source: AudioSource = {\n _tag: \"base64\",\n base64: Encoding.encodeBase64(original),\n mimeType: \"audio/mpeg\",\n }\n const blob = await Effect.runPromise(audioToBlob(source))\n expect(blob.type).toBe(\"audio/mpeg\")\n expect(blob.size).toBe(4)\n })\n\n it(\"fails InvalidRequest for url sources\", async () => {\n const source: AudioSource = { _tag: \"url\", url: \"https://x/y.mp3\", mimeType: \"audio/mpeg\" }\n const exit = await Effect.runPromiseExit(audioToBlob(source))\n expect(exit._tag).toBe(\"Failure\")\n if (exit._tag === \"Failure\") {\n expect(JSON.stringify(exit.cause)).toContain(\"InvalidRequest\")\n expect(JSON.stringify(exit.cause)).toContain(\"cloud_storage_url\")\n }\n })\n})\n\ndescribe(\"defaultFileName\", () => {\n it(\"maps audio/mpeg → audio.mp3\", () => {\n expect(defaultFileName(\"audio/mpeg\")).toBe(\"audio.mp3\")\n })\n it(\"maps audio/wav → audio.wav\", () => {\n expect(defaultFileName(\"audio/wav\")).toBe(\"audio.wav\")\n })\n it(\"falls back to audio (no extension) for unknown MIME\", () => {\n expect(defaultFileName(\"application/octet-stream\")).toBe(\"audio\")\n })\n})\n\ndescribe(\"httpStatusError\", () => {\n const tags = (status: number) => JSON.parse(JSON.stringify(httpStatusError(status, \"body\")))._tag\n it(\"maps 429 to RateLimited\", () => expect(tags(429)).toBe(\"RateLimited\"))\n it(\"maps 408/504 to Timeout\", () => {\n expect(tags(408)).toBe(\"Timeout\")\n expect(tags(504)).toBe(\"Timeout\")\n })\n it(\"maps 401/402/403 to AuthFailed\", () => {\n expect(tags(401)).toBe(\"AuthFailed\")\n expect(tags(402)).toBe(\"AuthFailed\")\n expect(tags(403)).toBe(\"AuthFailed\")\n })\n it(\"maps 5xx to Unavailable\", () => {\n expect(tags(500)).toBe(\"Unavailable\")\n expect(tags(503)).toBe(\"Unavailable\")\n })\n it(\"maps other 4xx to InvalidRequest\", () => {\n expect(tags(400)).toBe(\"InvalidRequest\")\n expect(tags(404)).toBe(\"InvalidRequest\")\n })\n})\n"],"mappings":"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"}
1
+ {"version":3,"file":"codec.test.mjs","names":["expect"],"sources":["../src/codec.test.ts"],"sourcesContent":["import { Effect } from \"effect\"\nimport { Base64 } from \"effect/encoding\"\nimport { describe, expect, it } from \"vitest\"\nimport type { AudioSource } from \"@effect-uai/core/Audio\"\nimport { audioToBlob, defaultFileName, formatToOutputSlug, httpStatusError } from \"./codec.js\"\n\ndescribe(\"formatToOutputSlug\", () => {\n it(\"encodes mp3 with default bitrate when omitted\", async () => {\n const slug = await Effect.runPromise(\n formatToOutputSlug({ container: \"mp3\", encoding: \"mp3\", sampleRate: 44100 }),\n )\n expect(slug).toBe(\"mp3_44100_128\")\n })\n\n it(\"honours an explicit mp3 bitrate\", async () => {\n const slug = await Effect.runPromise(\n formatToOutputSlug({ container: \"mp3\", encoding: \"mp3\", sampleRate: 22050, bitRate: 32 }),\n )\n expect(slug).toBe(\"mp3_22050_32\")\n })\n\n it(\"encodes raw pcm_s16le as `pcm_<sampleRate>`\", async () => {\n const slug = await Effect.runPromise(\n formatToOutputSlug({ container: \"raw\", encoding: \"pcm_s16le\", sampleRate: 16000 }),\n )\n expect(slug).toBe(\"pcm_16000\")\n })\n\n it(\"encodes mu-law as `ulaw_<sampleRate>`\", async () => {\n const slug = await Effect.runPromise(\n formatToOutputSlug({ container: \"raw\", encoding: \"pcm_mulaw\", sampleRate: 8000 }),\n )\n expect(slug).toBe(\"ulaw_8000\")\n })\n\n it(\"encodes opus with default bitrate\", async () => {\n const slug = await Effect.runPromise(\n formatToOutputSlug({ container: \"opus\", encoding: \"opus\", sampleRate: 48000 }),\n )\n expect(slug).toBe(\"opus_48000_128\")\n })\n\n it(\"encodes wav as `wav_<sampleRate>`\", async () => {\n const slug = await Effect.runPromise(\n formatToOutputSlug({ container: \"wav\", encoding: \"pcm_s16le\", sampleRate: 48000 }),\n )\n expect(slug).toBe(\"wav_48000\")\n })\n\n it(\"fails Unsupported for flac / aac / webm / ogg\", async () => {\n const exit = await Effect.runPromiseExit(\n formatToOutputSlug({ container: \"flac\", encoding: \"flac\", sampleRate: 44100 }),\n )\n expect(exit._tag).toBe(\"Failure\")\n if (exit._tag === \"Failure\") {\n expect(JSON.stringify(exit.cause)).toContain(\"Unsupported\")\n expect(JSON.stringify(exit.cause)).toContain(\"outputFormat\")\n }\n })\n})\n\ndescribe(\"audioToBlob\", () => {\n it(\"wraps bytes into a Blob with the right MIME type\", async () => {\n const source: AudioSource = {\n _tag: \"bytes\",\n bytes: new Uint8Array([1, 2, 3, 4]),\n mimeType: \"audio/wav\",\n }\n const blob = await Effect.runPromise(audioToBlob(source))\n expect(blob.type).toBe(\"audio/wav\")\n expect(blob.size).toBe(4)\n })\n\n it(\"decodes a base64 source into bytes\", async () => {\n const original = new Uint8Array([0xde, 0xad, 0xbe, 0xef])\n const source: AudioSource = {\n _tag: \"base64\",\n base64: Base64.encode(original),\n mimeType: \"audio/mpeg\",\n }\n const blob = await Effect.runPromise(audioToBlob(source))\n expect(blob.type).toBe(\"audio/mpeg\")\n expect(blob.size).toBe(4)\n })\n\n it(\"fails InvalidRequest for url sources\", async () => {\n const source: AudioSource = { _tag: \"url\", url: \"https://x/y.mp3\", mimeType: \"audio/mpeg\" }\n const exit = await Effect.runPromiseExit(audioToBlob(source))\n expect(exit._tag).toBe(\"Failure\")\n if (exit._tag === \"Failure\") {\n expect(JSON.stringify(exit.cause)).toContain(\"InvalidRequest\")\n expect(JSON.stringify(exit.cause)).toContain(\"cloud_storage_url\")\n }\n })\n})\n\ndescribe(\"defaultFileName\", () => {\n it(\"maps audio/mpeg → audio.mp3\", () => {\n expect(defaultFileName(\"audio/mpeg\")).toBe(\"audio.mp3\")\n })\n it(\"maps audio/wav → audio.wav\", () => {\n expect(defaultFileName(\"audio/wav\")).toBe(\"audio.wav\")\n })\n it(\"falls back to audio (no extension) for unknown MIME\", () => {\n expect(defaultFileName(\"application/octet-stream\")).toBe(\"audio\")\n })\n})\n\ndescribe(\"httpStatusError\", () => {\n const tags = (status: number) => JSON.parse(JSON.stringify(httpStatusError(status, \"body\")))._tag\n it(\"maps 429 to RateLimited\", () => expect(tags(429)).toBe(\"RateLimited\"))\n it(\"maps 408/504 to Timeout\", () => {\n expect(tags(408)).toBe(\"Timeout\")\n expect(tags(504)).toBe(\"Timeout\")\n })\n it(\"maps 401/402/403 to AuthFailed\", () => {\n expect(tags(401)).toBe(\"AuthFailed\")\n expect(tags(402)).toBe(\"AuthFailed\")\n expect(tags(403)).toBe(\"AuthFailed\")\n })\n it(\"maps 5xx to Unavailable\", () => {\n expect(tags(500)).toBe(\"Unavailable\")\n expect(tags(503)).toBe(\"Unavailable\")\n })\n it(\"maps other 4xx to InvalidRequest\", () => {\n expect(tags(400)).toBe(\"InvalidRequest\")\n expect(tags(404)).toBe(\"InvalidRequest\")\n })\n})\n"],"mappings":"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"}