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

@painda/client

v0.1.8

Published

Lightweight, browser-friendly client for PaindaProtocol

Downloads

39

Readme

🐼 @painda/client

The versatile, browser-compatible SDK for the PaindaProtocol.

@painda/client is the official client-side module for interacting with PaindaProtocol servers. It provides a familiar, Socket.io-like API while leveraging the full power of transparent binary encoding and state synchronization.

⚡ Highlights

  • Binary Schema Support: Use custom binary encoders/decoders for ultra-low overhead.
  • Auto Reconnect: Robust reconnection strategies with exponential, linear, and fibonacci backoff.
  • React Ready: Includes a first-class usePP hook for seamless React integration.
  • Message Queueing: Automatically queues messages while offline and flushes on reconnect.
  • Token Refresh: getToken callback is called on every reconnect — always a fresh JWT.
  • Delta Sync: Built-in support for receiving and applying binary state diffs.

Installation

npm install @painda/client

Quick Start

import { PPClient } from "@painda/client";

const client = new PPClient({
  url: "wss://your-game-server.com/ws",
  reconnect: true,
  getToken: async () => {
    // Called on every connect & reconnect — fresh token each time
    return await fetchAuthToken();
  },
});

client.on("chat_message", (msg) => {
  console.log("New chat message:", msg);
});

client.emit("chat_message", { text: "Hello from Painda Client" });

Event Listeners & Cleanup

on(event, handler) — Subscribe to events

client.on("game:state", (state) => {
  console.log("Game state:", state);
});

off(event, handler) — Unsubscribe from events

const handler = (state: GameState) => setGameState(state);

// Subscribe
client.on("game:state", handler);

// Unsubscribe (important for cleanup!)
client.off("game:state", handler);

once(event, handler) — Listen once, auto-remove

client.once("open", () => {
  console.log("Connected for the first time!");
});

onAny(handler) / offAny(handler) — Catch-all listeners

// Debug: log every event
const debugHandler = (event: string, ...args: unknown[]) => {
  console.log(`[PP] ${event}:`, ...args);
};
client.onAny(debugHandler);

// Cleanup:
client.offAny(debugHandler);

React Integration

usePP() Hook

The usePP hook manages the PPClient lifecycle automatically — connects on mount, disconnects on unmount, and provides stable references.

import { usePP } from "@painda/client";

function ChatComponent() {
  const { emit, on, connected, state } = usePP({
    url: "wss://my-game.com/ws",
    reconnect: true,
    getToken: async () => await refreshToken(),
  });

  useEffect(() => {
    // on() returns an unsubscribe function — perfect for useEffect cleanup
    return on("chat", (msg) => {
      setMessages(prev => [...prev, msg]);
    });
  }, [on]);

  // Subscribe to multiple events:
  useEffect(() => {
    const unsubs = [
      on("player_joined", (data) => setPlayers(data.players)),
      on("player_left", (data) => setPlayers(data.players)),
      on("game:state", (state) => setGameState(state)),
    ];
    return () => unsubs.forEach(u => u());
  }, [on]);

  return <div>{connected ? "🟢 Connected" : "🔴 Disconnected"}</div>;
}

React useEffect Cleanup (without usePP)

If you're using PPClient directly with React, always clean up event listeners:

useEffect(() => {
  const handler = (data: GameState) => setGameState(data);
  client.on("game:state", handler);

  return () => {
    client.off("game:state", handler); // ← Essential cleanup!
  };
}, [client]);

License

MIT License — free for private projects, open-source, and community use.

  • Enterprise (Paid): Commercial projects above a certain company size or revenue threshold require a commercial license. Inquiries via pp.painda.tools/enterprise.
  • Pro Plugins: Premium modules (Dashboard, Redis Adapter, Enterprise Support) available at pp.painda.tools/plugins.