YuKumo

API Reference

Comprehensive reference for every public export in YuKumo.

Comprehensive reference for every public export in YuKumo. Supports TypeScript and JavaScript (ESM + CommonJS).

YuKumo

The central orchestrator combining all subsystems.

class YuKumo {
  constructor(options: ManagerOptions);

  // Lifecycle
  init(): Promise<void>;
  destroy(): Promise<void>;

  // Search
  search(query: string | SearchOptions, source?: string): Promise<SearchResult>;
  lavaSearch(query: string, types?: LavaSearchType[], nodeName?: string): Promise<LavaSearchResult>;
  getLyrics(encodedTrack: string, nodeName?: string): Promise<any>;

  // Player management
  createPlayer(options: YuKumoPlayerCreateOptions): Promise<Player>;
  getPlayer(guildId: string): Player | undefined;
  getPlayers(): Player[];
  hasPlayer(guildId: string): boolean;
  destroyPlayer(guildId: string): Promise<boolean>;

  // Playback
  play(guildId: string, track: TrackData): Promise<void>;
  pause(guildId: string): Promise<void>;
  resume(guildId: string): Promise<void>;
  stop(guildId: string): Promise<void>;
  skip(guildId: string): Promise<TrackData | null>;
  setVolume(guildId: string, volume: number): Promise<void>;

  // Voice
  handleVoiceStateUpdate(data: VoiceStateUpdate): Promise<void>;
  handleVoiceServerUpdate(guildId: string, data: VoiceServerUpdate): Promise<void>;

  // Nodes
  getNode(id: string): Node | undefined;
  getNodes(): Node[];

  // Events
  on<E extends EventName>(event: E, callback: EventCallback<E>): this;

  // Subsystems (public for advanced use)
  readonly nodes: NodeManager;
  readonly players: PlayerManager;
  readonly plugins: PluginManager;
  readonly events: EventDispatcher;
  readonly storage: StorageAdapter;
  readonly voice: VoiceStateTracker;
}

ManagerOptions

PropertyTypeDefaultDescription
nodesNodeConfig[]requiredLavalink node configurations
storageAdapterStorageAdapterMemoryStorageCustom storage backend
pluginsPluginDef[][]Plugin instances to register
defaultNodeSelectorNodeSelectorLeastUsedSelectorDefault node selection strategy
send(guildId, payload) => void—Raw Discord gateway payload dispatcher for op: 4 voice state updates
onDisconnect{ destroyPlayer?: boolean; autoReconnect?: boolean }{ destroyPlayer: true }Behavior when bot is disconnected from voice channel
loggerLogger | LogLevelNoopLoggerLogger instance or minimum log level threshold ("debug" | "info" | "warn" | "error" | "silent")
searchCacheSearchCache | CacheOptionsSearchCacheCustom SearchCache instance or cache configuration options (maxSize, ttl)
linksAllowedbooleantrueWhen false, URL queries are rejected with an error load result
linksWhitelist(string | RegExp)[][]When non-empty, URL queries must match at least one entry
linksBlacklist(string | RegExp)[][]URL queries matching any entry are rejected (wins over whitelist)
httpHeadersRecord<string, string>—Custom headers for every node's REST requests + WS handshake
queueOptions{ persist?: boolean }{ persist: false }Auto-persist queues to the storage adapter and restore them on createPlayer()
playerDefaults{ maxErrorsPerTime?, minAutoPlayMs?, queueEmptyDestroyMs? }see belowPer-player protection defaults applied on create
playerClassnew (options) => PlayerPlayerCustom Player subclass instantiated by the manager

playerDefaults defaults: maxErrorsPerTime: { threshold: 35000, maxAmount: 3 } (destroy after >3 track errors within 35s; null disables), minAutoPlayMs: 10000 (block autoplay after error-ends of tracks that played under 10s), queueEmptyDestroyMs: 0 (disabled).

NodeConfig

