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

sync-request-curl

v5.1.0

Published

A high-performance Node.js alternative to sync-request for making synchronous web requests.

Readme

Sync Request Curl

pipeline   codecov   Maintainability   Snyk Security   GitHub top language

NPM Version   Depfu Dependencies   FOSSA Status   NPM License   GitHub issues

Quality Gate Status   Codacy Badge   DeepSource   GitHub stars


A high-performance Node.js alternative to sync-request for making synchronous web requests.


1. Installation

npm install sync-request-curl

2. Usage

request(method, url, options);

The request function is the package default export. ESM consumers can import FormData and public types from the root entry:

import request, { FormData } from 'sync-request-curl';
import type { Options, Response } from 'sync-request-curl';

GET request without options

import request from 'sync-request-curl';

const res = request('GET', 'https://comp1531namesages.alwaysdata.net');
console.log('Status Code:', res.statusCode);
const jsonBody = JSON.parse(res.body.toString());
console.log('Returned JSON object:', jsonBody);

GET request with query string parameters

import request from 'sync-request-curl';

const res = request('GET', 'https://comp1531forum.alwaysdata.net/echo/echo', {
  qs: { message: 'Hello, world!' },
});
console.log('Status Code:', res.statusCode);
const jsonBody = JSON.parse(res.body.toString());
console.log('Returned JSON object:', jsonBody);

POST request with headers and JSON payload

import request from 'sync-request-curl';

const res = request('POST', 'https://comp1531quiz.alwaysdata.net/quiz/create', {
  headers: { lab08quizsecret: "bruno's fight club" },
  json: {
    quizTitle: 'New Quiz',
    quizSynopsis: 'Sync request curl example',
  },
});

console.log('Status Code:', res.statusCode);
const jsonBody = JSON.parse(res.body.toString());
console.log('Returned JSON Object:', jsonBody);

POST request for file upload using multipart/form-data

import { readFileSync } from 'node:fs';
import request, { FormData } from 'sync-request-curl';

const form = new FormData();
form.append('example-file', readFileSync('./path/to/file.txt'), 'file.txt');
form.append('example-content', 'Example Content!');

const res = request('POST', 'https://example.com/upload', { form });
console.log('Status Code:', res.statusCode);

FormData also exposes the synchronous Node form-data helpers used by then-request: getHeaders(), getBoundary(), setBoundary(), getBuffer(), getLengthSync(), hasKnownLength(), and toString(). The append() options object supports filename, contentType, knownLength, and the advanced raw header override. A custom header is serialized verbatim and is responsible for its own multipart boundary and part headers. Stream-valued fields and callback/stream helpers such as getLength(), pipe(), and submit() are not provided.

Proxy request

import request from 'sync-request-curl';

const res = request('GET', 'https://ipinfo.io/json', {
  proxy: {
    url: 'http://your-proxy-url:port',
    username: 'proxyUsername',
    password: 'proxyPassword',
    auth: 'any',
    noProxy: ['localhost', '127.0.0.0/8'],
    headers: {
      'X-Proxy-Trace': 'trace-id',
    },
  },
});

console.log('Status Code:', res.statusCode);
const jsonBody = res.getJSON();
console.log(jsonBody);

Proxy URLs can use http://, https://, socks4://, socks4a://, socks5://, or socks5h://. auth applies to HTTP(S) proxies and supports basic, digest, ntlm, negotiate, and any; NTLM and Negotiate depend on the capabilities compiled into the active libcurl build. noProxy is an explicit per-request bypass list and does not re-enable ambient proxy environment variables. Proxy-specific headers are kept separate from origin headers during HTTPS CONNECT tunnelling. CIDR entries in noProxy require libcurl 7.86.0 or newer.

Mutual TLS with a client certificate

import request from 'sync-request-curl';

const res = request('GET', 'https://service.example', {
  caFile: './service-ca.pem',
  tls: {
    certFile: './client.pem',
    keyFile: './client-key.pem',
    minVersion: 'TLSv1.2',
  },
});

console.log('Status Code:', res.statusCode);

For a PKCS#12 identity, set certType: 'p12' and provide the .p12 file as certFile; passphrase unlocks either a PKCS#12 identity or an encrypted private key. A separate keyFile is intentionally not accepted with p12. The active libcurl TLS backend determines which client-certificate formats are supported. The bundled Windows build uses Schannel, where PKCS#12 is the portable file-based client-certificate form and a separate keyFile is not used. minVersion and maxVersion currently accept TLSv1.2 and TLSv1.3.

3. API reference

Request

request()

function request(
   method,
   url,
   options?
): Response;

Perform a synchronous HTTP(S) request and return the complete buffered response.

Parameters

| Parameter | Type | Description | | ------ | ------ | ------ | | method | HttpVerb | Recognised HTTP method. Matching is case-insensitive; CONNECT is rejected. | | url | string | URL | Absolute http: or https: URL, provided as a string or URL. | | options | Options | Request, transport, redirect, retry, and cache options. |

Returns

Response

The buffered response after redirects and retries complete.


HttpVerb

