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

@caiomultiversando/videolib

v1.3.2

Published

A abstração definitiva para WebRTC e Vídeo. Adicione chamadas 1x1, salas P2P, lives e VOD ao seu app com facilidade.

Readme

Video Lib 🎥

🇺🇸 Read in English | 🇧🇷 Leia em Português

Welcome to Video Lib! A modern JavaScript library for Node.js and browsers designed to completely abstract the complexity of real-time audio and video transmission using WebRTC.

You don't need to understand RTCPeerConnection, SDP (Session Description Protocol), ICE Candidates, STUN/TURN servers, or how to build a Signaling server. The library does all the heavy lifting behind the scenes, providing an elegant, asynchronous, and incredibly easy-to-use API.


🚀 Key Features

  • Simple 1x1 Calls: Connect two people instantly with just a few lines of code.
  • Multiple Rooms (Mesh P2P): Native support for multi-participant rooms, where the library manages all WebRTC sub-connections in a mesh topology.
  • Live Broadcasting: Stream to multiple viewers without them sending video back (optimized one-way stream).
  • Smart Auto-Reconnect: The library handles internet drops and instabilities using exponential backoff, reconnecting and re-joining rooms automatically.
  • Media Controls: Mute/unmute microphone, toggle camera, and share screen — all with a single method.
  • Video Streaming (VOD): Serve, watch, upload, and download video files with HTTP Range Requests (seek support).
  • Built-in Server: The VideoServer class in the backend handles signaling (WebSocket) and video streaming (HTTP) on a single port.
  • Express Compatible: If you already have a server running, just attach VideoServer to it — no port conflicts.

📦 How to Install

Make sure your Node.js project supports ES Modules ("type": "module" in package.json).

# Install the library and server
npm install @caiomultiversando/videolib

💻 Quick Start: Server (Backend)

The signaling server is the heart of the library. It coordinates the exchange of information between browsers so the P2P connection can be established. It can also serve video files for streaming and downloading.

Option 1: Standalone Server

If you do not have an HTTP server running, VideoServer creates one for you:

import { VideoServer } from '@caiomultiversando/videolib/server';

const server = new VideoServer();

// (Optional) Serve videos from a folder
server.videos('/path/to/videos/folder');

// Start the server on port 3000 (creates HTTP + WebSocket)
server.start(3000);

Option 2: Attach to an existing Express Server

If you already have an Express server (or any http.Server) running, use .attach() (or .anexar()) to avoid port conflicts:

import express from 'express';
import { VideoServer } from '@caiomultiversando/videolib/server';

const app = express();

app.get('/', (req, res) => res.send('My app!'));

const httpServer = app.listen(3000, () => {
    console.log('App running on port 3000');
});

// Attach VideoServer to the existing server
const video = new VideoServer();
video.attach(httpServer); // Everything runs on port 3000!

🌐 Quick Start: Client (Browser)

The frontend usage is designed to be intuitive. First, configure the server address:

import { Video } from '@caiomultiversando/videolib';

Video.configure({ 
    signalingUrl: 'ws://localhost:3000',  // WebSocket for calls/rooms
    serverUrl: 'http://localhost:3000'    // HTTP for VOD
});

📞 Private Call (1x1)

Ideal for connecting just two people.

<video id="myVideo" autoplay muted></video>
<video id="theirVideo" autoplay></video>

<script type="module">
    import { Video } from '@caiomultiversando/videolib';
    Video.configure({ signalingUrl: 'ws://localhost:3000' });

    const call = await Video.call("private-room-123");

    call.onVideo((stream) => {
        document.getElementById('theirVideo').srcObject = stream;
    });

    await call.video(document.getElementById('myVideo'));
    await call.audio();

    await call.join();
</script>

👥 Meeting Room (Multiple Participants)

For rooms where multiple people can join and leave at any time.

<video id="myVideo" autoplay muted></video>
<div id="videoGrid"></div>

<script type="module">
    import { Video } from '@caiomultiversando/videolib';

    const room = await Video.room("team-meeting");

    await room.video(document.getElementById('myVideo'));
    await room.audio();

    room.on("video", ({ usuario, stream }) => {
        const videoEl = document.createElement('video');
        videoEl.id = `video-${usuario.id}`;
        videoEl.autoplay = true;
        videoEl.srcObject = stream;
        document.getElementById('videoGrid').appendChild(videoEl);
    });

    room.on("sair", (usuario) => {
        document.getElementById(`video-${usuario.id}`)?.remove();
    });

    await room.join();
</script>

📡 Live Broadcasting

For cases where one person streams and many watch (unidirectional flow).

The Streamer

const live = await Video.stream("my-live-123");

await live.video(document.getElementById('myVideo'));
await live.audio();

await live.start();

The Viewer

const live = await Video.watch("my-live-123");
    
live.video(document.getElementById('player'));
await live.connect();

⚡ Auto-Reconnect & Error Handling

The library uses Exponential Backoff to automatically reconnect if the internet drops.

