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 🙏

© 2026 – Pkg Stats / Ryan Hefner

blixify-server

v1.0.4

Published

Shared server template: MongoDB, Firebase, Auth, Upload, and real-time Pub/Sub→SSE live-stream.

Readme

Blixify Server

Shared server template: MongoDB, Firebase, Auth, Upload, and real-time Pub/Sub→SSE live-stream.


SocketWrapper

Generalises the per-delivery Pub/Sub → SSE pattern for any collection.

Write → MongoWrapper.afterWrite → SocketWrapper.emit
                                        │
                              Pub/Sub topic (global bus)
                                   attributes.room
                                        │
                  ┌─────────────────────┴─────────────────────┐
             room="robots"                            room="robots-r001"
         (list-level SSE clients)              (doc-level SSE clients)

Every GAE instance publishes to the same Pub/Sub topic. Each SSE client gets its own temporary pull subscription filtered by attributes.room. A client on instance 2 receives events published by instance 1 — no Redis adapter, no sticky sessions.

Room naming

| Room | Who subscribes | What it receives | | --------------- | --------------------------------------------------------- | ------------------------------------ | | "robots" | DTW list view (bareSocketName="robots") | insert / update / delete for any doc | | "robots-r001" | DTW read/update view (bareSocketName="robots-r001") | update / delete for doc r001 only |

On every write, emit("robots", "r001", "update", payload) publishes to both rooms.

Install

yarn add @google-cloud/pubsub

GCP setup

  1. Create a Pub/Sub topic — e.g. blixify-live-events-prod (separate from any existing topics).
  2. Grant pubsub.topics.publish to the App Engine service account.
  3. Set PUBSUB_LIVE_TOPIC=blixify-live-events-prod in .env / App Engine env vars.

Server setup

import { PubSub } from "@google-cloud/pubsub";
import { SocketWrapper } from "blixify-server/dist/apis";

// INFO: null → no-op in local dev (mirrors the getPubSubClient pattern)
const pubsub = process.env.PUBSUB_LIVE_TOPIC ? new PubSub() : null;

export const socketWrapper = new SocketWrapper(
  pubsub,
  process.env.PUBSUB_LIVE_TOPIC ?? "",
  ["robots", "vehicles"], // INFO: opt-in whitelist
  {
    checkTopicAuth: async (room, req) =>
      req.query?.bm_apiToken === process.env.SECURITY_TOKEN ||
      req.body?.bm_apiToken === process.env.SECURITY_TOKEN,
  },
);

Wire to MongoWrapper

// afterWrite is optional — when unset, MongoWrapper behaviour is unchanged
wrapper.afterWrite = (type, id, payload) =>
  socketWrapper.emit("robots", id, type, payload);
//                             ↑
//              id="" for batch ops → only collection room receives it

SSE endpoint

Next.js:

// pages/api/live/[room].ts
export const config = { api: { bodyParser: false } };
export default socketWrapper.createSSEHandler();

Express:

app.get("/api/live/:room", socketWrapper.createSSEHandler());

Snapshot on reconnect

socketWrapper.registerSnapshotProvider("robots", async () => {
  const db = await mongoPromise;
  return db.db("robots-prod").collection("robots").find({}).toArray();
});

On each new SSE connection the handler immediately sends a snapshot envelope so the client reconciles rows that drifted while offline.

SocketEnvelope

interface SocketEnvelope<T = any> {
  topic: string; // collection name
  type: "insert" | "update" | "delete" | "snapshot";
  payload: T | T[]; // snapshot = T[]
  ts: number; // Unix ms
}

DTW client usage

Set workspace.sseEndpoint (or devSettings.sseEndpoint) to the base of your /api/live route:

// workspaceDev
export const workspaceDev = {
  apiEndpoint: `${apiPrefix}/api/data`,
  assetEndpoint: storageAPI,
  assetUploadEndpoint: `${apiPrefix}/api/asset`,
  apiEndpointToken: securityToken,
  sseEndpoint: `${apiPrefix}/api/live`,   // ← add this
};

// List view — subscribes room "robots"
<DataTemplateWrapper collectionId="robots" type="list"
  bareSettings={{ bareSocketName: "robots" }}
  workspace={workspaceDev} />

// Read/update view — subscribes room "robots-{id}"
<DataTemplateWrapper collectionId="robots" type="read" id={robotId}
  bareSettings={{ bareSocketName: `robots-${robotId}` }}
  workspace={workspaceDev} />

// MRQ polling fallback (1.5 s) — no Pub/Sub needed
<DataTemplateWrapper collectionId="robots" type="list"
  bareSettings={{ barePollingInterval: 1500 }}
  workspace={workspaceDev} />

The DTW opens EventSource at {sseEndpoint}/{room}?bm_apiToken={token}. No socket.io-client package needed.

Capacitor

EventSource is a plain HTTP long-lived GET. Works on iOS and Android WebView with no extra configuration — same as any other API call. No sticky sessions or instance_affinity required on GAE.

Local dev

pubsub = nullemit() is a silent no-op. The SSE endpoint stays open and sends periodic : ping keep-alives. The app saves correctly; other devices just don't receive a live push.

Tests

yarn test:unit

Covers: whitelist gating, dual-room publish (collection + doc), batch-op single-room publish, null-pubsub no-op, SSE auth rejection, snapshot on connect, MongoWrapper.afterWriteemit full chain.