type HttpVerb =
  | "GET"
  | "get"
  | "HEAD"
  | "head"
  | "POST"
  | "post"
  | "PUT"
  | "put"
  | "DELETE"
  | "delete"
  | "CONNECT"
  | "connect"
  | "OPTIONS"
  | "options"
  | "TRACE"
  | "trace"
  | "PATCH"
  | "patch"
  | "PROPFIND"
  | "propfind";

Recognised HTTP methods. Input is case-insensitive and is normalised to uppercase before transport.

CONNECT is retained in the union for source compatibility with sync-request, but request() rejects it because the buffered API cannot expose the tunnel socket created by a successful CONNECT response.


Options

type Options = {
  auth?: HttpAuthOptions;
  proxy?: ProxyOptions;
  httpVersion?: "auto"
     | "2"
     | "3"
     | "1.0"
     | "1.1"
     | "2-tls"
     | "2-prior-knowledge"
     | "3-only";
  rejectUnauthorized?: boolean;
  caFile?: string;
  tls?: TlsOptions;
  localAddress?: string;
  localInterface?: string;
  localPort?: number;
  localPortRange?: number;
  maxDownloadSpeed?: number;
  maxUploadSpeed?: number;
  family?: 0 | 4 | 6;
  tcpKeepAlive?: boolean
     | {
     idleSeconds?: number;
     intervalSeconds?: number;
     probeCount?: number;
   };
  cacheNamespace?: string;
  headers?: Headers;
  qs?: {
   [key: string]: unknown;
  };
  json?: JsonLike;
  body?: string | Buffer<ArrayBufferLike>;
  form?: FormData;
  timeout?: number;
  connectTimeout?: number;
  overallTimeout?: number;
  socketTimeout?: number;
  followRedirects?: boolean;
  maxRedirects?: number;
  allowRedirectHeaders?: string[];
  gzip?: boolean;
  cache?: "file" | "memory";
  isMatch?: CacheIsMatchFunction;
  isExpired?: CacheIsExpiredFunction;
  canCache?: CacheCanCacheFunction;
  agent?: boolean | Agent;
  retry?: boolean | RetryFunction;
  retryDelay?: number | RetryDelayFunction;
  maxRetries?: number;
};

Options accepted by request.

Payload precedence is form, then json, then body when more than one is supplied.

Type Declaration

| Name | Type | Description | | ------ | ------ | ------ | | auth? | HttpAuthOptions | HTTP origin authentication. Username/password authentication defaults to Basic; Bearer tokens use libcurl's OAuth2 bearer support. Cannot be combined with an explicit Authorization header. | | proxy? | ProxyOptions | Explicit HTTP(S) or SOCKS proxy configuration. Ambient proxy variables are ignored. Defaults to no proxy. | | httpVersion? | | "auto" | "2" | "3" | "1.0" | "1.1" | "2-tls" | "2-prior-knowledge" | "3-only" | HTTP protocol preference. Defaults to "auto". HTTP/3 values require an HTTP/3-capable linked libcurl build. | | rejectUnauthorized? | boolean | Verify the origin certificate chain and hostname. Defaults to true. | | caFile? | string | PEM CA bundle path for origin TLS verification. | | tls? | TlsOptions | Client certificate and TLS protocol-version controls for the origin. | | localAddress? | string | Source IPv4/IPv6 address. Hostnames are rejected. | | localInterface? | string | Source interface name. Mutually exclusive with localAddress. | | localPort? | number | Preferred local TCP source port. Valid values are 1-65535. When set, localPortRange can allow consecutive fallback ports. | | localPortRange? | number | Number of consecutive local ports libcurl may try, beginning at localPort. Requires localPort; 0 or 1 means the exact port only. | | maxDownloadSpeed? | number | Maximum download transfer rate in bytes per second. 0 (default) leaves download speed unlimited. | | maxUploadSpeed? | number | Maximum upload transfer rate in bytes per second. 0 (default) leaves upload speed unlimited. | | family? | 0 | 4 | 6 | IP address family used when resolving hostnames. 0 (default) allows either family, 4 restricts resolution to IPv4, and 6 to IPv6. | | tcpKeepAlive? | | boolean | { idleSeconds?: number; intervalSeconds?: number; probeCount?: number; } | Enable TCP keepalive, optionally with idle, interval, and probe-count controls. Defaults to false. probeCount requires libcurl 8.9.0 or newer and remains subject to operating-system support. | | cacheNamespace? | string | Private cache identity. Defaults to process.cwd(). | | headers? | Headers | Node-style request headers. | | qs? | { [key: string]: unknown; } | Query values merged with any existing query string. | | json? | JsonLike | JSON-compatible request body. Adds application/json when needed. | | body? | string | Buffer<ArrayBufferLike> | Raw string or Buffer request body. | | form? | FormData | Synchronous multipart/form-data body. | | timeout? | number | Maximum time to wait for response headers in milliseconds. Defaults to 0, which disables it. Authentication retries reuse the original deadline. | | connectTimeout? | number | Maximum time allowed for connection establishment in milliseconds. This includes DNS lookup, TCP connection, and TLS/protocol handshakes. Defaults to 0, which uses libcurl's default connection timeout. | | overallTimeout? | number | Complete-operation deadline in milliseconds. Defaults to 0, which disables it. | | socketTimeout? | number | Socket inactivity timeout in milliseconds. Defaults to 0, which disables it. Speed-limited transfers receive bounded inactivity allowance for newly transferred bytes; local throttling does not extend overallTimeout. | | followRedirects? | boolean | Follow redirects automatically. Defaults to true. | | maxRedirects? | number | Maximum redirects to follow. Defaults to no limit. Negative values and infinities also mean no limit; NaN is invalid. | | allowRedirectHeaders? | string[] | Caller headers allowed to be forwarded to redirect hops. Defaults to none. | | gzip? | boolean | Transparently decompress gzip/deflate responses. Defaults to true. | | cache? | "file" | "memory" | Enable the private HTTP-aware cache in file or memory storage. Defaults to disabled. | | isMatch? | CacheIsMatchFunction | Override whether a stored cache variant matches the outgoing request. When caching is enabled, defaults to the built-in Vary comparison. | | isExpired? | CacheIsExpiredFunction | Override whether a matched cached response is expired. When caching is enabled, defaults to the built-in freshness calculation. | | canCache? | CacheCanCacheFunction | Override whether a completed origin response may be stored. When caching is enabled, defaults to the built-in response cacheability rules. | | agent? | boolean | Agent | sync-request boolean agent option, or a keep-alive Node Agent for connection reuse. Defaults to the standard connection behaviour without a dedicated persistent pool. | | retry? | boolean | RetryFunction | Retry GET requests, or provide a callback to decide per attempt. Defaults to disabled. | | retryDelay? | number | RetryDelayFunction | Retry delay in milliseconds, or a callback returning the delay. Defaults to 200 milliseconds when retries are enabled. | | maxRetries? | number | Maximum retry count. Defaults to 5 when retries are enabled. |


