@samveys/http-client
Retries, timeouts, concurrency pool, fakes and SSRF protection
import { createHttpClient, isForbiddenAddress, vetUserUrl } from '@samveys/http-client'
Function (3)
createHttpClient
Function
Creates an HTTP client over `fetch`-style requests. See the package README.
function createHttpClient(options?: HttpClientOptions): HttpClient;
Exported from packages/http-client/src/client.ts
isForbiddenAddress
Function
True when the literal IP address must never be contacted on behalf of a user.
function isForbiddenAddress(address: string): boolean;
Exported from packages/http-client/src/ssrf.ts
vetUserUrl
Function
Vets a user-supplied URL and returns the address the connection must be pinned to. Every address the name resolves to has to be public, so a mixed answer is refused too.
function vetUserUrl(url: URL, resolver?: HostResolver): Promise<ResolvedAddress>;
Exported from packages/http-client/src/ssrf.ts
Interface (6)
HttpClient
Interface
No documentation comment.
interface HttpClient {
request(url: string, options?: RequestOptions): Promise<Response>;
get(url: string, options?: RequestOptions): Promise<Response>;
post(url: string, options?: RequestOptions): Promise<Response>;
put(url: string, options?: RequestOptions): Promise<Response>;
patch(url: string, options?: RequestOptions): Promise<Response>;
delete(url: string, options?: RequestOptions): Promise<Response>;
/** Sends the request and parses a successful JSON response. */
json<T = unknown>(url: string, options?: RequestOptions): Promise<T>;
/** A copy of this client that treats every URL as user supplied. */
…
Show the whole declaration (20 lines)
interface HttpClient {
request(url: string, options?: RequestOptions): Promise<Response>;
get(url: string, options?: RequestOptions): Promise<Response>;
post(url: string, options?: RequestOptions): Promise<Response>;
put(url: string, options?: RequestOptions): Promise<Response>;
patch(url: string, options?: RequestOptions): Promise<Response>;
delete(url: string, options?: RequestOptions): Promise<Response>;
/** Sends the request and parses a successful JSON response. */
json<T = unknown>(url: string, options?: RequestOptions): Promise<T>;
/** A copy of this client that treats every URL as user supplied. */
…interface HttpClient {
request(url: string, options?: RequestOptions): Promise<Response>;
get(url: string, options?: RequestOptions): Promise<Response>;
post(url: string, options?: RequestOptions): Promise<Response>;
put(url: string, options?: RequestOptions): Promise<Response>;
patch(url: string, options?: RequestOptions): Promise<Response>;
delete(url: string, options?: RequestOptions): Promise<Response>;
/** Sends the request and parses a successful JSON response. */
json<T = unknown>(url: string, options?: RequestOptions): Promise<T>;
/** A copy of this client that treats every URL as user supplied. */
userUrl(url: string, options?: RequestOptions): Promise<Response>;
/** Registers fakes. Requests matching a pattern never touch the network. */
fake(table?: FakeTable): HttpClient;
/** Unfaked requests fail with SVS_E106 while faking is active. */
preventStrayRequests(): HttpClient;
allowStrayRequests(): HttpClient;
/** Requests handled since the client was created (or {@link clearRecorded}). */
recorded(): readonly RecordedRequest[];
clearRecorded(): void;
}
Exported from packages/http-client/src/contracts.ts
HttpClientOptions
Interface
No documentation comment.
interface HttpClientOptions {
/** Prefix for relative request URLs. */
readonly baseUrl?: string;
/** Per-attempt timeout. Default 10 000 ms. */
readonly timeoutMs?: number;
readonly retries?: Partial<RetryOptions>;
/** Maximum simultaneous in-flight requests. Default 8. */
readonly concurrency?: number;
/** Headers sent with every request. */
readonly headers?: Readonly<Record<string, string>>;
…
Show the whole declaration (19 lines)
interface HttpClientOptions {
/** Prefix for relative request URLs. */
readonly baseUrl?: string;
/** Per-attempt timeout. Default 10 000 ms. */
readonly timeoutMs?: number;
readonly retries?: Partial<RetryOptions>;
/** Maximum simultaneous in-flight requests. Default 8. */
readonly concurrency?: number;
/** Headers sent with every request. */
readonly headers?: Readonly<Record<string, string>>;
…interface HttpClientOptions {
/** Prefix for relative request URLs. */
readonly baseUrl?: string;
/** Per-attempt timeout. Default 10 000 ms. */
readonly timeoutMs?: number;
readonly retries?: Partial<RetryOptions>;
/** Maximum simultaneous in-flight requests. Default 8. */
readonly concurrency?: number;
/** Headers sent with every request. */
readonly headers?: Readonly<Record<string, string>>;
/** Treat every URL as user supplied (SSRF protection). Default false. */
readonly untrusted?: boolean;
/** Redirects followed (each hop is re-vetted in untrusted mode). Default 5. */
readonly maxRedirects?: number;
/** Host resolver; defaults to `node:dns/promises` `lookup(all)`. */
readonly resolver?: HostResolver;
/** Transport override (tests, custom agents). */
readonly transport?: HttpTransport;
}
Exported from packages/http-client/src/contracts.ts
RecordedRequest
Interface
A request seen by the client, kept for assertions in tests.
interface RecordedRequest {
readonly method: string;
readonly url: string;
readonly headers: Readonly<Record<string, string>>;
readonly body: string | null;
readonly faked: boolean;
}
Exported from packages/http-client/src/contracts.ts
RequestOptions
Interface
No documentation comment.
interface RequestOptions {
readonly method?: string;
readonly headers?: Readonly<Record<string, string>>;
readonly query?: Readonly<Record<string, string | number | boolean | undefined>>;
/** Raw body. */
readonly body?: RequestBody | null;
/** JSON body; sets `content-type: application/json`. */
readonly json?: unknown;
readonly timeoutMs?: number;
readonly retries?: Partial<RetryOptions>;
…
Show the whole declaration (14 lines)
interface RequestOptions {
readonly method?: string;
readonly headers?: Readonly<Record<string, string>>;
readonly query?: Readonly<Record<string, string | number | boolean | undefined>>;
/** Raw body. */
readonly body?: RequestBody | null;
/** JSON body; sets `content-type: application/json`. */
readonly json?: unknown;
readonly timeoutMs?: number;
readonly retries?: Partial<RetryOptions>;
…interface RequestOptions {
readonly method?: string;
readonly headers?: Readonly<Record<string, string>>;
readonly query?: Readonly<Record<string, string | number | boolean | undefined>>;
/** Raw body. */
readonly body?: RequestBody | null;
/** JSON body; sets `content-type: application/json`. */
readonly json?: unknown;
readonly timeoutMs?: number;
readonly retries?: Partial<RetryOptions>;
readonly untrusted?: boolean;
readonly maxRedirects?: number;
readonly signal?: AbortSignal;
}
Exported from packages/http-client/src/contracts.ts
ResolvedAddress
Interface
A single resolved address of a host.
interface ResolvedAddress {
readonly address: string;
readonly family: 4 | 6;
}
Exported from packages/http-client/src/contracts.ts
RetryOptions
Interface
Retry policy: `count` extra attempts, waiting `backoffMs[attempt]` between them.
interface RetryOptions {
readonly count: number;
readonly backoffMs: readonly number[];
/** Response status codes that trigger a retry. Network errors always do. */
readonly on: readonly number[];
}
Exported from packages/http-client/src/contracts.ts
Type (6)
Awaitable
Type
No documentation comment.
type Awaitable<T> = T | Promise<T>;
Exported from packages/http-client/src/contracts.ts
FakeResponder
Type
A canned reply for {@link HttpClient.fake}.
type FakeResponder = Response | ((request: Request) => Awaitable<Response>) | {
Exported from packages/http-client/src/contracts.ts
FakeTable
Type
Fake table: URL pattern (a `*` matches any run of characters) to reply.
type FakeTable = Readonly<Record<string, FakeResponder>>;
Exported from packages/http-client/src/contracts.ts
HostResolver
Type
Resolves a host name to every address it points to.
type HostResolver = (hostname: string) => Promise<readonly ResolvedAddress[]>;
Exported from packages/http-client/src/contracts.ts
HttpTransport
Type
Performs one HTTP exchange without following redirects. `pinned` is set in untrusted mode: the socket MUST connect to that address.
type HttpTransport = (request: Request, pinned?: ResolvedAddress) => Promise<Response>;
Exported from packages/http-client/src/contracts.ts
RequestBody
Type
Anything `fetch` accepts as a request body.
type RequestBody = NonNullable<RequestInit['body']>;
Exported from packages/http-client/src/contracts.ts