room.on("reconnecting", (info) => {
    console.log(`Connection lost. Retrying... ${info.attempt}/${info.maxAttempts}`);
});

room.on("reconnected", () => {
    console.log("✅ Connection restored!");
});

🎤 Media Controls

Manage media without dropping the connection:

// Mute / Unmute
room.mute();
room.unmute();

// Pause / Resume camera (remote sees a black screen)
room.pauseVideo();
room.resumeVideo();

// Share Screen (Replaces camera track seamlessly)
await room.screen();
await room.stopScreen();

📺 Video Queue (Playlist / TV)

You can turn a Live stream or Room into a "TV Channel" using the built-in Video Queue feature. The library manages the list, automatically switches videos when one ends, and supports Looping.

const live = await Video.stream("tv-123");

// 1. Add videos (accepts File objects or blob URLs)
live.enqueue(file1);
live.enqueue(file2);

// 2. Want infinite loop?
live.loopQueue(true);

// 3. Start playback and broadcasting
await live.startQueue(document.getElementById('player'));
await live.start();

// Listen to video changes
live.on('fila:mudou', ({ index, item }) => {
    console.log(`Now playing video ${index + 1}: ${item.name}`);
});

🍿 YouTube Watch Party

Broadcasting YouTube videos via pure WebRTC is blocked by browsers due to CORS. However, our library implements a native "Watch Party" pattern using the YouTube Iframe API synced through our P2P signaling.

  • The Streamer pastes the link, and the library loads the YouTube player.
  • The Viewers load the same video locally.
  • The library intercepts Play, Pause, and Seeks from the Streamer and instantly syncs them to all Viewers.
// The container must be an empty <div>
const containerYt = document.getElementById('youtube-container');

// ====== Streamer Side ======
const live = await Video.stream("my-watch-party");
// You can pass a single link or an Array of links!
// The library enables auto-loop by default.
await live.youtube(containerYt, [
    "https://www.youtube.com/watch?v=dQw4w9WgXcQ",
    "https://www.youtube.com/watch?v=anotherlink"
]);
await live.start();

// ====== Viewer Side ======
const viewer = await Video.watch("my-watch-party");
viewer.youtube(containerYt); // Tells the library where to put the YT player when a sync arrives
await viewer.connect();

Tip: The package will automatically fetch and load the official YouTube Iframe API scripts for you.


🎬 Video Streaming (VOD)

The library also handles physical video files.

// Upload a file
await Video.upload(document.getElementById('inputFile').files[0]);

// Play a video with seeking support
await Video.play('http://localhost:3000/videos/class.mp4', document.getElementById('player'));

// Download a video
await Video.download('http://localhost:3000/videos/class.mp4', 'my-class.mp4');

📖 Complete API Reference

The library fully supports both Portuguese and English method aliases (.sala() === .room(), .entrar() === .join()).

| Method / Class | Description | |---|---| | Video.configure(opts) | Configures the WebSocket and Server URL. | | Video.call(id) | Creates a 1x1 P2P Call. Returns Promise<Call>. | | Video.room(id) | Creates a P2P Room (Mesh). Returns Promise<Room>. | | Video.stream(id) | Creates a live broadcast (Streamer). Returns Promise<Live>. | | Video.watch(id) | Accesses a broadcast (Viewer). Returns Promise<Viewer>. | | Video.play(url, el) | Streams (VOD) a video to a <video> element. | | Video.download(url, name) | Triggers a file download in the browser. | | Video.list(url?) | Returns a JSON array of available videos on the server. | | Video.upload(file) | Uploads a File object to the server. |

Room / Call / Live Instances

  • await room.join() / .start() (for Live)
  • await room.video(element)
  • await room.streamVideo(element)
  • await room.audio(true/false)
  • room.mute(), room.unmute()
  • room.pauseVideo(), room.resumeVideo()
  • await room.screen(element), await room.stopScreen()
  • room.enqueue(file), room.loopQueue(true/false), await room.startQueue(element)
  • await live.poster(fileOrUrl) (Sets a cover poster for the live)
  • await live.streamImage(fileOrUrl) (Replaces video feed with a static image)
  • await live.youtube(div, url) (for Watch Parties)

VideoServer (Backend)

  • server.videos(folderPath)
  • server.youtubeParty(roomId, playlist) (Starts a Headless YouTube Watch Party without a client streamer)
  • server.youtubeQueue(roomId, url)
  • server.youtubePlay(roomId), server.youtubePause(roomId), server.youtubeSeek(roomId, seconds)
  • server.stopYoutubeParty(roomId)
  • server.fileParty(roomId, playlist) (Starts a Headless VOD Sync Party for local files in /videos)
  • server.fileQueue(roomId, url)
  • server.filePlay(roomId), server.filePause(roomId), server.fileSeek(roomId, seconds)
  • server.stopFileParty(roomId)
  • server.start(port)
  • server.stop()
  • server.attach(httpServer)