export function immediateCancelIterable() { return { [Symbol.iterator]() { return { next() { console.log("source iterator started"); return { value: 1, done: false }; }, return(reason) { console.log("source iterator returned:", reason); return { value: undefined, done: true }; }, }; }, }; } export async function streamFromProtocolProbe() { const promiseChunk = Promise.resolve(8); const asyncSource = { [Symbol.asyncIterator]() { return { next() { return Promise.resolve({ value: promiseChunk, done: false }); }, }; }, }; const asyncReader = ReadableStream.from(asyncSource).getReader(); const asyncPart = await asyncReader.read(); console.log("async promise chunk preserved:", asyncPart.value === promiseChunk); await asyncReader.cancel(); try { ReadableStream.from({ [Symbol.iterator]() { return null; }, }); console.log("invalid iterator unexpectedly accepted"); } catch (error) { console.log("invalid iterator:", error.name); } try { ReadableStream.from({ [Symbol.asyncIterator]: false, *[Symbol.iterator]() { yield 1; }, }); console.log("noncallable async iterator unexpectedly accepted"); } catch (error) { console.log("noncallable async iterator:", error.name); } let nextReads = 0; let nextCalls = 0; const stableNextSource = { [Symbol.asyncIterator]() { return { get next() { nextReads++; return function () { nextCalls++; return Promise.resolve( nextCalls === 1 ? { value: 9, done: false } : { value: undefined, done: true }, ); }; }, }; }, }; const stableNextReader = ReadableStream.from(stableNextSource).getReader(); console.log("async next reads at setup:", nextReads); await stableNextReader.read(); await stableNextReader.read(); console.log("async next method reused:", nextReads, nextCalls); try { const invalidNextStream = ReadableStream.from({ [Symbol.asyncIterator]() { return { next: 1 }; }, }); await invalidNextStream.getReader().read(); console.log("noncallable next unexpectedly accepted"); } catch (error) { console.log("noncallable next:", error.name); } } export async function requestInitReadOrder(url) { const names = [ "body", "cache", "credentials", "dispatcher", "duplex", "headers", "integrity", "keepalive", "method", "mode", "priority", "redirect", "referrer", "referrerPolicy", "signal", "window", ]; const reads = []; const init = {}; for (const name of names) { Object.defineProperty(init, name, { get() { reads.push(name); return undefined; }, }); } await fetch(url, init); console.log("request init reads:", reads.join(",")); } export async function requestInitConversionOrder(url) { const events = []; const init = { get method() { events.push("get method"); return { toString() { events.push("convert method"); return "GET"; }, }; }, get redirect() { events.push("get redirect"); return { toString() { events.push("convert redirect"); return "follow"; }, }; }, }; await fetch(url, init); console.log("request init conversions:", events.join(",")); } export async function inheritedRequestBodyMethodOverrides(url) { for (const method of ["GET", "HEAD"]) { const constructorInput = new Request(url, { method: "POST", body: "constructor body", }); try { new Request(constructorInput, { method }); console.log("request inherited body unexpectedly accepted:", method); } catch (error) { console.log("request inherited body:", method, error.name, error.message); } const fetchInput = new Request(url, { method: "POST", body: "fetch body" }); try { await fetch(fetchInput, { method }); console.log("fetch inherited body unexpectedly accepted:", method); } catch (error) { console.log("fetch inherited body:", method, error.name, error.message); } } }