fetch with Headers/Request/
Response/FormData, WebSocket, EventSource and XMLHttpRequest, on a
native HTTP/1.1 + WebSocket transport with TLS.
Which means browser HTTP libraries work unmodified - ky, axios, ofetch,
jose, reconnecting-websocket, centrifuge, any SDK written for a browser or
a service worker.
Nothing here blocks the game: a request in flight costs you no frames, and
every callback still runs on the script thread, so there is no concurrency to
reason about in your own code.
Overview
fetch
Requests, responses, bodies, streaming, aborting.
WebSocket
Full-duplex sockets with subprotocols and close codes.
EventSource
Server-sent events with automatic reconnect.
Limits & TLS
What the transport does not do, and who decides trust.
fetch
res.ok yourself.
Bodies
string, Blob, ArrayBuffer, any typed array, FormData, URLSearchParams
and ReadableStream (with duplex: "half") are all accepted, and the implied
content-type is filled in when you leave it out.
text(), json(), bytes(), arrayBuffer(), blob() or
formData() - once each. res.clone() before reading if you need it twice.
Streaming
res.body is a real ReadableStream with working backpressure, so a large
download never has to be held in memory at once:
gzip, deflate and br
arrive decoded, and the body is a normal stream - pipe it
through a TextDecoderStream or a DecompressionStream if that suits you
better.
Aborting & timeouts
DOMException named TimeoutError:
Redirects
Followed by the transport, up to 20, with the spec’s method rewrite (a 303, and a 301/302 on a request with a body, continue asGET). Authorization and
Cookie are dropped when a redirect crosses to another origin.
redirect: "manual" deviates from the spec on purpose: a browser hands back an
opaque response with no headers, and a script fetches a 3xx precisely to read
its Location.
data: and blob: URLs
Resolved locally - no socket involved.Headers
Case-insensitive, sorted iteration,getSetCookie() for the one header that is
never merged - all as specified. Response headers are immutable.
There is no forbidden-header list: User-Agent, Host, Referer, Cookie and
Origin all go out as you set them. Three are filled in when you leave them
out - host, accept-encoding (gzip, deflate, br), and a desktop-Chrome
user-agent, because plenty of sites answer 403 to anything they do not
recognise.
WebSocket
binaryType, bufferedAmount, CloseEvent with the peer’s code
and reason, and the spec’s failure order (error, then a close that was not
clean). http/https URLs are mapped onto ws/wss; anything else throws a
SyntaxError.
permessage-deflate) is offered to the server, and
keep-alive pings plus an idle timeout come for free - a peer that dies quietly is
noticed and reported as a close, not waited on forever.
WebSocket only exists when the host has the transport, so
typeof WebSocket === "function" is an honest feature check rather than a
stub that fails later.Staying connected
Reconnect logic is not the socket’s job, so bring a library or a few lines:reconnecting-websocket, socket.io-client and centrifuge all work as they
are - they only ever needed a real WebSocket global.
EventSource
Server-sent events, for the one-directional case. Reconnects on its own, resumes withLast-Event-ID, honours a retry: field and treats a 204 as “do not come
back”.
200 with content-type: text/event-stream; anything else is a hard
failure and is not retried.
XMLHttpRequest
Also here, in full - because libraries look for it. axios’ default browser adapter is XHR, and so is every SDK written beforefetch existed.
readyState, timeout, upload, overrideMimeType and the
responseType values ""/text/json/arraybuffer/blob all behave as
specified. Two gaps:
open(..., false)- a synchronous request - throws. There is one script thread, and blocking it until a socket answers would freeze the game.- No DOM, so
responseXMLandresponseType: "document"are alwaysnull.responseTextstill has the raw body.
loadstart → progress → load → loadend run rather
than byte-by-byte - the request body is sent in one piece, so there is nothing in
between to report honestly.
TLS & certificates
Certificates are checked by Windows itself, against the same trust store a browser on that machine uses, and the verdict lands before a single byte of your request goes out. So a host is trusted here exactly when it is trusted in your browser - cross-signed and incomplete chains, revocation and the hostname check all included. Expired, wrong-host, self-signed, untrusted-root and revoked certificates are rejected with a readable reason:Limits
The transport is deliberately small. What it does not do:mode, cache, referrerPolicy and credentials are stored and echoed back
untouched, because libraries read them, but nothing acts on them.
Recipes
A small API client
Retry with backoff
Download to disk with progress
Error handling
Only transport-level problems reject:WebSocket never throws for a connection problem: it fires error and then
close with wasClean === false.
For the rest of the browser surface these build on - streams, Blob,
crypto.subtle, TextDecoder - see Web APIs.