PropertyTypeDefaultDescription
hoststringrequiredLavalink hostname
portnumberrequiredLavalink port
passwordstringrequiredLavalink password
namestringautoNode identifier
type"lavalink" | "nodelink" | "auto""auto"Server family; auto detects it from /v4/info on connect
isNodeLinkboolean—Deprecated — prefer type: "nodelink". Still honored
securebooleanfalseUse https/wss
resumeTimeoutnumber60Resume timeout (seconds)
resumeKeystringautoResume identifier
maxRetriesnumber5Connection retry limit
retryDelaynumber1000Initial retry delay (ms)
retryDelayMaxnumber30000Maximum retry delay (ms)
connectTimeoutnumber15000WS handshake timeout (ms)
httpHeadersRecord<string, string>—Custom headers for this node (overrides manager-level httpHeaders)
enableHeartbeatbooleantrueWS ping/pong dead-connection detection
heartbeatIntervalMsnumber30000Interval between heartbeat pings
heartbeatTimeoutMsnumber10000Pong wait before the socket is declared dead and terminated (auto-reconnects)

Node

Node

PropertyTypeDescription
configNodeConfigConfiguration this node was created with
wsWebSocketClientWebSocket client
restRestClientREST client
stateNodeStatedisconnected | connecting | connected | destroyed
type"lavalink" | "nodelink"Resolved server family
versionstring | nullServer version (from /v4/info)
capabilitiesNodeCapabilities | nullResolved features, filters, sources (null before ready)
sourceManagersreadonly string[]Enabled source names
isNodeLinkbooleanWhether the node is NodeLink
penaltiesPenaltiesCurrent penalty scores
playerCountnumberActive players on this node
MethodReturnsDescription
supports(feature)booleanWhether the node supports a NodeFeature
supportsFilter(name)booleanWhether a specific audio filter is available
assertSupports(feature)voidThrows YukumoUnsupportedFeatureError when unsupported
createVoiceReceiver(guildId)NodeLinkVoiceReceiverNodeLink voice receive (throws on Lavalink)

NodeFeature = "lyrics" \| "chapters" \| "meaning" \| "voiceReceive" \| "extraFilters" \| "stream" \| "mixer" \| "sponsorblock" \| "lyricsSubscribe" \| "groups" \| "youtubeConfig" \| "routeplanner" \| "sessionResume".

Config helpers: createNodeLinkNode(config) and createLavalinkNode(config) build a NodeConfig with the right type and resuming enabled.

NodeManager

MethodReturnsDescription
add(config)NodeRegister a new node
remove(id)booleanRemove and destroy a node
get(id)Node | undefinedGet node by name
getAll()Node[]Get all registered nodes
getConnected()Node[]Get only connected nodes
pick(guildId, opts?)Node | nullPick best node via selector; pass { feature } to require a capability
connectAll()Promise<void>Connect all nodes
destroyAll()Promise<void>Destroy all nodes
setSelector(selector)voidReplace selection strategy
size()numberNumber of registered nodes

Node Selectors

SelectorStrategy
LeastUsedSelector(Default) Fewest players
LeastPenaltySelectorLowest penalty (players + CPU + frames)
CpuUsageSelectorLowest Lavalink CPU load
MemoryUsageSelectorLowest memory usage
LowestPingSelectorLowest WebSocket round-trip ping
RegionSelectorRegion-aware with fallback selector
RoundRobinSelectorRound-robin order
RandomSelectorRandom connected node
CustomSelectorCustom function (nodes, guildId) => Node | null
import { RoundRobinSelector, RegionSelector, CustomSelector } from "yukumo";

client.nodes.setSelector(new RoundRobinSelector());

// Region-aware with fallback
client.nodes.setSelector(new RegionSelector("eu", new LeastPenaltySelector()));

// Custom function
client.nodes.setSelector(new CustomSelector((nodes, guildId) => {
  return nodes.find(n => n.state === "connected") ?? null;
}));

Player

Player

