Compare commits

...

4 Commits

Author SHA1 Message Date
Alistair Smith
167a7b26c1 Merge branch 'main' into ali/docs-bun-serve-ws-19659 2025-05-21 22:51:30 -07:00
alii
1080f1950e bun run prettier 2025-05-20 00:13:26 +00:00
Alistair Smith
90b4346e43 changes 2025-05-19 17:12:15 -07:00
Alistair Smith
04512a7610 Update docs/guides to change how WebSocketData gets passed #19659 (since routes/static breaks the existing api) 2025-05-19 17:11:00 -07:00
4 changed files with 38 additions and 20 deletions

View File

@@ -114,8 +114,7 @@ type WebSocketData = {
authToken: string;
};
// TypeScript: specify the type of `data`
Bun.serve<WebSocketData>({
Bun.serve({
fetch(req, server) {
const cookies = new Bun.CookieMap(req.headers.get("cookie")!);
@@ -131,8 +130,9 @@ Bun.serve<WebSocketData>({
return undefined;
},
websocket: {
// TypeScript: specify the type of the ws here
// handler called when a message is received
async message(ws, message) {
async message(ws: Bun.ServerWebSocket<WebSocketData>, message) {
const user = getUserFromToken(ws.data.authToken);
await saveMessageToDatabase({
@@ -164,22 +164,32 @@ socket.addEventListener("message", event => {
Bun's `ServerWebSocket` implementation implements a native publish-subscribe API for topic-based broadcasting. Individual sockets can `.subscribe()` to a topic (specified with a string identifier) and `.publish()` messages to all other subscribers to that topic (excluding itself). This topic-based broadcast API is similar to [MQTT](https://en.wikipedia.org/wiki/MQTT) and [Redis Pub/Sub](https://redis.io/topics/pubsub).
```ts
const server = Bun.serve<{ username: string }>({
type WebSocketData = { username: string };
const server = Bun.serve({
fetch(req, server) {
const url = new URL(req.url);
if (url.pathname === "/chat") {
console.log(`upgrade!`);
const username = getUsernameFromReq(req);
const success = server.upgrade(req, { data: { username } });
return success
? undefined
: new Response("WebSocket upgrade error", { status: 400 });
const success = server.upgrade<WebSocketData>(req, {
data: { username },
});
if (success) {
return;
}
return new Response("WebSocket upgrade error", { status: 400 });
}
return new Response("Hello world");
},
websocket: {
open(ws) {
// Make sure to specify the type of the `ws` argument in at
// least one of the websocket event handlers
open(ws: Bun.ServerWebSocket<WebSocketData>) {
const msg = `${ws.data.username} has entered the chat`;
ws.subscribe("the-group-chat");
server.publish("the-group-chat", msg);

View File

@@ -7,21 +7,26 @@ When building a WebSocket server, it's typically necessary to store some identif
With [Bun.serve()](https://bun.sh/docs/api/websockets#contextual-data), this "contextual data" is set when the connection is initially upgraded by passing a `data` parameter in the `server.upgrade()` call.
```ts
Bun.serve<{ socketId: number }>({
type WebSocketData = { socketId: number };
Bun.serve({
fetch(req, server) {
const success = server.upgrade(req, {
const success = server.upgrade<WebSocketData>(req, {
data: {
socketId: Math.random(),
socketId: Math.random(), // Do something better than this in a real app
},
});
if (success) return undefined;
if (success) {
return;
}
// handle HTTP request normally
// ...
},
websocket: {
// define websocket handlers
async message(ws, message) {
async message(ws: Bun.ServerWebSocket<WebSocketData>, message) {
// the contextual data is available as the `data` property
// on the WebSocket instance
console.log(`Received ${message} from ${ws.data.socketId}}`);
@@ -42,7 +47,7 @@ type WebSocketData = {
};
// TypeScript: specify the type of `data`
Bun.serve<WebSocketData>({
Bun.serve({
async fetch(req, server) {
// use a library to parse cookies
const cookies = parseCookies(req.headers.get("Cookie"));
@@ -60,7 +65,7 @@ Bun.serve<WebSocketData>({
if (upgraded) return undefined;
},
websocket: {
async message(ws, message) {
async message(ws: Bun.ServerWebSocket<WebSocketData>, message) {
// save the message to a database
await saveMessageToDatabase({
message: String(message),

View File

@@ -7,11 +7,13 @@ Bun's server-side `WebSocket` API provides a native pub-sub API. Sockets can be
This code snippet implements a simple single-channel chat server.
```ts
const server = Bun.serve<{ username: string }>({
type WebSocketData = { username: string };
const server = Bun.serve({
fetch(req, server) {
const cookies = req.headers.get("cookie");
const username = getUsernameFromCookies(cookies);
const success = server.upgrade(req, { data: { username } });
const success = server.upgrade<WebSocketData>(req, { data: { username } });
if (success) return undefined;
return new Response("Hello world");
@@ -22,7 +24,7 @@ const server = Bun.serve<{ username: string }>({
ws.subscribe("the-group-chat");
server.publish("the-group-chat", msg);
},
message(ws, message) {
message(ws: Bun.ServerWebSocket<WebSocketData>, message) {
// the server re-broadcasts incoming messages to everyone
server.publish("the-group-chat", `${ws.data.username}: ${message}`);
},

View File

@@ -7,9 +7,10 @@ Start a simple WebSocket server using [`Bun.serve`](https://bun.sh/docs/api/http
Inside `fetch`, we attempt to upgrade incoming `ws:` or `wss:` requests to WebSocket connections.
```ts
const server = Bun.serve<{ authToken: string }>({
const server = Bun.serve({
fetch(req, server) {
const success = server.upgrade(req);
if (success) {
// Bun automatically returns a 101 Switching Protocols
// if the upgrade succeeds