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

@profullstack/group-call

v0.6.1

Published

A group call on a phone number: dial in, key a room code, talk with everyone else who did, people and AI agents alike. Telnyx Call Control state machine extracted from nixamp's party line; the engine behind nixamp live joins and group.call.pit.world.

Readme

@profullstack/group-call

A group call on a phone number. People dial in, key a room code, and talk with everyone else who keyed the same code. AI agents phone in the same way, keying the code with DTMF, so a room holds both.

It's the engine behind nixamp's live-join party line and group.call.pit.world. Audio mixing is Telnyx's. This package answers Telnyx Call Control webhooks and runs the state machine: answer, ask for the code on the keypad, join or create the conference, welcome the caller, count who is there.

npm i @profullstack/group-call
import { GroupCall } from "@profullstack/group-call";

const line = new GroupCall({
  apiKey: process.env.TELNYX_API_KEY!,
  publicKey: process.env.TELNYX_PUBLIC_KEY!, // the account's ed25519 key, base64
  codeLength: 4,
  greeting: "Welcome to group call. Enter the four digit room code.",
  // Only rooms you know about open. Leave this out and any code is a room.
  onCode: (code) => (rooms.has(code) ? { welcome: `Welcome to ${rooms.get(code)}. ` } : { reject: "That is not a room." }),
  onJoin: (code, who) => console.log(`${who.name || who.from} joined ${code}`),
  onLeave: (code, who) => console.log(`${who.name || who.from} left ${code}`),
});

// Your webhook route. Check the signature against the raw body, then hand over the event.
if (!line.verify(rawBody, headers["telnyx-signature-ed25519"], headers["telnyx-timestamp"])) return 401;
await line.handle(JSON.parse(rawBody).data);

What it does

  • Keypad codes only. A misheard spoken digit is a different room that also exists. It asks three times, says how many digits it got, then says goodbye.
  • Conferences that outlive Telnyx's 4-hour expiry. A stale id is remade on the next join.
  • A fallback voice. If the main voice fails once, that leg hears the plain voice from then on, so a broken TTS voice can't loop silently.
  • ElevenLabs voices with voiceSettings: { api_key_ref }.
  • Agents with names. line.expect(code, callerId, "riotcoder") before an agent dials in, and the room knows who it is.
  • Call people in. dial(code, phone, { from, connectionId, name?, prompt? }) rings a phone from your number. Whoever answers presses 1 and is in the room, so voicemail never joins. The room rides in the call's client_state, so an answer after a restart still lands right.
  • Call people in from the call. With onInvite(code, who, digits), anyone already in a room presses *, a phone number and # (* again cancels): a person on their keypad, or an agent sending DTMF on its leg. The app decides whether it may and usually calls dial; the string it returns is said to whoever asked. Without the hook, keys pressed in a room do nothing.
  • Call a voice agent in. dial(code, "sip:[email protected]", { ..., direct: true, name, headers }) joins on answer with no press 1 and no greeting, and sends headers (X-... only) on the INVITE. ElevenLabs Agents expose them as dynamic variables (X-Otr-Episode -> {{sip_otr_episode}}).
  • Record a room. record(code) records the conference, everyone mixed, as mp3 (or wav) until it ends or stopRecording(code). onRecording({ code, conferenceId, recordingId, mp3, wav, ... }) fires on conference.recording.saved; the links are short-lived, so download straight away, or get fresh ones with recordingLinks(recordingId).
  • Room API. say(code, text, voice?) speaks into a room. Also participants(code), kick(code, leg), list(), hasCallers(code) and callersIn(code).
  • App hooks. onCode can join, welcome, reject, or take the call over: call.gather(...) asks another question (nixamp's "press 1 for a text").
  • Live transcripts. With transcribe: true, each participant's own leg is transcribed, and onTranscript(code, who, text) gets every finished line with its speaker, agents included. Telnyx bills this per minute per leg, so it's off unless you ask for it.
  • Survives restarts. Conference names carry a keyed hash of the room code. After a restart, the first caller into a room joins its running conference, not a new one.
  • Deploy-proof rooms. Save participants(code) plus each room's conference id from onJoin/onLeave, and pass them to restore() at boot. Each conference is checked against Telnyx, and the legs still in it come back with their names, so a restart neither splits a room nor forgets who is in it.
  • telnyxSms, verifyTelnyx, newRoomCode, sameSecret helpers.

MIT