PropertyTypeDescription
guildIdstringDiscord guild ID
nodeNodeAssigned Lavalink node
queueQueue<TrackData>Track queue
filtersFilterChainAudio filter chain
eventsEventDispatcherPlayer-local events
dataMap<string, any>Custom data map
statusPlayerStatusidle | playing | paused | destroyed
volumenumberVolume (0–1000)
pausedbooleanWhether paused
currentTrackTrackData | nullCurrent track
voiceStateInternalVoiceState | nullVoice connection state
positionnumberPlayback position (ms) — interpolated between server updates, clamped to track length
ping{ ws: number | null; lavalink: number | null }Node WS ping + per-player Lavalink ping
maxErrorsPerTime{ threshold, maxAmount } | nullSliding-window error-rate protection
minAutoPlayMsnumberMin play time before error-triggered autoplay runs
queueEmptyDestroyMsnumberDestroy this many ms after queue end (0 disables)
isPlayingbooleanstatus === "playing" && !paused (Poru/Riffy convention)
isPausedbooleanWhether paused (Poru/Riffy convention)
isConnectedbooleanWhether voice-connected (Poru/Riffy convention)
isDestroyedbooleanWhether destroyed (Poru/Riffy convention)
isAutoplaybooleanWhether autoplay is enabled (Poru/Riffy convention)
trackRepeatbooleanSingle-track repeat getter/setter (Magmastream/erela.js)
queueRepeatbooleanWhole-queue repeat getter/setter (Magmastream/erela.js)
MethodReturnsDescription
play(track?, options?)Promise<void>Begin playback. options: { position?, endTime?, noReplace?, paused?, volume? }
playTrack(track, options?)Promise<void>Play specific track (same PlayOptions)
skip()Promise<TTrack | null>Skip — runs the same path as a natural track end (autoplay/repeat/queueEnd all fire)
playPrevious()Promise<TTrack | null>Play previous track from history
pause() / resume()Promise<void>Idempotent pause/resume
stop()Promise<void>Stop playback
setVolume(vol)Promise<void>Change volume (0-1000); remembered while the node is down
seek(position)Promise<void>Seek (ms), clamped to [0, track length]
waitForVoiceReady(timeoutMs?)Promise<void>Wait for Discord voice credentials to be ready before playing (default: 15s)
resync()Promise<void>Re-send full player state & voice credentials to node after reconnect
destroy(reason?)Promise<void>Destroy player; reason (see DestroyReasons) is emitted with playerDestroy
setVoiceChannel(id)Promise<void>Move bot to channel
setTextChannel(id)voidUpdate text channel
search(query, source?)Promise<SearchResult>Shortcut for yukumo.search
setLoop(mode)thisShortcut for queue.setRepeatMode
getLyrics(track?)Promise<any>Fetch lyrics (requires Lyrics plugin)
setSponsorBlock(categories?)Promise<void>Set SponsorBlock auto-skip categories (SponsorBlock plugin)
getSponsorBlock() / deleteSponsorBlock()Promise<string[]> / Promise<void>Read / clear SponsorBlock categories
getCurrentLyrics(skipTrackSource?)Promise<unknown>Lyrics of the current track (LavaLyrics plugin)
subscribeLyrics() / unsubscribeLyrics()Promise<void>Toggle live lyricsLine events (LavaLyrics plugin)
moveNode(nodeId?)Promise<Node>Move to a node — auto-picks the least-loaded connected node when omitted
enableQueuePersistence()voidAuto-save the queue to the storage adapter on every change
restoreQueue()Promise<boolean>Restore a persisted queue
toJSON()PlayerJsonFull serializable player snapshot (queue, filters, voice, playback)
get(start?, end?)TTrack[]Queue slice from start (current track included) to end — Poru-compatible
setTrackRepeat(enabled?) / setQueueRepeat(enabled?)thisMagmastream/erela.js repeat aliases — never clobber the other repeat mode
setEqualizer(bands?)Promise<void>Replace the equalizer filter and sync to the node
setKaraoke(settings?)Promise<void>Replace the karaoke filter and sync to the node
setTimescale(settings?)Promise<void>Replace the timescale (speed/pitch) filter and sync to the node
setTremolo(settings?)Promise<void>Replace the tremolo filter and sync to the node
setVibrato(settings?)Promise<void>Replace the vibrato filter and sync to the node
setRotation(settings?)Promise<void>Replace the rotation (8D) filter and sync to the node
setDistortion(settings?)Promise<void>Replace the distortion filter and sync to the node
setChannelMix(settings?)Promise<void>Replace the channel mix filter and sync to the node
setLowPass(settings?)Promise<void>Replace the low-pass filter and sync to the node
setVolumeFilter(volume?)Promise<void>Replace the volume filter and sync to the node (default 1.0)
setPluginFilter(name, settings)Promise<void>Set/remove a server-side plugin filter (LavaDSPX etc.) via pluginFilters; pass false/null to remove
skipTo(index)Promise<TTrack | null>Jump to a queue index and start it on the node (skipped tracks go to history)
setEcho / setChorus / setReverb / setCompressor / setPhaser / setHighPass / setFlanger / setSpatial / setPhonograph / setTesseractPromise<void>NodeLink extra DSP filters (capability-gated)

PlayerManager

