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

@hazeljs/realtime

v1.0.5

Published

Real-time voice AI for HazelJS - OpenAI Realtime API & Gemini Live integration for low-latency speech-to-speech

Readme

@hazeljs/realtime

Voice AI, the HazelJS way.

Low-latency speech-to-speech with OpenAI Realtime API. Connect via WebSocket for voice conversations with sub-second latency — no separate STT → LLM → TTS pipeline.

npm version npm downloads License: Apache-2.0

Features

  • 🎙️ Speech-to-Speech — Native voice in, voice out — no intermediate text step
  • Low Latency — Sub-second response via WebSocket to OpenAI Realtime API
  • 🔌 WebSocket — Built on @hazeljs/websocket with @Realtime decorator
  • 🎛️ Configurable — Instructions, voice, output modalities per session
  • 🔄 Bidirectional — Proxy client ↔ OpenAI; send audio, receive audio + text
  • 📡 Event-Driven — Forward any OpenAI Realtime client/server events

Installation

npm install @hazeljs/realtime @hazeljs/core @hazeljs/websocket

Environment

Set OPENAI_API_KEY or pass openaiApiKey in RealtimeModule.forRoot().


Quick Start

1. Register Realtime Module

// app.module.ts
import { HazelModule } from '@hazeljs/core';
import { RealtimeModule } from '@hazeljs/realtime';

@HazelModule({
  imports: [
    RealtimeModule.forRoot({
      openaiApiKey: process.env.OPENAI_API_KEY,
      path: '/realtime',
      defaultSessionConfig: {
        instructions: 'You are a helpful voice assistant. Speak clearly and briefly.',
        voice: 'marin',
        outputModalities: ['audio', 'text'],
      },
    }),
  ],
})
export class AppModule {}

2. Bootstrap

// main.ts
import { HazelApp } from '@hazeljs/core';
import { AppModule } from './app.module';

async function bootstrap() {
  const app = new HazelApp(AppModule);
  const port = parseInt(process.env.PORT ?? '3000', 10);

  await app.listen(port);

  console.log(`Realtime voice AI at ws://localhost:${port}/realtime`);
}

bootstrap().catch(console.error);

The RealtimeGateway is automatically attached to the HTTP server when the app starts listening (via OnApplicationBootstrap).

For advanced use cases (e.g. custom HTTP server, attaching to a different port), you can still attach manually:

import { RealtimeGateway } from '@hazeljs/realtime';

const server = app.getServer();
const gateway = app.getContainer().resolve(RealtimeGateway);
if (server && gateway) gateway.attachToServer(server);

3. Connect from Client

const ws = new WebSocket('ws://localhost:3000/realtime');

ws.onopen = () => {
  // Optional: update session config
  ws.send(
    JSON.stringify({
      type: 'session.update',
      session: { instructions: 'Be extra friendly!' },
    })
  );
};

ws.onmessage = (e) => {
  const { event, data } = JSON.parse(e.data);
  if (event === 'realtime') {
    if (data.type === 'response.output_audio.delta') {
      // Play base64 PCM: data.delta
    }
  }
};

// Send audio (base64 PCM 24kHz)
ws.send(
  JSON.stringify({
    type: 'input_audio_buffer.append',
    audio: base64PcmChunk,
  })
);

Configuration

RealtimeModule.forRoot(options)

| Option | Type | Description | | ---------------------- | --------------------- | -------------------------------------------- | | openaiApiKey | string | OpenAI API key (or use OPENAI_API_KEY env) | | path | string | WebSocket path (default: /realtime) | | defaultSessionConfig | RealtimeSessionConfig | Default session config | | defaultProvider | 'openai' | 'gemini' | Provider (OpenAI supported first) |

RealtimeSessionConfig

| Option | Type | Description | | ------------------ | --------------------- | ------------------------------------------------------------------- | | instructions | string | System prompt for the model | | voice | OpenAIVoice | alloy, ash, ballad, coral, echo, sage, shimmer, verse, marin, cedar | | outputModalities | ('audio' | 'text')[] | Output modes (default: ['audio', 'text']) | | inputFormat | RealtimeAudioFormat | PCM format (default: 24kHz) | | turnDetection | boolean | Enable VAD (default: true) |


Client Events

Send any OpenAI Realtime client event over the WebSocket:

| Event | Description | | --------------------------- | --------------------------------- | | session.update | Update session config | | input_audio_buffer.append | Send base64 PCM audio | | input_audio_buffer.commit | Commit buffer (when VAD disabled) | | input_audio_buffer.clear | Clear buffer | | conversation.item.create | Add text message | | response.create | Trigger model response |


Server Events

You receive { event: 'realtime', data: <OpenAI server event> }:

| Event | Description | | ---------------------------------------------------------- | -------------------- | | session.created / session.updated | Session lifecycle | | response.output_audio.delta | Audio chunk (base64) | | response.output_audio.done | Audio complete | | response.output_text.delta / response.output_text.done | Text stream | | response.done | Response complete | | input_audio_buffer.speech_started / speech_stopped | VAD events |


Audio Format

  • Input: PCM 16-bit, 24kHz (or 8kHz for telephony)
  • Output: PCM 16-bit, 24kHz

Encode/decode base64 for transport over WebSocket.


Use Cases

  • 🎙️ Voice Assistants — Hands-free, low-latency voice interfaces
  • 📞 Call Centers — Real-time AI agents with natural speech
  • Accessibility — Voice-first interfaces
  • 🤖 Robotics — Voice control for devices
  • 🎮 Gaming — In-game voice NPCs

API Reference

RealtimeGateway

class RealtimeGateway extends WebSocketGateway {
  constructor(realtimeService: RealtimeService, options?: RealtimeGatewayOptions);
  attachToServer(
    server: HttpServer,
    options?: { path?: string; maxPayload?: number }
  ): WebSocketServer;
}

RealtimeService

class RealtimeService {
  createOpenAISession(client: RealtimeClientAdapter, overrides?: {...}): Promise<OpenAIRealtimeSession>;
  getSession(clientId: string): OpenAIRealtimeSession | undefined;
  removeSession(clientId: string): void;
  getStats(): RealtimeSessionStats[];
}

Testing

npm test

Contributing

Contributions are welcome! Please read our Contributing Guide for details.


License

Apache 2.0 © HazelJS


Links