npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

astro-bun-websocket

v1.0.1

Published

Use WebSockets in your Astro SSR Apps and run it on Bun

Downloads

124

Readme

astro-bun-websocket 🔌

This Astro integration provides an adapter for Astro that allows you to host SSG and SSR sites on Bun, with realtime features using WebSocket.

Why astro-bun-websocket?

The astro-bun-websocket integration allows you to handle WebSocket connections in your Astro project and deploy it on Bun, with realtime features. You no longer need to maintain a separate WebSocket server and complicated build processes to add realtime features. You can handle WebSocket requests directly in your API Routes, middleware, and even in the frontmatter of your Astro pages!

As a fork of the @NuroDev/astro-bun adapter, it provides the same configuration options, and remains backwards compatible with its features and behavior.

Installation

Manual Install

First, install the astro-bun-websocket package using your package manager. If you're using npm or aren't sure, run this in the terminal:

npm install astro-bun-websocket

Then, add this integration to your astro.config.* file using the adapter property:

    // astro.config.mjs
    import { defineConfig } from "astro/config"
-    import bun from "@nurodev/astro-bun"
+    import bunWebSocket from "astro-bun-websocket"

    export default defineConfig({
        // ...
-        adapter: bun()
+        adapter: bunWebSocket(),
        // ...
    });

Usage

The integration adds an upgradeWebSocket() method to the context.locals object. This method returns an object with response and socket fields.

// src/pages/api/socket.ts
export const GET: APIRoute = ctx => {
    if (ctx.request.headers.get("upgrade") === "websocket") {
        const { response, socket } = ctx.locals.upgradeWebSocket()
        socket.onmessage = event => {
            if (event.data === "ping") {
                socket.send("pong")
            }
        }
        return response
    }
    return new Response("Upgrade required", { status: 426 })
}

The response field provides a Response object that you can return to accept the WebSocket upgrade request. The socket field is a WebSocket object, which allows you to send messages to the browser and receive messages from it. This API of the WebSocket is fully compatible with the browser's WebSocket API, so you can program the server WebSocket in the same way you would program the browser WebSocket.

Note that this integration does not require any special client-side WebSocket library, you can use the native WebSocket API in the browser. Here is an example of the client-side code that connects to the above server WebSocket:

---
// src/pages/index.astro
---
<script>
    const socket = new WebSocket(`${location.origin}/api/socket`)
    socket onopen = event => {
        socket.send("ping")
    }
    socket.onmessage = event => {
        console.log(event.data)
    }
</script>

To simplify the detection of whether a request can be upgraded to a WebSocket connection, the adapter also adds locals.isUpgradeRequest to the context. This value is true if the request can be upgraded to a WebSocket connection, and false otherwise.

- if (ctx.request.headers.get("upgrade") === "websocket") { ... }
+ if (ctx.locals.isUpgradeRequest) { ... }

Authorizing and rejecting requests

If the endpoint returns any response other than the one provided by upgradeWebSocket(), the upgrade request will be rejected, and a WebSocket connection will not be established. This enables you to easily implement authorization logic or other checks before accepting the upgrade request.

For example, the following code shows how you would check for the presence of a cookie:

// src/pages/api/socket.ts
export const GET: APIRoute = ctx => {
    const cookie = ctx.cookies.get("xyz")
    if (!cookie) {
        return new Response("Unauthorized", { status: 401 })
    }
    if (!ctx.locals.isUpgradeRequest) {
        return new Response("Upgrade Required", { status: 426 })
    }
    const { response, socket } = ctx.locals.upgradeWebSocket()
    handleWebSocket(socket)
    return response
}

When a WebSocket connection fails to establish, browsers do not provide specific information in the error event about the cause. A WebSocket connection can close "cleanly" if it was successfully established and then intentionally closed. Alternatively, it can close non-cleanly if the server becomes unreachable due to network issues or if the connection could not be established in the first place. See the MDN documentation for more information: CloseEvent: wasClean property - Web APIs | MDN.

Troubleshooting

Error: "The request must be an upgrade request to upgrade the connection to a WebSocket."

This error occurs when a connection upgrade attempt is made using locals.upgradeWebSocket() on a request that does not have the necessary headers.

On the server, verify that the request is an upgrade request by checking locals.isUpgradeRequest before calling locals.upgradeWebSocket().

It is important to know that in the browser, the fetch API cannot be used to send an upgrade request. Make sure that you are instantiating the built-in WebSocket class. See examples on MDN: WebSocket - Web APIs | MDN.

For additional help, check out the Discussions tab on the GitHub repo.

Contributing

This package is maintained by lilnasy independently from Astro.

The code for this package is commited to the repository as a series of patches applied on top of the NuroDev/astro-bun repository, which is where the code for the @NuroDev/astro-bun adapter is maintained. Additionally, the NuroDev/astro-bun repository is added as a git submodule to make it easier to update the patches. The package.json file contains scripts to automatically manage the upstream repository and the patches.

To introduce a change, make sure you're in packages/bun-websocket directory:

../gratelets/ $ cd packages/bun-websocket

Then, run the load_patches script using pnpm to clone the upstream repository and apply the patches:

../gratelets/packages/bun-websocket/ $ pnpm run load_patches

Now, you can browse around the code by going into the NuroDev/astro-bun submodule:

../gratelets/packages/bun-websocket/ $ cd NuroDev/astro-bun
../bun-websocket/NuroDev/astro-bun/ $ code .

Note that dependencies would need to separately be installed in the NuroDev/astro-bun submodule.

../bun-websocket/NuroDev/astro-bun/ $ bun install

After you've made the changes you want, you can commit them as normal. However, instead of pushing the changes, you would update the patches by running create_patches script using pnpm:

../bun-websocket/NuroDev/astro-bun/ $ pnpm run create_patches

This will add and update patches present in packages/bun-websocket with the changes you've made.

Now, you can commit these patch files to the gratelets repository, and push.

../bun-websocket/NuroDev/astro-bun/ $ cd ../..
../gratelets/packages/bun-websocket/ $ git commit -m "fix bug"
../gratelets/packages/bun-websocket/ $ git push

Changelog

See CHANGELOG.md for a history of changes to this integration.