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

@typescriptprime/securereq

v2.0.0

Published

SecureReq is a lightweight utility for making secure HTTP requests, implemented in TypeScript

Downloads

2,097

Readme

SecureReq 🔐

SecureReq is a lightweight TypeScript utility for secure HTTP requests with strict TLS defaults, automatic http/1.1 to http/2 negotiation, streaming I/O, and typed response parsing.


🚀 Quick Summary

  • Class-first API that probes each origin with http/1.1 first, then upgrades future requests to http/2 when appropriate.
  • Also exposes SimpleSecureReq, a shared client instance for one-off requests without manual construction.
  • Automatic HTTP/2 probing is conservative: only safe body-less auto requests are retried from negotiation failure to http/1.1.
  • Supports response compression with zstd, gzip, and deflate.
  • Supports optional redirect following with configurable redirect limits.
  • Supports streaming uploads and streaming downloads.
  • Defaults to TLSv1.3, Post Quantum Cryptography key exchange, a limited set of strongest ciphers, and a User-Agent header.

📦 Installation

npm install @typescriptprime/securereq

Requirements: Node.js >= 24


Usage Examples 🔧

Create a client and reuse it per origin:

import { Readable } from 'node:stream'
import { SecureReq } from '@typescriptprime/securereq'

const client = new SecureReq()

// First request to an origin uses http/1.1 probing.
const first = await client.Request(new URL('https://api64.ipify.org?format=json'), {
  ExpectedAs: 'JSON',
})

// Later safe requests to the same origin can probe and establish http/2 automatically.
const second = await client.Request(new URL('https://api64.ipify.org?format=json'), {
  ExpectedAs: 'JSON',
})

console.log(first.Protocol) // 'http/1.1'
console.log(second.Protocol) // 'http/2' when available after the safe probe

// Follow redirects automatically
const redirected = await client.Request(new URL('https://example.com/old-path'), {
  ExpectedAs: 'String',
  FollowRedirects: true,
  MaxRedirects: 5,
})

console.log(redirected.Body)

// Stream upload + stream download
const streamed = await client.Request(new URL('https://example.com/upload'), {
  HttpMethod: 'POST',
  Payload: Readable.from(['chunk-1', 'chunk-2']),
  ExpectedAs: 'Stream',
})

for await (const chunk of streamed.Body) {
  console.log(chunk)
}

For quick one-off requests, you can use the exported shared client:

import { SimpleSecureReq } from '@typescriptprime/securereq'

const response = await SimpleSecureReq.Request(new URL('https://api64.ipify.org?format=json'), {
  ExpectedAs: 'JSON',
})

console.log(response.Body)

API Reference 📚

new SecureReq(Options?)

  • Recommended entry point.
  • Keeps per-origin capability state:
    • first request is sent with http/1.1
    • Accept-Encoding: zstd, gzip, deflate
    • later safe requests can probe http/2, and capability updates only reflect observed protocol/compression evidence
  • Close() closes cached http/2 sessions.
  • OriginCapabilityCacheLimit bounds remembered origin capability entries with LRU-style eviction.
  • Invalid constructor options fail fast during initialization.

SimpleSecureReq

  • An exported shared SecureReq instance for simple or occasional requests.
  • Useful when you do not need to manage your own client lifecycle manually.
  • Supports the same .Request(), .GetOriginCapabilities(), and .Close() methods as a manually created SecureReq instance.

client.Request(Url, Options?)

  • Url: URL — Target URL (must be an instance of URL).
  • Options?: HTTPSRequestOptions — Optional configuration object.

Returns:

  • If ExpectedAs is specified, Promise<HTTPSResponse<T>>
  • If ExpectedAs is omitted, Promise<HTTPSResponse<unknown>>

Throws:

  • TypeError when Url is not a URL instance.
  • Error on request failure or on failed response parsing (e.g., invalid JSON).

HTTPSRequestOptions

