Fetch: deviations from the WHATWG standard
This document lists the differences between the RSG runtime and the Fetch Standard. Each difference has an ID, such as F1 for fetch() or H1 for Headers. Items marked SDK are fixable in @roku-sdk; the other items are firmware behavior.
You can reproduce each result by running the fetch-spec-conformance example app.
In the Node.js 24 reference run, 24 of 25 checks pass; only F2 fails (a Roku extension). Streaming, CORS, redirect modes, and referrer policy are untested.
fetch()
The following table lists the differences in the global fetch() function.
| ID | Standard | RSG |
|---|---|---|
| F1 | Invalid init rejects with TypeError | Rejection fails instanceof TypeError |
| F2 | Not part of the standard | fetch.isFeatureSupported, fetch.apiVersion typed but undefined (SDK) |
Headers
The following table lists the differences in the Headers class.
| ID | Standard | RSG |
|---|---|---|
| H1 | new Headers() | Throws (SDK) |
| H2 | Sequence init | Throws; record init only |
| H3 | Case-insensitive names | Case-sensitive |
| H4 | append combines values | Keeps first value |
| H5 | Missing name: get() returns null | undefined |
| H6 | Invalid names throw | Accepted |
| H7 | Values normalized for whitespace | Not normalized |
| H8 | Iterable; entries, forEach, getSetCookie | Missing |
| H9 | keys()/values(): sorted, lower-cased iterators | Arrays, insertion order |
Request
The following table lists the differences in the Request class.
| ID | Standard | RSG |
|---|---|---|
| RQ1 | Body methods, clone | Missing |
| RQ2 | mode, credentials, cache, redirect, referrer, referrerPolicy, integrity, keepalive, signal, duplex | Missing |
| RQ3 | Relative URLs resolved | Kept as-is |
| RQ4 | Forbidden method throws TypeError | Throws Error |
Response
ResponseThe following table lists the differences in the Response class.
| ID | Standard | RSG |
|---|---|---|
| RS1 | Global Response | Missing (SDK) |
| RS2 | new Response(body, init) | Does not accept any arguments |
| RS3 | error, json, redirect statics | Missing |
| RS4 | statusText, type, redirected, body, bodyUsed, clone, formData | Missing |
| RS5 | blob() returns Blob | Returns ArrayBuffer |
| RS6 | Reused body rejects with TypeError | Rejects with Error |
AbortController / AbortSignal
AbortController / AbortSignalThe following table lists the differences in the AbortController and AbortSignal classes.
| ID | Standard | RSG |
|---|---|---|
| A1 | Global AbortController | Typed, but constructor throws (SDK) |
| A2 | addEventListener, onabort, throwIfAborted | Missing |
| A3 | abort, timeout, any statics | Missing |
Missing globals (G1)
The RSG runtime does not define the following globals: ReadableStream, WritableStream, TransformStream, Blob, File, FormData, URL, URLSearchParams, TextDecoder, DOMException, Event, EventTarget, and structuredClone.
Updated about 5 hours ago