### Fastify SSE Server Source: https://github.com/matthewwid/better-sse/blob/master/docs/src/content/docs/reference/recipes.mdx Create an SSE endpoint with Fastify. This example initializes a Fastify instance and defines a GET route for SSE. ```typescript import Fastify from "fastify" import { createSession } from "better-sse" const fastify = Fastify() fastify.get("/sse", async (request, reply) => { const session = await createSession(request.raw, reply.raw) session.push("Hello world!") }) fastify.listen({ port: 8080 }) ``` -------------------------------- ### Install better-sse with bun Source: https://github.com/matthewwid/better-sse/blob/master/README.md Use this command to install the package using bun. Ensure you have Bun installed. ```sh bun add better-sse ``` -------------------------------- ### Run Documentation Development Server Source: https://github.com/matthewwid/better-sse/blob/master/README.md Starts a local development server for the documentation site. ```bash pnpm dev ``` -------------------------------- ### Install better-sse with Deno Source: https://github.com/matthewwid/better-sse/blob/master/README.md Use this command to install the package using Deno. This command fetches and installs the package from JSR. ```sh deno install jsr:@mwid/better-sse ``` -------------------------------- ### Server-Side SSE Setup Source: https://github.com/matthewwid/better-sse/blob/master/docs/src/content/docs/index.mdx This snippet demonstrates the basic server-side setup for Better SSE. It initializes the SSE server and configures it to broadcast messages. Ensure you have the necessary imports for your framework. ```typescript import { SSE } from "better-sse"; const server = new SSE(); server.on("connection", (client) => { console.log("Client connected"); client.on("close", () => { console.log("Client disconnected"); }); }); // Example: Broadcast a message every 5 seconds setInterval(() => { server.broadcast("Hello, clients!"); }, 5000); // In a framework like Express, you would mount this: // app.use(server.requestHandler); ``` -------------------------------- ### Install Documentation Dependencies Source: https://github.com/matthewwid/better-sse/blob/master/README.md Installs dependencies required for building and running the documentation locally. ```bash cd docs pnpm i ``` -------------------------------- ### Install better-sse with npm Source: https://github.com/matthewwid/better-sse/blob/master/README.md Use this command to install the package using npm. Ensure you have Node.js and npm installed. ```sh npm install better-sse ``` -------------------------------- ### Install better-sse with yarn Source: https://github.com/matthewwid/better-sse/blob/master/README.md Use this command to install the package using yarn. Ensure you have Node.js and yarn installed. ```sh yarn add better-sse ``` -------------------------------- ### Install better-sse with pnpm Source: https://github.com/matthewwid/better-sse/blob/master/README.md Use this command to install the package using pnpm. Ensure you have Node.js and pnpm installed. ```sh pnpm add better-sse ``` -------------------------------- ### Install pnpm and Dependencies Source: https://github.com/matthewwid/better-sse/blob/master/README.md Installs the pnpm package manager globally and then installs project dependencies. ```bash npm i -g pnpm pnpm i ``` -------------------------------- ### Install Node.js with nvm Source: https://github.com/matthewwid/better-sse/blob/master/README.md Installs Node.js using the 'n' version manager. Ensure curl is installed. ```bash curl -L https://git.io/n-install | bash n auto ``` -------------------------------- ### Install Better SSE Source: https://context7.com/matthewwid/better-sse/llms.txt Install the better-sse package using your preferred package manager. ```bash npm install better-sse # or yarn add better-sse # or pnpm add better-sse # or bun add better-sse # or (Deno) deno install jsr:@mwid/better-sse ``` -------------------------------- ### Hapi SSE Server Source: https://github.com/matthewwid/better-sse/blob/master/docs/src/content/docs/reference/recipes.mdx Create an SSE endpoint with Hapi. This example initializes a Hapi server and defines a GET route handler that prevents further interaction with the response stream. ```typescript import Hapi from "@hapi/hapi" import { createSession } from "better-sse" const init = async () => { const server = Hapi.server({ port: 8080, host: "localhost", }) server.route({ method: "GET", path: "/sse", handler: async ({ raw }, { abandon }) => { const session = await createSession(raw.req, raw.res) session.push("Hello world!") // Prevent Hapi from interacting further with the response stream return abandon }, }) await server.start() } init() ``` -------------------------------- ### Hono Server Setup for SSE Source: https://github.com/matthewwid/better-sse/blob/master/docs/src/content/docs/guides/channels.mdx Set up a Hono server to serve static assets and manage SSE connections, registering sessions with the 'ticker' channel. ```typescript import { Hono } from "hono" import { serve } from "@hono/node-server" import { serveStatic } from "@hono/node-server/serve-static" import { createResponse } from "better-sse" import { ticker } from "./channels/ticker" const app = new Hono() app.use("*", serveStatic({ root: "./public" })) app.get("/sse", (c) => createResponse(c.req.raw, (session) => { ticker.register(session) }) ) serve({ fetch: app.fetch, port: 8080, }) ``` -------------------------------- ### Basic SSE Server with Ultimate Express Source: https://github.com/matthewwid/better-sse/blob/master/docs/src/content/docs/reference/recipes.mdx Set up a basic Server-Sent Events endpoint using Ultimate Express. Ensure you have express and better-sse installed. ```typescript import express from "ultimate-express" import { createSession, NodeHttp1Connection } from "better-sse" const app = express() app.get("/sse", async (req, res) => { const connection = new NodeHttp1Connection(req, res) const session = await createSession(connection) session.push("Hello world!") }) app.listen(8080) ``` -------------------------------- ### Deno Integration with Better SSE Source: https://context7.com/matthewwid/better-sse/llms.txt This example shows how to use Better SSE with Deno. It utilizes `createResponse` from 'npm:better-sse' and Deno's `serve` function. The pathname is checked to initiate the SSE connection. ```typescript import { createResponse } from "npm:better-sse" Deno.serve({ port: 8080 }, (req) => { if (new URL(req.url).pathname === "/sse") { return createResponse(req, (session) => session.push("Hello from Deno!")) } return new Response("Not Found", { status: 404 }) }) ``` -------------------------------- ### Koa SSE Server Setup Source: https://github.com/matthewwid/better-sse/blob/master/docs/src/content/docs/guides/connection-adapters.mdx Set up a Server-Sent Events endpoint using Koa and better-sse. Ensure KoaConnection listeners are added to the Koa app before defining routes. ```typescript import Koa from "koa" import Router from "@koa/router" import { createSession } from "better-sse" import { KoaConnection } from "./KoaConnection" const app = new Koa() const router = new Router() KoaConnection.addListeners(app) router.get("/sse", async (ctx) => { const connection = new KoaConnection(ctx) const session = await createSession(connection) session.push("Hello world!") }) app.use(router.routes()).use(router.allowedMethods()) app.listen(3000) ``` -------------------------------- ### NestJS (Express platform) Integration with Better SSE Source: https://context7.com/matthewwid/better-sse/llms.txt This example demonstrates integrating Better SSE into a NestJS application using the Express platform. It requires importing `Controller`, `Get`, `Req`, `Res` from '@nestjs/common' and `createSession` from 'better-sse'. ```typescript import { Controller, Get, Req, Res } from "@nestjs/common" import { createSession } from "better-sse" @Controller() export class SseController { @Get("sse") async sse(@Req() req, @Res() res) { const session = await createSession(req, res) session.push("Hello from NestJS!") } } ``` -------------------------------- ### Fetch API Server with @mjackson/node-fetch-server Source: https://github.com/matthewwid/better-sse/blob/master/docs/src/content/docs/reference/recipes.mdx Example of using Better SSE with a server framework that implements the Fetch API, specifically using `@mjackson/node-fetch-server`. It creates an SSE response for the /sse path. ```typescript import { createServer } from "node:http" import { createRequestListener, type FetchHandler } from "@mjackson/node-fetch-server" import { createResponse } from "better-sse" const handler: FetchHandler = (request) => { const url = new URL(request.url) switch (url.pathname) { case "/sse": { return createResponse(request, (session) => { session.push("Hello world!") }) } default: { return new Response("404 Not Found", { status: 404, headers: { "Content-Type": "text/plain", }, }) } } } const server = createServer(createRequestListener(handler)) server.listen(8080) ``` -------------------------------- ### Express Server Setup for SSE Source: https://github.com/matthewwid/better-sse/blob/master/docs/src/content/docs/guides/channels.mdx Configure an Express server to serve static files and handle SSE connections, registering sessions with the 'ticker' channel. ```typescript import express from "express" import { createSession } from "better-sse" import { ticker } from "./channels/ticker" const app = express() app.use(express.static("./public")) app.get("/sse", async (req, res) => { const session = await createSession(req, res) ticker.register(session) }) app.listen(8080) ``` -------------------------------- ### Create SSE Endpoint Source: https://github.com/matthewwid/better-sse/blob/master/docs/src/content/docs/guides/channels.mdx Sets up a basic SSE endpoint that sends a single 'ping' event to a connected client. This serves as a starting point before implementing channel broadcasting. ```typescript app.get("/sse", async (req, res) => { const session = await createSession(req, res) session.push("Hello world!", "ping") }) ``` ```typescript app.get("/sse", (c) => createResponse(c.req.raw, (session) => { session.push("Hello world!", "ping") }) ) ``` -------------------------------- ### Koa Server Source: https://github.com/matthewwid/better-sse/blob/master/docs/src/content/docs/reference/recipes.mdx This example shows how to implement SSE endpoints in a Koa.js application using `@koa/router`. It ensures Koa does not interfere with the SSE response and creates a session to push messages. ```typescript import Koa from "koa" import Router from "@koa/router" import { createSession } from "better-sse" const app = new Koa() const router = new Router() router.get("/sse", async (ctx) => { // Prevent Koa sending a response and closing the connection ctx.respond = false // Koa defaults to 404 if you do not set the response body ctx.status = 200 const session = await createSession(ctx.req, ctx.res) session.push("Hello world!") }) app.use(router.routes()) app.listen(8080) ``` -------------------------------- ### NestJS Fastify SSE Controller Source: https://github.com/matthewwid/better-sse/blob/master/docs/src/content/docs/reference/recipes.mdx Configure an SSE endpoint in NestJS using `@nestjs/platform-fastify`. This example uses `FastifyRequest` and `FastifyReply`. ```typescript 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!") } } ``` -------------------------------- ### Bun Integration with Better SSE Source: https://context7.com/matthewwid/better-sse/llms.txt Example of integrating Better SSE with Bun. It uses `createResponse` from 'better-sse' and Bun's `serve` function. This snippet includes `keepAlive` option for the SSE connection. ```typescript import { createResponse } from "better-sse" Bun.serve({ port: 8080, routes: { "/sse": (req) => createResponse(req, { keepAlive: 8000 }, (session) => session.push("Hello from Bun!") ), }, fetch() { return new Response("Not Found", { status: 404 }) }, }) ``` -------------------------------- ### Implement Custom SSE Connections with Koa using Better SSE Source: https://context7.com/matthewwid/better-sse/llms.txt Extend the `Connection` abstract class to integrate Better SSE with frameworks like Koa. This example shows how to create a `KoaConnection` adapter for handling SSE requests within a Koa application. ```typescript import { PassThrough } from "node:stream" import Koa, { Context } from "koa" import Router from "@koa/router" import { Connection, createSession } from "better-sse" class KoaConnection extends Connection { private controller: AbortController private stream: PassThrough url: URL request: Request response: Response constructor(private ctx: Context) { super() this.url = ctx.URL this.controller = new AbortController() this.request = new Request(this.url, { method: ctx.request.method ?? Connection.constants.REQUEST_METHOD, signal: this.controller.signal, }) Connection.applyHeaders(ctx.headers, this.request.headers) ctx.status = Connection.constants.RESPONSE_CODE ctx.set(Connection.constants.RESPONSE_HEADERS) this.response = new Response(null, { status: Connection.constants.RESPONSE_CODE, headers: Connection.constants.RESPONSE_HEADERS, }) this.stream = new PassThrough() this.stream.once("close", () => this.controller.abort()) ctx.body = this.stream } sendHead() { this.ctx.flushHeaders() } sendChunk(chunk: string) { this.stream.write(chunk) } cleanup() { this.stream.removeAllListeners("close") } } // Usage with Koa const app = new Koa() const router = new Router() router.get("/sse", async (ctx) => { const connection = new KoaConnection(ctx) const session = await createSession(connection) session.push("Hello from Koa!", "greeting") }) app.use(router.routes()) app.listen(3000) ``` -------------------------------- ### Fastify Integration with Better SSE Source: https://context7.com/matthewwid/better-sse/llms.txt Demonstrates integrating Better SSE with the Fastify framework. Ensure Fastify is installed and imported. The `createSession` function is used with Fastify's raw request and reply objects. ```typescript import Fastify from "fastify" import { createSession } from "better-sse" const fastify = Fastify() fastify.get("/sse", async (request, reply) => { const session = await createSession(request.raw, reply.raw) session.push("Hello from Fastify!") }) fastify.listen({ port: 8080 }) ``` -------------------------------- ### Node HTTP/2 Compatibility API Server Source: https://github.com/matthewwid/better-sse/blob/master/docs/src/content/docs/reference/recipes.mdx This example shows how to set up an SSE endpoint using Node.js's http2 compatibility API. It requires SSL certificates (key, cert) and handles SSE sessions similarly to the HTTP/1 API. ```typescript import { createSecureServer } from "node:http2" import { createSession } from "better-sse" const server = createSecureServer({key, cert}, async (req, res) => { switch (req.url) { case "/sse": { const session = await createSession(req, res) session.push("Hello world!") break } default: { res.stream.respond({ ":status": 404 }) break } } }) server.listen(8080) ``` -------------------------------- ### Create SSE Session with Express and Push Event Source: https://github.com/matthewwid/better-sse/blob/master/docs/src/content/docs/guides/getting-started.mdx Example of creating an SSE session with Express and immediately pushing an event. This is suitable for Node.js HTTP/1 or HTTP/2 APIs. ```typescript // Express uses the Node HTTP/1 API app.get("/sse", async (req, res) => { const session = await createSession(req, res) session.push("Hello world!") }) ``` -------------------------------- ### Deno HTTP API Server Source: https://github.com/matthewwid/better-sse/blob/master/docs/src/content/docs/reference/recipes.mdx Implement an SSE endpoint in Deno using its built-in HTTP server API. This example uses `better-sse`'s `createResponse` function to handle SSE requests. ```typescript import { createResponse } from "npm:better-sse" Deno.serve({ port: 8080 }, (request) => { const url = new URL(request.url) switch (url.pathname) { case "/sse": { return createResponse(request, (session) => { session.push("Hello world!") }) } default: { return new Response("404 Not Found", { status: 404, headers: { "Content-Type": "text/plain", }, }) } } }) ``` -------------------------------- ### Iterate and Send SSE Events Source: https://github.com/matthewwid/better-sse/blob/master/README.md This example shows how to send each item from a synchronous iterable (like an array) as a separate SSE event using session.iterate. ```typescript const iterable = [1, 2, 3] await session.iterate(iterable) ``` -------------------------------- ### Create a Server-Sent Events Session Source: https://github.com/matthewwid/better-sse/blob/master/docs/src/content/docs/reference/api.mdx Use createSession to instantiate a new Session object. It accepts arguments similar to the Session constructor and handles connection setup. For Fetch API-based frameworks, it resolves before connection; for Node.js HTTP APIs, it waits for the connection. ```typescript const session = await createSession(request); ``` ```typescript const session = await createSession(request, { headers: { "X-Custom-Header": "value" } }); ``` ```typescript const session = await createSession(connection); ``` ```typescript const session = await createSession(http2Request, http2Response); ``` ```typescript const session = await createSession(request, response); ``` -------------------------------- ### Adonis SSE Route Source: https://github.com/matthewwid/better-sse/blob/master/docs/src/content/docs/reference/recipes.mdx Set up an SSE endpoint in AdonisJS. This example uses the `router` service to define a GET route for SSE. ```typescript import router from "@adonisjs/core/services/router" import { createSession } from "better-sse" router.get("/sse", async ({ request, response }) => { const session = await createSession(request.request, response.response) session.push("Hello world!") }) ``` -------------------------------- ### Next.js App Router SSE Route Handler Source: https://github.com/matthewwid/better-sse/blob/master/docs/src/content/docs/reference/recipes.mdx Create an SSE endpoint using Next.js App Router's Route Handlers. This example uses the `GET` method to handle SSE requests. ```typescript import { createResponse } from "better-sse" export async function GET(request: Request) { return createResponse(request, (session) => { session.push("Hello world!") }) } ``` -------------------------------- ### Equivalent Session Creation and Event Push Source: https://github.com/matthewwid/better-sse/blob/master/docs/src/content/docs/reference/api.mdx Demonstrates two equivalent ways to create a session, listen for the 'connected' event, push a message, and return the response. The first uses createSession and event listeners, while the second uses the createResponse helper function. ```typescript const session = await createSession(request) session.addListener("connected", () => { session.push("Hello world!") }) return session.getResponse() ``` ```typescript return createResponse(request, (session) => { session.push("Hello world!") }) ``` -------------------------------- ### Build Project for Distribution Source: https://github.com/matthewwid/better-sse/blob/master/README.md Bundles the project for distribution using tsup. ```bash pnpm build ``` -------------------------------- ### Remix SSE Loader Function Source: https://github.com/matthewwid/better-sse/blob/master/docs/src/content/docs/reference/recipes.mdx Implement an SSE endpoint in Remix using a loader function. This example leverages `LoaderFunction` from `@remix-run/node`. ```typescript import { LoaderFunction } from "@remix-run/node" import { createResponse } from "better-sse" export const loader: LoaderFunction = ({ request }) => createResponse(request, (session) => { session.push("Hello world!") }) ``` -------------------------------- ### Session Constructor Overloads Source: https://github.com/matthewwid/better-sse/blob/master/docs/src/content/docs/reference/api.mdx Demonstrates the different ways to instantiate a `Session` object, accepting various request and response types from Node.js HTTP, Node.js HTTP/2, and the Fetch API. ```typescript new Session(IncomingMessage, ServerResponse, SessionOptions?) ``` ```typescript new Session(Http2ServerRequest, Http2ServerResponse, SessionOptions?) ``` ```typescript new Session(Request, Response, SessionOptions?) ``` ```typescript new Session(Request, SessionOptions?) ``` -------------------------------- ### Create SSE Session with Express Source: https://github.com/matthewwid/better-sse/blob/master/docs/src/content/docs/guides/getting-started.mdx Create an SSE session when a client makes a GET request to the /sse route using Express. ```typescript app.get("/sse", async (req, res) => { const session = await createSession(req, res) }) ``` -------------------------------- ### NestJS Express SSE Controller Source: https://github.com/matthewwid/better-sse/blob/master/docs/src/content/docs/reference/recipes.mdx Set up an SSE endpoint in NestJS using `@nestjs/platform-express`. This involves creating a controller with a GET route. ```typescript import { Controller, Get, Req, Res } from "@nestjs/common" import { Request, Response } from "express" import { createSession } from "better-sse" @Controller() export class SseController { @Get("sse") async sse(@Req() req: Request, @Res() res: Response) { const session = await createSession(req, res) session.push("Hello world!") } } ``` -------------------------------- ### Register Session with Channel Source: https://github.com/matthewwid/better-sse/blob/master/README.md This snippet demonstrates how to create a channel and register an SSE session with it to enable broadcasting messages to multiple clients. Requires 'better-sse'. ```typescript 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") }) ``` -------------------------------- ### Run Project Tests Source: https://github.com/matthewwid/better-sse/blob/master/README.md Executes the project's test suite using Vitest. ```bash pnpm t ``` -------------------------------- ### Cancel Web Stream on Disconnect Source: https://github.com/matthewwid/better-sse/blob/master/docs/src/content/docs/reference/faq.mdx Example of how to cancel a Web Streams API `ReadableStream` when a session disconnects, ensuring proper resource management. ```typescript const stream = ReadableStream.from(...) session.stream(stream) session.once("disconnected", () => { stream.cancel() }) ``` -------------------------------- ### Clean Up Node Stream on Disconnect Source: https://github.com/matthewwid/better-sse/blob/master/docs/src/content/docs/reference/faq.mdx Example of how to properly destroy a `node:stream` when a session disconnects to prevent memory leaks and resource issues. ```typescript const stream = Readable.from(...) session.stream(stream) session.once("disconnected", () => { stream.destroy() }) ``` -------------------------------- ### Hono SSE Server Source: https://github.com/matthewwid/better-sse/blob/master/docs/src/content/docs/reference/recipes.mdx Set up an SSE endpoint using Hono. Requires importing `Hono`, `serve`, and `createResponse`. ```typescript 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 }) ``` -------------------------------- ### Open EventSource Connection Source: https://github.com/matthewwid/better-sse/blob/master/docs/src/content/docs/guides/getting-started.mdx Use this to open a connection to the server to begin receiving events. Ensure the path matches your server configuration. ```javascript const eventSource = new EventSource("/sse") ``` -------------------------------- ### FetchConnection Constructor Source: https://github.com/matthewwid/better-sse/blob/master/docs/src/content/docs/reference/api.mdx Initializes a new FetchConnection instance. This connection type is based on the Fetch API. ```APIDOC ## `new FetchConnection(req: Request, res: Response | null[, options: BuiltInConnectionsOptions])` ### Description Initializes a new `FetchConnection` instance. This connection type is based on the Fetch API. ### Parameters #### Path Parameters - **req** (Request) - Required - An instance of `Request`. - **res** (Response | null) - Optional - An instance of `Response` or `null` if you do not want to provide response status code and headers. - **options** (BuiltInConnectionsOptions) - Optional - Additional options for the connection. ``` -------------------------------- ### createResponse - Create an SSE session (Fetch API) Source: https://context7.com/matthewwid/better-sse/llms.txt Creates a new `Session` for Fetch-based frameworks and returns a `Response` object. The callback is invoked once the response stream is being consumed and the session is connected. Options include `retry` and `keepAlive`. ```APIDOC ## createResponse - Create an SSE session (Fetch API) ### Description Creates a new `Session` for Fetch-based frameworks (Hono, Deno, Bun, Cloudflare Workers, Next.js App Router, Remix, etc.) and synchronously returns the `Response` object to be returned from the route handler. The callback is invoked once the response stream is being consumed and the session is connected. ### Method Signature ```typescript createResponse(request: Request, options?: SessionOptions, callback?: (session: Session) => void): Response ``` ### Parameters #### Request - `request` (Request): The incoming Fetch API Request object. - `options` (SessionOptions) - Optional: Configuration for the session. - `retry` (number): Time in milliseconds to tell the client to wait before reconnecting. - `keepAlive` (number): Time in milliseconds to send a keep-alive comment. - `callback` ((session: Session) => void) - Optional: A function to execute once the session is established. ### Response - `Response`: A Fetch API Response object configured for Server-Sent Events. ### Request Example (Hono) ```typescript 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, { retry: 2000, keepAlive: 8000 }, (session) => { session.push({ status: "connected" }, "init") const timer = setInterval(() => { if (!session.isConnected) { clearInterval(timer) return } session.push({ time: new Date().toISOString() }, "tick") }, 1000) session.once("disconnected", () => clearInterval(timer)) } ) ) serve({ fetch: app.fetch, port: 8080 }) ``` ### Request Example (Next.js App Router) ```typescript import { createResponse } from "better-sse" export async function GET(request: Request) { return createResponse(request, (session) => { session.push("Hello from Next.js!", "greeting") }) } ``` ### Request Example (Cloudflare Workers) ```typescript export default { async fetch(request: Request): Promise { const url = new URL(request.url) if (url.pathname === "/sse") { return createResponse(request, (session) => { session.push("Hello from Workers!", "greeting") }) } return new Response("Not Found", { status: 404 }) }, } ``` ``` -------------------------------- ### Express Server Source: https://github.com/matthewwid/better-sse/blob/master/docs/src/content/docs/reference/recipes.mdx Integrate Better SSE with an Express.js application. This snippet sets up a GET route for /sse that creates an SSE session and pushes a message. ```typescript import express from "express" import { createSession } from "better-sse" const app = express() app.get("/sse", async (req, res) => { const session = await createSession(req, res) session.push("Hello world!") }) app.listen(8080) ``` -------------------------------- ### Register Session to Channel Source: https://github.com/matthewwid/better-sse/blob/master/docs/src/content/docs/guides/channels.mdx Registers the current SSE session to the 'ticker' channel. This ensures that the client will receive events broadcast on this channel. This is added to the existing SSE endpoint setup. ```typescript import { createSession } from "better-sse" import { ticker } from "./channels/ticker" app.get("/sse", async (req, res) => { const session = await createSession(req, res) session.push("Hello world!", "ping") ticker.register(session) ) ``` ```typescript import { createResponse } from "better-sse" import { ticker } from "./channels/ticker" app.get("/sse", (c) => createResponse(c.req.raw, (session) => { session.push("Hello world!", "ping") ticker.register(session) }) ) ``` -------------------------------- ### Encode Binary Data for SSE Source: https://github.com/matthewwid/better-sse/blob/master/docs/src/content/docs/reference/faq.mdx When sending binary data over SSE, encode it using Base64 on the server and decode it on the client. This example shows the server-side encoding and the client-side decoding process. ```typescript const encoded = btoa(binary) session.push(encoded, "binary-data") ``` ```typescript eventSource.addEventListener("binary-data", ({ data }) => { const parsed = JSON.parse(data) const decoded = atob(parsed) console.log(decoded) }) ``` -------------------------------- ### Node HTTP/1 (raw) Integration with Better SSE Source: https://context7.com/matthewwid/better-sse/llms.txt This snippet shows how to set up a basic HTTP server in Node.js and integrate Better SSE to handle Server-Sent Events. It requires importing `createServer` from 'node:http' and `createSession` from 'better-sse'. ```typescript import { createServer } from "node:http" import { createSession } from "better-sse" createServer(async (req, res) => { if (req.url === "/sse") { const session = await createSession(req, res) session.push("Hello from Node HTTP!") } else { res.writeHead(404).end() } }).listen(8080) ``` -------------------------------- ### Create SSE Session Manually with Fetch API Source: https://github.com/matthewwid/better-sse/blob/master/docs/src/content/docs/guides/getting-started.mdx Manually create an SSE session using createSession and return the response using getResponse(). This is for Fetch API-based frameworks like Hono. ```typescript // Hono uses the Fetch API app.get("/sse", async (c) => { const session = await createSession(c.req.raw) session.addListener("connected", () => { session.push("Hello world!") }) return session.getResponse() }) ``` -------------------------------- ### Create SSE Session with Hono Source: https://github.com/matthewwid/better-sse/blob/master/README.md Use this snippet to create a new SSE session with Hono. It requires the 'better-sse' package and Hono framework. ```typescript import { createResponse } from "better-sse" app.get("/sse", (c) => createResponse(c.req.raw, (session) => { session.push("Hello world!", "message") }) ) ``` -------------------------------- ### Bun HTTP API Server Source: https://github.com/matthewwid/better-sse/blob/master/docs/src/content/docs/reference/recipes.mdx This snippet demonstrates setting up an SSE endpoint with Bun's HTTP server. It configures a keep-alive interval to prevent premature connection closure. ```typescript import { createResponse } from "better-sse" Bun.serve({ port: 8080, routes: { "/sse": (req) => createResponse( request, // Set the keep-alive interval to below // Bun's default idle timeout of ten (10) seconds { keepAlive: 8000 }, (session) => { session.push("Hello world!") } ), }, fetch() { return new Response("404 Not Found", { status: 404, headers: { "Content-Type": "text/plain", }, }) }, }) ``` -------------------------------- ### Iterating and Sending Events with Session#iterate Source: https://context7.com/matthewwid/better-sse/llms.txt Use `session.iterate` to send each item from a sync or async iterable as an SSE event. This is useful for generators or arrays. The example shows iteration over both a simple array and an async generator. ```typescript import { createSession } from "better-sse" // Async generator example — e.g., streaming DB rows async function* fetchRows() { const rows = [{ id: 1 }, { id: 2 }, { id: 3 }] for (const row of rows) { await new Promise((r) => setTimeout(r, 100)) // simulate async fetch yield row } } app.get("/iterate-sse", async (req, res) => { const session = await createSession(req, res) // Sync iterable await session.iterate([10, 20, 30], { eventName: "number" }) // Sends 3 events named "number" // Async generator await session.iterate(fetchRows(), { eventName: "row" }) // Sends 3 events named "row", one per resolved yield session.push("Done iterating", "complete") }) ``` -------------------------------- ### Create SSE Session with createResponse Utility Source: https://github.com/matthewwid/better-sse/blob/master/docs/src/content/docs/guides/getting-started.mdx Use the createResponse utility function for a concise way to handle SSE sessions in Fetch API-based frameworks like Hono. ```typescript app.get("/sse", (c) => createResponse(c.req.raw, (session) => { session.push("Hello world!") }) ) ``` -------------------------------- ### Create SSE Response (Fetch API) Source: https://context7.com/matthewwid/better-sse/llms.txt Use `createResponse` for Fetch-based frameworks like Hono, Deno, Bun, Cloudflare Workers, Next.js App Router, and Remix. It returns the `Response` object and invokes a callback once the session is connected. ```typescript // Hono 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, { retry: 2000, keepAlive: 8000 }, (session) => { session.push({ status: "connected" }, "init") // Push events on a timer const timer = setInterval(() => { if (!session.isConnected) { clearInterval(timer) return } session.push({ time: new Date().toISOString() }, "tick") }, 1000) session.once("disconnected", () => clearInterval(timer)) } ) ) serve({ fetch: app.fetch, port: 8080 }) // Next.js App Router (app/api/sse/route.ts) import { createResponse } from "better-sse" export async function GET(request: Request) { return createResponse(request, (session) => { session.push("Hello from Next.js!", "greeting") }) } // Cloudflare Workers export default { async fetch(request: Request): Promise { const url = new URL(request.url) if (url.pathname === "/sse") { return createResponse(request, (session) => { session.push("Hello from Workers!", "greeting") }) } return new Response("Not Found", { status: 404 }) }, } ``` -------------------------------- ### Lint and Format Code Source: https://github.com/matthewwid/better-sse/blob/master/README.md Applies linting rules and formats the code using Biome. ```bash pnpm lint pnpm format ``` -------------------------------- ### createSession Source: https://github.com/matthewwid/better-sse/blob/master/docs/src/content/docs/reference/api.mdx Creates a new `Session` instance. It supports various argument combinations for different HTTP and HTTP/2 server environments, as well as Fetch API requests. ```APIDOC ## `createSession` ### Description Create a new [`Session`](#sessionstate). Takes the [same arguments as the `Session` class constructor](#new-sessionstate--defaultsessionstatereq-incomingmessage--http2serverrequest--request-res-serverresponse--http2serverresponse--response--sessionoptions-options-sessionoptions). When using the Fetch API, resolves immediately with a session instance before it has connected. You can listen for the `connected` event on the session to know when it has connected, or otherwise use the shorthand `createResponse` function that does so for you instead. When using the Node HTTP APIs, waits for the session to connect before resolving with its instance. ### Overloads ```typescript createSession(IncomingMessage, ServerResponse, SessionOptions?): Promise createSession(Http2ServerRequest, Http2ServerResponse, SessionOptions?): Promise createSession(Request, Response, SessionOptions?): Promise createSession(Request, SessionOptions?): Promise createSession(Connection, SessionOptions?): Promise ``` ``` -------------------------------- ### Create a Response with Session and Callback Source: https://github.com/matthewwid/better-sse/blob/master/docs/src/content/docs/reference/api.mdx Use createResponse for Fetch API-based frameworks to create a session and immediately return its Response object. A callback function is provided to interact with the session once it's connected. ```typescript return createResponse(request, (session) => { session.push("Hello world!"); }); ``` ```typescript return createResponse(request, { headers: { "X-Custom-Header": "value" } }, (session) => { session.push("Hello world!"); }); ``` ```typescript return createResponse(request, response, (session) => { session.push("Hello world!"); }); ``` ```typescript return createResponse(request, response, { headers: { "X-Custom-Header": "value" } }, (session) => { session.push("Hello world!"); }); ``` -------------------------------- ### Connection - Custom connection adapters Source: https://context7.com/matthewwid/better-sse/llms.txt An abstract base class to decouple SSE session logic from the underlying transport, enabling Better SSE to work with frameworks not natively supported. ```APIDOC ## `Connection` — Custom connection adapters An abstract base class that decouples the SSE session logic from the underlying transport. Extend it to make Better SSE work with any framework not supported out of the box (e.g., Koa, uWebSockets, custom protocols). ### Usage with Koa ```typescript import { PassThrough } from "node:stream" import Koa, { Context } from "koa" import Router from "@koa/router" import { Connection, createSession } from "better-sse" class KoaConnection extends Connection { private controller: AbortController private stream: PassThrough url: URL request: Request response: Response constructor(private ctx: Context) { super() this.url = ctx.URL this.controller = new AbortController() this.request = new Request(this.url, { method: ctx.request.method ?? Connection.constants.REQUEST_METHOD, signal: this.controller.signal, }) Connection.applyHeaders(ctx.headers, this.request.headers) ctx.status = Connection.constants.RESPONSE_CODE ctx.set(Connection.constants.RESPONSE_HEADERS) this.response = new Response(null, { status: Connection.constants.RESPONSE_CODE, headers: Connection.constants.RESPONSE_HEADERS, }) this.stream = new PassThrough() this.stream.once("close", () => this.controller.abort()) ctx.body = this.stream } sendHead() { this.ctx.flushHeaders() } sendChunk(chunk: string) { this.stream.write(chunk) } cleanup() { this.stream.removeAllListeners("close") } } // Usage with Koa const app = new Koa() const router = new Router() router.get("/sse", async (ctx) => { const connection = new KoaConnection(ctx) const session = await createSession(connection) session.push("Hello from Koa!", "greeting") }) app.use(router.routes()) app.listen(3000) ``` ``` -------------------------------- ### Manual Connection Adapter Configuration Source: https://github.com/matthewwid/better-sse/blob/master/docs/src/content/docs/guides/connection-adapters.mdx To resolve auto-detection issues with frameworks like Ultimate Express, manually create and pass an instance of the appropriate built-in connection adapter to `createSession`. This bypasses the detection mechanism. ```typescript import express from "ultimate-express" import { createSession, NodeHttp1Connection } from "better-sse" const app = express() app.get("/sse", async (req, res) => { const session = await createSession(req, res) const connection = new NodeHttp1Connection(req, res) const session = await createSession(connection) }) ``` -------------------------------- ### Add Initial Metadata to Session (Hono) Source: https://github.com/matthewwid/better-sse/blob/master/docs/src/content/docs/reference/faq.mdx Provide initial state in the constructor options for sessions. State persists only for the session's lifetime. ```typescript app.get("/sse", (c) => createResponse( request, { state: { username: "Alice", }, }, (session) => { session.state.username = 123456 // Error: Type 'number' is not assignable to type 'string' } ) ) ``` -------------------------------- ### createResponse Source: https://github.com/matthewwid/better-sse/blob/master/docs/src/content/docs/reference/api.mdx Creates a new session using the Fetch API and returns its corresponding `Response` object. This is a helper function primarily for Fetch-based frameworks. ```APIDOC ## `createResponse` ### Description Create a new session using the [Fetch API](https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API) and return its corresponding `Response` object. Takes the [same arguments as the `Session` class constructor](#new-sessionstate--defaultsessionstatereq-incomingmessage--http2serverrequest--request-res-serverresponse--http2serverresponse--response--sessionoptions-options-sessionoptions). The last argument should be a callback function `CreateResponseCallback` that will be invoked with the session instance once it has connected. ### Overloads ```typescript createResponse(Request, CreateResponseCallback): Response createResponse(Request, SessionOptions, CreateResponseCallback): Response createResponse(Request, Response, CreateResponseCallback): Response createResponse(Request, Response, SessionOptions, CreateResponseCallback): Response ``` ``` -------------------------------- ### Client-Side EventSource with Multiple Listeners Source: https://github.com/matthewwid/better-sse/blob/master/docs/src/content/docs/guides/channels.mdx Establish an EventSource connection and set up listeners for both 'tick' and 'session-count' events to update different UI elements in real-time. ```javascript // public/client.js const eventSource = new EventSource("/sse") const sessionsElement = document.createElement("pre") document.body.appendChild(sessionsElement) eventSource.addEventListener("tick", ({ data }) => { countElement.innerText = `The clock has ticked! The count is now ${data}.` }) const countElement = document.createElement("pre") document.body.appendChild(countElement) eventSource.addEventListener("session-count", ({ data }) => { sessionsElement.innerText = `There are ${data} person(s) here right now!` }) ``` -------------------------------- ### Generate CPU Load Source: https://github.com/matthewwid/better-sse/blob/master/examples/resource-monitor/public/index.html Use this command to generate continuous CPU load for testing resource monitoring. This command is useful for observing how the system resource monitor reacts to high CPU utilization. ```bash yes ``` -------------------------------- ### Session#batch Source: https://context7.com/matthewwid/better-sse/llms.txt Buffers multiple events and flushes them all to the client in a single TCP transmission, greatly reducing bandwidth and improving performance compared to calling `push` repeatedly. ```APIDOC ## `Session#batch` — Batch multiple events in a single transmission Buffers multiple events and flushes them all to the client in a single TCP transmission, greatly reducing bandwidth and improving performance compared to calling `push` repeatedly. ```typescript import { createSession } from "better-sse" app.get("/batch-sse", async (req, res) => { const session = await createSession(req, res) // Batch with a callback — the EventBuffer is flushed once the callback resolves await session.batch(async (buffer) => { buffer.push({ step: 1 }, "progress") buffer.push({ step: 2 }, "progress") buffer.push({ step: 3 }, "progress") // Async work inside batch is supported await new Promise((r) => setTimeout(r, 10)) buffer.push({ step: 4 }, "progress") }) // All 4 events are sent in one network write // Batch using an iterable await session.batch(async (buffer) => { await buffer.iterate(["alpha", "beta", "gamma"], { eventName: "item" }) }) session.push("All batches sent", "done") }) ``` ``` -------------------------------- ### Import createSession (CommonJS) Source: https://github.com/matthewwid/better-sse/blob/master/docs/src/content/docs/guides/getting-started.mdx Import the createSession function when using CommonJS. ```javascript const { createSession } = require("better-sse") ``` -------------------------------- ### Add Initial Metadata to Session (Express) Source: https://github.com/matthewwid/better-sse/blob/master/docs/src/content/docs/reference/faq.mdx Provide initial state in the constructor options for sessions. State persists only for the session's lifetime. ```typescript app.get("/sse", async (req, res) => { const session = await createSession(req, res, { state: { username: "Alice", } }) session.state.username = 123456 // Error: Type 'number' is not assignable to type 'string' }) ``` -------------------------------- ### Add Metadata to Session or Channel Source: https://github.com/matthewwid/better-sse/blob/master/docs/src/content/docs/reference/faq.mdx Demonstrates how to add metadata to sessions and channels based on authentication status. Ensure the correct state type is used when registering sessions to avoid type errors. ```typescript type AuthenticatedState = { userId: string } type UnauthenticatedState = { tempId: string } const protectedChannel = createChannel() app.get("/sse", (c) => { if (isAuthenticated()) { return createResponse(c.req.raw, (session) => { protectedChannel.register(session) }) } else { return createResponse(c.req.raw, (session) => { // Error: Argument of type 'SessionState' // is not assignable to parameter of type 'SessionState' protectedChannel.register(session) }) } }) ``` -------------------------------- ### Remix Integration with Better SSE Source: https://context7.com/matthewwid/better-sse/llms.txt Shows how to integrate Better SSE within a Remix application's loader function. It uses `createResponse` from 'better-sse' to handle the SSE stream. ```typescript import { createResponse } from "better-sse" export const loader = ({ request }) => createResponse(request, (session) => session.push("Hello from Remix!")) ``` -------------------------------- ### Create a New Channel Instance Source: https://github.com/matthewwid/better-sse/blob/master/docs/src/content/docs/reference/api.mdx Instantiate a new Channel with optional custom state. The state can be used to manage channel-specific data and is typed by the generic parameter. ```typescript const channel = new Channel<{ count: number }>(); ``` ```typescript const channel = new Channel({ state: { count: 0 } }); ``` -------------------------------- ### Explicit Fetch API Connection for SSE Source: https://github.com/matthewwid/better-sse/blob/master/docs/src/content/docs/guides/connection-adapters.mdx Manually create a FetchConnection when you need explicit control or are not using a framework that automatically detects the Fetch API Request. ```typescript import { createResponse, FetchConnection } from "better-sse" app.get("/sse", async (c) => { const connection = new FetchConnection(c.req.raw, null) return createResponse(connection, (session) => { session.push("Hello world!") }) }) ``` -------------------------------- ### Create SSE Response with Fetch API Request Source: https://github.com/matthewwid/better-sse/blob/master/docs/src/content/docs/guides/connection-adapters.mdx Use this when integrating with frameworks like Hono that provide Fetch API Request objects. It automatically uses the FetchConnection adapter. ```typescript import { createResponse } from "better-sse" app.get("/sse", async (c) => createResponse(c.req.raw, (session) => { session.push("Hello world!") }) ) ``` -------------------------------- ### createChannel Source: https://github.com/matthewwid/better-sse/blob/master/docs/src/content/docs/reference/api.mdx Factory function to create a new Channel instance. ```APIDOC ### `createChannel`: `(...args: ConstructorParameters) => Channel` ### Description Creates and returns an instance of a `Channel`. Accepts the same arguments as the `Channel` class constructor. ### Parameters - `...args` (ConstructorParameters) - Arguments for the Channel constructor. ```