Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/MercuryWorkshop/epoxy-tls/llms.txt

Use this file to discover all available pages before exploring further.

EpoxyClient.fetch() lets you make HTTP requests through a Wisp proxy directly from the browser. Its options object mirrors the standard fetch() API, so you can swap it in with minimal changes to existing code. The method returns a standard Response object extended with a few extra properties that expose proxy-specific information.

Basic GET request

The simplest call needs only a URL. Like the native fetch(), the method defaults to GET and follows redirects automatically.
import init, { EpoxyClient, EpoxyClientOptions } from "@mercuryworkshop/epoxy-tls";

await init();

const options = new EpoxyClientOptions();
options.user_agent = navigator.userAgent;
options.wisp_v2 = true;

const client = new EpoxyClient("wss://wisp.mercurywork.shop", options);

const resp = await client.fetch("https://example.com");
console.log(await resp.text());

Setting the request method and headers

Pass method and headers in the options object. headers can be either a plain object or a Headers instance.
// Plain object headers
const resp = await client.fetch("https://httpbin.org/post", {
  method: "POST",
  headers: {
    "Content-Type": "application/json",
    "X-Custom-Header": "my-value",
  },
  body: JSON.stringify({ hello: "world" }),
});

// Headers instance
const resp2 = await client.fetch("https://httpbin.org/get", {
  headers: new Headers({ Accept: "application/json" }),
});
The Host header is always managed by Epoxy and will be ignored if you try to set it manually.

Sending request bodies

Every body type supported by the standard Fetch API is accepted.
const resp = await client.fetch("https://httpbin.org/post", {
  method: "POST",
  body: "raw string body",
});

Redirect handling

Control redirect behavior with the redirect option.
ValueBehavior
"follow"Follow redirects automatically up to redirect_limit hops (default)
"manual"Return the redirect response immediately without following it
"error"Return the redirect response without following it (same as "manual")
// Default: follow redirects transparently
const resp = await client.fetch("https://httpbin.org/redirect/3");
console.log(resp.redirected); // true
console.log(resp.url);        // final URL after redirects

// Capture the redirect response directly
const redir = await client.fetch("https://httpbin.org/redirect/1", {
  redirect: "manual",
});
console.log(redir.status);                   // 302
console.log(redir.headers.get("location")); // redirect target
The default redirect_limit is 10 hops. You can raise or lower it on the client instance at any time:
client.redirect_limit = 20;

Response properties

The response object is a standard web_sys::Response extended with three extra properties:
PropertyTypeDescription
.statusnumberHTTP status code
.headersHeadersStandard Headers object (merged duplicates)
.urlstringFinal URL after all redirects
.redirectedbooleantrue if at least one redirect was followed
.rawHeadersobjectRaw header map; values are strings or arrays of strings for repeated headers
const resp = await client.fetch("https://httpbin.org/get");

console.log(resp.status);     // 200
console.log(resp.url);        // "https://httpbin.org/get"
console.log(resp.redirected); // false

// rawHeaders preserves duplicate header values as an array
console.log(resp.rawHeaders["set-cookie"]); // ["a=1", "b=2"] or "a=1"

Streaming the response body

Response bodies are exposed as ReadableStream<Uint8Array> and can be read incrementally without buffering the full payload.
const resp = await client.fetch("https://httpbin.org/stream-bytes/1024");

const reader = resp.body.getReader();
const decoder = new TextDecoder();

while (true) {
  const { value, done } = await reader.read();
  if (done) break;
  process(decoder.decode(value, { stream: true }));
}
Alternatively, pipe through TextDecoderStream for a cleaner streaming pattern:
const reader = resp.body
  .pipeThrough(new TextDecoderStream())
  .getReader();

while (true) {
  const { value, done } = await reader.read();
  if (done) break;
  console.log(value); // decoded string chunk
}
When certificate validation is disabled (options.disable_certificate_validation = true) or custom PEM certificate files are supplied (options.pem_files), every response will carry an X-Epoxy-CertsTampered: true header. Inspect this header to detect that TLS verification was modified before trusting the response.
HTTP/2 support (multiplexed streams, header compression) is only available in the full build of Epoxy TLS. The minimal build uses HTTP/1.1 exclusively. See Bundle Variants for details.

Build docs developers (and LLMs) love