MethodReturnsDescription
create(options)Promise<Player>Create a player
get(guildId)Player | undefinedGet by guild ID
has(guildId)booleanCheck if exists
destroy(guildId, reason?)Promise<boolean>Destroy a player
getAll()Player[]All players
getByNode(nodeId)Player[]Players on a node
destroyAll(reason?)Promise<void>Destroy all
size()numberActive player count

YuKumoPlayerCreateOptions

PropertyTypeDefaultDescription
guildIdstringrequiredDiscord guild ID
voiceChannelIdstringrequiredVoice channel
textChannelIdstring—Text channel
selfDeafbooleantrueDeafen on join
selfMutebooleanfalseMute on join
nodeSelectorNodeSelectordefaultPer-player selector override

Queue

Queue<T>

MethodReturnsDescription
enqueue(track, index?)numberAdd track (optionally at index)
dequeue()T | nullRemove and return front
start()voidBegin from front
next()T | nullAdvance to next
previous()T | nullGo back
peek()T | nullView without advancing
clear()voidRemove all
shuffle()voidFisher-Yates shuffle
swap(indexA, indexB)booleanSwap two track positions
skipTo(index)T | nullJump to queue index
remove(index)T | nullRemove at index
removeRange(start, end)T[]Remove range
clearExceptCurrent()voidClear queue except current track
setRepeatMode(mode)void"none" | "track" | "queue"
sortBy(key, order?)thisSort upcoming tracks by "duration" | "title" | "author" or a comparator, "asc" | "desc"
removeTrack(query)T[]Remove by track object / array / predicate (matches identity, then encoded); never removes the playing track
export() / import(state)SerializedQueue / voidSerialize / restore full queue state
toArray()T[]All tracks as array
PropertyTypeDescription
onChanged() => voidHook invoked after every queue mutation — drives queue persistence, usable as a change watcher
PropertyTypeDescription
sizenumberCurrent track count
totalSizenumberIncluding history
currentTrackT | nullCurrent track
repeatModeRepeatModeRepeat setting
const queue = new Queue<TrackData>();
queue.enqueue(track1);
queue.enqueue(track2, 0);
queue.setRepeatMode("queue");
queue.shuffle();
queue.start();

let track;
while ((track = queue.next()) !== null) {
  // process track
}

Track

TrackData

interface TrackData {
  encoded: string;
  info: TrackInfo;
  pluginInfo: Record<string, unknown>;
  userData?: Record<string, unknown>;
}

interface TrackInfo {
  identifier: string;
  isSeekable: boolean;
  author: string;
  length: number;
  isStream: boolean;
  position: number;
  title: string;
  uri: string | null;
  artworkUrl: string | null;
  isrc: string | null;
  sourceName: string;
}

Track

The Track class wraps a TrackData with convenient getters and client-side encoding:

PropertyTypeDescription
encodedstringLavalink v4 base64 track
infoTrackInfoTrack metadata
pluginInfoRecord<string, unknown>Plugin data
requesterunknownAuto-populated from userData.requester
metadataRecord<string, unknown>Same as userData
durationFormattedstringHuman-readable duration (uses formatDuration)
Static MethodReturnsDescription
encode(info)stringEncode TrackInfo into Lavalink v4 base64 — byte-for-byte compatible with @lavalink/encoding, no server needed
decode(encoded)TrackInfoDecode a Lavalink v4 base64 track into raw info fields
build(info, requester?)TrackBuild a playable track entirely on the client — encodes locally so it plays without resolving against a node (Wavelink PartialTrack.create() equivalent)
from(data, requester?)TrackWrap an existing TrackData
import { Track } from "yukumo";

// Build + play a track with no server round-trip
const track = Track.build({ title: "My Local Song", author: "Me" });
await player.play(track);

// Encode / decode
const encoded = Track.encode({ title: "Song", author: "Artist", length: 214_000, ... });
const info = Track.decode(encoded);

The lower-level encodeTrackInfo() / decodeTrackInfo() functions are also exported.

SearchResult

interface SearchResult {
  loadType: "track" | "playlist" | "search" | "empty" | "error";
  tracks: TrackData[];
  playlistInfo?: { name: string; selectedTrack: number };
  exception?: { message: string; severity: "common" | "suspicious" | "fault" };
}

SearchOptions

interface SearchOptions {
  query: string;
  source?: string;
  nodeName?: string;
  requester?: unknown; // stamped onto every returned track's userData (cache hits included)
}
const result = await kumo.search({ query: "lofi", requester: { id: "user-1" } });
result.tracks[0]?.userData?.requester; // { id: "user-1" }

