Audition
Audition combines multiple clients into one state stream, call surface, and
event stream.
For larger apps, this avoids forcing the UI to swap service references manually when flows shift between contexts, such as moving from a lobby into a chat room.
Merge clients
import { Audition } from "liminal"
import { ChatClient } from "./chat/ChatClient.ts"
import { LobbyClient } from "./lobby/LobbyClient.ts"
export const audition = Audition.empty.pipe(
Audition.add(LobbyClient),
Audition.add(ChatClient),
)After that, callers can use one method surface:
Effect.gen(function* () {
yield* audition.fn("JoinRoom")({ roomId })
yield* audition.fn("SendMessage")({ content: "Hello!" })
})The audition.fn(method) signature mirrors Client.fn(method). The effect's
required services are the union of services for every underlying client in the
audition.
Merge events
const source = audition.eventsAn app-wide view can listen to merged events, or subscribe to audition.state
for the currently active hydrated state.
const source = audition.events.pipe(Stream.forever)
const state = audition.state.pipe(Stream.forever)Method resolution order
Audition.add(...) is ordered.
With:
Audition.empty.pipe(Audition.add(LobbyClient), Audition.add(ChatClient))runtime lookup tries LobbyClient first, then falls back to ChatClient.
Fallback only triggers when the prior client produces an AuditionError. Other
errors such as ConnectionError or UnresolvedError propagate directly without
trying the next client.
If multiple clients expose the same method name, keep the method definitions identical. The type-level merge assumes matching shapes for overlapping method keys.