Getting Started with Dialogue

This guide covers installation, basic setup, and your first real-time application using Dialogue.

1. Overview

Dialogue is an event-based realtime communication library built on Socket.IO, Hono, and Bun. It provides a simple, type-safe API for building real-time applications like chat, notifications, live dashboards, multiplayer games, and IoT systems.

1.1 Key Features

  • Config-first with dynamic rooms: Define common rooms upfront, create others at runtime
  • Event-centric: Events are first-class citizens with optional Zod schema validation
  • Type-safe: Full TypeScript support with inferred types from schemas
  • Bounded rooms: Optional maxSize for predictable scaling
  • Unified mental model: Backend and frontend share similar APIs

2. Installation

Install Dialogue and zod:

bun add dialogue-ts zod

Dialogue requires Bun runtime for the backend server.

3. Quick Start

3.1 Define Events

Create a configuration file to define your events and rooms:

// dialogue.config.ts
import { createDialogue, defineEvent } from "dialogue-ts";
import { z } from "zod";

// Define events with optional schema validation
export const Message = defineEvent("message", {
  schema: z.object({
    text: z.string().min(1).max(1000),
    senderId: z.string(),
  }),
  description: "Chat message sent by a user",
});

export const Typing = defineEvent("typing", {
  schema: z.object({
    isTyping: z.boolean(),
  }),
});

// Create the dialogue instance
export const dialogue = createDialogue({
  port: 3000,
  rooms: {
    chat: {
      name: "Chat Room",
      events: [Message, Typing],
      defaultSubscriptions: ["message"],
    },
  },
  hooks: {
    clients: {
      onConnected: (client) => {
        console.log(`Client connected: ${client.userId}`);
        client.join("chat");
      },
    },
  },
});

Dynamic Room Creation

While config-first is recommended, you can also create rooms dynamically at runtime:

// Create room on-demand
dialogue.createRoom({
  id: `game-${gameId}`,
  name: 'Game Session',
  events: [
    { name: 'move', schema: z.object({ x: z.number(), y: z.number() }) },
    { name: 'chat', schema: z.object({ message: z.string() }) }
  ]
});

Recommendation: Use predefined rooms for ~80% of your use cases (known room types), and dynamic creation for ~20% (user-generated content, temporary sessions).

3.2 Start the Server

// server.ts
import { dialogue } from "./dialogue.config";

await dialogue.start();
// Server running on http://localhost:3000

Run with Bun:

bun run server.ts

3.3 Trigger Events from Backend

You can trigger events from anywhere in your backend code:

import { dialogue, Message } from "./dialogue.config";

// From an API route, webhook, or background job
dialogue.trigger("chat", Message, {
  text: "Welcome to the chat!",
  senderId: "system",
});

3.4 Connect from Frontend

import { createDialogueClient } from "dialogue-ts/client";

const client = createDialogueClient({
  url: "ws://localhost:3000",
  auth: { userId: "user-123" },
});

await client.connect();

// Join a room
const chat = await client.join("chat");

// Listen for events
chat.on("message", (msg) => {
  console.log(`${msg.from}: ${msg.data.text}`);
});

// Send events
chat.trigger("message", {
  text: "Hello, everyone!",
  senderId: "user-123",
});

4. Project Structure

Here's the recommended structure for a Dialogue application:

my-app/
├── server/
│   ├── index.ts          # Dialogue server setup
│   └── rooms.ts          # Room configurations
├── client/
│   ├── App.tsx           # React app (or your framework)
│   └── useDialogue.ts    # Client hooks
└── package.json

This is a minimal, focused view showing only application code. The Dialogue library itself is installed as dependencies and doesn't appear in your project structure.

5. Next Steps

This documentation reflects the current implementation and is subject to evolution. Contributions and feedback are welcome.