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

bun-in-browser

v0.1.0

Published

Run Bun.js-style servers in the browser with a WebSocket-based reverse proxy

Downloads

11

Readme

bun-in-browser

Run Bun.js-style servers in the browser with a WebSocket-based reverse proxy.

Installation

bun add bun-in-browser

Usage

Public WebSocket Service

bun-in-browser offers a public WebSocket service that is recommended for most use cases:

  • URL: wss://browser-proxy.web4.near.page
  • This service allows you to run your bun-in-browser applications without setting up your own server.
  • When you connect to this WebSocket, your application becomes available at a unique subdomain of web4.near.page.
  • Example: If your client ID is "abc123", your site would be accessible at https://abc123.web4.near.page.

Use this public WebSocket service unless you expect heavy load for your application.

Self-hosted Server

If you need to run your own server (e.g., for high-load applications), you can do so using the provided app.js script:

PORT=3000 BASE_URL=http://localhost:3000 USE_SUBDOMAINS=false bun app.js

Or use the startReverseProxy function in your own script:

import { startReverseProxy } from 'bun-in-browser/src/server.js';

const { server, stop } = startReverseProxy({
  port: 3000,
  baseUrl: 'http://localhost:3000',
  useSubdomains: false
});

console.log(`Server started on port 3000. Base URL: http://localhost:3000`);

// Handle graceful shutdown
process.on('SIGINT', () => {
  console.log('Received SIGINT. Shutting down gracefully...');
  stop();
  process.exit(0);
});

Demo

A public demo is available to showcase bun-in-browser capabilities:

To run the demo locally:

bun run demo

After starting the server, navigate to the demo URL provided in the console output (typically http://localhost:3001).

Simple Demo

The simple demo (View Source) demonstrates basic routing and JSON responses. Here's an example of the client-side code:

import { BunInBrowser } from 'bun-in-browser/client';

const bunInBrowser = new BunInBrowser('wss://browser-proxy.web4.near.page');

const serverModule = {
  fetch(req) {
    const url = new URL(req.url);
    if (url.pathname === "/") {
      return new Response("Hello from Bun.js in the browser!");
    }
    if (url.pathname === "/json") {
      return Response.json({ message: "This is JSON data" });
    }
    return new Response("Not Found", { status: 404 });
  },
};

bunInBrowser.serverModule = serverModule;

Advanced Demo

The advanced demo (View Source) showcases a more complex application: a guest book. It demonstrates handling different routes, processing form submissions, and generating dynamic HTML responses. Here's an excerpt from the demo:

const serverModule = {
  guestBook: [],
  fetch(req) {
    const url = new URL(req.url);
    if (url.pathname === "/") {
      return new Response(this.renderGuestBook(), {
        headers: { "Content-Type": "text/html" }
      });
    }
    if (url.pathname === "/sign" && req.method === "POST") {
      return this.handleSignGuestBook(req);
    }
    if (url.pathname === "/api") {
      return Response.json({ 
        message: "This is a JSON response from Bun.js",
        clientId: window.clientId,
        clientUrl: window.clientUrl
      });
    }
    return new Response("Not Found", { status: 404 });
  },
  renderGuestBook() {
    let html = `
      <div style="font-family: Arial, sans-serif; max-width: 600px; margin: 0 auto; padding: 20px;">
        <h1 style="color: #333;">Welcome to our Guest Book!</h1>
        <form action='/sign' method='POST' style="margin-bottom: 20px;">
          <input type='text' name='name' placeholder='Your Name' required style="margin: 5px 0; padding: 5px;">
          <input type='text' name='message' placeholder='Your Message' required style="margin: 5px 0; padding: 5px;">
          <button type='submit' style="margin: 5px 0; padding: 5px; background-color: #4CAF50; color: white; border: none; cursor: pointer;">Sign Guest Book</button>
        </form>
        <h2>Entries:</h2>
        <ul style="list-style-type: none; padding: 0;">
          ${this.guestBook.map(entry => `<li style="margin-bottom: 10px;"><strong>${entry.name}</strong>: ${entry.message}</li>`).join('')}
        </ul>
      </div>
    `;
    return html;
  },
  async handleSignGuestBook(req) {
    const formData = await req.formData();
    const name = formData.get("name");
    const message = formData.get("message");
    this.guestBook.push({ name, message });
    return new Response("Entry added successfully", { 
      status: 302, 
      headers: { "Location": "/" } 
    });
  }
};

const bunInBrowser = new BunInBrowser('wss://browser-proxy.web4.near.page', serverModule);

API

Client-side

new BunInBrowser(wsUrl, serverModule)

Creates a new BunInBrowser instance.

  • wsUrl: The WebSocket URL to connect to (use wss://browser-proxy.web4.near.page for the public service)
  • serverModule: (Optional) The server module object

bunInBrowser.serverModule

Set this property to your Bun.js server module object. The module should have:

  • fetch(req): A function that handles incoming requests and returns a Response object

bunInBrowser.waitUntilReady()

Returns a promise that resolves when the BunInBrowser instance is ready to use.

bunInBrowser.close()

Closes the WebSocket connection.

bunInBrowser.clientId

The unique identifier for this client.

bunInBrowser.clientUrl

The URL where this client's server can be accessed.

Server-side

startReverseProxy(options)

Starts the reverse proxy server.

  • options.port: The port for the server (default: 3000)
  • options.baseUrl: The base URL for the server (default: 'http://localhost:3000')
  • options.useSubdomains: Whether to use subdomains for client identification (default: false)

Returns an object with:

  • server: The server instance
  • stop(): Function to stop the server

Features

  • Run Bun.js-style servers in the browser
  • WebSocket-based communication between browser and server
  • Public WebSocket service for easy deployment
  • Support for various HTTP methods (GET, POST, etc.)
  • JSON response handling
  • HTML response generation
  • Form data processing
  • Custom status codes and headers
  • Optional subdomain-based client identification
  • Environment variable configuration
  • Graceful shutdown handling
  • Interactive demo with editable code

Development

To run tests:

bun test

Debugging

This project uses the debug package for logging. To enable debug logs, set the DEBUG environment variable:

DEBUG=bun-in-browser:* bun run your-script.js

For running tests with debug logs:

DEBUG=test:client bun test

Environment Variables

When using the app.js script, you can configure the server using the following environment variables:

  • PORT: The port number for the server (default: 3000)
  • BASE_URL: The base URL for the server (default: http://localhost:${PORT})
  • USE_SUBDOMAINS: Whether to use subdomains for client identification (default: false)

Note: When using startReverseProxy directly, the default baseUrl is the fixed string 'http://localhost:3000'.

License

MIT