better-sse Documentation

repository·master·Indexed 21 days ago

https://github.com/matthewwid/better-sse

A lightweight, dependency-free, and spec-compliant Server-Sent Events (SSE) implementation for TypeScript. It is framework-agnostic, supporting Express, Hono, Fastify, Bun, Deno, and others. Features include session management, event broadcasting via channels, event batching for performance, and support for JavaScript iterables and Node.js readable streams.

Tokens
21.1K
Snippets
73
Records
86
Agent score
74%

What's inside better-sse

  1. Explore Better SSE use cases and frameworks

    master

    The examples directory contains several implementations of Better SSE categorized by use case, framework compatibility, and connection adapters:

    Use Cases

    • Getting Started: Basic introduction to the library.
    • Channels: Using channels for organized event distribution.
    • Streams: Working with streaming data.
    • Benchmarks: Performance comparisons.
    • Chat room: Implementing real-time chat functionality.
    • System Resource Monitor: Monitoring system resources via SSE.

    Frameworks & APIs

    • Node HTTP/1 API: Implementation using standard Node.js HTTP/1.
    • Node HTTP/2 Compatibility API: Implementation using Node.js HTTP/2.
    • Fetch API: Implementation compatible with the Fetch API.

    Connection Adapters

    • Koa: Using the Koa connection adapter.
  2. Key features of Better SSE

    master

    Better SSE is designed for high-performance real-time communication with the following capabilities:

    • Easy real-time communication: Operates directly over HTTP without WebSockets, pinging, or long-polling.
    • Multi-client broadcasting: Send events to specific individual clients or broadcast to many clients simultaneously using broadcast channels.
    • Web standards compliant: Full compliance with the WHATWG SSE specification and support for frameworks using the Fetch API.
    • Event batching: Improves performance and reduces bandwidth by batching multiple events into a single transmission.
    • First-class TypeScript: Ships with built-in types, allowing you to define types for state and event data.
    • Highly configurable: Supports customization of reconnection time, message serialization, data sanitization, and response headers.
  3. Compare Better SSE features with other SSE libraries

    master

    Better SSE is designed to be a TypeScript-first, framework-independent library that supports a wider range of features compared to other Node.js SSE libraries. Key advantages include the ability to send events to multiple clients at once, modify individual fields within events, and automatic connection keep-alive. It also provides built-in support for JSON serialization, newline sanitization, and EventSource polyfills.

    |Feature|[`better-sse`](https://www.npmjs.com/package/better-sse)|[`sse-channel`](https://www.npmjs.com/package/sse-channel)|[`sse`](https://www.npmjs.com/package/sse)|[`express-sse`](https://www.npmjs.com/package/express-sse)|[`sse-stream`](https://www.npmjs.com/package/sse-stream)|[`sse-pubsub`](https://www.npmjs.com/package/sse-pubsub)|[`nestjs @Sse`](https://docs.nestjs.com/techniques/server-sent-events)|[`hono/streaming`](https://hono.dev/helpers/streaming#streamsse)|
    |-|:-:|:-:|:-:|:-:|:-:|:-:|:-:|:-:|\n|Send events to individual clients|✔|✔|✔|✔|✔|✔|✔|✔|✔|
    |Send events to multiple clients at once|✔|✔|❌|❌|❌|✔|❌|❌|
    |Send/Modify individual fields|✔|✔|❌|❌|❌|❌|❌|❌|
    |Framework independent|✔|✔|✔|❌|❌|✔|❌|❌|
    |TypeScript types|✔|❌|❌|❌|❌|❌|✔|✔|
    |[`EventSource` polyfill support](https://www.npmjs.com/package/event-source-polyfill)|✔|✔|❌|❌|❌|❌|❌|❌|
    |Automatic connection keep-alive|✔|✔|❌|✔|✔|✔|✔|❌|
    |Serialize data as JSON|✔|✔|❌|✔|❌|✔|✔|❌|
    |Sanitize newlines from data|✔|✔|✔|✔|✔|✔|✔|❌|
    |Ignore client-given last event ID|✔|❌|❌|❌|❌|❌|❌|❌|
    |Event history maintenance|❌|✔|❌|❌|❌|✔|❌|❌|
    |Modify response headers|✔|❌|❌|✔|❌|❌|✔|✔|
    |Modify response status code|✔|❌|❌|✔|❌|❌|❌|❌|
  4. Broadcast events to many clients using channels

    master

    Channels allow you to group multiple sessions together and broadcast a single event to all registered clients simultaneously.

    1. Create a channel using createChannel().
    2. Register a session to the channel using channel.register(session).
    3. Send a message to all clients in the channel using channel.broadcast(data, eventName).
    import { createSession, createChannel } from "better-sse"
    
    const channel = createChannel()
    
    app.get("/sse", async (req, res) => {
    	const session = await createSession(req, res)
    
    	channel.register(session)
    
    	channel.broadcast("A user has joined.", "join-notification")
    })
  5. Implement a custom Connection for new frameworks

    master

    If your framework is not supported by the built-in NodeHttp1Connection, NodeHttp2CompatConnection, or FetchConnection, you can implement the Connection abstract class.

    To implement a Connection, you must provide:

    • url: The URL of the connection.
    • request: A Request object representing the incoming request. Its signal should trigger when the connection closes.
    • response: A Response object representing the outgoing response.
    • sendHead(): An abstract method to send the response status and headers.
    • sendChunk(chunk: string): An abstract method to write data chunks (UTF-8 encoded).
    • cleanup(): An abstract method for resource cleanup.

    Connection.applyHeaders is a static utility available to help merge header objects into a Headers instance.

  6. What are connection adapters in Better SSE?

    master

    In Better SSE, connection adapters implement the underlying connection logic, acting as the bridge between the library and your specific protocol, framework, or runtime.

    While sessions manage the high-level request/response lifecycle and SSE-specific data formatting, connection adapters are responsible for:

    • Extracting request headers and query parameters.
    • Sending response headers and data chunks.
    • Reporting when the connection closes.

    Better SSE automatically detects and uses the appropriate built-in adapter based on the arguments you pass to createResponse or createSession.

  7. How channels work in Better SSE

    master

    Channels are an abstraction used to broadcast events to many clients simultaneously.

    Workflow:

    1. Create: Define a channel using createChannel().
    2. Register: When a client connects (via a session), register that session to one or more channels using channel.register(session).
    3. Broadcast: Use channel.broadcast(data, eventName) to send data to all registered sessions.
    4. Automatic Cleanup: Sessions are automatically deregistered from a channel when they disconnect. You can also manually deregister a session using channel.deregister(session, session) if needed.

    Channels allow for dynamic configuration, as you can register sessions to different channels based on authorization or user context.

    import { createChannel } from "better-sse"
    
    // 1. Create
    const myChannel = createChannel()
    
    // 2. Register (inside your route handler)
    // myChannel.register(session)
    
    // 3. Broadcast
    // myChannel.broadcast("hello everyone", "message")
  8. Quickstart with Better SSE

    master

    Better SSE provides a dead simple, dependency-less, and spec-compliant implementation for real-time server-to-client communication over HTTP. It allows for multi-client broadcasting, event batching, and full TypeScript support without requiring WebSockets or long-polling.

    // Server-side setup example
    import { createSSE } from 'better-sse';
    
    const sse = createSSE();
    
    // In your HTTP handler:
    // return sse.respond(res);
  9. Use Better SSE with Hono and Cloudflare Workers

    master

    For Fetch-based environments like Hono or Cloudflare Workers, use createResponse.

    • Hono: Pass the raw request object c.req.raw to createResponse.
    • Cloudflare Workers: Requires enabling nodejs_compat in your wrangler.jsonc configuration to support the necessary polyfills.
    // Hono Example
    import { Hono } from "hono"
    import { serve } from "@hono/node-server"
    import { createResponse } from "better-sse"
    
    const app = new Hono()
    
    app.get("/sse", (c) =>
        createResponse(c.req.raw, (session) => {
            session.push("Hello world!")
        })
    )
    
    serve({ fetch: app.fetch, port: 8080 })
  10. Run Better SSE examples

    master

    To explore the provided examples, follow these steps to install dependencies and start a specific example project:

    1. Navigate to the examples directory and install dependencies:
      cd examples
      npm i
    2. Navigate to the specific example directory you wish to run (e.g., getting-started):
      cd getting-started
    3. Start the example:
      npm run start
    cd examples && npm i
    cd getting-started && npm run start
  11. Use Better SSE with NestJS

    master

    NestJS integration depends on the underlying platform used:

    • @nestjs/platform-express: Use await createSession(req, res) where req and res are standard Express objects.
    • @nestjs/platform-fastify: Use await createSession(req.raw, res.raw) to pass the underlying Node.js HTTP objects to Better SSE.
    // NestJS Fastify Example
    import { Controller, Get, Req, Res } from "@nestjs/common"
    import { FastifyReply, FastifyRequest } from "fastify"
    import { createSession } from "better-sse"
    
    @Controller()
    export class SseController {
      @Get("sse")
      async sse(@Req() req: FastifyRequest, @Res() res: FastifyReply) {
        const session = await createSession(req.raw, res.raw)
        session.push("Hello world!")
      }
    }
  12. Use the Node HTTP/1 API adapter

    master

    When working with the standard Node.js HTTP/1 API (such as with Express), passing IncomingMessage and ServerResponse objects to createSession will trigger the use of the NodeHttp1Connection adapter.

    import { createSession } from "better-sse"
    
    // Example using Express
    app.get("/sse", async (req, res) => {
        const session = await createSession(req, res)
        session.push("Hello world!")
    })