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 🙏

© 2024 – Pkg Stats / Ryan Hefner

ryder

v0.2.1

Published

Remote Procedure Call & Subscription via `postMessage`

Downloads

5

Readme

Ryder

A Remote Procedure Call & Subscription Utility via postMessage

The name

Ryder is of old English origin and means cavalrymen, messenger. And, Ryder is the main protagonist of the TV series PAW Patrol.

Features

Platform Agnostic

Ryder supports any message event sources that implements postMessage and message event. So window, MessagePort, node:worker_threads, WebWorker, ServiceWorker and BroadcastChannel are supported out of the box.

Other message event sources like WebSocket, WebRTC and Server-sent events could be supported with postMessage implemented by users.

Use Case

| | Client | Server | | ------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------- | ---------------------------------------------------------- | | An iframe executes functions, accesses or subscribes data in another iframe | window(of an iframe) | window(of another iframe) | | A web page executes functions, accesses or subscribes data in WebWorker or ServiceWorker | window | WebWorker or ServiceWorker | | A NodeJS module executes functions, accesses or subscribes data in node:worker_threads | node:worker_threads (parentPort) | node:worker_threads | | A web page executes functions, accesses or subscribes data from another web server | WebSocket(with postMessage wrapper) | WebSocket (with postMessage wrapper, via ws package) | | A web page executes functions, accesses or subscribes data from another peer (WebRTC, peer-to-peer communication) | RTCDataChannel (with postMessage wrapper) | RTCDataChannel (with postMessage wrapper) |

Reference implementation of WebSocket postMessage wrapper
class RyderWebSocket extends WebSocket {
  postMessage(data) {
    return this.send(data);
  }
}

Robust Connection

Installation

# npm
npm install ryder

# yarn
yarn add ryder

# pnpm
pnpm add ryder

Usage

Server

async function fetchData(type: string) {
  await timeout(1000);
  return `Answer for ${type} is 42`;
}

const rpcMap = {
  fetchAnswer: fetchData,
  isLoading: false,
};

const subscriptionMap = {
  // Outputs 0, 1, 2, 3, 4 ... every 1000ms
  interval: intervalSubscription,
};

const { messageHandler } = createServerBridge({
  /**
   * Handler for client calling `subscribe` to subscribe a data source.
   * Multiple subscription request of the same property key will not have
   * duplicated subscription to the data source.
   */
  subscriptionHandler: (
    propertyPath: string[],
    onValueChange: (value: unknown) => void
  ) => {
    const unsubscribe = subscriptionMap(propertyPath[0]).subscribe(
      onValueChange
    );
    return unsubscribe;
  },
  /**
   * Handler for client calling `invoke` to execute a function, or get data.
   */
  invokeHandler: (propertyPath: PropertyKey[]) => rpcMap[propertyPath[0]],
});

Client

const bridge = createClientBridge({
  /**
   * The callback function to provide a Ryder Server to connect.
   */
  serverFinder,
  /**
   * Indicates if Ryder coalesces multiple requests into one if possible. coalesced requests reduce
   * the number of `postMessage` calls, and guarantee the execution order without `await` if no data access needed
   */
  requestCoalescing: true,
});

window.addEventListener('message', bridge.messageHandler);

// Function invocation, call remote `fetchData` with no parameters
const result = await bridge.invoke(
  ['fetchAnswer'],
  ['life the universe and everything']
); // Returns "Answer for life the universe and everything is 42"

// Variable access
const result = await bridge.invoke(['isLoading']); // Returns false

// Subscription
const unsubscribe = bridge.subscribe(['interval'], (value: number) => {
  console.log(value); // Prints 0, 1, 2, 3, 4 ... every 1000ms
});

Advanced Techniques

Usage of JavaScript Proxy

Request Coalescing