Fields:

  • TLS?: { IsHTTPSEnforced?: boolean, MinTLSVersion?: 'TLSv1.2'|'TLSv1.3', MaxTLSVersion?: 'TLSv1.2'|'TLSv1.3', Ciphers?: string[], KeyExchanges?: string[], RejectUnauthorized?: boolean }
    • Defaults: IsHTTPSEnforced: true, both Min and Max set to TLSv1.3, a small secure cipher list and key exchange choices.
    • When IsHTTPSEnforced is true, a non-https: URL will throw.
    • KeyExchanges is forwarded to Node.js as the TLS supported groups / curve list. For strict TLSv1.2 + ECDSA servers, overly narrow values such as only X25519 may fail; include a compatible certificate curve such as P-256 when needed.
  • HttpHeaders?: Record<string,string> — Custom headers. A User-Agent header is provided by default.
  • HttpMethod?: 'GET'|'POST'|'PUT'|'DELETE'|'PATCH'|'HEAD'|'OPTIONS'
  • Payload?: string | ArrayBuffer | Uint8Array | Readable | AsyncIterable
  • ExpectedAs?: 'JSON'|'String'|'ArrayBuffer'|'Stream' — How to parse the response body.
    • Omitting ExpectedAs keeps the runtime extension heuristic (.json, .txt, fallback ArrayBuffer) but the body type is intentionally unknown.
  • PreferredProtocol?: 'auto'|'http/1.1'|'http/2'|'http/3'
    • http/3 is currently a placeholder preference and uses the same TCP/TLS negotiation path as http/2 until native HTTP/3 transport is added.
  • EnableCompression?: boolean — Enables automatic Accept-Encoding negotiation and transparent response decompression.
  • FollowRedirects?: boolean — Follows redirect responses with a Location header.
  • MaxRedirects?: number — Maximum redirect hops when FollowRedirects is enabled. Default: 5.
  • TimeoutMs?: number — Aborts the request if headers or body transfer exceed the given number of milliseconds.
  • Signal?: AbortSignal — Cancels the request using a standard abort signal.

HTTPSResponse

  • { StatusCode: number, Headers: Record<string,string|string[]|undefined>, Body: T, Protocol: 'http/1.1'|'http/2', ContentEncoding: 'identity'|'zstd'|'gzip'|'deflate', DecodedBody: boolean }

Notes:

  • If ExpectedAs is omitted, a heuristic is still used at runtime: .jsonJSON, .txtString, otherwise ArrayBuffer.
  • Because omitted ExpectedAs may produce different runtime body shapes, the TypeScript return type is unknown. Prefer explicit ExpectedAs in application code.
  • When ExpectedAs is JSON, the body is parsed and an error is thrown if parsing fails.
  • When ExpectedAs is Stream, the body is returned as a Node.js readable stream.
  • Redirects are returned as-is by default. Set FollowRedirects: true to follow them.
  • 301/302 convert POST into GET, 303 converts non-HEAD methods into GET, and 307/308 preserve method and payload.
  • Redirects that require replaying a streaming payload are rejected instead of silently re-sending the stream.

Security & Behavior Notes 🔐

  • Strict TLS defaults lean on TLSv1.3 and a reduced cipher list to encourage secure transport out of the box.
  • TLS options are forwarded to Node's HTTPS or http/2 TLS layer (minVersion, maxVersion, ciphers, ecdhCurve).
  • When SecureReq performs an ALPN probe for HTTPS, the negotiated TLSSocket is reused for the actual http/2 or http/1.1 request instead of opening a second TLS connection.
  • The library uses zod for runtime validation of options.
  • Compression negotiation is origin-scoped. Subdomains are tracked independently.
  • GetOriginCapabilities().PreferredProtocol is updated from actual observed transport, and automatic fallback only occurs for safe negotiation failures before request bytes are sent.
  • GetOriginCapabilities().SupportedCompressions is only narrowed when the response provided actual compression evidence.
  • GetOriginCapabilities().PreferredProtocol reflects the currently usable transport (http/1.1 or http/2), while HTTP3Advertised records whether the origin advertised h3.
  • http/3 advertisement points are recorded from response headers, but Node.js built-in http/3 transport is not yet used.

Development & Testing 🧪

  • Build: npm run build (uses tsc -p sources/tsconfig.json)
  • Test: npm test (uses ava)
  • Lint: npm run lint

Contributing

Contributions, bug reports and PRs are welcome — please follow the repository's contribution guidelines.


License

This project is licensed under the Apache-2.0 License. See the LICENSE file for details.