npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

raftlink-apex

v1.0.0

Published

A Modern, Parallelized, Cloud-Native Audio System for Node.js

Readme

The Apex Philosophy

RAFTLINK: Apex Edition represents the peak of modern Lavalink client engineering, built on the latest stable technologies and advanced architectural patterns for unparalleled stability and performance.

  1. True Parallelism via Actor Model: Every voice session is a completely isolated process (worker_thread). This provides the ultimate level of fault tolerance and performance, as no single session can impact the stability of the main application or any other session. This is the gold standard for resilient systems.

  2. Predictable State Management: Inspired by modern frontend frameworks, each session actor manages its state immutably. Actions are dispatched to a reducer, ensuring predictable, debuggable, and race-condition-free state transitions.

  3. Cloud-Native Persistence with MongoDB: All session data is persisted to a MongoDB Atlas cluster using the latest mongodb v6 driver. This provides limitless scalability, robust data management, and the ability for your bot to run across multiple instances (shards) while sharing a single source of truth.

  4. Self-Healing & Intelligent Orchestration: The Cluster Manager actively monitors node health, performs zero-downtime session migrations, and automatically respawns crashed session actors, ensuring the system is constantly working to maintain a perfect state.

Core Features

  • Actor Model Architecture: Unmatched performance and stability through true parallelism.
  • Predictable State Management: Immutable state and Redux-like actions prevent bugs.
  • Latest MongoDB v6 Integration: Professional-grade, scalable, and cloud-native persistence.
  • Fault-Tolerant & Self-Healing: Automatic failover, session migration, and actor respawning.
  • Geographic Load Balancing: Latency-based routing for optimal global performance.
  • Cognitive Search: Intelligent query parsing finds what users mean.
  • Advanced Player Controls: Rich queue management, looping, history, and a modern filter engine.

1. Project Setup

Installation

Install RAFTLINK and its peer dependencies from npm.

npm install raftlink-apex ws undici mongodb pino pino-pretty

Lavalink Server Configuration

This is the most crucial step. To unlock all-source support (Spotify, Apple Music, etc.), you must configure your Lavalink server's application.yml. RAFTLINK remains keyless; your Lavalink server holds the keys.

Example application.yml for Lavalink:

# application.yml on your Lavalink server
server:
  port: 2333
lavalink:
  server:
    password: "youshallnotpass"
    sources:
      youtube: true
      soundcloud: true
    plugins:
      - dependency: "com.github.topi314.lavasrc:lavasrc-plugin:4.0.0" # Example
plugins:
  lavasrc:
    spotify:
      clientId: "YOUR_SPOTIFY_CLIENT_ID"
      clientSecret: "YOUR_SPOTIFY_CLIENT_SECRET"

2. Configuration

RAFTLINK is configured via a simple options object.

import { createApexClient } from 'raftlink-apex';

const apex = createApexClient({
    userId: 'YOUR_BOT_ID_HERE',
    sendGatewayPayload: (payload) => { /* Function to send data to Discord */ },
    nodes: [ // Array of your Lavalink nodes
        {
          "identifier": "Lavalink-US-East",
          "host": "us-east.lavalink.example.com",
          "port": 443,
          "password": "youshallnotpass",
          "secure": true,
          "region": "US_EAST"
        }
    ],
    database: {
        uri: "YOUR_MONGODB_ATLAS_CONNECTION_STRING",
        dbName: "RaftlinkApex"
    },
    logLevel: "info"
});

3. Basic Usage

Here is a complete, minimal example using discord.js.

import { Client, GatewayIntentBits } from 'discord.js';
import { createApexClient } from 'raftlink-apex';

const client = new Client({ intents: [GatewayIntentBits.Guilds, GatewayIntentBits.GuildVoiceStates] });

const apex = createApexClient({
    userId: 'YOUR_BOT_ID_HERE',
    sendGatewayPayload: (payload) => {
        client.guilds.cache.get(payload.d.guild_id)?.shard.send(payload);
    },
    nodes: [ /* Your nodes array from above */ ],
    database: { /* Your database object from above */ }
});

async function main() {
    await apex.connect(); // Connects to the database

    client.on('ready', () => apex.logger.info(`Discord client logged in as ${client.user.tag}`));
    
    // This is the critical link for voice functionality
    client.on('raw', (d) => apex.handleVoiceUpdate(d.d));

    client.on('interactionCreate', async (interaction) => {
        if (!interaction.isChatInputCommand() || interaction.commandName !== 'play') return;
        
        const { member, guild } = interaction;
        if (!member.voice.channel) {
            return interaction.reply({ content: 'You must be in a voice channel!', ephemeral: true });
        }

        await interaction.deferReply();
        
        try {
            const session = await apex.getPlayer(guild.id, member.voice.channel.id);
            const query = interaction.options.getString('query');
            const { tracks, loadType } = await session.loadTracks(query);

            if (loadType === 'NO_MATCHES') return interaction.editReply('Could not find any results.');

            await session.addToQueue(tracks);
            
            const state = await session.getState();
            if (!state.isPlaying) await session.play();

            const reply = loadType === 'PLAYLIST_LOADED' ? `Queued **${tracks.length}** songs!` : `Queued: **${tracks[0].info.title}**`;
            await interaction.editReply(reply);
        } catch (error) {
            apex.logger.error(error, `Error in play command`);
            await interaction.editReply(`An error occurred: ${error.message}`);
        }
    });

    client.login('YOUR_DISCORD_BOT_TOKEN_HERE');
}

main().catch(console.error);

4. Mastering the Apex API

The SessionProxy object (returned by apex.getPlayer()) is the primary interface for all player-related actions.

Player Control

  • await session.play(): Starts or resumes playback. Automatically handles queue logic.
  • await session.pause(): Toggles the pause state.
  • await session.stop(): Stops playback and clears the queue.
  • await session.skip(): Skips the current track.
  • await session.setLoop('track'): Sets loop mode ('none', 'track', 'queue').
  • await session.getState(): Retrieves the current state object ({ isPlaying, currentTrack, queue, ... }).

Queue Management

  • await session.addToQueue(tracks): Adds a track or array of tracks.
  • await session.shuffleQueue(): Randomizes the queue.

Events

The SessionProxy is an EventEmitter.

session.on('trackStart', ({ track }) => {
    console.log(`Track started: ${track.info.title}`);
});

session.on('queueEnd', () => {
    console.log('The queue has finished.');
});