// The fetch differential suite, running ISLAND-side under scriptc and as // plain Node code under the oracle: text/json/POST/header round trips // against the harness's local HTTP server, chunked streaming through the // reader protocol, 404-resolves, redirect following, and connection- // refused rejection — byte-exact output both sides. The SSE path lives in // the ssefetch fixture package (the AI-SDK shape exactly). const out = (line) => process.stdout.write(line + "\n"); export function run(base, refusedBase) { (async () => { // GET text: status/ok/statusText, body decode, response headers const r1 = await fetch(base + "/text"); out(`text ${r1.status} ${r1.ok} ${JSON.stringify(r1.statusText)} ${JSON.stringify(await r1.text())}`); out(`text-headers ${r1.headers.get("x-kind")} ${r1.headers.get("content-type")}`); // GET json const r2 = await fetch(base + "/json"); const j = await r2.json(); out(`json ${j.n} ${j.s} ${JSON.stringify(j.arr)}`); // POST with a string body: implicit text/plain content-type const r3 = await fetch(base + "/post-echo", { method: "POST", body: "payload é 😀" }); out(`post ${JSON.stringify(await r3.json())}`); // Node's request-body reader accepts string chunks from an island-side // ReadableStream and UTF-8 encodes each one before writing it. const stringBody = new ReadableStream({ start(controller) { controller.enqueue("stream-"); controller.enqueue("é 😀"); controller.close(); }, }); const r3s = await fetch(base + "/post-echo", { method: "POST", body: stringBody, duplex: "half", }); out(`post-stream-string ${JSON.stringify(await r3s.json())}`); // POST with URLSearchParams: implicit form content-type const r4 = await fetch(base + "/post-echo", { method: "POST", body: new URLSearchParams({ a: "1 2", b: "é" }), }); out(`post-form ${JSON.stringify(await r4.json())}`); // PUT with an explicit content-type const r5 = await fetch(base + "/post-echo", { method: "PUT", body: "{}", headers: { "content-type": "application/json" }, }); out(`put ${JSON.stringify(await r5.json())}`); // request headers echo + multi-valued response header combining const r6 = await fetch(base + "/header-echo", { headers: { "X-Echo-One": "v1", "x-echo-two": "v2" }, }); out(`headers ${await r6.text()}`); out(`multi ${r6.headers.get("x-multi")}`); // HTTP errors RESOLVE const r7 = await fetch(base + "/missing"); out(`missing ${r7.status} ${r7.ok} ${JSON.stringify(r7.statusText)} ${JSON.stringify(await r7.text())}`); // redirects are followed; url/redirected reflect the hop const r8 = await fetch(base + "/redirect"); const tail = r8.url.slice(r8.url.lastIndexOf("/")); out(`redirect ${r8.status} ${r8.redirected} ${tail} ${JSON.stringify(await r8.text())}`); // gzip/deflate response bodies arrive DECODED; the headers keep the // wire's content-encoding (Node's fetch shape exactly) const rg = await fetch(base + "/gzip"); const gz = await rg.text(); out(`gzip ${rg.headers.get("content-encoding")} len=${gz.length} ${JSON.stringify(gz.slice(0, 22))}`); const rd = await fetch(base + "/deflate"); out(`deflate ${rd.headers.get("content-encoding")} ${JSON.stringify(await rd.text())}`); // chunked body consumed incrementally through the reader protocol const r9 = await fetch(base + "/chunked"); const chunks = []; for await (const c of r9.body.pipeThrough(new TextDecoderStream())) chunks.push(c); out(`chunked ${JSON.stringify(chunks.join(""))}`); // only NETWORK failure rejects — TypeError, Node's exact message try { await fetch(refusedBase + "/nope"); out("refused no-throw"); } catch (e) { out(`refused ${e instanceof TypeError} ${e.name}: ${e.message}`); } out("done"); })().catch((e) => { out(`FATAL ${e}`); }); }