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

lazy-rpc

v1.0.2

Published

Production-ready RPC management library with load balancing, exponential backoff, and support for 15+ EVM chains. Features TypeScript-first design, WebSocket support, and intelligent failure handling.

Readme

LAZY RPC DOCUMENTATION

Overview

LAZY RPC is a robust, production-ready library designed to manage and validate Remote Procedure Call (RPC) URLs for blockchain interactions. It supports both HTTP and WebSocket (WS) calls, intelligent failure tracking, exponential backoff retry logic, load balancing strategies, and automatic validation of endpoints.

Features

  • Multi-Protocol Support: HTTP and WebSocket RPC endpoints
  • Smart Failure Tracking: Exponential backoff retry logic with automatic recovery
  • Load Balancing: Multiple strategies (fastest, round-robin, random)
  • Auto-Refresh: Valid RPCs refreshed based on configurable TTL
  • Chain Validation: Ensures correct blockchain chain ID usage
  • Memory Safe: Proper cleanup of WebSocket connections and timeouts
  • TypeScript First: Full TypeScript support with comprehensive interfaces
  • Production Ready: Enhanced error handling, logging, and monitoring
  • Extensive Chain Support: 15+ EVM chains built-in, any EVM chain via custom RPC list

Installation

npm install lazy-rpc

Quick Start

import { RPC } from "lazy-rpc";

// Basic usage
const rpc = new RPC({
  chainId: "0x0001", // Ethereum mainnet
  ttl: 30,
  loadBalancing: "fastest"
});

// Get HTTP RPC URL
const httpUrl = rpc.getRpc("https");

// Get WebSocket RPC URL
const wsUrl = rpc.getRpc("ws");

// Handle failures
try {
  // Make your RPC call here
} catch (error) {
  rpc.drop(httpUrl); // Mark as failed for smart retry
}

// Clean up when done
rpc.destroy();

Using Any EVM Chain

The library comes with 15+ built-in chains, but you can use any EVM-compatible blockchain by providing your own RPC list:

import { RPC } from "lazy-rpc";

// Example: Telos EVM (chainId 40 = 0x28)
const rpc = new RPC({
  chainId: "0x28",
  pathToRpcJson: "./my-rpcs.json"
});
// my-rpcs.json
{
  "x28": [
    "https://mainnet.telos.net/evm",
    "https://rpc1.eu.telos.net/evm"
  ],
  "x28_WS": [
    "wss://mainnet.telos.net/evm"
  ]
}

Any chain, any RPC — private nodes, Infura, Alchemy, self-hosted, or public endpoints all work.

Configuration

Constructor Options

interface RPCConfig {
  chainId: string;                    // Required: Blockchain chain ID (hex format, e.g. "0x0001")
  ttl?: number;                      // Optional: Refresh interval in seconds (1-3600, default: 10)
  maxRetry?: number;                 // Optional: Max retries before dropping (0-10, default: 3)
  pathToRpcJson?: string;           // Optional: Custom RPC list file path
  log?: boolean;                    // Optional: Enable logging (default: false)
  loadBalancing?: LoadBalancingStrategy; // Optional: Load balancing strategy (default: "fastest")
}

type LoadBalancingStrategy = "fastest" | "round-robin" | "random";

[!NOTE] Chain IDs use a zero-padded hex format specific to this library (e.g., "0x0001" for Ethereum mainnet, "0x89" for Polygon). See the Supported Chains table for the exact values to use.

Example Configurations

// Production configuration
const prodRpc = new RPC({
  chainId: "0x0001",
  ttl: 60,
  maxRetry: 5,
  loadBalancing: "round-robin",
  log: false
});

// Development configuration  
const devRpc = new RPC({
  chainId: "0x0001",
  ttl: 10,
  maxRetry: 2,
  loadBalancing: "fastest",
  log: true
});

// Custom RPC list
const customRpc = new RPC({
  chainId: "0x0001",
  pathToRpcJson: "/path/to/custom-rpcs.json",
  loadBalancing: "random"
});

Supported Chains

| Chain | Chain ID | HTTP RPCs | WebSocket RPCs | |-------|----------|-----------|----------------| | Ethereum Mainnet | 0x0001 | 50+ | 7+ | | Polygon | 0x89 | 18+ | 3+ | | Polygon Mumbai | 0x13881 | 9+ | 2+ | | BSC Mainnet | 0x38 | 14+ | 2+ | | BSC Testnet | 0x61 | 6+ | 1+ | | Arbitrum One | 0xa4b1 | 13+ | 3+ | | Arbitrum Sepolia | 0x66eed | 5+ | 1+ | | Optimism | 0xa | 14+ | 3+ | | Optimism Sepolia | 0xaa37dc | 6+ | 1+ | | Base Mainnet | 0x2105 | 13+ | 3+ | | Base Sepolia | 0x14a34 | 6+ | 1+ | | Avalanche C-Chain | 0xa86a | 20+ | 3+ | | Avalanche Fuji | 0xa869 | 12+ | 2+ |

API Reference

Core Methods

getRpc(type: "ws" | "https"): string

Retrieves a valid RPC URL based on the configured load balancing strategy.

const httpUrl = rpc.getRpc("https");
const wsUrl = rpc.getRpc("ws");

getRpcAsync(type: "ws" | "https"): Promise<string>

Asynchronously retrieves a valid RPC URL after ensuring initialization is complete.

const httpUrl = await rpc.getRpcAsync("https");
const wsUrl = await rpc.getRpcAsync("ws");

drop(url: string): void

Marks an RPC URL as failed, triggering exponential backoff retry logic.

rpc.drop("https://failed-rpc.com");