Filters

FilterChain

MethodDescription
add(filter)Add a filter
remove(filter)Remove a filter
clear()Remove all
toPayload()Serialize to API payload
has(filter)Check if exists
getAll()Get all filters
setPluginFilter(name, settings)Set/remove a server-side plugin filter (pluginFilters); false/null removes
getPluginFilter(name) / hasPluginFilter(name)Read / check a plugin filter

player.setFilters() accepts either a FilterChain or a raw Lavalink FiltersObject, and applies it to the node in real time:

await player.setFilters({ equalizer: [{ band: 0, gain: 0.5 }] });

Available Filters

FilterKey Methods
VolumeFiltersetVolume(value)
EqualizerFiltersetBand(index, gain)
KaraokeFiltersetLevel(), setMonoloLevel(), setFilterBand(), setFilterWidth()
TimescaleFiltersetSpeed(), setPitch(), setRate()
TremoloFiltersetFrequency(), setDepth()
VibratoFiltersetFrequency(), setDepth()
RotationFiltersetRotationHz()
DistortionFiltersetSinOffset(), setSinScale(), setCosOffset(), setCosScale(), setTanOffset(), setTanScale(), setOffset(), setScale()
ChannelMixFiltersetLeftToLeft(), setLeftToRight(), setRightToLeft(), setRightToRight()
LowPassFiltersetSmoothing()

NodeLink-only extra filters (via player.setEcho() etc., capability-gated): EchoFilter, ChorusFilter, CompressorFilter, PhaserFilter, HighPassFilter, FlangerFilter, ReverbFilter, SpatialFilter, PhonographFilter, TesseractFilter. Server-side filter plugins (LavaDSPX etc.) go through FilterChain.setPluginFilter(name, settings) / player.setPluginFilter().

import { FilterChain, EqualizerFilter, TimescaleFilter } from "yukumo";

const chain = new FilterChain();
chain
  .add(new EqualizerFilter().setBand(0, 0.4))
  .add(new TimescaleFilter().setSpeed(1.25));

player.filters.add(new EqualizerFilter().setBand(0, 0.5));

Filter Presets

One-line preset methods on FilterChain (also available on player.filters):

PresetDescription
setBassBoost(level)Bass boost EQ preset ("low", "medium", "high", "extreme")
setNightcore(enabled?)Nightcore timescale (speed 1.25, pitch 1.25)
setVaporwave(enabled?)Vaporwave timescale (speed 0.85, pitch 0.8)
setSlowedReverb(enabled?)Slowed + Reverb preset (speed 0.85, pitch 0.85, lowPass filter)
set8D(enabled?) / set3DAudio(enabled?)8D / 3D audio spatial rotation (0.2 Hz panning)
setPitchShift(semitones)Shifts audio pitch by semitones (+/- 12 semitones)
setVoiceIsolation(enabled?)Vocal frequency boost EQ curve
setKaraoke(enabled?)Karaoke vocal removal filter
setPop(enabled?)Pop EQ preset
setSoft(enabled?)Soft EQ preset
setTrebleBass(enabled?)Treble & Bass EQ preset
setRock(enabled?)Rock EQ preset
setClassical(enabled?)Classical EQ preset
setElectronic(enabled?)Electronic EQ preset
setAudioOutput(output)Channel-mix routing: "mono", "stereo" (reset), "left", "right" (presets exported as AudioOutputs)
registerPreset(name, payload)Registers a custom global named preset
applyPreset(name)Applies a registered custom preset
// Apply bass boost
player.filters.setBassBoost("high");

// Enable nightcore
player.filters.setNightcore();

// Disable a preset
player.filters.setNightcore(false);

// Route audio to mono / left / right, back to stereo to reset
player.filters.setAudioOutput("mono");
player.filters.setAudioOutput("stereo");

Voice

VoiceStateTracker

MethodReturnsDescription
handleVoiceStateUpdate(data)Promise<void>Process state update
handleVoiceServerUpdate(guildId, data)Promise<void>Process server update
isReady(guildId)booleanConnection established?
getState(guildId)VoiceState | undefinedGet connection state
getVoiceState(guildId)InternalVoiceState | undefinedGet internal state
getAll()Map<string, VoiceState>All tracked states
remove(guildId)voidRemove state

