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

@ismail-elkorchi/http-client

v0.1.0

Published

Strict streaming HTTP/1.1 and HTTP/2 client with bounded transfers and network safety.

Downloads

86

Readme

HTTP Client

A strict streaming HTTP/1.1 and HTTP/2 client with bounded transfers, address-pinned DNS resolution, explicit outcomes, redirects, content decoding, proxy and TLS configuration, and memory-to-file response storage.

The package targets Node.js 24 or newer. Its installed package is also tested through Deno 2.9's Node compatibility layer.

Install

From npm:

npm install @ismail-elkorchi/http-client

From JSR:

import { NodeHttpClient } from "jsr:@ismail-elkorchi/http-client@^0.1.0";

Stream a response

import { NodeHttpClient } from "@ismail-elkorchi/http-client";

const client = new NodeHttpClient();

try {
  const result = await client.fetch("https://example.com/");
  if (result.kind === "failure") {
    console.error(result.error.code, result.error.message);
  } else {
    const bytes = new Uint8Array(await new Response(result.body).arrayBuffer());
    const completion = await result.completion;

    if (completion.kind === "complete") {
      console.log(result.statusCode, bytes.byteLength);
      console.log(completion.transfer.wireBytesReceived);
    } else if (completion.kind === "failure") {
      console.error(completion.error.code, completion.error.message);
    }
  }
} finally {
  await client.close();
}

request() performs one exchange. fetch() follows redirects. Both resolve when the response field section arrives, while completion reports the final body transfer outcome. Consume or cancel every streaming response body so its connection and deadline can be released.

Invalid definitions and request shapes reject with HttpConfigurationError. Network, protocol, timeout, transfer-limit, and cancellation failures use the failure result with a stable HttpClientError.code.

Buffer a response

import {
  NodeHttpClient,
  disposeResponseBody,
  readResponseBody,
} from "@ismail-elkorchi/http-client";

const client = new NodeHttpClient({
  responseStorage: {
    memoryThresholdBytes: 512 * 1024,
  },
});

try {
  const result = await client.fetchBuffered("https://example.com/");
  if (result.kind === "response") {
    try {
      const bytes = await readResponseBody(result.body);
      console.log(bytes.byteLength);
      console.log(result.attempts.at(-1)?.transfer?.wireBytesReceived);
    } finally {
      await disposeResponseBody(result.body);
    }
  }
} finally {
  await client.close();
}

Responses larger than memoryThresholdBytes are written to private files. Dispose buffered response bodies after use. openResponseBodyFile() adopts an existing file without granting disposal permission to delete it, while collectResponseBody() stores a byte stream under an explicit limit and storage policy.

Send request bodies

Text, byte, stream, and multipart bodies are replayable across redirects. Stream factories are invoked only after network admission and must return a fresh ReadableStream<Uint8Array> or AsyncIterable<Uint8Array> each time.

await client.fetch("https://example.com/upload", {
  method: "POST",
  body: {
    kind: "stream",
    contentLength: 3,
    create: () =>
      new ReadableStream({
        start(controller) {
          controller.enqueue(new Uint8Array([1, 2, 3]));
          controller.close();
        },
      }),
  },
});

Extension methods are explicit:

import { defineHttpMethod } from "@ismail-elkorchi/http-client";

await client.request("https://example.com/resource", {
  method: defineHttpMethod("PROPFIND"),
});

HTTP fields

Requests accept ordered field lines and responses expose an immutable HttpFields collection. Repeated lines, including set-cookie, remain separate.

const result = await client.request("https://example.com/", {
  fields: [
    { name: "x-trace", value: "first" },
    { name: "x-trace", value: "second" },
  ],
});

if (result.kind === "response") {
  console.log(result.fields.all("set-cookie"));
}

Use first(), all(), has(), lines(), or iteration without losing field line order. toHeaders() is available when the Web Headers representation is appropriate. Request field values use the transport's Latin-1 byte model.

Network safety, proxies, and TLS

Public addresses are allowed by default. Local, private, special-purpose, and mixed public/non-public DNS results are rejected. A custom resolver is validated and its approved addresses are snapshotted before connection pinning.

const localClient = new NodeHttpClient({
  networkSafety: { allowLocalhost: true },
});

Applications that evaluate targets before making a request can reuse the same policy semantics through NetworkSafetyPolicy. Its decide() operation accepts an optional abort signal.

An explicit HTTP proxy resolves the target itself, so proxy use requires an explicit opt-out from target address pinning:

const proxyClient = new NodeHttpClient({
  networkSafety: { enabled: false },
  proxy: { url: "http://proxy.example:8080/" },
});

protocolPreference: "http2" requires a TLS origin and verified HTTP/2 ALPN negotiation before request bytes are sent. TLS certificate authorities, client certificates, protocol versions, ciphers, and server names are configurable.

Limits, deadlines, and observation

Client and request configuration controls request body bytes, request and response field bytes, wire response bytes, decoded response bytes, content encoding layers, redirects, retained origins, and connections per origin.

Set timeouts.totalMs or timeouts.responseBodyProgressMs to null to disable that deadline. The body-progress deadline runs while a consumer waits for a chunk and pauses while the consumer applies backpressure. Connect and response-field deadlines remain bounded.

Observers receive discriminated attempt, upload, response, and download events. Synchronous and asynchronous observer failures are contained. Session adapters can synchronously or asynchronously prepare request fields and accept response state for cookies, authentication, tracing, and application policy.

Lifecycle

close() stops new work and drains accepted exchanges. destroy() aborts active deadlines and response bodies before closing the transport. Concurrent shutdown calls share one completion operation.

Public API

The runtime entrypoint exports:

  • NodeHttpClient
  • HttpFields and mergeHttpFields()
  • NetworkSafetyPolicy
  • parseContentLength() and requestAfterRedirect()
  • defineHttpMethod()
  • HttpClientError, HttpConfigurationError, and HttpClientStateError
  • collectResponseBody(), openResponseBodyFile(), readResponseBody(), responseBodyPrefix(), responseBodySize(), responseBodyStream(), and disposeResponseBody()
  • ResponseBodyCollectionLimitError

The same entrypoint exports the TypeScript definitions for configuration, requests, bodies, observations, transfers, failures, and response outcomes.

Development

npm ci
npm run check

The check runs strict TypeScript, lint, runtime and public-type tests, offline packed-package consumers for Node.js and Deno, and the JSR publication dry run.