Headers

type Headers = IncomingHttpHeaders;

HTTP header map used by then-request.

This is an alias of Node.js' IncomingHttpHeaders, exposed under the historical then-request name so consumers do not need to import Node's type directly.


JsonPrimitive

type JsonPrimitive = string | number | boolean | null;

Primitive JSON values accepted in request bodies.


NestedJsonLike

type NestedJsonLike =
  | JsonLike
  | undefined
  | {
  toJSON: () => NestedJsonLike;
};

Values accepted when nested inside JSON request bodies.


JsonLike

type JsonLike =
  | JsonPrimitive
  | readonly NestedJsonLike[]
  | {
[key: string]: NestedJsonLike;
}
  | {
  toJSON: () => JsonLike;
};

Values accepted for JSON request bodies.

This intentionally follows practical JSON.stringify() inputs rather than only strict JSON syntax. undefined is allowed inside objects and arrays, and objects with toJSON() (for example Date) are supported.


HttpVersion

type HttpVersion =
  | "auto"
  | "1.0"
  | "1.1"
  | "2"
  | "2-tls"
  | "2-prior-knowledge"
  | "3"
  | "3-only";

HTTP protocol preference passed to libcurl.

HTTP/3 values require the linked libcurl build to include HTTP/3 support.


IpFamily

type IpFamily = 0 | 4 | 6;

IP address family used when resolving hostnames.

0 allows either IPv4 or IPv6, 4 restricts resolution to IPv4, and 6 restricts resolution to IPv6.


TlsVersion

type TlsVersion = "TLSv1.2" | "TLSv1.3";

TLS protocol versions supported by the high-level version bounds.


TlsCertificateType

type TlsCertificateType = "pem" | "p12";

Client certificate file formats supported by the high-level TLS API.

PEM certificates use a separate keyFile when the TLS backend requires one. PKCS#12 files contain the certificate and private key together and can be unlocked with passphrase.


TlsOptions

type TlsOptions = {
  minVersion?: TlsVersion;
  maxVersion?: TlsVersion;
} & (
  | {
  certFile?: never;
  certType?: never;
  keyFile?: never;
  passphrase?: never;
}
  | {
  certFile: string;
  certType?: "pem";
  keyFile?: string;
  passphrase?: string;
}
  | {
  certFile: string;
  certType: "p12";
  keyFile?: never;
  passphrase?: string;
});

High-level origin TLS controls.

Existing top-level caFile and rejectUnauthorized options remain separate for backwards compatibility. Client certificate format support depends on the active libcurl TLS backend; PKCS#12 is supported by the package's bundled OpenSSL and Schannel builds.

Type Declaration

| Name | Type | Description | | ------ | ------ | ------ | | minVersion? | TlsVersion | Minimum TLS protocol version accepted for the origin connection. | | maxVersion? | TlsVersion | Maximum TLS protocol version accepted for the origin connection. |


HttpAuthType

type HttpAuthType = "basic" | "digest" | "ntlm" | "negotiate" | "any";

HTTP origin authentication method offered to libcurl.

"any" lets libcurl probe the server challenge and select the strongest supported method from this set. NTLM and Negotiate remain dependent on how libcurl was built on the current platform.


HttpAuthOptions

type HttpAuthOptions =
  | {
  username: string;
  password?: string;
  type?: HttpAuthType;
  bearer?: never;
}
  | {
  bearer: string;
  username?: never;
  password?: never;
  type?: never;
};

