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

@nage-api/realtime

v1.0.0-beta.4

Published

Realtime for @nage-api — authenticated sockets and a cross-instance propagator

Readme

@nage-api/realtime

Authenticated sockets and a cross-instance propagator (PLAN.md §8, §12, §25 P2).

§12 names three specific defects in the legacy socket layer. This package exists to make all three unrepresentable.

No token in the query string. A token in a URL is written to every access log, every proxy log, every Referer sent to a third-party asset, and the browser history. The handshake reads Authorization: Bearer … and nothing else — and refuses a connection that puts a credential in the query rather than quietly ignoring it, because a client sending one has tokens in its URLs and its author needs to know.

No default guest. A connection with no valid bearer token is refused. The legacy gateway assigned an identity, which made every "authenticated" room reachable by anyone who opened a socket.

Rooms are authorised. Joining a room named by the client is an authorization decision, so RoomPolicy.canJoin runs on every join and the default policy refuses everything — an unconfigured gateway must not be an open one. A refusal never names the room back, because which rooms exist is not something an unauthorised caller may enumerate.

import { Module } from '@nestjs/common';
import { NageRealtimeModule, type Propagator, type RealtimeTransport } from '@nage-api/realtime';
import type { AuthUser } from '@nage-api/contracts';

// The application's own token verification, over `@nage-api/auth`: a feature package
// may not import a sibling feature package (§7.2), so the socket layer takes the
// resolution as a port.
declare const principals: { fromAccessToken(token: string): Promise<AuthUser> };
// Both bindings are yours today; neither the Socket.IO transport nor the Redis
// propagator is written (see "Not yet implemented").
declare const socketIo: RealtimeTransport;
declare const redisPropagator: Propagator;

@Module({
  imports: [
    NageRealtimeModule.forRoot({
      realtime: { enabled: true, adapter: 'redis' },
      authenticator: { authenticate: (token) => principals.fromAccessToken(token) },
      roomPolicy: { canJoin: (user, room) => room === `user:${String(user.id)}` },
      transport: socketIo,
      propagator: redisPropagator,
    }),
  ],
})
export class AppModule {}

authenticator is required and has no default, because the only possible default would be "accept anyone". realtime.enabled must be true: anything else contributes no providers at all, so RealtimeGateway is unavailable rather than present and inert.

Across instances

Without a propagator, a two-pod deployment delivers each event to whichever fraction of users happens to be connected to the pod that emitted it. Events carry the emitting instance's id, so an event that comes back from the propagator is delivered locally exactly once rather than looping between pods.

Asking for adapter: 'redis' without supplying a propagator is refused — accepting it would be a silent lie.

Connections per principal are bounded, because a client in a reconnect loop otherwise accumulates sockets until the process runs out of file descriptors.

Transport-independent

Which socket library carries the bytes is a binding; who may connect, who may join what, and what happens on a second instance are decisions. The decisions live here, where they are testable — testing them through a real socket server would be testing Socket.IO.

With no transport supplied the gateway gets MemoryTransport, which records every emission and delivers to nobody. That is the right default for a test and the wrong one for a deployment: until the Socket.IO binding lands, a running application needs a RealtimeTransport of its own or its events go nowhere.

Not yet implemented

  • The Socket.IO binding (§27.5) and the Redis propagator. RealtimeTransport and Propagator are the seams.
  • Per-connection rate limiting, and presence (who is in a room, across instances).