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

@rudderjs/http

v1.0.0

Published

Fluent HTTP client for RudderJS — retries, timeouts, pools, interceptors, and Http.fake() for testing

Readme

@rudderjs/http

Fluent HTTP client for RudderJS — retries, timeouts, request/response interceptors, concurrent pools, and Http.fake() for testing.

Installation

pnpm add @rudderjs/http

Basic requests

import { Http } from '@rudderjs/http'

// Simple GET
const res = await Http.get('https://api.example.com/users')
const users = res.json<User[]>()

// POST with JSON body
const res = await Http.post('https://api.example.com/users', { name: 'Alice' })

// PUT, PATCH, DELETE
await Http.put('/api/users/1', { name: 'Alice' })
await Http.patch('/api/users/1', { name: 'Alice' })
await Http.delete('/api/users/1')
await Http.head('/api/health')

Response

res.status        // → 200
res.body          // → raw response string
res.headers       // → Record<string, string>
res.ok()          // → true if 2xx
res.json<T>()     // → parsed JSON (throws on invalid JSON)

Fluent configuration

Methods can be chained before sending:

await Http
  .baseUrl('https://api.example.com')
  .withToken('secret-token')
  .withHeaders({ 'X-App': 'myapp' })
  .withQueryParameters({ page: 1, limit: 20 })
  .retry(3, 200)
  .timeout(5000)
  .get('/users')

Authentication

Http.withToken('bearer-token').get('/api/me')
Http.withBasicAuth('user', 'pass').get('/api/data')

Request body

// JSON (default when using .withBody() or verb shorthand with data)
Http.post('/api/users', { name: 'Alice' })

// Form-encoded
Http.asForm().withBody({ email: '[email protected]', password: 'secret' }).post('/auth/login')

Query parameters

Http.withQueryParameters({ q: 'hello', page: 2 }).get('/search')
// → GET /search?q=hello&page=2

Retries

// Retry up to 3 times with 200ms delay between attempts (grows linearly)
await Http.retry(3, 200).get('/api/data')

Timeout

// Abort after 5 seconds
await Http.timeout(5000).get('/api/slow')
// Throws: [RudderJS/Http] Request timed out after 5000ms

Concurrent pools

Run multiple requests in parallel with an optional concurrency limit:

import { Http } from '@rudderjs/http'

const results = await Http.pool(pool => {
  pool.add(http => http.get('/api/users'))
  pool.add(http => http.get('/api/posts'))
  pool.add(http => http.post('/api/events', { type: 'view' }))
})
  .concurrency(2)
  .send()

const [users, posts, _event] = results

Results are returned in submission order.


Interceptors

Intercept and transform requests or responses globally:

// Global request interceptor (e.g. add auth header to all requests)
Http.interceptRequest(req => {
  return req.withHeaders({ 'X-Request-Id': crypto.randomUUID() })
})

// Global response interceptor (e.g. log all responses)
Http.interceptResponse(res => {
  console.log(`[http] ${res.status}`)
  return res
})

// Clear all interceptors
Http.clearInterceptors()

Per-request interceptors:

Http
  .withRequestMiddleware(req => req.withHeaders({ 'X-Custom': 'value' }))
  .withResponseMiddleware(async res => {
    if (!res.ok()) throw new Error(`HTTP ${res.status}`)
    return res
  })
  .get('/api/data')

Testing with Http.fake()

import { Http } from '@rudderjs/http'

// Create a fake
const fake = Http.fake()

// Register responses
fake.register('api.example.com/users', {
  status:  200,
  body:    [{ id: 1, name: 'Alice' }],
  headers: {},
})

// Sequence — responses cycle through in order, last one repeats
fake.register('api.example.com/flaky', [
  { status: 503, body: '', headers: {} },
  { status: 200, body: { ok: true }, headers: {} },
])

// Prevent unmocked requests from hitting the network
fake.preventStrayRequests()

// Use the faked client in tests
const client = fake.client()
const res = await client.get('https://api.example.com/users')
res.json() // → [{ id: 1, name: 'Alice' }]

// Assertions
fake.assertSent(req => req.url.includes('/users'))
fake.assertNotSent(req => req.method === 'DELETE')
fake.assertSentCount(1)
fake.assertNothingSent()  // would fail — 1 request was sent

// Inspect all recorded requests
fake.recorded()  // → RecordedRequest[]

URL patterns can be strings (substring match) or regular expressions:

fake.register(/\/users\/\d+/, { status: 200, body: { id: 1 }, headers: {} })

http() factory

For creating pre-configured client instances (e.g. per-service API clients):

import { http } from '@rudderjs/http'

const githubClient = http()
  .baseUrl('https://api.github.com')
  .withToken(process.env['GITHUB_TOKEN']!)
  .withHeaders({ Accept: 'application/vnd.github.v3+json' })

const res = await githubClient.get('/repos/rudderjs/rudder')

API Reference

Http (static facade)

| Method | Description | |--------|-------------| | Http.get(url, query?) | GET request | | Http.post(url, data?) | POST request | | Http.put(url, data?) | PUT request | | Http.patch(url, data?) | PATCH request | | Http.delete(url) | DELETE request | | Http.head(url) | HEAD request | | Http.baseUrl(url) | Set base URL | | Http.withHeaders(h) | Set headers | | Http.withToken(token) | Bearer auth | | Http.withBasicAuth(u, p) | Basic auth | | Http.withBody(data) | Set JSON body | | Http.asForm() | Form-encoded body | | Http.withQueryParameters(q) | Append query params | | Http.retry(times, delay?) | Configure retries | | Http.timeout(ms) | Configure timeout | | Http.interceptRequest(fn) | Add global request interceptor | | Http.interceptResponse(fn) | Add global response interceptor | | Http.clearInterceptors() | Remove all global interceptors | | Http.pool(configure) | Create a concurrent request pool | | Http.fake() | Create a FakeManager for testing |

FakeManager

| Method | Description | |--------|-------------| | .register(pattern, response\|responses[]) | Register fake response(s) | | .preventStrayRequests() | Throw on unregistered URLs | | .client() | Get a PendingRequest wired to this fake | | .recorded() | All recorded requests | | .assertSent(fn) | Assert a matching request was sent | | .assertNotSent(fn) | Assert no matching request was sent | | .assertSentCount(n) | Assert exactly n requests were sent | | .assertNothingSent() | Assert no requests were sent |