High-level HTTP origin authentication configuration.

Username/password authentication defaults to Basic when type is omitted. Bearer authentication uses libcurl's OAuth2 bearer support. Authentication configured here is never forwarded to a different origin during redirects. Usernames cannot contain ASCII control characters. Basic, Digest, and Any also reject : in usernames and ASCII controls in passwords. Bearer tokens must use RFC 6750 b64token syntax. Negotiated authentication is not supported with HEAD payloads; omit the payload or use preemptive Basic/Bearer authentication.


ProxyAuthType

type ProxyAuthType = "basic" | "digest" | "ntlm" | "negotiate" | "any";

HTTP proxy authentication method offered to libcurl.

"any" lets libcurl negotiate the strongest method supported by both the proxy and the active libcurl build. NTLM and Negotiate remain dependent on how libcurl was built on the current platform.


ProxyOptions

Explicit HTTP(S) or SOCKS proxy configuration.

Properties

| Property | Type | Description | | ------ | ------ | ------ | | url | string | Proxy origin URL. Supported schemes are http, https, socks4, socks4a, socks5, and socks5h. May contain URL-encoded credentials. | | username? | string | Overrides both URL credentials. An omitted password becomes an empty string. HTTP Basic, Digest, and Any authentication reject : in usernames. | | password? | string | Proxy password. Requires an explicit username. Defaults to an empty string. HTTP Basic, Digest, and Any authentication reject ASCII controls. | | auth? | ProxyAuthType | HTTP(S) proxy authentication method. Defaults to libcurl's Basic mode. NTLM and Negotiate require support in the active libcurl build. | | noProxy? | string[] | Hosts, domains, IP addresses, or CIDR ranges that should bypass this proxy. "*" bypasses the proxy for every host. CIDR matching requires libcurl 7.86.0 or newer. | | headers? | Headers | Headers sent to an HTTP(S) proxy. For HTTPS origins these are used for the CONNECT request and are kept separate from origin request headers. Content-Length, Transfer-Encoding, Authorization, and Cookie are rejected, including empty values. Proxy-Authorization cannot be combined with URL or structured proxy authentication credentials. |


RetryResponse

Response shape passed to retry policy callbacks.

getBody() follows the same status handling as a normal response. Retry callbacks receive this buffered response before the next attempt begins.

Extended by
Methods
getBody()
Call Signature
getBody(encoding): string;

Read the response body as a string using the requested encoding.

Parameters

| Parameter | Type | | ------ | ------ | | encoding | BufferEncoding |

Returns

string

Call Signature
getBody(): Buffer;

Read the response body as a Buffer.

Returns

Buffer

Properties

| Property | Type | Description | | ------ | ------ | ------ | | statusCode | number | HTTP response status code. | | headers | Headers | Node-style response headers with lowercase keys. | | url | string | Final effective URL for the completed attempt. | | body | Buffer | Buffered response body. |


CachedResponse

Buffered cached response passed to cache policy callbacks.

The body, headers, and request headers are defensive copies. Mutating them does not modify the stored cache entry.

Properties

| Property | Type | Description | | ------ | ------ | ------ | | statusCode | number | Cached HTTP response status code. | | headers | Headers | Cached Node-style response headers with lowercase keys. | | body | Buffer | Buffered cached response body. | | requestHeaders | Headers | Request headers stored with this cache variant. | | requestTimestamp | number | Timestamp when the cached request started, in Unix milliseconds. |


CachePolicyResponse

Buffered origin response passed to canCache.

This is the normal public response shape for the completed GET request.

Extends
Methods
getBody()
Call Signature
getBody(encoding): string;

Read the response body as a string using the requested encoding.

Parameters

| Parameter | Type | | ------ | ------ | | encoding | BufferEncoding |

Returns

string

Inherited from

RetryResponse.getBody

Call Signature
getBody(): Buffer;

Read the response body as a Buffer.

Returns

Buffer

Inherited from

RetryResponse.getBody

getJSON()
getJSON<T>(encoding?): T;

Parse the buffered response body as JSON.

Type Parameters

| Type Parameter | Default type | | ------ | ------ | | T | any |

Parameters

| Parameter | Type | | ------ | ------ | | encoding? | BufferEncoding |

Returns

T

Properties

| Property | Type | Description | Inherited from | | ------ | ------ | ------ | ------ | | statusCode | number | HTTP response status code. | RetryResponse.statusCode | | headers | Headers | Node-style response headers with lowercase keys. | RetryResponse.headers | | url | string | Final effective URL for the completed attempt. | RetryResponse.url | | body | Buffer | Buffered response body. | RetryResponse.body |


CacheIsMatchFunction

type CacheIsMatchFunction = (
  requestHeaders: Headers,
  cachedResponse: CachedResponse,
  defaultValue: boolean,
) => boolean;

Override whether a stored cache variant matches the outgoing request.

defaultValue is the built-in Vary comparison result.

Parameters

| Parameter | Type | | ------ | ------ | | requestHeaders | Headers | | cachedResponse | CachedResponse | | defaultValue | boolean |

Returns

boolean


