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

smocket

v1.0.0

Published

Socket.IO mock for frontend development and testing across rooms, namespaces, and broadcasts.

Readme

Why smocket?

When developing a Socket.IO frontend, you need to see several clients connect, join rooms, and receive different events. Before the backend event API is ready, there is nowhere in the frontend to run that flow, so work on the multi-client UI has to wait too.

A hand-written socket object can call a listener, but it usually has one handler map. It cannot choose recipients from room membership, namespace, a broadcast target, or the lifetime of an acknowledgement. An HTTP mock can define requests and responses, but it does not own that long-lived connection state or Socket.IO routing.

A separate local Socket.IO server is accurate, but it also needs another process, configuration, and a reachable host. That makes it awkward for isolated component development and static previews, especially when the frontend only needs the application event layer.

Run Socket.IO application events in memory

smocket creates distinct client and server sockets without opening a network server. It runs the supported Socket.IO connection handlers, room and namespace membership, targeted and broadcast delivery, acknowledgements, and socket lifecycle in the same JavaScript environment as the frontend.

io.on('connection', (socket) => {
  socket.on('say', (room: string, text: string) => {
    socket.to(room).emit('said', text);
  });
});

The event handlers and domain logic inside the supported surface can be shared with a real Socket.IO server. For several same-origin browser tabs, the explicit SharedWorker path lets those pages use one in-browser server and one in-memory state. smocket does not reproduce network transport or replace a production backend.

Quick start

npm install -D smocket smocket-client

Install both packages at the same version. smocket owns the in-process server; smocket-client provides the application-facing connection. Neither package requires a test runner.

// quick-start.ts
import { Server } from 'smocket';
import { connect } from 'smocket-client';

async function main() {
  const URL = 'http://localhost:3000';
  const io = new Server(URL);

  io.on('connection', (socket) => {
    socket.on('join', async (room: string, done: () => void) => {
      await socket.join(room);
      done();
    });

    socket.on('say', (room: string, text: string) => {
      socket.to(room).emit('said', text);
    });
  });

  const alice = connect(URL);
  const bob = connect(URL);

  const joinLobby = (client: ReturnType<typeof connect>) =>
    new Promise<void>((done) => client.emit('join', 'lobby', done));

  try {
    await Promise.all([joinLobby(alice), joinLobby(bob)]);

    const bobHeard = new Promise<string>((done) => bob.once('said', done));
    alice.emit('say', 'lobby', 'hello');

    console.log(`Bob heard: ${await bobHeard}`);
  } finally {
    await io.close();
  }
}

void main();

Save the file and run it with the TypeScript runner already used by your project, or use npx tsx quick-start.ts for a standalone copy. It prints Bob heard: hello, then close() disconnects both clients and unregisters the server. The repository's executable room and acknowledgement workflow is in examples/chat-room; run it with pnpm example:chat-room.

An existing application can keep its socket.io-client import and map that package name to smocket-client in the environment that uses the mock:

// application code
import { io } from 'socket.io-client';

See test-runner integration for Vitest and Jest mapping, or package entry points when the application owns its imports directly.

See it in a React drawing game

The drawing game is a React multi-user application that runs in three browser pages. Its automated flow covers drawing, chat, answer acknowledgements, the end of a round, page closure, refresh, and connection cleanup.

The smocket path hosts the session in a SharedWorker. The real path starts a Node Socket.IO server. Both use the same application event handler, event types, domain state, React UI, and user actions; only the connection bootstrap changes.

How the supported boundary stays checked

The project links each public claim to a maintained workflow rather than copying test counts into this page.

| Question | Maintained path | | ------------------------------------------------ | -------------------------------------------------------------- | | Does delivery and routing match Socket.IO? | dual-run conformance | | Can several browser tabs share one mock server? | Chromium and SharedWorker workflow | | Does the event layer work in a real frontend? | React drawing game | | Can applications consume the published packages? | clean consumer checks |

The conformance report also names the surface not yet compared and every deliberate difference. Package checks install release artifacts outside the workspace across supported module, type, test-runner, browser, and SharedWorker entry paths.

Move to a real Socket.IO server

When an application keeps socket.io-client as its import, remove the mock-only mapping and point it at the real server. Start the network server and move the shared application handler into that server's bootstrap. Event names, supported handler shapes, and framework-independent domain logic can stay the same.

The parts that should change are the parts smocket deliberately does not provide: transport configuration, authentication against real infrastructure, persistence, cross-device access, reconnection, and scaling. Keep integration and end-to-end tests for those boundaries.

Out of scope

These are not unfinished transport features. A mock does not open a network connection, so reproducing them would require behaviour with no live transport to act on.

  • Reconnection behaviour reproduction. There is no dropped network connection to re-establish. Application responses to a disconnected state can still be exercised directly.
  • Transport fallback. There is no WebSocket or HTTP long-polling transport to switch between.
  • Heartbeat. There is no live connection to ping or time out. The resulting disconnect state remains observable through socket.disconnect().
  • Multi-server scaling. One in-memory process has no second server for a Redis adapter to reach.
  • Binary encoding. Nothing is serialised onto a wire, so there are no frames to encode. Binary-containing direct payloads stay on the documented in-memory passthrough path; this is not binary protocol support.

See the complete scope boundary and deliberate differences before relying on an API outside the documented surface.

FAQ

No. It runs the application event layer in memory for frontend development and testing. A real backend is still required for transport, security, persistence, cross-device use, and production operation.

No. The quick start is plain TypeScript, and the drawing game runs as a browser application. Test runners are optional integration paths for projects that already use them.

Yes, through smocket/shared-worker and smocket-client/shared-worker. Pages must share the same origin, browser profile, worker URL, and worker name. The SharedWorker guide covers the lifecycle and storage boundary.

The supported application event handlers, event names, and domain logic can be shared. The connection bootstrap and real infrastructure still change, and code outside smocket's documented scope needs its own integration checks.

The generated conformance report is the exact boundary. Each listed case runs against real Socket.IO and smocket from the same test file; the report also lists unmeasured APIs and deliberate differences.

Documentation

| Document or path | What it answers | | ------------------------------------------------------------ | ----------------------------------------------------------------- | | Public documentation | the deployed documentation entry point | | Documentation map | where to go for adoption, guarantees, and maintenance | | Package entry points | which server, client, and SharedWorker import to use | | Drawing-game workflow | React development with smocket and real Socket.IO | | SharedWorker | sharing one in-browser server across same-origin tabs | | Test-runner integration | mapping socket.io-client in Vitest and Jest | | Conformance | behaviour compared with real Socket.IO and the unmeasured surface | | Scope and differences | the supported layer; see also differences | | Troubleshooting | adoption failures by observed signal | | Roadmap | durable gates and the path toward v1.0.0 |

The maintained Korean entry points are README.ko.md and CONTRIBUTING.ko.md. English documentation is authoritative; the two Korean guides link to it instead of mirroring every page.

Contributing

Contributions are welcome, and the most useful ones encode how Socket.IO actually behaves.

The shortest route in is a conformance case, because it has a mechanical comparison. Read the current compared surface and how to add a case before starting.

The milestones show what each release is aiming for, and the issue tracker carries the rest.

See CONTRIBUTING.md for setup, where to report or propose work, commit conventions, and how pull requests are merged. The Korean guide covers the same path. See AGENTS.md for how to run the two test targets.

Code of Conduct

Participation in smocket is governed by the Contributor Covenant Code of Conduct.

Contributors

Contributors

License

MIT. See LICENSE. Third-party font and project asset provenance is recorded in THIRD_PARTY_NOTICES.md.