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

react-liverpc

v0.1.2

Published

A live RPC implementation for Hono/React, bring your own db.

Readme

react-liverpc

A simple real-time RPC (Remote Procedure Call) library for React applications with Hono backend support. This library enables seamless real-time communication between your React frontend and Hono backend, with built-in support for live queries and mutations.

This library is designed to be flexible withe the choice of database/kv etc... While Hono is the only included backend supported, the library provide a way for the developer to use any socket by providing the needed function to the RPCs backend and frontend clients. The library supports manual invalidation of queries, allowing you to trigger real-time updates broadcasted to your client.

Notes:

  • I like deploying my own Soketi service (Pusher alternative that allows to user the pusher-js packages). However, note that it has a 10Kb limit per broadcasted event...

Features

  • 🔄 Real-time data synchronization
  • 🎯 Type-safe RPC calls
  • 🔌 Built-in support for Hono backend
  • 🚀 Easy integration with React Query
  • 📡 Flexible socket implementation (Pusher, Socket.IO, etc.)
  • 🔒 Built-in authorization support
  • 🎨 Clean and intuitive API

Installation

npm install react-liverpc
yarn add react-liverpc
pnpm add react-liverpc

Quick Start

Backend Setup (Hono)

// rpc.ts

import { Hono } from 'hono';
import { LiveRPC, LiveRPCBuilder } from 'react-liverpc';
import { z } from 'zod';
import Pusher from 'pusher';

// Initialize Pusher (or your preferred real-time solution)
const pusher = new Pusher({
  // your backend pusher
});

// Create RPC configuration
const rpcConfig = new LiveRPCBuilder()
  .addQuery('getPosts', {
    params: z.undefined(),
    query: async (params, request) => {
      // Your database query here
      return await db.posts.findMany();
    }
  })
  .addQuery('getPost', {
    params: z.object({
      id: z.string().min(1)
    })
  })
  .addMutation('createPost', {
    params: z.object({
      title: z.string().min(1),
      content: z.string().min(1),
    }),
    mutation: async (params, request) => {
      // params here is parse by zod
      const { title, content } = params;
      const id = crypto.randomUUID();
      await db.posts.create({id, title, content});
      return {id, title, content}
    },
    invalidateQueries: {
      getPosts: () => undefined // Invalidate getPosts query after mutation
      getPost: (mutationParams, mutationResults) => ({id: mutationResults.id})
    }
  })
  .addMutation('deleteAllPosts', {
    params: z.undefined(),
    mutation: async (params, request) => {
      const IDs = await db.posts.findMany({ id }) // get all the ids string[]
      return IDs;
    },
    invalidateQueries: {
      getPosts: () => undefined // Invalidate getPosts query after mutation
      getPost: (mutationParams, mutationResults) => mutationResults.map(id => ({ id }))
    }
  });

// For client type-safety, export the type of your config
export type TypeMyLiveRPC = typeof config;

// Initialize LiveRPC
export const rpc = new LiveRPC({
  socket: {
    broadcast: async (channel, event, data) => {
      await pusher.trigger(channel, event, data);
    },
    batchBroadcast: async (broadcasts) => {
      await pusher.triggerBatch(broadcasts);
    },
    maxBatchSize: 10
  },
  config: rpcConfig
});
// route.ts

import {rpc} from "./rpc"
// Create Hono app
const app = new Hono();

// Add RPC endpoint
app.post('/rpc/*', async (c) => {
  return await rpc.handleRequest(c);
});

export default app;
// types.d.ts

// create this file, import the config type and export it 
// so that your client can only use the type from the backend,
// good for monorepos

import type { TypeMyLiveRPC } from "./config";

export type { TypeMyLiveRPC };

Frontend Setup (React)

// rpc.ts

import type { TypeMyLiveRPC } from "path_to_my_backend/type"
import { createClientLiveRPC } from 'react-liverpc';
import Pusher from 'pusher-js';

// Initialize Pusher client
const pusher = new Pusher('your-key', {
  // rest of pusher config
});

// Create RPC client
const { useQuery, useLiveQuery, useMutation } = createClientLiveRPC<TypeMyLiveRPC>({
  url: 'http://localhost:3000',
  basePath: '/rpc',
  socketFn: (channelName, eventName, callback) => {
    const channel = pusher.subscribe(channelName);
    channel.bind(eventName, callback);
    return () => {
      channel.unbind(eventName);
      pusher.unsubscribe(channelName);
    };
  }
});
// post-page.tsx

// Use in your React components
function PostList() {
  // Regular query for all posts
  const { data: posts, isLoading } = useQuery('getPosts', undefined);

  // Live query for all posts (updates in real-time)
  const { data: livePosts, isLoading: isLoadingLive } = useLiveQuery('getPosts', undefined);

  // Mutations
  const createPost = useMutation('createPost');
  const deleteAllPosts = useMutation('deleteAllPosts');

  const handleCreatePost = async () => {
    await createPost.mutate({
      title: 'New Post',
      content: 'This is the content of my new post'
    });
  };

  const handleDeleteAllPosts = async () => {
    await deleteAllPosts.mutate(undefined);
  };

  if (isLoading) return <div>Loading...</div>;

  return (
    <div>
      <h1>Posts</h1>
      <div className="actions">
        <button onClick={handleCreatePost}>Create New Post</button>
        <button onClick={handleDeleteAllPosts}>Delete All Posts</button>
      </div>
      <ul>
        {livePosts?.map(post => (
          <li key={post.id}>
            <h2>{post.title}</h2>
            <p>{post.content}</p>
          </li>
        ))}
      </ul>
    </div>
  );
}

// Example of a single post view component
function PostView({ postId }: { postId: string }) {
  // Live query for a single post
  const { data: post, isLoading } = useLiveQuery('getPost', { id: postId });

  if (isLoading) return <div>Loading...</div>;
  if (!post) return <div>Post not found</div>;

  return (
    <div>
      <h1>{post.title}</h1>
      <p>{post.content}</p>
    </div>
  );
}

Not included but could be added

  • Additional backend framework integrations (Express.js)
  • Enhanced error handling and retry mechanisms
  • WebSocket fallback support
  • Built-in caching strategies

Contributing

Contributions are welcome! Please feel free to submit a Pull Request.

License

MIT