CacheIsExpiredFunction

type CacheIsExpiredFunction = (
  cachedResponse: CachedResponse,
  defaultValue: boolean,
) => boolean;

Override whether a matched cached response is expired.

defaultValue is the result of the built-in freshness calculation.

Parameters

| Parameter | Type | | ------ | ------ | | cachedResponse | CachedResponse | | defaultValue | boolean |

Returns

boolean


CacheCanCacheFunction

type CacheCanCacheFunction = (
  response: CachePolicyResponse,
  defaultValue: boolean,
) => boolean;

Override whether a completed origin response may be stored in the cache.

defaultValue is the built-in response cacheability result. Request-side Cache-Control: no-store still disables storage before this callback runs.

Parameters

| Parameter | Type | | ------ | ------ | | response | CachePolicyResponse | | defaultValue | boolean |

Returns

boolean


RetryFunction

type RetryFunction = (
  error: CurlError | RequestError | null,
  response: RetryResponse | undefined,
  attemptNumber: number,
) => boolean;

Decide whether a GET request should be retried after an error or response.

attemptNumber starts at 1 for the first completed attempt. Transport failures are passed as CurlError instances; response parser failures are passed as RequestError instances.

Parameters

| Parameter | Type | | ------ | ------ | | error | CurlError | RequestError | null | | response | RetryResponse | undefined | | attemptNumber | number |

Returns

boolean


RetryDelayFunction

type RetryDelayFunction = (
  error: CurlError | RequestError | null,
  response: RetryResponse | undefined,
  attemptNumber: number,
) => number;

Return the delay in milliseconds before the next retry.

attemptNumber starts at 1 for the first completed attempt. Transport failures are passed as CurlError instances; response parser failures are passed as RequestError instances.

Parameters

| Parameter | Type | | ------ | ------ | | error | CurlError | RequestError | null | | response | RetryResponse | undefined | | attemptNumber | number |

Returns

number

Response

GetBody

type GetBody = {
  <Encoding extends BufferEncoding>(encoding: Encoding): string;
  (): Buffer;
};

Read the current response body.

Calling without an encoding returns the Buffer. Passing an encoding returns a string. A response with statusCode >= 300 throws ResponseError.

Call Signature
<Encoding extends BufferEncoding>(encoding: Encoding): string;
Type Parameters

| Type Parameter | | ------ | | Encoding extends BufferEncoding |

Parameters

| Parameter | Type | | ------ | ------ | | encoding | Encoding |

Returns

string

Call Signature
(): Buffer;
Returns

Buffer


GetJSON

type GetJSON = <T = any>(encoding?: BufferEncoding) => T;

Parse the current response body as JSON.

Unlike GetBody, this helper does not reject HTTP error status codes. It only throws if the body cannot be parsed as JSON. Defaults to any for v4 compatibility. Pass an explicit type argument to describe the expected result; this does not perform runtime validation.

Type Parameters

| Type Parameter | Default type | | ------ | ------ | | T | any |

Parameters

| Parameter | Type | | ------ | ------ | | encoding? | BufferEncoding |

Returns

T


Response

Buffered synchronous response returned by request.

Helper methods observe later mutations to the public response object rather than a hidden immutable snapshot.

Properties

| Property | Type | Description | | ------ | ------ | ------ | | isError | () => boolean | Return whether the response represents an HTTP error. | | getBody | GetBody | Read the response body and throw ResponseError for HTTP status >= 300. | | getJSON | GetJSON | Parse the response body as JSON without applying HTTP status handling. | | statusCode | number | HTTP response status code. | | headers | Headers | Node-style response headers with lowercase keys. | | url | string | Final effective URL after query handling and redirects. | | body | Buffer<ArrayBufferLike> | Mutable buffered response body. |


BufferEncoding

type BufferEncoding =
  | "base64"
  | "ascii"
  | "utf8"
  | "utf-8"
  | "utf16le"
  | "utf-16le"
  | "ucs2"
  | "ucs-2"
  | "base64url"
  | "latin1"
  | "binary"
  | "hex";

Buffer encodings accepted by response body helpers.

Multipart

FormDataEntry

One multipart entry accepted by FormData.

Properties

| Property | Type | Description | | ------ | ------ | ------ | | contentType? | string | Optional media type override. | | knownLength? | number | Accepted for form-data append-option compatibility. | | header? | string | Optional raw multipart header that replaces generated part headers. | | key | string | Multipart field name. | | value | string | number | boolean | Buffer<ArrayBufferLike> | Blob | Synchronously materialisable multipart field value. | | fileName? | string | Optional file name. Path components are stripped before sending. |


FormData

Synchronous multipart/form-data builder compatible with the Node.js FormData surface exposed by then-request.

Stream-valued parts and callback/stream methods from the form-data package are intentionally omitted because this package is synchronous-only.

Constructors
Constructor
new FormData(): FormData;
Returns

FormData

Methods
append()
append(
   key,
   value,
   options?
): void;

Append a synchronously materialisable multipart field.

Numbers and booleans are converted to strings. The third argument may be a filename string or the synchronous subset of form-data append options. A custom header is serialized verbatim and replaces the generated boundary and part headers, matching Node's form-data behavior. Local path components are stripped from generated filenames before sending.

