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

@direct.dev/sdk

v1.0.6

Published

Direct.dev SDK for RPC fetch acceleration.

Downloads

943

Readme

@direct.dev/sdk

A drop-in fetch wrapper for Direct.dev RPC endpoints. Your existing code keeps working — Direct.dev quietly takes over JSON-RPC requests to its own URLs and serves them faster, with caching, sync, and failover built in.

Highlights

Sub-millisecond responses Popular requests are answered from a local cache; the rest are routed through the Direct.dev edge.

Less bandwidth Direct Sync streams only what changed since your last request, instead of resending the full payload every time.

Compact wire format Direct Wire is a binary protocol tuned for Web3 traffic — smaller frames and faster decode than JSON-RPC.

Built-in failover Requests reroute through a healthy path automatically when an upstream is unavailable. No retry logic to write.

Drop-in Plugs into native fetch, so viem, ethers, and your own code work unchanged. Only Direct.dev URLs are intercepted.

Install

npm install @direct.dev/sdk

Quick start

Run install() once at app startup and you're done:

import { install } from "@direct.dev/sdk";

install();

const res = await fetch("https://rpc.direct.dev/v1/<project>.<token>/ethereum", {
  method: "POST",
  headers: { "Content-Type": "application/json" },
  body: JSON.stringify({ jsonrpc: "2.0", id: 1, method: "eth_blockNumber", params: [] }),
});

const { result } = await res.json();
// "0x134a1c0"

That's it. Every request to a Direct.dev RPC URL now goes through the SDK.

With options

install({
  logging: { client: "warn", requests: "summary" },
});

Without touching globals

If you'd rather not wrap globalThis.fetch (e.g. inside a library, or to scope to a single instance), use createFetch():

import { createFetch } from "@direct.dev/sdk";

const directFetch = createFetch({
  logging: { client: "info" },
});

const res = await directFetch("https://rpc.direct.dev/v1/<project>.<token>/ethereum", {
  method: "POST",
  headers: { "Content-Type": "application/json" },
  body: JSON.stringify({ jsonrpc: "2.0", id: 1, method: "eth_blockNumber", params: [] }),
});

const { result } = await res.json();

Pick one — install() or createFetch(). Don't mix them.

Using with viem

With install(), viem (and anything else that reaches for fetch) just works:

import { install } from "@direct.dev/sdk";
import { createPublicClient, http } from "viem";
import { mainnet } from "viem/chains";

install();

const client = createPublicClient({
  chain: mainnet,
  transport: http("https://rpc.direct.dev/v1/<project>.<token>/ethereum"),
});

await client.getBlockNumber();

If you'd rather keep the global fetch untouched, pass createFetch() directly:

import { createPublicClient, http } from "viem";
import { mainnet } from "viem/chains";
import { createFetch } from "@direct.dev/sdk";

const directFetch = createFetch({ logging: { client: "info" } });

const client = createPublicClient({
  chain: mainnet,
  transport: http("https://rpc.direct.dev/v1/<project>.<token>/ethereum", {
    fetch: directFetch,
  }),
});

Preload

Warm endpoints at startup so the first request resolves locally.

In the browser, prefer an HTML preload link. It lets the browser start fetching the warmup payload before your JS bundle even loads:

<link
  rel="preload"
  as="fetch"
  crossorigin="anonymous"
  href="https://rpc.direct.dev/v1/<project>.<token>/ethereum"
/>

On the server, or in environments without preload links, pass preload to install():

install({
  preload: [
    "https://rpc.direct.dev/v1/<project>.<token>/ethereum",
    "https://rpc.direct.dev/v1/<project>.<token>/sonic",
  ],
});

Configuration

| Option | Type | Default | Description | | --- | --- | --- | --- | | logging.client | "silent" \| "error" \| "warn" \| "info" \| "debug" | "warn" | Operational / lifecycle log verbosity. | | logging.requests | "off" \| "summary" \| "debug" | "off" | Per-request tracing. | | logging.onEvent | (event: LogEvent) => void | — | Structured event sink. Replaces console output when set. | | fetch | typeof fetch | globalThis.fetch | Underlying fetch to wrap. | | createWebSocket | (url) => WebSocket | globalThis.WebSocket | WebSocket factory for Direct Wire sync. | | preload | string[] | auto from <link rel="preload"> | Endpoint URLs to warm at startup. In the browser, the SDK already picks up <link rel="preload"> tags automatically — use this option for SSR / non-browser runtimes, or to add endpoints not declared in the HTML. |

fetch

Wrap a specific implementation instead of globalThis.fetch. Useful in tests, custom runtimes, or when you need a createFetch() instance that bypasses an existing install():

const directFetch = createFetch({
  fetch: window.fetch.bind(window),
});

createWebSocket

Provide your own constructor for the Direct Wire sync connection. Handy for instrumentation, tests, or runtimes where globalThis.WebSocket isn't what you want:

install({
  createWebSocket: (url) => new WebSocket(url),
});

Logging

The logging option covers three independent concerns:

  • logging.client — operational logs (preload, sync, client phases).
  • logging.requests — per-request tracing.
  • logging.onEvent — a structured sink. When set, events go here instead of the console.

logging.client and logging.requests don't gate each other — requests: "summary" still logs request summaries when client is "warn".

logging.client

| Level | What's emitted | | --- | --- | | silent | Nothing. | | error | Errors only. [direct:ERROR] Batch contains duplicate request IDs { ids: [1, 1] } | | warn | Errors + warnings. [direct:WARN] Request failed { input: ..., err: ... } | | info | Sparse operational summaries, including live sync connection state. | | debug | Full lifecycle: preload, sync, client phases. |

Example debug output:

[direct:DEBUG] preload.phase {
  phase: "applied",
  client_instance_id: "client_ethereum_f47ac10b_1",
  network_id: "ethereum"
}
[direct:DEBUG] client.phase {
  phase: "created",
  client_instance_id: "client_ethereum_f47ac10b_1",
  network_id: "ethereum"
}
[direct:INFO] sync.connection {
  client_instance_id: "client_ethereum_f47ac10b_1",
  network_id: "ethereum",
  connected: true,
  transport: "wire_socket",
  reason: "started"
}
[direct:INFO] sync.ready {
  client_instance_id: "client_ethereum_f47ac10b_1",
  network_id: "ethereum",
  ready: true,
  transport: "wire_socket",
  reason: "block_state_available",
  current_block_height: "0x134a1c0"
}
[direct:INFO] block.advanced {
  client_instance_id: "client_ethereum_f47ac10b_1",
  network_id: "ethereum",
  source: "wire_socket",
  current_block_height: "0x134a1c1"
}

logging.requests

| Level | What's emitted | | --- | --- | | off | No request tracing. | | summary | One concise resolution log per handled request. | | debug | request_resolution + request_pipeline_resolution + request_handled + block.state_probe. |

Summary example:

[direct:REQUEST] request_resolution {
  method: "eth_blockNumber",
  latency_ms: 8,
  stage_type: "cache",
  stage_name: "local_memory_cache"
}

Debug example (a single request):

[direct:REQUEST_DEBUG] request_pipeline_resolution {
  method: "eth_call",
  latency_ms: 12,
  stage_type: "cache",
  stage_name: "continuum_cache"
}
[direct:REQUEST_DEBUG] request_handled {
  req: { jsonrpc: "2.0", id: 1, method: "eth_call", params: [...] },
  res: { jsonrpc: "2.0", id: 1, result: "0x1" },
  latency_ms: 12
}

logging.onEvent

Get events as structured objects — useful for dashboards, telemetry, or piping into your own observability stack:

import { install, type LogEvent } from "@direct.dev/sdk";

const onDirectEvent = (event: LogEvent) => {
  dashboard.push(event);
};

install({
  logging: {
    client: "debug",
    requests: "debug",
    onEvent: onDirectEvent,
  },
});

Event shape:

type LogEvent = {
  level: "debug" | "info" | "warn" | "error";
  name: string;
  value: Record<string, unknown>;
  timestamp: number;
};

Stable public events — always safe to consume:

  • request_resolution
  • preload.phase
  • preload.clock_sync
  • sync.rebuild
  • sync.connection
  • sync.ready
  • block.advanced
  • client.phase

Debug-only diagnostics — only emitted when the relevant log level is active:

  • request_pipeline_resolution
  • request_handled
  • block.state_probe

The SDK exports LogEvent, LoggingOptions, and CreateFetchOptions for typed integrations.

Inspecting the live client

The SDK intercepts a special JSON-RPC method, direct_client_status, and answers it locally without touching the network. Useful for debugging your integration:

const res = await fetch("https://rpc.direct.dev/v1/<project>.<token>/ethereum", {
  method: "POST",
  headers: { "Content-Type": "application/json" },
  body: JSON.stringify({
    jsonrpc: "2.0",
    id: 1,
    method: "direct_client_status",
    params: [],
  }),
});

const { result } = await res.json();
// {
//   initialized: true,
//   projectId: "f47ac10b-58cc-4372-a567-0e02b2c3d479",
//   projectToken: "abc123",
//   networkId: "ethereum",
//   baseUrl: "https://rpc.direct.dev",
//   logging: { client: "warn", requests: "off" }
// }

How it works

The SDK only takes over POST requests whose body is JSON-RPC and whose URL matches a Direct.dev RPC endpoint:

  • https://rpc.direct.dev/v1/<project>.<token>/<network>
  • https://staging.rpc.direct.dev/v1/<project>.<token>/<network>
  • https://prod.rpc.direct.dev/v1/<project>.<token>/<network>

License

Provided under the Direct.dev Terms and Conditions. Use of this package requires agreement to those terms.

For questions, reach out at [email protected].