Monitoring & Management

getValidRPCCount(type: "ws" | "https"): number

Returns the count of currently valid RPCs.

const httpCount = rpc.getValidRPCCount("https");
const wsCount = rpc.getValidRPCCount("ws");

getAllValidRPCs(type: "ws" | "https"): RPCEndpoint[]

Returns all valid RPCs with performance metrics.

const httpRpcs = rpc.getAllValidRPCs("https");
// Returns: [{ url: "https://...", time: 150 }, ...]

getFailureStats(): FailureStats

Returns comprehensive failure statistics.

const stats = rpc.getFailureStats();
// Returns: { totalFailed: 5, inBackoff: 2, overMaxRetries: 1 }

refresh(): Promise<void>

Manually triggers RPC validation refresh.

await rpc.refresh();

clearFailedURLs(): void

Clears all failed URL records (useful for testing or manual resets).

rpc.clearFailedURLs();

destroy(): void

Destroys the RPC instance, clearing all timers and internal state. Call this when the instance is no longer needed to prevent memory leaks from periodic refresh timers.

rpc.destroy();

Load Balancing Strategies

Fastest (Default)

Always returns the RPC with the lowest response time.

const rpc = new RPC({ 
  chainId: "0x0001", 
  loadBalancing: "fastest" 
});

Round Robin

Cycles through available RPCs in order, distributing load evenly.

const rpc = new RPC({ 
  chainId: "0x0001", 
  loadBalancing: "round-robin" 
});

Random

Randomly selects from available RPCs.

const rpc = new RPC({ 
  chainId: "0x0001", 
  loadBalancing: "random" 
});

Error Handling & Retry Logic

Exponential Backoff

Failed RPCs are automatically placed in an exponential backoff queue:

  • 1st failure: 1 second backoff
  • 2nd failure: 2 second backoff
  • 3rd failure: 4 second backoff
  • Maximum backoff: 60 seconds

Automatic Recovery

Failed RPCs are automatically reset after 6 hours, allowing for natural recovery from temporary issues.

Best Practices

async function makeRpcCall(rpc: RPC) {
  const url = rpc.getRpc("https");
  
  try {
    const response = await fetch(url, {
      method: "POST",
      headers: { "Content-Type": "application/json" },
      body: JSON.stringify({
        jsonrpc: "2.0",
        method: "eth_blockNumber",
        params: [],
        id: 1
      })
    });
    
    if (!response.ok) {
      throw new Error(`HTTP ${response.status}`);
    }
    
    return await response.json();
  } catch (error) {
    rpc.drop(url); // Mark as failed
    throw error;
  }
}

WebSocket Usage

function createWebSocket(rpc: RPC) {
  const wsUrl = rpc.getRpc("ws");
  const ws = new WebSocket(wsUrl);
  
  ws.onopen = () => {
    console.log("Connected to", wsUrl);
  };
  
  ws.onerror = (error) => {
    rpc.drop(wsUrl); // Mark as failed
    console.error("WebSocket error:", error);
  };
  
  return ws;
}

Custom RPC Lists

Not limited to built-in chains! Use pathToRpcJson to add support for any EVM blockchain — including private networks, testnets, L2s, and chains not in the bundled list.

Custom RPC List Format

Create a JSON file where keys are the chain ID (hex, without 0x prefix, prefixed with x), and _WS suffix for WebSocket endpoints:

{
  "x0001": [
    "https://your-ethereum-rpc1.com",
    "https://your-ethereum-rpc2.com"
  ],
  "x0001_WS": [
    "wss://your-ethereum-ws1.com"
  ],
  "x28": [
    "https://mainnet.telos.net/evm",
    "https://rpc1.eu.telos.net/evm"
  ],
  "x28_WS": [
    "wss://mainnet.telos.net/evm"
  ]
}

Then pass it to the constructor:

const rpc = new RPC({
  chainId: "0x28",  // Telos EVM
  pathToRpcJson: "/path/to/your-rpcs.json"
});

If the file at pathToRpcJson does not exist, the library automatically falls back to the bundled list.

Migration from v0.1.0

Breaking Changes

  1. Constructor now requires an object parameter:
// Old (v0.1.x)
const rpc = new RPC("0x0001", 10, 3, false);

// New (v0.2.0+)
const rpc = new RPC({
  chainId: "0x0001",
  ttl: 10,
  maxRetry: 3,
  log: false
});
  1. Enhanced error messages and validation
  2. WebSocket calls now properly return Promises

New Features

  • Load balancing strategies
  • Enhanced monitoring methods
  • Exponential backoff retry logic
  • destroy() method for proper cleanup
  • Memory leak fixes
  • TypeScript interfaces

Performance Considerations

  • Initialization: First RPC validation happens during construction
  • Memory Usage: Minimal footprint with automatic cleanup
  • Network Calls: Intelligent batching and caching
  • Retry Logic: Exponential backoff prevents thundering herd

Troubleshooting

Common Issues

No valid URLs found

// Check if your chain ID is supported
console.log(rpc.getValidRPCCount("https"));

// Try refreshing the RPC list
await rpc.refresh();

High failure rates

// Check failure statistics
const stats = rpc.getFailureStats();
console.log("Failed RPCs:", stats);

// Consider decreasing TTL for more frequent validation
const rpc = new RPC({ chainId: "0x0001", ttl: 10 });

WebSocket connection issues

// Enable logging for debugging
const rpc = new RPC({ 
  chainId: "0x0001", 
  log: true 
});

Contributing

Issues and pull requests are welcome! Please see our GitHub repository for contribution guidelines.

License

This project is licensed under the MIT License.