Parameters

| Parameter | Type | | ------ | ------ | | key | string | | value | string | number | boolean | Buffer<ArrayBufferLike> | Blob | | options? | | string | { filename?: string; contentType?: string; knownLength?: number; header?: string; } |

Returns

void

getHeaders()
Call Signature
getHeaders(): IncomingHttpHeaders & {
  content-type: string;
};

Return multipart request headers, merged with optional caller headers.

Returns

IncomingHttpHeaders & { content-type: string; }

Call Signature
getHeaders(userHeaders): Headers;

Return multipart request headers, merged with optional caller headers.

Parameters

| Parameter | Type | | ------ | ------ | | userHeaders | Headers |

Returns

Headers

getBoundary()
getBoundary(): string;

Return the boundary used to serialize this form.

Returns

string

setBoundary()
setBoundary(boundary): void;

Set the multipart boundary used by headers and serialization.

Parameters

| Parameter | Type | | ------ | ------ | | boundary | string |

Returns

void

getBuffer()
getBuffer(): Buffer;

Serialize the complete multipart payload synchronously.

Returns

Buffer

getLengthSync()
getLengthSync(): number;

Return the exact byte length of getBuffer().

Returns

number

hasKnownLength()
hasKnownLength(): boolean;

All supported field values have a synchronously known length.

Returns

boolean

toString()
toString(): string;

Match the identity string returned by Node's form-data package.

Returns

string

Errors

RequestErrorCode

type RequestErrorCode = "ETIMEDOUT" | "ERR_TOO_MANY_REDIRECTS" | "ERR_REQUEST_FAILED";

Stable transport-neutral error codes emitted by the TypeScript request layer.


CurlError

Raw libcurl transport failure.

The numeric code is retained for compatibility with earlier sync-request-curl releases and maps to libcurl's documented error codes.

Extends
Constructors
Constructor
new CurlError(code, message): CurlError;
Parameters

| Parameter | Type | | ------ | ------ | | code | number | | message | string |

Returns

CurlError

Overrides
Error.constructor
Properties

| Property | Type | Description | | ------ | ------ | ------ | | code | number | Numeric libcurl error code. |


RequestError

Transport-neutral request failure created by the TypeScript request layer.

Extends
Constructors
Constructor
new RequestError(
   code,
   message,
   options?
): RequestError;
Parameters

| Parameter | Type | | ------ | ------ | | code | RequestErrorCode | | message | string | | options? | ErrorOptions |

Returns

RequestError

Overrides
Error.constructor
Properties

| Property | Modifier | Type | Description | | ------ | ------ | ------ | ------ | | code | readonly | RequestErrorCode | Stable transport-neutral request error code. |


ResponseError

HTTP status error thrown by response.getBody() for status codes >= 300.

The status, headers, body, and response URL that produced the error remain available on the error object.

Extends
Constructors
Constructor
new ResponseError(
   statusCode,
   headers,
   body,
   encoding?,
   url?
): ResponseError;
Parameters

| Parameter | Type | | ------ | ------ | | statusCode | number | | headers | Headers | | body | Buffer | | encoding? | BufferEncoding | | url? | string |

Returns

ResponseError

Overrides
Error.constructor
Properties

| Property | Modifier | Type | Description | | ------ | ------ | ------ | ------ | | statusCode | readonly | number | HTTP status code that caused the error. | | headers | readonly | Headers | Response headers returned by the server. | | body | readonly | Buffer | Buffered response body returned by the server. | | url? | readonly | string | Final response URL when the error came from Response#getBody(). |

4. Differences from sync-request

4.1. Additions

  • Response#getJSON() is available as a convenience helper.
  • cache: "memory" is available as an alternative to the file cache.
  • isMatch, isExpired, and canCache expose the synchronous cache-policy hooks from http-basic. Callback/stream-based custom cache implementations remain out of scope; use the built-in "file" or "memory" cache.
  • retry and retryDelay can be callbacks when you need to decide retry behaviour at runtime. Transport failures passed to these callbacks are CurlError instances with numeric libcurl error codes, while response parser failures are RequestError instances rather than Node ErrnoException errors.
  • agent still accepts the boolean values supported by sync-request, and can also take a keep-alive Node Agent for connection reuse.
  • overallTimeout sets a deadline for the whole operation, alongside the response-header timeout, connection-establishment connectTimeout, and inactivity socketTimeout options.
  • TLS, local network binding, and TCP keepalive have dedicated options. The tls object adds file-based client certificates for mutual TLS plus TLS 1.2 and TLS 1.3 minimum/maximum version bounds without moving the existing caFile or rejectUnauthorized fields. localAddress / localInterface select the source address or interface, while localPort and localPortRange can pin the source TCP port or allow consecutive fallback ports. maxDownloadSpeed and maxUploadSpeed can cap network transfer rates in bytes per second without changing cache identity or connection pooling. Client certificate identity is retained only across same-origin redirects. TCP keepalive probe counts require libcurl 8.9.0 or newer and operating-system support. Unsupported linked libcurl/platform combinations return a transport error rather than silently ignoring the setting.
  • httpVersion can request HTTP/1.0, HTTP/1.1, HTTP/2, HTTP/2 over TLS, HTTP/2 prior knowledge, HTTP/3, or HTTP/3-only behaviour. HTTP/3 requires the linked libcurl build to include HTTP/3 support.
  • family can leave address-family selection automatic or restrict hostname resolution to IPv4 or IPv6.
  • Explicit proxy configuration supports HTTP(S), SOCKS4/SOCKS4a, and SOCKS5/SOCKS5h URL schemes. HTTP(S) proxies can select Basic, Digest, NTLM, Negotiate, or automatic authentication, add proxy-only headers, and define a per-request noProxy bypass list. NTLM and Negotiate remain dependent on the active libcurl build. Ambient proxy environment variables remain disabled.
  • auth provides origin Basic, Digest, NTLM, Negotiate, automatic challenge selection, and Bearer authentication through libcurl. High-level authentication cannot be combined with another Authorization source and is retained only across same-origin redirects. NTLM and Negotiate remain dependent on the active libcurl build.

