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

@dotex/erpc

v0.3.2

Published

Encrypted RPC for any two counterparties over any bidirectional channel

Readme

eRPC

npm license types

Encrypted, typed RPC over any bidirectional channel. Two peers, one shared secret (or one keypair). Every call is end-to-end encrypted with XSalsa20-Poly1305 AEAD. WebSocket, postMessage, MessagePort, chrome.runtime, BroadcastChannel, WebRTC — if a channel can carry bytes, eRPC encrypts and types what flows through it.

Think tRPC, but transport-agnostic and encrypted by default.

npm install @dotex/erpc

eRPC

Highlights

  • Typed procedures with Zod input/output validation
  • End-to-end encryption. X25519 ECDH, XSalsa20-Poly1305 AEAD, HKDF-SHA-256, with forward secrecy by design
  • Lazy handshake on the first call. Transparent auto-retry when the session drops
  • Three auth modes: pre-shared secret, asymmetric (Ed25519 / ECDSA / JWT / cert / multifactor), or both for defense-in-depth
  • Synchronous client() and server(). Runs in Node.js, browsers, Service Workers, React Native, Vercel Edge, Cloudflare Workers, Deno Deploy
  • Tiny surface. @noble/* crypto, @msgpack/msgpack, zod, and nothing else
  • Pure ESM + CJS dual build, side-effect-free, tree-shakeable

Quick start

import { chain, server, client } from "@dotex/erpc";
import { z } from "zod";

const d = chain();

const router = {
  greet: d
    .input(z.object({ name: z.string() }))
    .output(z.object({ message: z.string() }))
    .handler(async ({ input }) => ({
      message: `Hello, ${input.name}!`,
    })),
};

const secret = crypto.getRandomValues(new Uint8Array(32));
const auth = { secret: () => secret };

const { destroy: stopServer } = server(router, serverChannel, { auth });
const { api, destroy: stopClient } = client<typeof router>(clientChannel, { auth });

const { message } = await api.greet({ name: "World" });

client() and server() are synchronous. No top-level await. The handshake runs lazily on the first procedure call. If the session drops, the next call retries once with a fresh handshake.

Channel: the only transport contract

interface Channel {
  send(data: Uint8Array): void | Promise<void>;
  receive(cb: (data: Uint8Array) => void): () => void; // returns unsubscribe
}

Anything that satisfies this can host an eRPC session. Ready-made adapters for WebSocket, postMessage, MessagePort, Chrome extension ports, BroadcastChannel, WebRTC, TCP, and SSE live in spec/integrations.md.

Authentication

Three modes. The auth block is the same shape in all three.

// Secret only. Simple, fast, controlled environments.
auth: { secret: () => sharedSecret }

// Asymmetric only. Public clients, no shared secrets.
auth: {
  sign: (transcript) => signWithDeviceKey(transcript),
  verify: (proof, transcript) => verifyPeerSignature(proof, transcript),
}

// Both. Session binding plus identity proof.
auth: {
  secret: () => deriveSessionSecret(sessionId, deploymentSecret),
  sign: (transcript) => signWithDeviceKey(transcript),
  verify: (proof, transcript) => verifyPeerSignature(proof, transcript),
}

Built-in helpers cover Ed25519, ECDSA P-256, JWT, certificate-based, and multifactor auth. All bind their proof to the handshake transcript, so a captured payload cannot be replayed into a new session. The full threat model lives in spec/security.md.

Errors

import { RPCError, RemoteRPCError } from "@dotex/erpc";

try {
  await api.greet({ name: "World" });
} catch (err) {
  if (err instanceof RemoteRPCError) {
    // The remote peer threw. err.code / err.message / err.data come from there.
  } else if (err instanceof RPCError) {
    // Local failure: TIMEOUT, SESSION, HANDSHAKE, INPUT_VALIDATION, ...
  } else {
    throw err;
  }
}

Package layout

src/
  common.ts       : shared types, crypto, msgpack, chain builder
  server.ts       : resilient handshake server
  client.ts       : lazy handshake client with auto-retry
  auth.ts         : re-exports for auth helpers
  authClient.ts   : Ed25519, ECDSA, JWT client helpers
  authServer.ts   : Ed25519, ECDSA, JWT, certificate, multifactor server helpers
  index.ts        : public entry point
import { chain, server, client, RPCError } from "@dotex/erpc";
// Subpaths are also available for tree-shaking:
import { server } from "@dotex/erpc/server";
import { client } from "@dotex/erpc/client";
import { chain, RPCError } from "@dotex/erpc/common";

Compatibility

Node.js 18+, modern browsers, Service / Web / Shared Workers, React Native, Vercel Edge, Cloudflare Workers, Deno Deploy. WebCrypto is required only for the ECDSA and certificate helpers.

Project status

0.x with a stable wire protocol (drpc-v1 HKDF info, erpc-hs-{hello,reply}-v1 transcript prefixes). Test coverage for handshake attacks, replay, tampering, type confusion, prototype pollution, middleware misuse, and DoS limits lives in test/security/. A 1.0 release will lock the public API surface.

Releasing

One command bumps the version, publishes to npm, and pushes the tag:

npm version patch    # or: minor / major / 1.2.3-beta.0

prepublishOnly runs lint, tests, and build before publishing. The postversion hook then runs npm publish && git push --follow-tags. The pushed vX.Y.Z tag triggers .github/workflows/release.yml, which verifies the version is live on npm and creates a GitHub Release with auto-generated changelog notes since the previous tag.

If npm publish fails, the tag exists locally but is not pushed. Fix the issue and re-run npm publish && git push --follow-tags. To abort, run git tag -d vX.Y.Z && git reset --hard HEAD~1.

License

MIT © Dotex