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

stealth-fetch

v0.2.1

Published

HTTP/1.1 + HTTP/2 client for Cloudflare Workers via cloudflare:sockets, bypassing cf-* header injection

Downloads

202

Readme

stealth-fetch

License npm

HTTP client for Cloudflare Workers that bypasses automatic cf-* header injection. Built on cloudflare:sockets with platform TLS and WASM TLS fallbacks, depending on the entry point.

Why stealth-fetch

Cloudflare Workers' built-in fetch automatically injects cf-connecting-ip, cf-ipcountry, cf-ray, and other headers into every outbound request. These headers reveal that requests originate from a Workers environment, which can cause issues when proxying to third-party APIs.

stealth-fetch uses raw TCP sockets (cloudflare:sockets) with a WASM-compiled TLS stack (rustls) to establish connections directly, completely bypassing the Workers HTTP pipeline and its header injection.

Features

  • No cf-* headers --- raw socket connections bypass Workers HTTP pipeline
  • HTTP/1.1 + HTTP/2 --- ALPN negotiation with protocol caching
  • WASM TLS --- rustls-based TLS 1.2/1.3 compiled to WebAssembly
  • NAT64 hedged retry --- automatic fallback through multiple NAT64 prefixes with EWMA health scoring
  • Connection pooling --- HTTP/2 multiplexing and connection reuse
  • Redirects, retries, timeouts --- configurable with sensible defaults
  • Raw headers preserved --- original order and multi-value headers maintained
  • Three entry points --- stealth-fetch (full), stealth-fetch/web (Worker + NAT64/WASM fallback), and stealth-fetch/lite (Worker direct TLS)

Quick Start

npm install stealth-fetch
import { request } from "stealth-fetch";

const response = await request("https://api.example.com/v1/chat/completions", {
  method: "POST",
  headers: {
    Authorization: "Bearer sk-...",
    "Content-Type": "application/json",
  },
  body: JSON.stringify({
    model: "gpt-4",
    messages: [{ role: "user", content: "Hello" }],
  }),
});

const data = await response.json();

Worker Entry Point (NAT64/WASM fallback, no nodejs_compat)

import { request } from "stealth-fetch/web";

const response = await request("https://httpbin.org/headers", {
  headers: { "User-Agent": "my-worker/1.0" },
});
const data = await response.json();

The /web entry uses only Web platform APIs (cloudflare:sockets, WebAssembly, ReadableStream) and supports HTTP/1.1 only.

Lite Entry Point (platform TLS direct, no nodejs_compat)

import { request } from "stealth-fetch/lite";

const response = await request("https://httpbin.org/headers", {
  headers: { "User-Agent": "my-worker/1.0" },
});
const data = await response.json();

The /lite entry uses only Web platform APIs and supports HTTP/1.1 only. It does not include DoH detection, NAT64 fallback, or WASM TLS.

API Reference

request(url, options?)

Returns Promise<HttpResponse>.

Options

| Option | Type | Default | Description | | ---------------- | ------------------------------------------------------------ | ---------- | ------------------------------------------------------------- | | method | string | 'GET' | HTTP method | | headers | Record<string, string> | {} | Request headers | | body | string \| Uint8Array \| ReadableStream<Uint8Array> \| null | null | Request body | | protocol | 'h2' \| 'http/1.1' \| 'auto' | 'auto' | Protocol selection | | timeout | number | 30000 | Overall timeout (ms), includes retries and redirects | | headersTimeout | number | --- | Timeout waiting for response headers | | bodyTimeout | number | --- | Idle timeout waiting for body data | | signal | AbortSignal | --- | Cancellation signal | | redirect | 'follow' \| 'manual' | 'follow' | Redirect handling | | maxRedirects | number | 5 | Max redirects to follow | | decompress | boolean | true | Auto-decompress gzip/deflate | | retry | number \| RetryOptions \| false | 2 | Retry on network errors and retryable status codes | | strategy | 'compat' \| 'fast-h1' | 'compat' | compat: ALPN + h2; fast-h1: platform TLS for non-CF hosts |

RetryOptions

| Option | Type | Default | Description | | ------------- | ---------- | ----------------------------------- | --------------------- | | limit | number | 2 | Max retry attempts | | methods | string[] | GET, HEAD, OPTIONS, PUT, DELETE | Methods to retry | | statusCodes | number[] | 408, 413, 429, 500, 502, 503, 504 | Status codes to retry | | maxDelay | number | 30000 | Max retry delay (ms) |

HttpResponse

interface HttpResponse {
  status: number;
  statusText: string;
  headers: Record<string, string>;
  rawHeaders: ReadonlyArray<[string, string]>;
  protocol: "h2" | "http/1.1";
  body: ReadableStream<Uint8Array>;

  text(): Promise<string>;
  json(): Promise<unknown>;
  arrayBuffer(): Promise<ArrayBuffer>;
  getSetCookie(): string[];
}

toWebResponse(response, options?)

Converts HttpResponse to a standard Web Response. Pass { tee: true } to get a pre-cloned pair.

import { request, toWebResponse } from "stealth-fetch";

const resp = await request("https://httpbin.org/headers");
const webResp = toWebResponse(resp);

Advanced APIs

import {
  Http2Client, // HTTP/2 client with stream multiplexing
  Http2Connection, // Low-level HTTP/2 connection
  http1Request, // HTTP/1.1 over a raw socket
  clearPool, // Clear HTTP/2 connection pool
  preconnect, // Pre-establish HTTP/2 connection
  prewarmDns, // Warm DNS and CF-detection cache
  clearNat64PrefixStats, // Reset NAT64 prefix health scores
} from "stealth-fetch";

Requirements

  • Cloudflare Workers runtime
  • stealth-fetch: requires nodejs_compat compatibility flag
  • stealth-fetch/web: no compatibility flags needed
  • stealth-fetch/lite: no compatibility flags needed

License

Apache-2.0