4.2. Behavioural differences

  • RFC 9110 defines request framing independently of the method, so request content is permitted on GET, DELETE, and HEAD. The standard also notes that this content has no generally defined semantics and may be rejected by some implementations.
  • Falsy JSON values such as false, 0, "", and null are valid payloads.
  • Response#getBody() throws ResponseError for HTTP status codes >= 300. It still extends Error and exposes statusCode, headers, and body, but its name is "ResponseError" rather than sync-request's default "Error".
  • Invalid HTTP framing is rejected rather than sending conflicting Content-Length and Transfer-Encoding headers.
  • Obsolete HTTP/1 response line folding is normalised to spaces as required for user agents by RFC 9112. sync-request inherits Node's stricter parser, which can reject those responses instead.
  • CONNECT is rejected explicitly. Although sync-request accepts it at the type level, its underlying buffered request stack does not complete a successful CONNECT tunnel response.
  • libcurl applies RFC 3986 URL normalisation, including removal of . and .. path segments. Response#url reports libcurl's effective URL, so it can reflect that normalisation instead of preserving the caller's literal URL.
  • An explicit Authorization header takes precedence over credentials in the URL, and a caller-supplied Accept-Encoding header is left unchanged.
  • 307 and 308 redirects preserve the request method and body. sync-request can rewrite some body-bearing redirects to GET.
  • A redirect response without a Location header is returned unchanged rather than being converted into an exception. RFC 9110's redirection semantics define automatic redirection in terms of a provided Location value. This intentionally differs from http-basic, which throws when a redirect status has no redirect target.
  • Query merging preserves additional literal ? and # delimiters that sync-request can truncate while splitting URLs.
  • Default cache handling is stricter: no-store takes precedence, Age is updated on cache hits, cached headers are isolated from mutation, and recoverable cache-read errors are treated as misses.
  • HTTPS requests can negotiate HTTP/2 automatically when supported.

5. License

MIT

6. Compatibility

sync-request-curl supports Node.js 16.17.0 and newer.

The package manager selects a matching native binary when one is available. Installing or importing the package does not compile native code.

6.1. Windows

Prebuilt binaries are available for x64, arm64, and x86 (ia32) Windows. For x86, use a Node.js release that provides an x86 runtime.

Requests can fail with Libcurl Error 60 (CURLE_PEER_FAILED_VERIFICATION) when the peer certificate cannot be verified. rejectUnauthorized: false disables origin certificate and hostname verification and should only be used when that trade-off is intentional.

The bundled Windows libcurl uses Schannel. For file-based mutual TLS, use a PKCS#12 client identity (tls.certType: "p12"); Schannel expects the private key to be part of that identity and ignores a separate tls.keyFile.

6.2. macOS

Prebuilt binaries are available for Apple Silicon (arm64) and Intel (x64) macOS. The default bundled libcurl uses OpenSSL, with Apple SecTrust for native certificate verification. File-based mutual TLS supports PEM certificate/key pairs and PKCS#12 identities through the high-level tls option.

Only explicit --libcurl=system builds inherit the client-certificate formats and TLS-version capabilities of the selected system libcurl and TLS backend.

6.3. Linux

Prebuilt binaries are available for x64 and arm64 Linux on both glibc and musl. GNU/Linux release binaries require GLIBC 2.31 or newer. The bundled Linux libcurl uses OpenSSL and supports PEM certificate/key pairs and PKCS#12 client identities through the high-level tls option.

6.4. Building from source

If a prebuilt binary is unavailable for your platform, or if optional dependencies were intentionally omitted, build the installed package explicitly using your package manager:

npm exec --no -- sync-request-curl-build
pnpm exec sync-request-curl-build
yarn run sync-request-curl-build

Run the build with the same Node.js architecture that will use the library. Run sync-request-curl-build --help for the current prerequisites.

Source builds use the libcurl bundled by curl-sys by default on all supported platforms. On macOS, the bundled OpenSSL backend uses Apple SecTrust for native certificate verification. Override the libcurl source explicitly when needed:

npm exec --no -- sync-request-curl-build --libcurl=system
npm exec --no -- sync-request-curl-build --libcurl=bundled

