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

@voxera/protocol

v0.3.3

Published

Versioned wire protocol and shared types for Voxera SDKs and server

Readme

@voxera/protocol

The wire contract shared by the Voxera voice server and every client SDK — web, React Native, Flutter, iOS, and Android. Event names, command names, payload types, and JSON Schemas live here and nowhere else.

This package exists so that a rename in one codebase cannot silently break another. Anything sent over the socket has a name defined in this file, and that name is a wire identifier: it does not change because the product, directory, or class was renamed.

  • Protocol version: 1.0 (VOXERA_PROTOCOL_VERSION)
  • Transport: socket.io for signalling, mediasoup/WebRTC for media
  • No runtime dependencies

Installing

npm install @voxera/protocol

Most people never install this directly — it arrives as a dependency of @voxera/sdk-web or @voxera/sdk-react-native, and those re-export what a client needs. Install it on its own when you are writing a client of your own, or a server that talks to one, and want the event names and payload types rather than string literals.

import {
  CLIENT_COMMANDS,
  SERVER_EVENTS,
  type ConversationMessage,
  type InitSessionConnection,
} from "@voxera/protocol";

socket.on(SERVER_EVENTS.toolTriggered, handleToolCall);
socket.emit(CLIENT_COMMANDS.conversationStart, { sessionId });

Inside this repository the same package is linked from source, so a change to a wire type reaches every consumer without a publish. The iOS, Android and Flutter SDKs do not consume the TypeScript package — they mirror the same constants in their own languages, which is why a change here is a change to five codebases.

Rebuild after editing wire types

dist/ is gitignored and produced by the build. A file: dependency resolves to the directory as it is on disk, so consumers keep compiling against the previous dist/ until it is rebuilt:

npm run build      # emits ESM + CJS + .d.ts
npm test           # == npm run validate

Editing src/index.ts and rebuilding only the consumer is the most common way to get a confusing type error that disappears on a second, unrelated build.

What it exports

import {
  VOXERA_PROTOCOL_VERSION,
  CLIENT_COMMANDS,
  SERVER_EVENTS,
  LEGACY_SERVER_EVENT_ALIASES,
  type InitSessionConnection,
  type ConversationMessage,
  type JsonValue,
} from "@voxera/protocol";

socket.emit(CLIENT_COMMANDS.conversationStart);
socket.on(SERVER_EVENTS.transcriptUpdate, handleTranscript);

Import the constants rather than writing the strings. A typo in a string literal is a silent no-op — the server simply never receives the command, and nothing errors.

| Export | Purpose | | --- | --- | | CLIENT_COMMANDS | Every command a client may emit. server/src/mediasoup/mediasoup.gateway.ts subscribes to exactly these. | | SERVER_EVENTS | Every event the server emits. | | LEGACY_SERVER_EVENT_ALIASES | Old names still emitted alongside the current ones, for clients that have not migrated. New clients must not listen for these. | | InitSessionConnection | The session handshake payload — see below. | | TranscriptionConfig, ModelConfig, TtsConfig | Provider stage configuration. | | FunctionToolDefinition | Tool/function-calling schema. | | ConversationMessage, InitialMessage | Conversation history shapes. | | ProtocolCapabilities | What the connected server supports. |

JSON Schemas

For consumers that validate at runtime, or that are not written in TypeScript:

import initSchema from "@voxera/protocol/schemas/v1/init-session-connection.schema.json";

schemas/v1/ holds init-session-connection.schema.json, command-result.schema.json, and a manifest.json listing them. npm run validate checks the schemas against the TypeScript types, and runs as part of prepack.

Legacy aliases

LEGACY_SERVER_EVENT_ALIASES = {
  newProducer: ["newProducer"],   // current: "new-producer"
  clearAction: ["clear-action"],
}

The server emits both spellings. These exist to keep already-shipped mobile builds working and will be removed once those versions are out of support.

Session authorization

init-session-connection is the first command of every session and decides what the session is allowed to do. It accepts one of two credentials:

// Preferred. Your backend exchanges its secret key for a short-lived token.
{ sessionToken: "...", sessionId: "..." }

// Direct-client. A publishable key, optionally pinned to one agent.
{ appKey: "vx_pk_...", agentId: "..." }

A secret key (vx_sk_*) must never appear here. The control plane refuses one that arrives through a client — once a secret key has passed through a browser or an app binary it is no longer secret. Secret keys are for POST /api/v1/sessions/token from your own backend, nothing else.

The server decides the pipeline, not the client

InitSessionConnection carries transcriptionConfig, modelConfig, ttsConfig, tools, additionalSystemPrompts, selectedModel, and selectedVoice. On a managed session these are overwritten by the published agent version before they are read. Setting them changes nothing.

The exceptions are tools and additionalSystemPrompts, which are merged with the agent's own only when that agent version's runtimePolicy sets allowRuntimeTools / allowRuntimePrompts. Everything else is taken from the immutable agent snapshot returned by the control plane.

These fields remain in the type because the legacy direct-configuration path — where a client supplies its own provider config against a server-side APP_KEY — still exists for migration. New integrations should configure the agent in the manager application and send none of them.

Untrusted by construction

userInfo, user, metadata, and chatProfile are caller-supplied and reach the assistant as conversation context. They are data, not instructions: anything a user can influence can attempt prompt injection through these fields. Do not put authorization decisions behind values that arrive here.

Related

  • server/README.md — how the server consumes the handshake
  • persistence-service/README.md — how tokens and app keys are minted
  • pkg/web/README.md — the reference TypeScript client