
Security News
GitHub Actions Checkout Now Blocks Risky pull_request_target Checkouts
GitHub Actions checkout now blocks risky pull_request_target checkouts by default to help prevent pwn request supply chain attacks.
@eric8810/catcher-napi-http
Advanced tools
Rust-powered HTTP + SSE client for Node.js via napi-rs. Part of the catcher toolkit.
Wraps catcher-http's HttpTransport — reqwest + retry + circuit breaker, compiled to a native addon. Includes typed TypeScript wrappers with auto-generated .d.ts.
Migrate from 0.2.x → 0.3.x — see napi API docs for full details.
v0.3.2:
HttpResponse,RequestOptions,Metricstypes now correctly use camelCase (auto-generated by NAPI-RS). JSON config types (HttpClientConfig, etc.) remain snake_case.
| Change | Before | After |
|---|---|---|
| Entry point | client.js / client.d.ts | dist/client.js / dist/client.d.ts |
| Config format | JSON.stringify(config) only | Typed object or JSON string |
| Class names | JsHttpClient, JsSseStream, JsSseClient | HttpClient, SseStream, SseClient |
| Callback events | Raw JSON strings, need JSON.parse() | Typed objects, auto-parsed |
| Default backoff | Exponential | Fixed |
Default connect_timeout_ms | 5000 | 10000 |
Default min_backoff_ms | 500 | 100 |
Default max_backoff_ms | 30000 | 10000 |
| camelCase fields | Not supported | #[serde(alias)] — both snake_case and camelCase accepted |
- const client = require('@eric8810/catcher-napi-http').HttpClient
- const c = new HttpClient(JSON.stringify({ base_url: '...' }))
+ import { HttpClient } from '@eric8810/catcher-napi-http'
+ const c = new HttpClient({ base_url: '...' })
npm install @eric8810/catcher-napi-http
Pre-built binaries available for Linux (x64/arm64 gnu/musl), macOS (x64/arm64), and Windows (x64/arm64). Installed automatically via platform-specific optionalDependencies.
import { HttpClient } from '@eric8810/catcher-napi-http'
import type { HttpClientConfig, SseEvent } from '@eric8810/catcher-napi-http/types'
// Config as typed object (recommended) or JSON string
const client = new HttpClient({
base_url: 'https://api.example.com',
connect_timeout_ms: 10000,
retry: { max_attempts: 3, backoff: 'Fixed' },
circuit_breaker: { failure_threshold: 5, reset_timeout_ms: 30000 },
dns: {
mode: 'catcher',
cache_size: 512,
cache_ttl_secs: 300,
negative_ttl_secs: 60,
stale_ttl_secs: 3600,
stale_on_error: true,
host_mapping: { 'api.internal': '10.0.0.10' },
},
msgpack: true,
})
// GET
const resp = await client.get('/users/1')
console.log(resp.status, resp.body.toString())
// POST
await client.post('/messages', Buffer.from(JSON.stringify({ text: 'hello' })), {
contentType: 'application/json',
})
// Circuit breaker state
console.log(client.circuitBreakerState()) // 'closed' | 'open' | 'half-open'
// SSE (one-shot stream)
import { SseStream } from '@eric8810/catcher-napi-http/sse'
const stream = new SseStream(
{ url: 'https://stream.example.com/events' },
(event: SseEvent) => {
if (event.type === 'Line') console.log(event.data)
},
)
// later: stream.close()
// SSE (auto-reconnect client)
import { SseClient } from '@eric8810/catcher-napi-http/sse'
const sse = new SseClient(
{
url: 'https://stream.example.com/events',
reconnect: { max_retries: 10, initial_delay_ms: 1000 },
},
(event: SseEvent) => {
if (event.type === 'Line') console.log(event.data)
},
)
new HttpClient(config: HttpClientConfig | string)Create a client from a typed config object or JSON string. All fields are optional with sensible defaults. Supports both snake_case and camelCase field names.
interface HttpClientConfig {
base_url?: string
connect_timeout_ms?: number // default: 10000
response_timeout_ms?: number // default: 30000
pool?: PoolConfig
tls?: TlsConfig
dns?: DnsConfig
retry?: RetryConfig
circuit_breaker?: CircuitBreakerConfig
max_concurrency?: number // default: 50
default_headers?: Record<string, string>
hostname_override?: string
proxy?: ProxyConfig
redirect?: RedirectConfig
auth?: { username: string; password: string }
bearer_token?: string
msgpack?: boolean // default: false
}
interface DnsConfig {
mode?: 'catcher' | 'native' // default: 'catcher'
cache_size?: number // default: 512
cache_ttl_secs?: number // default: 300
negative_ttl_secs?: number // default: 60
stale_ttl_secs?: number // default: 3600
stale_on_error?: boolean // default: true
nameservers?: string[]
host_mapping?: Record<string, string>
}
When msgpack is enabled, JSON request bodies are encoded as MessagePack and MessagePack responses are decoded back to JSON bytes when the response content type contains msgpack.
| Method | Signature |
|---|---|
get(url, options?) | async (url: string, options?: RequestOptions) => HttpResponse |
post(url, body?, options?) | async (url: string, body?: Buffer, options?: RequestOptions) => HttpResponse |
put(url, body?, options?) | async (url: string, body?: Buffer, options?: RequestOptions) => HttpResponse |
delete(url, options?) | async (url: string, options?: RequestOptions) => HttpResponse |
patch(url, body?, options?) | async (url: string, body?: Buffer, options?: RequestOptions) => HttpResponse |
circuitBreakerState() | () => 'closed' | 'open' | 'half-open' |
metrics() | () => Metrics |
executeStream(method, url, body?, options?, onChunk?) | (method: string, url: string, body?: Buffer, options?: RequestOptions, onChunk?: (event: StreamEvent) => void) => void |
setAdaptiveTimeout(min, max, mult, win) | (min: number, max: number, mult: number, win: number) => void |
cancelAll() | () => void |
cancelRequest(requestId) | (requestId: number) => boolean |
nextRequestId() | () => number |
RequestOptionsPer-request options (NAPI-RS auto-generated, camelCase fields):
interface RequestOptions {
headers?: Record<string, string>
timeoutMs?: number
contentType?: string
}
HttpResponseNAPI-RS auto-generated (camelCase fields):
interface HttpResponse {
status: number
headers: Record<string, string>
body: Buffer
elapsedMs: number
}
MetricsRuntime metrics snapshot (NAPI-RS auto-generated, camelCase fields):
interface Metrics {
httpRequests: number
httpSuccessRate: number
httpAvgLatencyUs: number
httpRetries: number
wsConnectSuccessRate: number
wsDisconnects: number
wsMessagesSent: number
wsMessagesReceived: number
cbOpenCount: number
queueTimeouts: number
}
Note:
HttpResponse,RequestOptions, andMetricsare auto-generated by NAPI-RS (camelCase fields). JSON config types likeHttpClientConfiguse snake_case (serde-based).
| Class | Description |
|---|---|
SseStream | One-shot SSE stream (no auto-reconnect) |
SseClient | Long-lived SSE client with auto-reconnect |
new SseStream(config: SseClientConfig | string, onEvent: (event: SseEvent) => void)
new SseClient(config: SseClientConfig | string, onEvent: (event: SseEvent) => void)
type SseEvent =
| { type: 'Line'; data: string }
| { type: 'Error'; message: string }
| { type: 'End' }
StreamEventtype StreamEvent =
| { type: 'Headers'; status: number; headers: Record<string, string> }
| { type: 'Chunk'; data: string } // base64 encoded
| { type: 'Done' }
| { type: 'Error'; message: string }
Requires Rust toolchain.
npm run build # napi build + tsup compile
npm run build:ts # tsup only (no Rust rebuild)
MIT
FAQs
catcher HTTP native addon for Node.js via napi-rs
We found that @eric8810/catcher-napi-http demonstrated a healthy version release cadence and project activity because the last version was released less than a year ago. It has 1 open source maintainer collaborating on the project.
Did you know?

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Security News
GitHub Actions checkout now blocks risky pull_request_target checkouts by default to help prevent pwn request supply chain attacks.

Product
Socket now supports Custom Roles and Repository Access Permissions so organizations can control who can access specific repositories and actions.

Product
Socket MCP now lets AI assistants review org alerts, investigate threats using the Socket threat feed, and inspect package files in addition to dependency scoring.