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 🙏

© 2025 – Pkg Stats / Ryan Hefner

@nookuio/rpc

v1.0.5

Published

A lightweight, type-safe RPC (Remote Procedure Call) library for bidirectional communication between processes. Built with TypeScript and designed for use in Electron applications, web workers, iframes, or any scenario requiring cross-context communicatio

Downloads

238

Readme

@nookuio/rpc

A lightweight, type-safe RPC (Remote Procedure Call) library for bidirectional communication between processes. Built with TypeScript and designed for use in Electron applications, web workers, iframes, or any scenario requiring cross-context communication.

Features

  • Type-safe: Full TypeScript support with generic types for remote and local contexts
  • Bidirectional: Both sides can expose methods and emit/listen to events
  • Promise-based: All remote calls return promises automatically
  • Event system: Built-in event emitter for real-time communication
  • Flexible transport: Works with any message-passing mechanism (IPC, postMessage, etc.)
  • Performance optimized: Proxy caching to minimize overhead
  • Configurable: Custom serialization, timeouts, and error handling

Installation

pnpm add @nookuio/rpc

Basic Usage

Creating a Client

import { createClient } from '@nookuio/rpc';

// Define your local context (methods available to remote)
const localContext = {
  greet: (name: string) => `Hello, ${name}!`,
  calculate: (a: number, b: number) => a + b
};

// Define your remote context type (methods available from remote)
interface RemoteContext {
  getData: () => Promise<string>;
  saveData: (data: string) => Promise<void>;
}

// Create the client
const client = createClient<RemoteContext, typeof localContext, {}, {}>(localContext, {
  invoke: async (request) => {
    // Send request to remote
    return await ipcRenderer.invoke('rpc-request', request);
  },
  handle: (handler) => {
    // Handle incoming requests from remote
    ipcRenderer.on('rpc-request', async (event, request) => {
      const response = await handler(request);
      event.sender.send('rpc-response', response);
    });
  },
  emit: (event) => {
    // Emit events to remote
    ipcRenderer.send('rpc-event', event);
  },
  handleEvent: (handler) => {
    // Handle events from remote
    ipcRenderer.on('rpc-event', (_, event) => handler(event));
  }
});

// Use remote methods
const data = await client.getData();
await client.saveData('new data');

// Access local context
console.log(client.$context.greet('World'));

API Reference

createClient<R, L, RE, LE>(localContext, options)

Creates an RPC client with type-safe remote method calls.

Type Parameters:

  • R - Remote context type (methods available from remote)
  • L - Local context type (methods available to remote)
  • RE - Remote events type (events emitted by remote)
  • LE - Local events type (events emitted locally)

Parameters:

  • localContext - Object containing methods exposed to the remote process
  • options - Configuration object

Options:

interface ClientOptions {
  // Send requests to remote process
  invoke: (request: ContextRequest) => Promise<ContextResponse>;

  // Handle incoming requests from remote
  handle: (handler: (request: ContextRequest) => Promise<ContextResponse>) => void;

  // Emit events to remote process
  emit: (request: EventRequest) => void;

  // Handle events from remote process
  handleEvent: (handler: (request: EventRequest) => void) => void;

  // Custom serialization (default: JSON.stringify)
  serialize?: (data: any) => any;

  // Custom deserialization (default: JSON.parse)
  deserialize?: (data: any) => any;

  // Request timeout in milliseconds (default: 5000)
  timeout?: number;

  // Cleanup function
  destroy?: () => void | Promise<void>;

  // Handle timeout errors
  onTimeout?: (request: ContextRequest) => void;
}

Client Methods

$context Access the local context object.

client.$context.myMethod();

$destroy() Cleanup the client, remove all listeners, and call the destroy function.

client.$destroy();

on(eventName, listener) Listen to events from the remote process.

client.on('dataUpdated', (data) => {
  console.log('Data updated:', data);
});

off(eventName, listener) Remove an event listener.

const listener = (data) => console.log(data);
client.on('dataUpdated', listener);
client.off('dataUpdated', listener);

emit(eventName, ...args) Emit an event to the remote process.

client.emit('userAction', { action: 'click', target: 'button' });

removeAllListeners() Remove all event listeners.

client.removeAllListeners();

Examples

With Events

// Define event types
interface RemoteEvents extends RpcEvents {
  dataChanged: (data: string) => void;
  error: (error: Error) => void;
}

interface LocalEvents extends RpcEvents {
  userAction: (action: string) => void;
}

const client = createClient<RemoteContext, LocalContext, RemoteEvents, LocalEvents>(localContext, options);

// Listen to remote events
client.on('dataChanged', (data) => {
  console.log('Remote data changed:', data);
});

client.on('error', (error) => {
  console.error('Remote error:', error);
});

// Emit local events
client.emit('userAction', 'button-click');

Custom Serialization

import superjson from 'superjson';

const client = createClient<RemoteContext, LocalContext, {}, {}>(localContext, {
  // ... other options
  serialize: (data) => superjson.stringify(data),
  deserialize: (data) => superjson.parse(data)
});

How It Works

  1. Proxy-based API: The client uses JavaScript Proxies to intercept property access and method calls
  2. Request/Response: Method calls are serialized into requests, sent to the remote process, and responses are deserialized
  3. Event System: Built-in event emitter allows both sides to emit and listen to events
  4. Caching: Proxies are cached by path to optimize performance
  5. Type Safety: TypeScript generics ensure type safety across the RPC boundary

Performance

  • Proxy caching minimizes object creation overhead
  • Configurable timeouts prevent hanging requests
  • Efficient serialization with custom serializer support
  • No polling - event-driven architecture