Skip to content

Easy, Composable, and type-safe Server-Sent Events (SSE)

License

Notifications You must be signed in to change notification settings

Bewinxed/river.ts

Folders and files

NameName
Last commit message
Last commit date

Latest commit

Β 

History

33 Commits
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

Repository files navigation

00171-1636846244

🌊 river.ts | ✨ Composable, Typesafe SSE Events

License TypeScript

npm

river.ts is a Based library for handling server-sent events (SSE) in TypeScript. It allows you to build a common interface for events, then call it from one place Both on server and client. Currently compatible with express-like backends.

🌟 Features

  • πŸ’‘ Easy-to-use API for subscribing to and handling events
  • πŸ”„ Automatic reconnection with configurable delay
  • πŸ”Œ Works with GET & Other HTTP Methods along with custom headers, body, etc...
  • πŸ› οΈ Event listeners for events, with typesafe event handlers.

πŸ“¦ Installation

Bun

bun install river.ts

NPM (why tho)

npm install river.ts

πŸš€ Usage

πŸ— Build your event map

Chain commands together to build a map of events, you can add the types as type arguments or function arguments.

import { RiverEvents } from 'river.ts';

const events = new RiverEvents()
	.map_event("ping", {
		message: "pong",
	})
	.map_event("payload", {
		data: [
			{ id: 1, name: "Alice" },
			{ id: 2, name: "Bob" },
		],
	}).build()

🌠 On the Server

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

// init the server
const server = RiverEmitter.init(events)

// Then, use .stream() as body init it using the `Response` object of your framework
function GET(req: Request) {
	return new Response(
		server.stream((emitter) => {
			// do stuff
			// emit simple text message
			emitter.emit_event("ping", { message: "pong" });

			// do more stuff
			// emit complex json data
			emitter.emit_event("payload", {
				// type safe data
				data: [
					{ id: 1, name: "Alice" },
					{ id: 2, name: "Bob" },
				],
			});
		}),
		{
			// convenience method to set headers for text/event-stream
			headers:
				server.headers(
					// optional, set your headers
				),
		},
	);
}

πŸš€ On the client

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

// On the client
const client = RiverClient.init(events)

await client
	// add url, method, headers, etc (GET/POST/Etc, all work)
	.prepare("http://localhost:3000/events", {
		// custom headers
		method: "POST",
		body: JSON.stringify({}),
	})
	// add event listeners
	.on("ping", (res) => {
		console.log("on data", res);
		// typeof res
		// {
		// 	message: string;
		// 	type: "ping";
		// }
	})
	// add more event listeners
	.on("payload", (res) => {
		console.log("on data", res);
		// typeof res
		// {
		// 	data: {
		// 		id: number;
		// 		name: string;
		// 	}[];
		// 	type: "payload";
		// };
		if (!res.data) {
			// you can close it anytime if you assign it to a constant beforehand
			client.close();
		}
	})
	// start the stream
	.stream();

πŸ” Type Safety

After building the event map, You can either use typeof events.{event} or use the type InferEventType with the event name

import { InferEventType } from 'river.ts';

const events = ....build()
type Events = typeof events
type PingEvent = InferEventType<Events, "ping">;
// {
// 	message: string;
// 	type: "ping";
// }

const events: PingEvent[] = []

// then you can push to it if you want and the types will be ok
events.push({
	message: "pong",
	type: "ping",
})

Framework Examples

πŸŽ‰ Contributing

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

πŸ“„ License

Don't be a bozo

About

Easy, Composable, and type-safe Server-Sent Events (SSE)

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages