river.ts

Easy, Composable, and type-safe Server-Sent Events (SSE)
GitHub
63
Created 5 months ago, last commit 3 months ago
Number of contributors not available
34 commits
Stars added on GitHub, month by month
N/A
N/A
N/A
N/A
N/A
N/A
N/A
11
12
1
2
3
4
5
6
7
8
9
10
2023
2024
Stars added on GitHub, per day, on average
Yesterday
=
Last week
0.0
/day
Last month
+0.1
/day
npmPackage on NPM
river.ts
1.0.21
Monthly downloads on NPM
0
0
0
0
0
0
0
11
12
1
2
3
4
5
6
7
8
9
10
2023
2024
No dependencies
README

00171-1636846244

🌊 river.ts | ✨ Composable, Typesafe SSE Events

License TypeScript npm

river.ts is a powerful library for handling server-sent events (SSE) in TypeScript. It allows you to build a common interface for events, then use it consistently on both server and client sides. Compatible with express-like backends and modern frontend frameworks.

🌟 Features

  • 💡 Easy-to-use API for defining, emitting, and handling events
  • 🔄 Automatic reconnection with configurable options
  • 🔌 Works with various HTTP methods and supports custom headers, body, etc.
  • 🛠️ Type-safe event handlers and payload definitions
  • 🚀 Streamlined setup for both server and client sides

📦 Installation

npm install river.ts
# or
yarn add river.ts
# or
pnpm add river.ts
# or
bun add river.ts

🚀 Usage

🏗 Define your event map

Use the RiverEvents class to define your event structure:

import { RiverEvents } from 'river.ts';

const events = new RiverEvents()
  .defineEvent('ping', {
    message: 'pong'
  })
  .defineEvent('payload', {
    data: [
      { id: 1, name: 'Alice' },
      { id: 2, name: 'Bob' }
    ],
    stream: true
  })
  .build();

🌠 On the Server

Use RiverEmitter to set up the server-side event emitter:

import { RiverEmitter } from 'river.ts/server';
import { events } from './events';

const emitter = RiverEmitter.init(events);

function handleSSE(req: Request, res: Response) {
  const stream = emitter.stream({
    callback: async (emit) => {
      await emit('ping', { message: 'pong' });
      await emit('payload', {
        data: [
          { id: 1, name: 'Alice' },
          { id: 2, name: 'Bob' }
        ]
      });
    },
    clientId: '...', // optional param to set a custom client ID
    ondisconnect: (clientId) => {
      // optional param to handle disconnections
    }
  });

  return new Response(stream, {
    headers: emitter.headers()
  });
}

🚀 On the Client

Use RiverClient to set up the client-side event listener:

import { RiverClient } from 'river.ts/client';
import { events } from './events';

const client = RiverClient.init(events);

client
  .prepare('http://localhost:3000/events', {
    method: 'GET',
    headers: {
      // Add any custom headers here
    }
  })
  .on('ping', (data) => {
    console.log('Ping received:', data.message);
  })
  .on('payload', (data) => {
    console.log('Payload received:', data);
  })
  .stream();

🔍 Type Safety

Leverage TypeScript's type system for type-safe event handling:

import { InferEventType } from 'river.ts';

type Events = typeof events;
type PingEvent = InferEventType<Events, 'ping'>;
// {
//   message: string;
//   type: "ping";
// }

const pingEvents: PingEvent[] = [];
pingEvents.push({
  message: 'pong',
  type: 'ping'
});

🎉 Contributing

Contributions are welcome! If you find any issues or have suggestions for improvements, please open an issue or submit a pull request.

📄 License

This project is licensed under the MIT License.