Voice Events

EventFires When
voiceReadyBoth sessionId and endpoint+token received (50ms debounce)
voiceDisconnectedchannelId becomes null
voiceReconnectingSession ID changes while connected

VoiceStateUpdate

interface VoiceStateUpdate {
  guildId: string;
  sessionId: string;
  channelId: string | null;
  userId?: string;
}

VoiceServerUpdate

interface VoiceServerUpdate {
  token: string;
  endpoint: string | null;
}

Storage

StorageAdapter

interface StorageAdapter {
  get(key: string): Promise<unknown | null>;
  set(key: string, value: unknown): Promise<void>;
  delete(key: string): Promise<boolean>;
  has(key: string): Promise<boolean>;
  clear(): Promise<void>;
}
AdapterDescription
MemoryStorage(Default) In-memory Map. Zero overhead
RedisStorageRedis persistence (requires redis package)
import { RedisStorage } from "yukumo";

const yukumo = new YuKumo({
  nodes: [...],
  storageAdapter: new RedisStorage({ url: "redis://localhost:6379" }),
});

Logging

YuKumo includes a pluggable logging subsystem with level filtering.

Logger Interface

interface Logger {
  debug(message: string, ...args: unknown[]): void;
  info(message: string, ...args: unknown[]): void;
  warn(message: string, ...args: unknown[]): void;
  error(message: string, ...args: unknown[]): void;
}

type LogLevel = "debug" | "info" | "warn" | "error" | "silent";

Loggers & Helper Functions

SymbolDescription
ConsoleLoggerBuilt-in logger outputting formatted logs to standard console
NoopLoggerSilent logger that discards all log messages (default)
levelFilteredLogger(inner: Logger, level: LogLevel)Helper function wrapping a logger to drop messages below the specified threshold
import { YuKumo, ConsoleLogger, levelFilteredLogger } from "yukumo";

const yukumo = new YuKumo({
  nodes: [...],
  logger: levelFilteredLogger(new ConsoleLogger(), "info"),
});

Search & Caching

SearchCache

A high-performance in-memory LRU cache for search results with TTL support.

interface CacheOptions {
  /** Maximum number of entries to keep in cache (default: 100) */
  maxSize?: number;
  /** Time to live in milliseconds (default: 3600000 / 1 hour) */
  ttl?: number;
}

class SearchCache {
  constructor(options?: CacheOptions);
  get<T extends SearchResult | LavaSearchResult>(key: string): T | null;
  set(key: string, data: SearchResult | LavaSearchResult): void;
  clear(): void;
}
import { SearchCache } from "yukumo";

const cache = new SearchCache({ maxSize: 500, ttl: 1800000 }); // 30 mins

Utilities

parseDuration

Parses a duration string into milliseconds. Accepts "m:ss", "h:mm:ss", plain second counts, or a numeric value. Returns 0 on unparseable input.

import { parseDuration } from "yukumo";

parseDuration("3:32");    // 212000
parseDuration("1:02:03"); // 3723000
parseDuration("90");      // 90000
parseDuration(90);        // 90000

encodeTrackInfo / decodeTrackInfo

Low-level Lavalink v4 track encoding helpers (used by Track.encode() / Track.decode()):

import { encodeTrackInfo, decodeTrackInfo } from "yukumo";

const encoded = encodeTrackInfo(trackInfo); // Lavalink v4 base64 string
const info = decodeTrackInfo(encoded);      // TrackInfo

Framework Adapters

YuKumo provides first-class gateway adapters that automatically forward voice state and server updates from your Discord library.

AdapterLibrary
DiscordJSAdapterdiscord.js v14
ErisAdapterEris
SeyfertAdapterSeyfert
OceanicAdapterOceanic.js
DiscordenoAdapterDiscordeno
RawGatewayAdapterCustom / raw gateway
DaveyAdapterDavey voice connections

Usage

import { YuKumo, DiscordJSAdapter } from "yukumo";
import { Client } from "discord.js";

const discordClient = new Client({ intents: [...] });
const yukumo = new YuKumo({ nodes: [...] });

// Adapter handles voice state forwarding automatically
const adapter = new DiscordJSAdapter(discordClient, yukumo);

// Connect to voice via the adapter
adapter.sendVoiceStateUpdate(guildId, voiceChannelId);

For custom integrations, use RawGatewayAdapter:

import { RawGatewayAdapter } from "yukumo";

