char/avril

(wip) why'd you have to go and make things so complicaaaaated?

git clone https://git.t4t.associates/char/avril

Charlotte Somrearrange libs into lib and extensions into extsf4a0f5b

main
25.4 KiB600 linesraw
1diff --git a/src/lib/byte-length-queuing-strategy.ts b/src/lib/byte-length-queuing-strategy.ts
2index c650548..b5a9075 100644
3--- a/src/lib/byte-length-queuing-strategy.ts
4+++ b/src/lib/byte-length-queuing-strategy.ts
5@@ -1,3 +1,5 @@
6+declare function markUncloneable(value: object, transferable?: boolean): void;
7+
8 import type { QueuingStrategy, QueuingStrategyInit } from './queuing-strategy';
9 import { setFunctionName, typeIsObject } from './helpers/miscellaneous';
10 import { assertRequiredArgument } from './validators/basic';
11@@ -19,6 +21,7 @@ export default class ByteLengthQueuingStrategy implements QueuingStrategy<ArrayB
12   readonly _byteLengthQueuingStrategyHighWaterMark: number;
13 
14   constructor(options: QueuingStrategyInit) {
15+    markUncloneable(this);
16     assertRequiredArgument(options, 1, 'ByteLengthQueuingStrategy');
17     options = convertQueuingStrategyInit(options, 'First parameter');
18     this._byteLengthQueuingStrategyHighWaterMark = options.highWaterMark;
19diff --git a/src/lib/count-queuing-strategy.ts b/src/lib/count-queuing-strategy.ts
20index 3753f99..29643c5 100644
21--- a/src/lib/count-queuing-strategy.ts
22+++ b/src/lib/count-queuing-strategy.ts
23@@ -1,3 +1,5 @@
24+declare function markUncloneable(value: object, transferable?: boolean): void;
25+
26 import type { QueuingStrategy, QueuingStrategyInit } from './queuing-strategy';
27 import { setFunctionName, typeIsObject } from './helpers/miscellaneous';
28 import { assertRequiredArgument } from './validators/basic';
29@@ -19,6 +21,7 @@ export default class CountQueuingStrategy implements QueuingStrategy<any> {
30   readonly _countQueuingStrategyHighWaterMark!: number;
31 
32   constructor(options: QueuingStrategyInit) {
33+    markUncloneable(this);
34     assertRequiredArgument(options, 1, 'CountQueuingStrategy');
35     options = convertQueuingStrategyInit(options, 'First parameter');
36     this._countQueuingStrategyHighWaterMark = options.highWaterMark;
37diff --git a/src/lib/helpers/webidl.ts b/src/lib/helpers/webidl.ts
38index bce6b50..0984ee5 100644
39--- a/src/lib/helpers/webidl.ts
40+++ b/src/lib/helpers/webidl.ts
41@@ -1,10 +1,17 @@
42-import { rethrowAssertionErrorRejection } from './miscellaneous';
43 import assert from '../../stub/assert';
44 
45-const originalPromise = Promise;
46-const originalPromiseResolve = Promise.resolve.bind(originalPromise);
47-const originalPromiseThen = Promise.prototype.then;
48-const originalPromiseReject = Promise.reject.bind(originalPromise);
49+declare function markPromiseHandled(promise: Promise<unknown>): void;
50+
51+declare function safeNewPromise<T>(executor: (resolve: (value: T | PromiseLike<T>) => void, reject: (reason?: any) => void) => void): Promise<T>;
52+declare const safePromiseResolve: typeof Promise.resolve;
53+declare const safePromiseReject: typeof Promise.reject;
54+declare const then: <T, R1 = T, R2 = never>(promise: Promise<T>, fulfilled?: (value: T) => R1 | PromiseLike<R1>, rejected?: (reason: any) => R2 | PromiseLike<R2>) => Promise<R1 | R2>;
55+declare const apply: typeof Reflect.apply;
56+
57+const originalPromise = safeNewPromise;
58+const originalPromiseResolve = safePromiseResolve;
59+const originalPromiseThen = then;
60+const originalPromiseReject = safePromiseReject;
61 
62 export const promiseResolve = originalPromiseResolve;
63 
64@@ -13,7 +20,7 @@ export function newPromise<T>(executor: (
65   resolve: (value: T | PromiseLike<T>) => void,
66   reject: (reason?: any) => void
67 ) => void): Promise<T> {
68-  return new originalPromise(executor);
69+  return originalPromise(executor);
70 }
71 
72 // https://webidl.spec.whatwg.org/#a-promise-resolved-with
73@@ -21,6 +28,15 @@ export function promiseResolvedWith<T>(value: T | PromiseLike<T>): Promise<T> {
74   return newPromise(resolve => resolve(value));
75 }
76 
77+const resolvedUndefinedPromise = originalPromise<undefined>(resolve => resolve(undefined));
78+// Shadowing constructor would invalidate V8's global promise-species protector.
79+Object.freeze(resolvedUndefinedPromise);
80+
81+// Only for internal reactions, not public results or promise assimilation.
82+export function promiseResolvedWithUndefined(): Promise<undefined> {
83+  return resolvedUndefinedPromise;
84+}
85+
86 // https://webidl.spec.whatwg.org/#a-promise-rejected-with
87 export function promiseRejectedWith<T = never>(reason: any): Promise<T> {
88   return originalPromiseReject(reason);
89@@ -33,7 +49,7 @@ export function PerformPromiseThen<T, TResult1 = T, TResult2 = never>(
90 ): Promise<TResult1 | TResult2> {
91   // There doesn't appear to be any way to correctly emulate the behaviour from JavaScript, so this is just an
92   // approximation.
93-  return originalPromiseThen.call(promise, onFulfilled, onRejected) as Promise<TResult1 | TResult2>;
94+  return originalPromiseThen(promise, onFulfilled, onRejected);
95 }
96 
97 // Bluebird logs a warning when a promise is created within a fulfillment handler, but then isn't returned
98@@ -44,11 +60,7 @@ export function uponPromise<T>(
99   onFulfilled?: (value: T) => null | PromiseLike<null>,
100   onRejected?: (reason: any) => null | PromiseLike<null>
101 ): void {
102-  PerformPromiseThen(
103-    PerformPromiseThen(promise, onFulfilled, onRejected),
104-    undefined,
105-    rethrowAssertionErrorRejection
106-  );
107+  setPromiseIsHandledToTrue(PerformPromiseThen(promise, onFulfilled, onRejected));
108 }
109 
110 export function uponFulfillment<T>(promise: Promise<T>, onFulfilled: (value: T) => null | PromiseLike<null>): void {
111@@ -68,7 +80,7 @@ export function transformPromiseWith<T, TResult1 = T, TResult2 = never>(
112 }
113 
114 export function setPromiseIsHandledToTrue(promise: Promise<unknown>): void {
115-  PerformPromiseThen(promise, undefined, rethrowAssertionErrorRejection);
116+  markPromiseHandled(promise);
117 }
118 
119 let _queueMicrotask: (callback: () => void) => void = (callback) => {
120@@ -87,7 +99,7 @@ export function reflectCall<T, A extends any[], R>(F: (this: T, ...fnArgs: A) =>
121   if (typeof F !== 'function') {
122     throw new TypeError('Argument is not a function');
123   }
124-  return Function.prototype.apply.call(F, V, args);
125+  return apply(F, V, args);
126 }
127 
128 export function promiseCall<T, A extends any[], R>(
129diff --git a/src/lib/readable-stream.ts b/src/lib/readable-stream.ts
130index 95a0fb1..f420dfa 100644
131--- a/src/lib/readable-stream.ts
132+++ b/src/lib/readable-stream.ts
133@@ -1,3 +1,5 @@
134+declare function markUncloneable(value: object, transferable?: boolean): void;
135+
136 import assert from '../stub/assert';
137 import {
138   promiseRejectedWith,
139@@ -408,6 +410,7 @@ export function CreateReadableStream<R>(
140   InitializeReadableStream(stream);
141 
142   const controller: ReadableStreamDefaultController<R> = Object.create(ReadableStreamDefaultController.prototype);
143+  markUncloneable(controller);
144   SetUpReadableStreamDefaultController(stream, controller, startAlgorithm, pullAlgorithm, cancelAlgorithm, highWaterMark, sizeAlgorithm);
145 
146   return stream;
147@@ -423,12 +426,14 @@ export function CreateReadableByteStream(
148   InitializeReadableStream(stream);
149 
150   const controller: ReadableByteStreamController = Object.create(ReadableByteStreamController.prototype);
151+  markUncloneable(controller);
152   SetUpReadableByteStreamController(stream, controller, startAlgorithm, pullAlgorithm, cancelAlgorithm, 0, undefined);
153 
154   return stream;
155 }
156 
157 function InitializeReadableStream(stream: ReadableStream) {
158+  markUncloneable(stream, true);
159   stream._state = 'readable';
160   stream._reader = undefined;
161   stream._storedError = undefined;
162diff --git a/src/lib/readable-stream/async-iterator.ts b/src/lib/readable-stream/async-iterator.ts
163index 503472d..c697e80 100644
164--- a/src/lib/readable-stream/async-iterator.ts
165+++ b/src/lib/readable-stream/async-iterator.ts
166@@ -1,3 +1,5 @@
167+declare function markUncloneable(value: object, transferable?: boolean): void;
168+
169 import { ReadableStream } from '../readable-stream';
170 import {
171   AcquireReadableStreamDefaultReader,
172@@ -58,7 +60,7 @@ export class ReadableStreamAsyncIteratorImpl<R> {
173 
174   private _nextSteps(): Promise<ReadableStreamDefaultReadResult<R>> {
175     if (this._isFinished) {
176-      return Promise.resolve({ value: undefined, done: true });
177+      return promiseResolvedWith({ value: undefined, done: true });
178     }
179 
180     const reader = this._reader;
181@@ -71,7 +73,7 @@ export class ReadableStreamAsyncIteratorImpl<R> {
182 
183   private _returnSteps(value: any): Promise<ReadableStreamDefaultReadResult<any>> {
184     if (this._isFinished) {
185-      return Promise.resolve({ value, done: true });
186+      return promiseResolvedWith({ value, done: true });
187     }
188     this._isFinished = true;
189 
190@@ -173,6 +175,7 @@ export function AcquireReadableStreamAsyncIterator<R>(
191   const reader = AcquireReadableStreamDefaultReader<R>(stream);
192   const impl = new ReadableStreamAsyncIteratorImpl(reader, preventCancel);
193   const iterator: ReadableStreamAsyncIteratorInstance<R> = Object.create(ReadableStreamAsyncIteratorPrototype);
194+  markUncloneable(iterator);
195   iterator._asyncIteratorImpl = impl;
196   return iterator;
197 }
198diff --git a/src/lib/readable-stream/byob-reader.ts b/src/lib/readable-stream/byob-reader.ts
199index dfc103f..5458438 100644
200--- a/src/lib/readable-stream/byob-reader.ts
201+++ b/src/lib/readable-stream/byob-reader.ts
202@@ -1,3 +1,5 @@
203+declare function markUncloneable(value: object, transferable?: boolean): void;
204+
205 import assert from '../../stub/assert';
206 import { SimpleQueue } from '../simple-queue';
207 import {
208@@ -119,6 +121,7 @@ export class ReadableStreamBYOBReader {
209   _readIntoRequests: SimpleQueue<ReadIntoRequest<any>>;
210 
211   constructor(stream: ReadableStream<Uint8Array>) {
212+    markUncloneable(this);
213     assertRequiredArgument(stream, 1, 'ReadableStreamBYOBReader');
214     assertReadableStream(stream, 'First parameter');
215 
216diff --git a/src/lib/readable-stream/byte-stream-controller.ts b/src/lib/readable-stream/byte-stream-controller.ts
217index e435b76..c44d980 100644
218--- a/src/lib/readable-stream/byte-stream-controller.ts
219+++ b/src/lib/readable-stream/byte-stream-controller.ts
220@@ -1,3 +1,5 @@
221+declare function markUncloneable(value: object, transferable?: boolean): void;
222+
223 import assert from '../../stub/assert';
224 import { SimpleQueue } from '../simple-queue';
225 import { ResetQueue } from '../abstract-ops/queue-with-sizes';
226@@ -34,7 +36,7 @@ import {
227   TransferArrayBuffer
228 } from '../abstract-ops/ecmascript';
229 import { CancelSteps, CanPullSyncSteps, PullSteps, ReleaseSteps } from '../abstract-ops/internal-methods';
230-import { promiseResolvedWith, uponPromise } from '../helpers/webidl';
231+import { promiseResolvedWith, promiseResolvedWithUndefined, uponPromise } from '../helpers/webidl';
232 import { assertRequiredArgument, convertUnsignedLongLongWithEnforceRange } from '../validators/basic';
233 import {
234   type ArrayBufferViewConstructor,
235@@ -1016,6 +1018,7 @@ export function ReadableByteStreamControllerGetBYOBRequest(controller: ReadableB
236     );
237 
238     const byobRequest: ReadableStreamBYOBRequest = Object.create(ReadableStreamBYOBRequest.prototype);
239+    markUncloneable(byobRequest);
240     SetUpReadableStreamBYOBRequest(byobRequest, controller, view as Uint8Array<ArrayBuffer>);
241     controller._byobRequest = byobRequest;
242   }
243@@ -1161,6 +1164,7 @@ export function SetUpReadableByteStreamControllerFromUnderlyingSource(
244   highWaterMark: number
245 ) {
246   const controller: ReadableByteStreamController = Object.create(ReadableByteStreamController.prototype);
247+  markUncloneable(controller);
248 
249   let startAlgorithm: () => void | PromiseLike<void>;
250   let pullAlgorithm: () => Promise<void>;
251@@ -1174,12 +1178,12 @@ export function SetUpReadableByteStreamControllerFromUnderlyingSource(
252   if (underlyingByteSource.pull !== undefined) {
253     pullAlgorithm = () => underlyingByteSource.pull!(controller);
254   } else {
255-    pullAlgorithm = () => promiseResolvedWith(undefined);
256+    pullAlgorithm = promiseResolvedWithUndefined;
257   }
258   if (underlyingByteSource.cancel !== undefined) {
259     cancelAlgorithm = reason => underlyingByteSource.cancel!(reason);
260   } else {
261-    cancelAlgorithm = () => promiseResolvedWith(undefined);
262+    cancelAlgorithm = promiseResolvedWithUndefined;
263   }
264 
265   const autoAllocateChunkSize = underlyingByteSource.autoAllocateChunkSize;
266diff --git a/src/lib/readable-stream/default-controller.ts b/src/lib/readable-stream/default-controller.ts
267index 11eb3be..0f9086e 100644
268--- a/src/lib/readable-stream/default-controller.ts
269+++ b/src/lib/readable-stream/default-controller.ts
270@@ -1,3 +1,5 @@
271+declare function markUncloneable(value: object, transferable?: boolean): void;
272+
273 import type { QueuingStrategySizeCallback } from '../queuing-strategy';
274 import assert from '../../stub/assert';
275 import { DequeueValue, EnqueueValueWithSize, type QueuePair, ResetQueue } from '../abstract-ops/queue-with-sizes';
276@@ -12,7 +14,7 @@ import { IsReadableStreamLocked, ReadableStream, ReadableStreamClose, ReadableSt
277 import type { ValidatedUnderlyingSource } from './underlying-source';
278 import { setFunctionName, typeIsObject } from '../helpers/miscellaneous';
279 import { CancelSteps, CanPullSyncSteps, PullSteps, ReleaseSteps } from '../abstract-ops/internal-methods';
280-import { promiseResolvedWith, uponPromise } from '../helpers/webidl';
281+import { promiseResolvedWith, promiseResolvedWithUndefined, uponPromise } from '../helpers/webidl';
282 
283 /**
284  * Allows control of a {@link ReadableStream | readable stream}'s state and internal queue.
285@@ -387,6 +389,7 @@ export function SetUpReadableStreamDefaultControllerFromUnderlyingSource<R>(
286   sizeAlgorithm: QueuingStrategySizeCallback<R>
287 ) {
288   const controller: ReadableStreamDefaultController<R> = Object.create(ReadableStreamDefaultController.prototype);
289+  markUncloneable(controller);
290 
291   let startAlgorithm: () => void | PromiseLike<void>;
292   let pullAlgorithm: () => Promise<void>;
293@@ -400,12 +403,12 @@ export function SetUpReadableStreamDefaultControllerFromUnderlyingSource<R>(
294   if (underlyingSource.pull !== undefined) {
295     pullAlgorithm = () => underlyingSource.pull!(controller);
296   } else {
297-    pullAlgorithm = () => promiseResolvedWith(undefined);
298+    pullAlgorithm = promiseResolvedWithUndefined;
299   }
300   if (underlyingSource.cancel !== undefined) {
301     cancelAlgorithm = reason => underlyingSource.cancel!(reason);
302   } else {
303-    cancelAlgorithm = () => promiseResolvedWith(undefined);
304+    cancelAlgorithm = promiseResolvedWithUndefined;
305   }
306 
307   SetUpReadableStreamDefaultController(stream, controller, startAlgorithm, pullAlgorithm, cancelAlgorithm, highWaterMark, sizeAlgorithm);
308diff --git a/src/lib/readable-stream/default-reader.ts b/src/lib/readable-stream/default-reader.ts
309index b0a432c..8d8007c 100644
310--- a/src/lib/readable-stream/default-reader.ts
311+++ b/src/lib/readable-stream/default-reader.ts
312@@ -1,3 +1,5 @@
313+declare function markUncloneable(value: object, transferable?: boolean): void;
314+
315 import assert from '../../stub/assert';
316 import { SimpleQueue } from '../simple-queue';
317 import {
318@@ -103,6 +105,7 @@ export class ReadableStreamDefaultReader<R = any> {
319   _readRequests: SimpleQueue<ReadRequest<R>>;
320 
321   constructor(stream: ReadableStream<R>) {
322+    markUncloneable(this);
323     assertRequiredArgument(stream, 1, 'ReadableStreamDefaultReader');
324     assertReadableStream(stream, 'First parameter');
325 
326diff --git a/src/lib/readable-stream/from.ts b/src/lib/readable-stream/from.ts
327index d745178..deceee7 100644
328--- a/src/lib/readable-stream/from.ts
329+++ b/src/lib/readable-stream/from.ts
330@@ -6,7 +6,7 @@ import {
331 } from './readable-stream-like';
332 import { ReadableStreamDefaultControllerClose, ReadableStreamDefaultControllerEnqueue } from './default-controller';
333 import { GetIterator, GetMethod, IteratorNext } from '../abstract-ops/ecmascript';
334-import { promiseCall, promiseRejectedWith, promiseResolvedWith, transformPromiseWith } from '../helpers/webidl';
335+import { promiseCall, promiseRejectedWith, promiseResolvedWith, promiseResolvedWithUndefined, transformPromiseWith } from '../helpers/webidl';
336 import { typeIsObject } from '../helpers/miscellaneous';
337 import { noop } from '../../utils';
338 
339@@ -54,7 +54,7 @@ export function ReadableStreamFromIterable<R>(asyncIterable: Iterable<R> | Async
340       return promiseRejectedWith(e);
341     }
342     if (returnMethod === undefined) {
343-      return promiseResolvedWith(undefined);
344+      return promiseResolvedWithUndefined();
345     }
346     const returnPromise = promiseCall(returnMethod, iterator, [reason]);
347     return transformPromiseWith(returnPromise, (iterResult) => {
348diff --git a/src/lib/readable-stream/pipe.ts b/src/lib/readable-stream/pipe.ts
349index 8044696..e0a4810 100644
350--- a/src/lib/readable-stream/pipe.ts
351+++ b/src/lib/readable-stream/pipe.ts
352@@ -23,6 +23,7 @@ import {
353   newPromise,
354   PerformPromiseThen,
355   promiseResolvedWith,
356+  promiseResolvedWithUndefined,
357   setPromiseIsHandledToTrue,
358   uponFulfillment,
359   uponPromise,
360@@ -32,6 +33,8 @@ import { noop } from '../../utils';
361 import { type AbortSignal, isAbortSignal } from '../abort-signal';
362 import { DOMException } from '../../stub/dom-exception';
363 
364+declare const safePromiseAll: typeof Promise.all;
365+
366 export function ReadableStreamPipeTo<T>(
367   source: ReadableStream<T>,
368   dest: WritableStream<T>,
369@@ -79,7 +82,13 @@ export function ReadableStreamPipeTo<T>(
370             return promiseResolvedWith(undefined);
371           });
372         }
373-        shutdownWithAction(() => Promise.all(actions.map(action => action())), true, error);
374+        shutdownWithAction(() => {
375+          const promises = [];
376+          for (let index = 0; index < actions.length; index++) {
377+            promises[index] = actions[index]();
378+          }
379+          return safePromiseAll(promises);
380+        }, true, error);
381       };
382 
383       if (signal.aborted) {
384@@ -234,7 +243,7 @@ class PipeState<T> {
385   _shuttingDown = false;
386 
387   // This is used to keep track of the spec's requirement that we wait for ongoing writes during shutdown.
388-  _currentWrite = promiseResolvedWith<void>(undefined);
389+  _currentWrite = promiseResolvedWithUndefined();
390 
391   constructor(readonly _writer: WritableStreamDefaultWriter<T>) {}
392 
393diff --git a/src/lib/readable-stream/tee.ts b/src/lib/readable-stream/tee.ts
394index 5b05eb1..3a82830 100644
395--- a/src/lib/readable-stream/tee.ts
396+++ b/src/lib/readable-stream/tee.ts
397@@ -22,7 +22,7 @@ import {
398   type ReadIntoRequest
399 } from './byob-reader';
400 import assert from '../../stub/assert';
401-import { newPromise, promiseResolvedWith, queueMicrotask, uponRejection } from '../helpers/webidl';
402+import { newPromise, promiseResolvedWithUndefined, queueMicrotask, uponRejection } from '../helpers/webidl';
403 import {
404   ReadableStreamDefaultControllerClose,
405   ReadableStreamDefaultControllerEnqueue,
406@@ -79,7 +79,7 @@ export function ReadableStreamDefaultTee<R>(
407   function pullAlgorithm(): Promise<void> {
408     if (reading) {
409       readAgain = true;
410-      return promiseResolvedWith(undefined);
411+      return promiseResolvedWithUndefined();
412     }
413 
414     reading = true;
415@@ -132,7 +132,7 @@ export function ReadableStreamDefaultTee<R>(
416     };
417     ReadableStreamDefaultReaderRead(reader, readRequest);
418 
419-    return promiseResolvedWith(undefined);
420+    return promiseResolvedWithUndefined();
421   }
422 
423   function cancel1Algorithm(reason: any): Promise<void> {
424@@ -369,7 +369,7 @@ export function ReadableByteStreamTee(stream: ReadableByteStream): [ReadableByte
425   function pull1Algorithm(): Promise<void> {
426     if (reading) {
427       readAgainForBranch1 = true;
428-      return promiseResolvedWith(undefined);
429+      return promiseResolvedWithUndefined();
430     }
431 
432     reading = true;
433@@ -381,13 +381,13 @@ export function ReadableByteStreamTee(stream: ReadableByteStream): [ReadableByte
434       pullWithBYOBReader(byobRequest._view!, false);
435     }
436 
437-    return promiseResolvedWith(undefined);
438+    return promiseResolvedWithUndefined();
439   }
440 
441   function pull2Algorithm(): Promise<void> {
442     if (reading) {
443       readAgainForBranch2 = true;
444-      return promiseResolvedWith(undefined);
445+      return promiseResolvedWithUndefined();
446     }
447 
448     reading = true;
449@@ -399,7 +399,7 @@ export function ReadableByteStreamTee(stream: ReadableByteStream): [ReadableByte
450       pullWithBYOBReader(byobRequest._view!, true);
451     }
452 
453-    return promiseResolvedWith(undefined);
454+    return promiseResolvedWithUndefined();
455   }
456 
457   function cancel1Algorithm(reason: any): Promise<void> {
458diff --git a/src/lib/transform-stream.ts b/src/lib/transform-stream.ts
459index f800382..1775e8d 100644
460--- a/src/lib/transform-stream.ts
461+++ b/src/lib/transform-stream.ts
462@@ -1,8 +1,11 @@
463+declare function markUncloneable(value: object, transferable?: boolean): void;
464+
465 import assert from '../stub/assert';
466 import {
467   newPromise,
468   promiseRejectedWith,
469   promiseResolvedWith,
470+  promiseResolvedWithUndefined,
471   setPromiseIsHandledToTrue,
472   transformPromiseWith,
473   uponPromise
474@@ -171,6 +174,7 @@ export function CreateTransformStream<I, O>(
475   );
476 
477   const controller: TransformStreamDefaultController<O> = Object.create(TransformStreamDefaultController.prototype);
478+  markUncloneable(controller);
479 
480   SetUpTransformStreamDefaultController(stream, controller, transformAlgorithm, flushAlgorithm, cancelAlgorithm);
481 
482@@ -187,6 +191,7 @@ function InitializeTransformStream<I, O>(
483   readableHighWaterMark: number,
484   readableSizeAlgorithm: QueuingStrategySizeCallback<O>
485 ) {
486+  markUncloneable(stream, true);
487   function startAlgorithm(): Promise<void> {
488     return startPromise;
489   }
490@@ -411,6 +416,7 @@ function SetUpTransformStreamDefaultControllerFromTransformer<I, O>(
491   transformer: ValidatedTransformer<I, O>
492 ) {
493   const controller: TransformStreamDefaultController<O> = Object.create(TransformStreamDefaultController.prototype);
494+  markUncloneable(controller);
495 
496   let transformAlgorithm: (chunk: I) => Promise<void>;
497   let flushAlgorithm: () => Promise<void>;
498@@ -422,7 +428,7 @@ function SetUpTransformStreamDefaultControllerFromTransformer<I, O>(
499     transformAlgorithm = (chunk) => {
500       try {
501         TransformStreamDefaultControllerEnqueue(controller, chunk as unknown as O);
502-        return promiseResolvedWith(undefined);
503+        return promiseResolvedWithUndefined();
504       } catch (transformResultE) {
505         return promiseRejectedWith(transformResultE);
506       }
507@@ -432,13 +438,13 @@ function SetUpTransformStreamDefaultControllerFromTransformer<I, O>(
508   if (transformer.flush !== undefined) {
509     flushAlgorithm = () => transformer.flush!(controller);
510   } else {
511-    flushAlgorithm = () => promiseResolvedWith(undefined);
512+    flushAlgorithm = promiseResolvedWithUndefined;
513   }
514 
515   if (transformer.cancel !== undefined) {
516     cancelAlgorithm = reason => transformer.cancel!(reason);
517   } else {
518-    cancelAlgorithm = () => promiseResolvedWith(undefined);
519+    cancelAlgorithm = promiseResolvedWithUndefined;
520   }
521 
522   SetUpTransformStreamDefaultController(stream, controller, transformAlgorithm, flushAlgorithm, cancelAlgorithm);
523diff --git a/src/lib/writable-stream.ts b/src/lib/writable-stream.ts
524index 08966c9..bc98b62 100644
525--- a/src/lib/writable-stream.ts
526+++ b/src/lib/writable-stream.ts
527@@ -1,8 +1,11 @@
528+declare function markUncloneable(value: object, transferable?: boolean): void;
529+
530 import assert from '../stub/assert';
531 import {
532   newPromise,
533   promiseRejectedWith,
534   promiseResolvedWith,
535+  promiseResolvedWithUndefined,
536   setPromiseIsHandledToTrue,
537   uponPromise
538 } from './helpers/webidl';
539@@ -237,6 +240,7 @@ function CreateWritableStream<W>(
540   InitializeWritableStream(stream);
541 
542   const controller: WritableStreamDefaultController<W> = Object.create(WritableStreamDefaultController.prototype);
543+  markUncloneable(controller);
544 
545   SetUpWritableStreamDefaultController(
546     stream, controller, startAlgorithm, writeAlgorithm, closeAlgorithm,
547@@ -246,6 +250,7 @@ function CreateWritableStream<W>(
548 }
549 
550 function InitializeWritableStream<W>(stream: WritableStream<W>) {
551+  markUncloneable(stream, true);
552   stream._state = 'writable';
553 
554   // The error that will be reported by new method calls once the state becomes errored. Only set when [[state]] is
555@@ -616,6 +621,7 @@ export class WritableStreamDefaultWriter<W = any> {
556   _readyPromiseState!: 'pending' | 'fulfilled' | 'rejected';
557 
558   constructor(stream: WritableStream<W>) {
559+    markUncloneable(this);
560     assertRequiredArgument(stream, 1, 'WritableStreamDefaultWriter');
561     assertWritableStream(stream, 'First parameter');
562 
563@@ -843,7 +849,7 @@ function WritableStreamDefaultWriterCloseWithErrorPropagation(writer: WritableSt
564 
565   const state = stream._state;
566   if (WritableStreamCloseQueuedOrInFlight(stream) || state === 'closed') {
567-    return promiseResolvedWith(undefined);
568+    return promiseResolvedWithUndefined();
569   }
570 
571   if (state === 'errored') {
572@@ -1124,6 +1130,7 @@ function SetUpWritableStreamDefaultControllerFromUnderlyingSink<W>(
573   sizeAlgorithm: QueuingStrategySizeCallback<W>
574 ) {
575   const controller = Object.create(WritableStreamDefaultController.prototype);
576+  markUncloneable(controller);
577 
578   let startAlgorithm: () => void | PromiseLike<void>;
579   let writeAlgorithm: (chunk: W) => Promise<void>;
580@@ -1138,17 +1145,17 @@ function SetUpWritableStreamDefaultControllerFromUnderlyingSink<W>(
581   if (underlyingSink.write !== undefined) {
582     writeAlgorithm = chunk => underlyingSink.write!(chunk, controller);
583   } else {
584-    writeAlgorithm = () => promiseResolvedWith(undefined);
585+    writeAlgorithm = promiseResolvedWithUndefined;
586   }
587   if (underlyingSink.close !== undefined) {
588     closeAlgorithm = () => underlyingSink.close!();
589   } else {
590-    closeAlgorithm = () => promiseResolvedWith(undefined);
591+    closeAlgorithm = promiseResolvedWithUndefined;
592   }
593   if (underlyingSink.abort !== undefined) {
594     abortAlgorithm = reason => underlyingSink.abort!(reason);
595   } else {
596-    abortAlgorithm = () => promiseResolvedWith(undefined);
597+    abortAlgorithm = promiseResolvedWithUndefined;
598   }
599 
600   SetUpWritableStreamDefaultController(stream, controller, startAlgorithm, writeAlgorithm, closeAlgorithm, abortAlgorithm, highWaterMark, sizeAlgorithm);