--libcurl=system is strict: if curl-sys cannot discover a compatible system libcurl, the build fails instead of silently falling back to its bundled copy. On Unix systems, system discovery uses the platform libcurl or pkg-config. On Windows, curl-sys uses vcpkg. System builds inherit the capabilities and TLS behaviour of the selected libcurl. --libcurl=bundled uses the pinned libcurl shipped by curl-sys and retains the package's vendored build configuration. The flag selects the libcurl implementation. Both modes continue to use curl-sys as the Rust FFI layer.

Source builds require:

  • Rust 1.88 or newer and Cargo
  • Linux and other Unix systems: a C/C++ compiler, make, Perl, pkg-config, and CA certificates
  • macOS: Xcode Command Line Tools
  • Windows: Visual Studio C++ Build Tools and the Windows SDK for the target CPU
  • Access to the locked Cargo dependencies, or an already populated Cargo cache

Other architectures and Unix platforms may work when Node.js, Rust, and the required native dependencies support them, but they are not part of the prebuilt release matrix.

Set CARGO_BUILD_TARGET when you need to select a Rust target explicitly. The build must still run with a Node.js architecture compatible with the resulting addon.

To use an externally managed native build, set SYNC_REQUEST_CURL_NATIVE_PATH to the absolute path of its .node file.

7. Caveats

sync-request-curl was developed to improve performance with sending synchronous requests in Node.js. It is also free from the sync-request bug which leaves an orphaned sync-rpc process, resulting in a leaked handle being detected in Jest.

sync-request-curl was initially designed to work with UNIX-like systems for UNSW students enrolled in COMP1531 Software Engineering Fundamentals. The native distribution targets glibc- and musl-based Linux, Windows, and macOS on the architectures listed in the compatibility section.

Please note that this library's primary goal is to simplify the learning of JavaScript for novice programmers, hence its synchronous nature. However, we recommend to always use an asynchronous alternative where possible.

7.1. Authentication and HEAD payloads

Authentication usernames must not contain ASCII control characters (including CR, LF, and DEL). Basic, Digest, and Any authentication also reject colons in usernames and ASCII control characters in passwords. NTLM and Negotiate passwords may contain CR/LF, but no authentication method accepts NUL in a password. Bearer tokens must use the RFC 6750 b64token syntax. These rules also apply to percent-decoded HTTP(S) proxy URL credentials; SOCKS usernames must not contain ASCII controls, and SOCKS passwords must not contain NUL. Origin URL credentials are percent-decoded and checked using the Basic authentication rules. An explicit Authorization header takes precedence over origin URL credentials, which are removed before transport so they cannot become active when a redirect drops the header. auth cannot be combined with origin URL credentials or an explicit Authorization header.

HEAD requests with a payload cannot use negotiated origin or proxy authentication (any, digest, ntlm, or negotiate). This combination is rejected before network I/O, rather than returning an intermediate challenge as a successful transfer or waiting for a HEAD response body that will never arrive. Omit the payload to use negotiated authentication with HEAD, or use preemptive Basic or Bearer authentication when supported by the server. This restriction also applies to empty explicit payloads and multipart forms.

7.2. Timeouts with authentication and transfer limits

timeout remains a response-header deadline across libcurl's internal requests, including authentication retries. A new request reactivates the same deadline; it does not receive a fresh timeout budget. Draining an intermediate authentication response, including an accepted empty upload probe, still counts towards this deadline. Only terminal response bodies (including a final 401/407) are governed by socketTimeout and overallTimeout instead.

The native transport tracks outgoing request boundaries separately from received header text, so accepted Digest probes do not discard validation of earlier responses or permit forged status lines in trailers. Pending-body detection uses libcurl's Ignoring the response-body diagnostic notification without logging or retaining debug data. Custom/system builds with verbose strings disabled cannot provide this signal: negotiated authentication with a positive timeout fails explicitly with libcurl error 4 rather than silently losing timeout protection. Use the bundled libcurl build for this combination. Changes to libcurl diagnostic notifications must be verified against the authentication regression tests.

When transfer speed limits are enabled, socketTimeout allows bounded additional time for local throttling. Each newly transferred byte earns at most its configured transmission time as an inactivity allowance. Repeated progress callbacks without new bytes do not extend the allowance. Reaching the final upload byte preserves the allowance already earned, including that final burst: libcurl can still pause for its upload rate limit before reading the response. Without further progress, this allowance expires normally; a server that never responds still times out after the remaining allowance and inactivity budget expire. overallTimeout includes both throttling and authentication and is never extended.

7.3. Proxy request headers

proxy.headers cannot supply Content-Length or Transfer-Encoding, including explicit empty values. Body framing is managed by the request implementation; non-tunnelled HTTP proxy requests combine the origin and proxy header lists. proxy.headers also rejects Authorization and Cookie; these origin-sensitive headers belong in the main request headers. Proxy-Authorization cannot be combined with proxy URL credentials, proxy.username, proxy.password, or proxy.auth. Both the public API and the native entry point reject these combinations and framing overrides before network I/O. Other proxy headers retain ordinary header validation.