const adapter = new RawGatewayAdapter(yukumo);

// Forward raw gateway payloads manually
adapter.handleRawVoiceStateUpdate(rawPayload);
adapter.handleRawVoiceServerUpdate(rawPayload);

Plugin System

Plugin interface

interface Plugin {
  name: string;
  version: string;
  init?(): void | Promise<void>;
  start?(): void | Promise<void>;
  destroy?(): void | Promise<void>;
}

PluginManager

MethodReturnsDescription
register(plugin)voidRegister plugin
unregister(name)booleanRemove plugin
get(name)Plugin | undefinedGet by name
getAll()Plugin[]All plugins
startAll()Promise<void>Start all
destroyAll()Promise<void>Destroy all
addHook(hook, handler)voidAdd lifecycle hook
removeHook(hook, handler)voidRemove lifecycle hook

Lifecycle Hooks

HookSignatureCancelable
beforeSearch(query, source?) => { query, source? } | nullYes
afterSearch(result) => SearchResult | nullYes
beforeConnect(guildId, channelId) => { guildId, channelId } | nullYes
afterConnect(guildId, channelId) => voidNo
beforePlay(guildId, track) => TrackData | nullYes
afterPlay(guildId, track) => voidNo
beforeDestroy(guildId) => booleanYes (return false)
afterDestroy(guildId) => voidNo
onNodeSelect(guildId, nodes) => string | nullYes

Errors

ErrorWhen
YuKumoErrorBase error class
NodeErrorNode failures
NodeConnectionErrorConnection failures
PlayerErrorPlayer failures
PlayerNotConnectedErrorPlayer not connected
RestErrorHTTP errors (includes status code)
QueueErrorQueue operation errors
QueueFullErrorQueue at capacity
PluginErrorPlugin lifecycle errors
VoiceErrorVoice state errors
LoadErrorTrack loading errors
YukumoUnsupportedFeatureErrorA feature was requested on a node that doesn't support it (code: "UNSUPPORTED_FEATURE", with feature, nodeId, nodeType)
import { RestError, PlayerNotConnectedError } from "yukumo";

try {
  await yukumo.play("guildId", track);
} catch (error) {
  if (error instanceof RestError) {
    console.error(`HTTP ${error.statusCode}: ${error.message}`);
  }
  if (error instanceof PlayerNotConnectedError) {
    console.error("Player not connected");
  }
}

Events

YuKumo-level

EventPayloadDescription
trackStart(guildId, track)Track started
trackEnd(guildId, track, reason)Track ended
trackStuck(guildId, track, thresholdMs)Track stuck
trackException(guildId, track, exception)Track error
queueEnd(guildId)Queue empty
playerCreate(guildId)Player created
playerDestroy(guildId)Player destroyed
nodeReady(nodeId)Node connected
nodeDisconnected(nodeId, code, reason)Node disconnected
nodeReconnected(nodeId)Node reconnected
nodeError(nodeId, error)Node error
stats(nodeId, stats)Node stats (~60s interval)
voiceReady(guildId)Voice connected
voiceDisconnected(guildId)Voice disconnected
voiceReconnecting(guildId)Voice reconnecting
segmentsLoaded(guildId, segments)SponsorBlock segments loaded for the current track
segmentSkipped(guildId, segment)SponsorBlock segment auto-skipped
chaptersLoaded(guildId, chapters)SponsorBlock chapters loaded
chapterStarted(guildId, chapter)SponsorBlock chapter started
lyricsFound(guildId, lyrics)LavaLyrics: lyrics found
lyricsNotFound(guildId)LavaLyrics: no lyrics found
lyricsLine(guildId, line)LavaLyrics: live lyrics line

playerDestroy now emits (guildId, reason?) — reasons come from the DestroyReasons export:

import { DestroyReasons } from "yukumo";
// QueueEmpty · NodeDestroy · NodeDeleted · LavalinkNoVoice · NodeReconnectFail
// Disconnected · PlayerReconnectFail · ChannelDeleted · DisconnectAllNodes
// TrackErrorMaxTracksErroredPerTime · TrackStuckMaxTracksErroredPerTime
// EmptyVoiceChannel · ManualDestroy

Player-level (player.events)

EventPayload
trackStart(guildId, track)
trackEnd(guildId, track, reason)
trackStuck(guildId, track, thresholdMs)
trackException(guildId, track, exception)
queueEnd(guildId)

On this page