Adapters
SSE
Integrate crossws with server-sent events and fetch-api.
If your deployment target does not supports handling WebSocket upgrades, crossws SSE adapter allows to add integration based on web platform standards (fetch
and EventSource
)
This is an experimental adapter, requires server support and a different way of connection from clients.
HTTP/2 server support is recommended in order to increase browser limitations about number of SSE connections (from 6 to 100) and also to allow bidirectional messaging with streaming.
Usage
Server side
Define adapter:
import sseAdapter from "crossws/adapters/sse";
const ws = sseAdapter({
bidir: true, // Enable bidirectional messaging support
hooks: {
upgrade(request) {
// In case of bidirectional mode, extra auth is recommended based on request
// You can return a new Response() instead to abort
return {
headers: {},
};
},
open(peer) {
// Use this hook to send messages to peer
peer.send(`Welcome ${peer}`);
},
message(peer, message) {
// Accepting messages from peer (bidirectional mode)
console.log(`Message from ${peer}: ${message}`); // Message from <id>: ping
},
},
});
Inside your web server handler:
async fetch(request) {
const url = new URL(request.url)
// Handle SSE
if (url.pathname === "/sse") {
return ws.fetch(request);
}
return new Response("default page")
}
Client side
In order to receive messages from server, you need to use an EventSource
client.
In order to send messages to the server make sure bdir: true
option is enabled on the server, then you need to first wait for crosswd-id
to get the peer id associated with connection and then use fetch calls to send messages to the server. You can optionally use a stream to send multiple messages to the server via single connection similar to WebSockets.
In theory, it is possible to bidirectional communication on a single HTTP/2 connection, however, due to a current limitation in fetch standard we need 2 connections, one for receiving messages and one for sending.
const ev = new EventSource("http://<server>/sse");
ev.addEventListener("message", (event) => {
// Listen for messages from server
console.log("Message:", event.data); // Welcome <id>!
});
ev.addEventListener("crossws-id", (event) => {
// Using peer id we can send messages to the server
const peerId = event.id;
// Method 1: Send each message with a separated fetch call
fetch(url, {
method: "POST",
headers: { "x-crossws-id": peerId },
body: "ping", // message
});
// Method 2: Using body stream to send multiple messages (requires HTTP/2 + TLS)
fetch(url, {
method: "POST",
duplex: "half",
headers: {
"content-type": "application/octet-stream",
"x-crossws-id": peerId,
},
body: new ReadableStream({
start(controller) {
// You can send multiple messages to the server with single connection
controller.enqueue("ping");
},
}).pipeThrough(new TextEncoderStream()),
});
});
See
test/fixture/sse.ts
for demo and src/adapters/sse.ts
for implementation.