cloudworker-proxy
Version:
An api gateway for cloudflare workers
1,225 lines (1,215 loc) • 120 kB
JavaScript
const SymbolPolyfill = typeof Symbol === 'function' && typeof Symbol.iterator === 'symbol' ?
Symbol :
description => `Symbol(${description})`;
/// <reference lib="dom" />
function noop() {
// do nothing
}
function getGlobals() {
/* global self, window, global */
if (typeof self !== 'undefined') {
return self;
}
else if (typeof window !== 'undefined') {
return window;
}
else if (typeof global !== 'undefined') {
return global;
}
return undefined;
}
const globals = getGlobals();
// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number/isNaN#Polyfill
const NumberIsNaN = Number.isNaN || function (x) {
// eslint-disable-next-line no-self-compare
return x !== x;
};
function typeIsObject(x) {
return (typeof x === 'object' && x !== null) || typeof x === 'function';
}
function createDataProperty(o, p, v) {
Object.defineProperty(o, p, { value: v, writable: true, enumerable: true, configurable: true });
}
function createArrayFromList(elements) {
// We use arrays to represent lists, so this is basically a no-op.
// Do a slice though just in case we happen to depend on the unique-ness.
return elements.slice();
}
function ArrayBufferCopy(dest, destOffset, src, srcOffset, n) {
new Uint8Array(dest).set(new Uint8Array(src, srcOffset, n), destOffset);
}
function IsFiniteNonNegativeNumber(v) {
if (IsNonNegativeNumber(v) === false) {
return false;
}
if (v === Infinity) {
return false;
}
return true;
}
function IsNonNegativeNumber(v) {
if (typeof v !== 'number') {
return false;
}
if (NumberIsNaN(v)) {
return false;
}
if (v < 0) {
return false;
}
return true;
}
function Call(F, V, args) {
if (typeof F !== 'function') {
throw new TypeError('Argument is not a function');
}
return Function.prototype.apply.call(F, V, args);
}
function CreateAlgorithmFromUnderlyingMethod(underlyingObject, methodName, algoArgCount, extraArgs) {
const method = underlyingObject[methodName];
if (method !== undefined) {
if (typeof method !== 'function') {
throw new TypeError(`${method} is not a method`);
}
switch (algoArgCount) {
case 0: {
return () => {
return PromiseCall(method, underlyingObject, extraArgs);
};
}
case 1: {
return arg => {
const fullArgs = [arg].concat(extraArgs);
return PromiseCall(method, underlyingObject, fullArgs);
};
}
}
}
return () => Promise.resolve();
}
function InvokeOrNoop(O, P, args) {
const method = O[P];
if (method === undefined) {
return undefined;
}
return Call(method, O, args);
}
function PromiseCall(F, V, args) {
try {
return Promise.resolve(Call(F, V, args));
}
catch (value) {
return Promise.reject(value);
}
}
// Not implemented correctly
function TransferArrayBuffer(O) {
return O;
}
// Not implemented correctly
function IsDetachedBuffer(O) {
return false;
}
function ValidateAndNormalizeHighWaterMark(highWaterMark) {
highWaterMark = Number(highWaterMark);
if (NumberIsNaN(highWaterMark) || highWaterMark < 0) {
throw new RangeError('highWaterMark property of a queuing strategy must be non-negative and non-NaN');
}
return highWaterMark;
}
function MakeSizeAlgorithmFromSizeFunction(size) {
if (size === undefined) {
return () => 1;
}
if (typeof size !== 'function') {
throw new TypeError('size property of a queuing strategy must be a function');
}
return chunk => size(chunk);
}
function PerformPromiseThen(promise, onFulfilled, onRejected) {
// There doesn't appear to be any way to correctly emulate the behaviour from JavaScript, so this is just an
// approximation.
return Promise.prototype.then.call(promise, onFulfilled, onRejected);
}
function WaitForAll(promises, successSteps, failureSteps) {
let rejected = false;
const rejectionHandler = (arg) => {
if (rejected === false) {
rejected = true;
failureSteps(arg);
}
};
let index = 0;
let fulfilledCount = 0;
const total = promises.length;
const result = new Array(total);
for (const promise of promises) {
const promiseIndex = index;
const fulfillmentHandler = (arg) => {
result[promiseIndex] = arg;
++fulfilledCount;
if (fulfilledCount === total) {
successSteps(result);
}
};
PerformPromiseThen(promise, fulfillmentHandler, rejectionHandler);
++index;
}
}
function WaitForAllPromise(promises, successSteps, failureSteps = undefined) {
let resolvePromise;
let rejectPromise;
const promise = new Promise((resolve, reject) => {
resolvePromise = resolve;
rejectPromise = reject;
});
if (failureSteps === undefined) {
failureSteps = arg => {
throw arg;
};
}
const successStepsWrapper = (results) => {
try {
const stepsResult = successSteps(results);
resolvePromise(stepsResult);
}
catch (e) {
rejectPromise(e);
}
};
const failureStepsWrapper = (reason) => {
try {
const stepsResult = failureSteps(reason);
resolvePromise(stepsResult);
}
catch (e) {
rejectPromise(e);
}
};
WaitForAll(promises, successStepsWrapper, failureStepsWrapper);
return promise;
}
const rethrowAssertionErrorRejection = noop;
function DequeueValue(container) {
const pair = container._queue.shift();
container._queueTotalSize -= pair.size;
if (container._queueTotalSize < 0) {
container._queueTotalSize = 0;
}
return pair.value;
}
function EnqueueValueWithSize(container, value, size) {
size = Number(size);
if (!IsFiniteNonNegativeNumber(size)) {
throw new RangeError('Size must be a finite, non-NaN, non-negative number.');
}
container._queue.push({ value, size });
container._queueTotalSize += size;
}
function PeekQueueValue(container) {
const pair = container._queue[0];
return pair.value;
}
function ResetQueue(container) {
container._queue = [];
container._queueTotalSize = 0;
}
const AbortSteps = SymbolPolyfill('[[AbortSteps]]');
const ErrorSteps = SymbolPolyfill('[[ErrorSteps]]');
class WritableStream {
constructor(underlyingSink = {}, strategy = {}) {
InitializeWritableStream(this);
const size = strategy.size;
let highWaterMark = strategy.highWaterMark;
const type = underlyingSink.type;
if (type !== undefined) {
throw new RangeError('Invalid type is specified');
}
const sizeAlgorithm = MakeSizeAlgorithmFromSizeFunction(size);
if (highWaterMark === undefined) {
highWaterMark = 1;
}
highWaterMark = ValidateAndNormalizeHighWaterMark(highWaterMark);
SetUpWritableStreamDefaultControllerFromUnderlyingSink(this, underlyingSink, highWaterMark, sizeAlgorithm);
}
get locked() {
if (IsWritableStream(this) === false) {
throw streamBrandCheckException('locked');
}
return IsWritableStreamLocked(this);
}
abort(reason) {
if (IsWritableStream(this) === false) {
return Promise.reject(streamBrandCheckException('abort'));
}
if (IsWritableStreamLocked(this) === true) {
return Promise.reject(new TypeError('Cannot abort a stream that already has a writer'));
}
return WritableStreamAbort(this, reason);
}
getWriter() {
if (IsWritableStream(this) === false) {
throw streamBrandCheckException('getWriter');
}
return AcquireWritableStreamDefaultWriter(this);
}
}
// Abstract operations for the WritableStream.
function AcquireWritableStreamDefaultWriter(stream) {
return new WritableStreamDefaultWriter(stream);
}
// Throws if and only if startAlgorithm throws.
function CreateWritableStream(startAlgorithm, writeAlgorithm, closeAlgorithm, abortAlgorithm, highWaterMark = 1, sizeAlgorithm = () => 1) {
const stream = Object.create(WritableStream.prototype);
InitializeWritableStream(stream);
const controller = Object.create(WritableStreamDefaultController.prototype);
SetUpWritableStreamDefaultController(stream, controller, startAlgorithm, writeAlgorithm, closeAlgorithm, abortAlgorithm, highWaterMark, sizeAlgorithm);
return stream;
}
function InitializeWritableStream(stream) {
stream._state = 'writable';
// The error that will be reported by new method calls once the state becomes errored. Only set when [[state]] is
// 'erroring' or 'errored'. May be set to an undefined value.
stream._storedError = undefined;
stream._writer = undefined;
// Initialize to undefined first because the constructor of the controller checks this
// variable to validate the caller.
stream._writableStreamController = undefined;
// This queue is placed here instead of the writer class in order to allow for passing a writer to the next data
// producer without waiting for the queued writes to finish.
stream._writeRequests = [];
// Write requests are removed from _writeRequests when write() is called on the underlying sink. This prevents
// them from being erroneously rejected on error. If a write() call is in-flight, the request is stored here.
stream._inFlightWriteRequest = undefined;
// The promise that was returned from writer.close(). Stored here because it may be fulfilled after the writer
// has been detached.
stream._closeRequest = undefined;
// Close request is removed from _closeRequest when close() is called on the underlying sink. This prevents it
// from being erroneously rejected on error. If a close() call is in-flight, the request is stored here.
stream._inFlightCloseRequest = undefined;
// The promise that was returned from writer.abort(). This may also be fulfilled after the writer has detached.
stream._pendingAbortRequest = undefined;
// The backpressure signal set by the controller.
stream._backpressure = false;
}
function IsWritableStream(x) {
if (!typeIsObject(x)) {
return false;
}
if (!Object.prototype.hasOwnProperty.call(x, '_writableStreamController')) {
return false;
}
return true;
}
function IsWritableStreamLocked(stream) {
if (stream._writer === undefined) {
return false;
}
return true;
}
function WritableStreamAbort(stream, reason) {
const state = stream._state;
if (state === 'closed' || state === 'errored') {
return Promise.resolve(undefined);
}
if (stream._pendingAbortRequest !== undefined) {
return stream._pendingAbortRequest._promise;
}
let wasAlreadyErroring = false;
if (state === 'erroring') {
wasAlreadyErroring = true;
// reason will not be used, so don't keep a reference to it.
reason = undefined;
}
const promise = new Promise((resolve, reject) => {
stream._pendingAbortRequest = {
_promise: undefined,
_resolve: resolve,
_reject: reject,
_reason: reason,
_wasAlreadyErroring: wasAlreadyErroring
};
});
stream._pendingAbortRequest._promise = promise;
if (wasAlreadyErroring === false) {
WritableStreamStartErroring(stream, reason);
}
return promise;
}
// WritableStream API exposed for controllers.
function WritableStreamAddWriteRequest(stream) {
const promise = new Promise((resolve, reject) => {
const writeRequest = {
_resolve: resolve,
_reject: reject
};
stream._writeRequests.push(writeRequest);
});
return promise;
}
function WritableStreamDealWithRejection(stream, error) {
const state = stream._state;
if (state === 'writable') {
WritableStreamStartErroring(stream, error);
return;
}
WritableStreamFinishErroring(stream);
}
function WritableStreamStartErroring(stream, reason) {
const controller = stream._writableStreamController;
stream._state = 'erroring';
stream._storedError = reason;
const writer = stream._writer;
if (writer !== undefined) {
WritableStreamDefaultWriterEnsureReadyPromiseRejected(writer, reason);
}
if (WritableStreamHasOperationMarkedInFlight(stream) === false && controller._started === true) {
WritableStreamFinishErroring(stream);
}
}
function WritableStreamFinishErroring(stream) {
stream._state = 'errored';
stream._writableStreamController[ErrorSteps]();
const storedError = stream._storedError;
for (const writeRequest of stream._writeRequests) {
writeRequest._reject(storedError);
}
stream._writeRequests = [];
if (stream._pendingAbortRequest === undefined) {
WritableStreamRejectCloseAndClosedPromiseIfNeeded(stream);
return;
}
const abortRequest = stream._pendingAbortRequest;
stream._pendingAbortRequest = undefined;
if (abortRequest._wasAlreadyErroring === true) {
abortRequest._reject(storedError);
WritableStreamRejectCloseAndClosedPromiseIfNeeded(stream);
return;
}
const promise = stream._writableStreamController[AbortSteps](abortRequest._reason);
promise.then(() => {
abortRequest._resolve();
WritableStreamRejectCloseAndClosedPromiseIfNeeded(stream);
}, (reason) => {
abortRequest._reject(reason);
WritableStreamRejectCloseAndClosedPromiseIfNeeded(stream);
});
}
function WritableStreamFinishInFlightWrite(stream) {
stream._inFlightWriteRequest._resolve(undefined);
stream._inFlightWriteRequest = undefined;
}
function WritableStreamFinishInFlightWriteWithError(stream, error) {
stream._inFlightWriteRequest._reject(error);
stream._inFlightWriteRequest = undefined;
WritableStreamDealWithRejection(stream, error);
}
function WritableStreamFinishInFlightClose(stream) {
stream._inFlightCloseRequest._resolve(undefined);
stream._inFlightCloseRequest = undefined;
const state = stream._state;
if (state === 'erroring') {
// The error was too late to do anything, so it is ignored.
stream._storedError = undefined;
if (stream._pendingAbortRequest !== undefined) {
stream._pendingAbortRequest._resolve();
stream._pendingAbortRequest = undefined;
}
}
stream._state = 'closed';
const writer = stream._writer;
if (writer !== undefined) {
defaultWriterClosedPromiseResolve(writer);
}
}
function WritableStreamFinishInFlightCloseWithError(stream, error) {
stream._inFlightCloseRequest._reject(error);
stream._inFlightCloseRequest = undefined;
// Never execute sink abort() after sink close().
if (stream._pendingAbortRequest !== undefined) {
stream._pendingAbortRequest._reject(error);
stream._pendingAbortRequest = undefined;
}
WritableStreamDealWithRejection(stream, error);
}
// TODO(ricea): Fix alphabetical order.
function WritableStreamCloseQueuedOrInFlight(stream) {
if (stream._closeRequest === undefined && stream._inFlightCloseRequest === undefined) {
return false;
}
return true;
}
function WritableStreamHasOperationMarkedInFlight(stream) {
if (stream._inFlightWriteRequest === undefined && stream._inFlightCloseRequest === undefined) {
return false;
}
return true;
}
function WritableStreamMarkCloseRequestInFlight(stream) {
stream._inFlightCloseRequest = stream._closeRequest;
stream._closeRequest = undefined;
}
function WritableStreamMarkFirstWriteRequestInFlight(stream) {
stream._inFlightWriteRequest = stream._writeRequests.shift();
}
function WritableStreamRejectCloseAndClosedPromiseIfNeeded(stream) {
if (stream._closeRequest !== undefined) {
stream._closeRequest._reject(stream._storedError);
stream._closeRequest = undefined;
}
const writer = stream._writer;
if (writer !== undefined) {
defaultWriterClosedPromiseReject(writer, stream._storedError);
}
}
function WritableStreamUpdateBackpressure(stream, backpressure) {
const writer = stream._writer;
if (writer !== undefined && backpressure !== stream._backpressure) {
if (backpressure === true) {
defaultWriterReadyPromiseReset(writer);
}
else {
defaultWriterReadyPromiseResolve(writer);
}
}
stream._backpressure = backpressure;
}
class WritableStreamDefaultWriter {
constructor(stream) {
if (IsWritableStream(stream) === false) {
throw new TypeError('WritableStreamDefaultWriter can only be constructed with a WritableStream instance');
}
if (IsWritableStreamLocked(stream) === true) {
throw new TypeError('This stream has already been locked for exclusive writing by another writer');
}
this._ownerWritableStream = stream;
stream._writer = this;
const state = stream._state;
if (state === 'writable') {
if (WritableStreamCloseQueuedOrInFlight(stream) === false && stream._backpressure === true) {
defaultWriterReadyPromiseInitialize(this);
}
else {
defaultWriterReadyPromiseInitializeAsResolved(this);
}
defaultWriterClosedPromiseInitialize(this);
}
else if (state === 'erroring') {
defaultWriterReadyPromiseInitializeAsRejected(this, stream._storedError);
defaultWriterClosedPromiseInitialize(this);
}
else if (state === 'closed') {
defaultWriterReadyPromiseInitializeAsResolved(this);
defaultWriterClosedPromiseInitializeAsResolved(this);
}
else {
const storedError = stream._storedError;
defaultWriterReadyPromiseInitializeAsRejected(this, storedError);
defaultWriterClosedPromiseInitializeAsRejected(this, storedError);
}
}
get closed() {
if (IsWritableStreamDefaultWriter(this) === false) {
return Promise.reject(defaultWriterBrandCheckException('closed'));
}
return this._closedPromise;
}
get desiredSize() {
if (IsWritableStreamDefaultWriter(this) === false) {
throw defaultWriterBrandCheckException('desiredSize');
}
if (this._ownerWritableStream === undefined) {
throw defaultWriterLockException('desiredSize');
}
return WritableStreamDefaultWriterGetDesiredSize(this);
}
get ready() {
if (IsWritableStreamDefaultWriter(this) === false) {
return Promise.reject(defaultWriterBrandCheckException('ready'));
}
return this._readyPromise;
}
abort(reason) {
if (IsWritableStreamDefaultWriter(this) === false) {
return Promise.reject(defaultWriterBrandCheckException('abort'));
}
if (this._ownerWritableStream === undefined) {
return Promise.reject(defaultWriterLockException('abort'));
}
return WritableStreamDefaultWriterAbort(this, reason);
}
close() {
if (IsWritableStreamDefaultWriter(this) === false) {
return Promise.reject(defaultWriterBrandCheckException('close'));
}
const stream = this._ownerWritableStream;
if (stream === undefined) {
return Promise.reject(defaultWriterLockException('close'));
}
if (WritableStreamCloseQueuedOrInFlight(stream) === true) {
return Promise.reject(new TypeError('cannot close an already-closing stream'));
}
return WritableStreamDefaultWriterClose(this);
}
releaseLock() {
if (IsWritableStreamDefaultWriter(this) === false) {
throw defaultWriterBrandCheckException('releaseLock');
}
const stream = this._ownerWritableStream;
if (stream === undefined) {
return;
}
WritableStreamDefaultWriterRelease(this);
}
write(chunk) {
if (IsWritableStreamDefaultWriter(this) === false) {
return Promise.reject(defaultWriterBrandCheckException('write'));
}
if (this._ownerWritableStream === undefined) {
return Promise.reject(defaultWriterLockException('write to'));
}
return WritableStreamDefaultWriterWrite(this, chunk);
}
}
// Abstract operations for the WritableStreamDefaultWriter.
function IsWritableStreamDefaultWriter(x) {
if (!typeIsObject(x)) {
return false;
}
if (!Object.prototype.hasOwnProperty.call(x, '_ownerWritableStream')) {
return false;
}
return true;
}
// A client of WritableStreamDefaultWriter may use these functions directly to bypass state check.
function WritableStreamDefaultWriterAbort(writer, reason) {
const stream = writer._ownerWritableStream;
return WritableStreamAbort(stream, reason);
}
function WritableStreamDefaultWriterClose(writer) {
const stream = writer._ownerWritableStream;
const state = stream._state;
if (state === 'closed' || state === 'errored') {
return Promise.reject(new TypeError(`The stream (in ${state} state) is not in the writable state and cannot be closed`));
}
const promise = new Promise((resolve, reject) => {
const closeRequest = {
_resolve: resolve,
_reject: reject
};
stream._closeRequest = closeRequest;
});
if (stream._backpressure === true && state === 'writable') {
defaultWriterReadyPromiseResolve(writer);
}
WritableStreamDefaultControllerClose(stream._writableStreamController);
return promise;
}
function WritableStreamDefaultWriterCloseWithErrorPropagation(writer) {
const stream = writer._ownerWritableStream;
const state = stream._state;
if (WritableStreamCloseQueuedOrInFlight(stream) === true || state === 'closed') {
return Promise.resolve();
}
if (state === 'errored') {
return Promise.reject(stream._storedError);
}
return WritableStreamDefaultWriterClose(writer);
}
function WritableStreamDefaultWriterEnsureClosedPromiseRejected(writer, error) {
if (writer._closedPromiseState === 'pending') {
defaultWriterClosedPromiseReject(writer, error);
}
else {
defaultWriterClosedPromiseResetToRejected(writer, error);
}
}
function WritableStreamDefaultWriterEnsureReadyPromiseRejected(writer, error) {
if (writer._readyPromiseState === 'pending') {
defaultWriterReadyPromiseReject(writer, error);
}
else {
defaultWriterReadyPromiseResetToRejected(writer, error);
}
}
function WritableStreamDefaultWriterGetDesiredSize(writer) {
const stream = writer._ownerWritableStream;
const state = stream._state;
if (state === 'errored' || state === 'erroring') {
return null;
}
if (state === 'closed') {
return 0;
}
return WritableStreamDefaultControllerGetDesiredSize(stream._writableStreamController);
}
function WritableStreamDefaultWriterRelease(writer) {
const stream = writer._ownerWritableStream;
const releasedError = new TypeError('Writer was released and can no longer be used to monitor the stream\'s closedness');
WritableStreamDefaultWriterEnsureReadyPromiseRejected(writer, releasedError);
// The state transitions to "errored" before the sink abort() method runs, but the writer.closed promise is not
// rejected until afterwards. This means that simply testing state will not work.
WritableStreamDefaultWriterEnsureClosedPromiseRejected(writer, releasedError);
stream._writer = undefined;
writer._ownerWritableStream = undefined;
}
function WritableStreamDefaultWriterWrite(writer, chunk) {
const stream = writer._ownerWritableStream;
const controller = stream._writableStreamController;
const chunkSize = WritableStreamDefaultControllerGetChunkSize(controller, chunk);
if (stream !== writer._ownerWritableStream) {
return Promise.reject(defaultWriterLockException('write to'));
}
const state = stream._state;
if (state === 'errored') {
return Promise.reject(stream._storedError);
}
if (WritableStreamCloseQueuedOrInFlight(stream) === true || state === 'closed') {
return Promise.reject(new TypeError('The stream is closing or closed and cannot be written to'));
}
if (state === 'erroring') {
return Promise.reject(stream._storedError);
}
const promise = WritableStreamAddWriteRequest(stream);
WritableStreamDefaultControllerWrite(controller, chunk, chunkSize);
return promise;
}
class WritableStreamDefaultController {
/** @internal */
constructor() {
throw new TypeError('WritableStreamDefaultController cannot be constructed explicitly');
}
error(e) {
if (IsWritableStreamDefaultController(this) === false) {
throw new TypeError('WritableStreamDefaultController.prototype.error can only be used on a WritableStreamDefaultController');
}
const state = this._controlledWritableStream._state;
if (state !== 'writable') {
// The stream is closed, errored or will be soon. The sink can't do anything useful if it gets an error here, so
// just treat it as a no-op.
return;
}
WritableStreamDefaultControllerError(this, e);
}
/** @internal */
[AbortSteps](reason) {
const result = this._abortAlgorithm(reason);
WritableStreamDefaultControllerClearAlgorithms(this);
return result;
}
/** @internal */
[ErrorSteps]() {
ResetQueue(this);
}
}
// Abstract operations implementing interface required by the WritableStream.
function IsWritableStreamDefaultController(x) {
if (!typeIsObject(x)) {
return false;
}
if (!Object.prototype.hasOwnProperty.call(x, '_controlledWritableStream')) {
return false;
}
return true;
}
function SetUpWritableStreamDefaultController(stream, controller, startAlgorithm, writeAlgorithm, closeAlgorithm, abortAlgorithm, highWaterMark, sizeAlgorithm) {
controller._controlledWritableStream = stream;
stream._writableStreamController = controller;
// Need to set the slots so that the assert doesn't fire. In the spec the slots already exist implicitly.
controller._queue = undefined;
controller._queueTotalSize = undefined;
ResetQueue(controller);
controller._started = false;
controller._strategySizeAlgorithm = sizeAlgorithm;
controller._strategyHWM = highWaterMark;
controller._writeAlgorithm = writeAlgorithm;
controller._closeAlgorithm = closeAlgorithm;
controller._abortAlgorithm = abortAlgorithm;
const backpressure = WritableStreamDefaultControllerGetBackpressure(controller);
WritableStreamUpdateBackpressure(stream, backpressure);
const startResult = startAlgorithm();
const startPromise = Promise.resolve(startResult);
startPromise.then(() => {
controller._started = true;
WritableStreamDefaultControllerAdvanceQueueIfNeeded(controller);
}, r => {
controller._started = true;
WritableStreamDealWithRejection(stream, r);
}).catch(rethrowAssertionErrorRejection);
}
function SetUpWritableStreamDefaultControllerFromUnderlyingSink(stream, underlyingSink, highWaterMark, sizeAlgorithm) {
const controller = Object.create(WritableStreamDefaultController.prototype);
function startAlgorithm() {
return InvokeOrNoop(underlyingSink, 'start', [controller]);
}
const writeAlgorithm = CreateAlgorithmFromUnderlyingMethod(underlyingSink, 'write', 1, [controller]);
const closeAlgorithm = CreateAlgorithmFromUnderlyingMethod(underlyingSink, 'close', 0, []);
const abortAlgorithm = CreateAlgorithmFromUnderlyingMethod(underlyingSink, 'abort', 1, []);
SetUpWritableStreamDefaultController(stream, controller, startAlgorithm, writeAlgorithm, closeAlgorithm, abortAlgorithm, highWaterMark, sizeAlgorithm);
}
// ClearAlgorithms may be called twice. Erroring the same stream in multiple ways will often result in redundant calls.
function WritableStreamDefaultControllerClearAlgorithms(controller) {
controller._writeAlgorithm = undefined;
controller._closeAlgorithm = undefined;
controller._abortAlgorithm = undefined;
controller._strategySizeAlgorithm = undefined;
}
function WritableStreamDefaultControllerClose(controller) {
EnqueueValueWithSize(controller, 'close', 0);
WritableStreamDefaultControllerAdvanceQueueIfNeeded(controller);
}
function WritableStreamDefaultControllerGetChunkSize(controller, chunk) {
try {
return controller._strategySizeAlgorithm(chunk);
}
catch (chunkSizeE) {
WritableStreamDefaultControllerErrorIfNeeded(controller, chunkSizeE);
return 1;
}
}
function WritableStreamDefaultControllerGetDesiredSize(controller) {
return controller._strategyHWM - controller._queueTotalSize;
}
function WritableStreamDefaultControllerWrite(controller, chunk, chunkSize) {
const writeRecord = { chunk };
try {
EnqueueValueWithSize(controller, writeRecord, chunkSize);
}
catch (enqueueE) {
WritableStreamDefaultControllerErrorIfNeeded(controller, enqueueE);
return;
}
const stream = controller._controlledWritableStream;
if (WritableStreamCloseQueuedOrInFlight(stream) === false && stream._state === 'writable') {
const backpressure = WritableStreamDefaultControllerGetBackpressure(controller);
WritableStreamUpdateBackpressure(stream, backpressure);
}
WritableStreamDefaultControllerAdvanceQueueIfNeeded(controller);
}
// Abstract operations for the WritableStreamDefaultController.
function WritableStreamDefaultControllerAdvanceQueueIfNeeded(controller) {
const stream = controller._controlledWritableStream;
if (controller._started === false) {
return;
}
if (stream._inFlightWriteRequest !== undefined) {
return;
}
const state = stream._state;
if (state === 'erroring') {
WritableStreamFinishErroring(stream);
return;
}
if (controller._queue.length === 0) {
return;
}
const writeRecord = PeekQueueValue(controller);
if (writeRecord === 'close') {
WritableStreamDefaultControllerProcessClose(controller);
}
else {
WritableStreamDefaultControllerProcessWrite(controller, writeRecord.chunk);
}
}
function WritableStreamDefaultControllerErrorIfNeeded(controller, error) {
if (controller._controlledWritableStream._state === 'writable') {
WritableStreamDefaultControllerError(controller, error);
}
}
function WritableStreamDefaultControllerProcessClose(controller) {
const stream = controller._controlledWritableStream;
WritableStreamMarkCloseRequestInFlight(stream);
DequeueValue(controller);
const sinkClosePromise = controller._closeAlgorithm();
WritableStreamDefaultControllerClearAlgorithms(controller);
sinkClosePromise.then(() => {
WritableStreamFinishInFlightClose(stream);
}, reason => {
WritableStreamFinishInFlightCloseWithError(stream, reason);
}).catch(rethrowAssertionErrorRejection);
}
function WritableStreamDefaultControllerProcessWrite(controller, chunk) {
const stream = controller._controlledWritableStream;
WritableStreamMarkFirstWriteRequestInFlight(stream);
const sinkWritePromise = controller._writeAlgorithm(chunk);
sinkWritePromise.then(() => {
WritableStreamFinishInFlightWrite(stream);
const state = stream._state;
DequeueValue(controller);
if (WritableStreamCloseQueuedOrInFlight(stream) === false && state === 'writable') {
const backpressure = WritableStreamDefaultControllerGetBackpressure(controller);
WritableStreamUpdateBackpressure(stream, backpressure);
}
WritableStreamDefaultControllerAdvanceQueueIfNeeded(controller);
}, reason => {
if (stream._state === 'writable') {
WritableStreamDefaultControllerClearAlgorithms(controller);
}
WritableStreamFinishInFlightWriteWithError(stream, reason);
}).catch(rethrowAssertionErrorRejection);
}
function WritableStreamDefaultControllerGetBackpressure(controller) {
const desiredSize = WritableStreamDefaultControllerGetDesiredSize(controller);
return desiredSize <= 0;
}
// A client of WritableStreamDefaultController may use these functions directly to bypass state check.
function WritableStreamDefaultControllerError(controller, error) {
const stream = controller._controlledWritableStream;
WritableStreamDefaultControllerClearAlgorithms(controller);
WritableStreamStartErroring(stream, error);
}
// Helper functions for the WritableStream.
function streamBrandCheckException(name) {
return new TypeError(`WritableStream.prototype.${name} can only be used on a WritableStream`);
}
// Helper functions for the WritableStreamDefaultWriter.
function defaultWriterBrandCheckException(name) {
return new TypeError(`WritableStreamDefaultWriter.prototype.${name} can only be used on a WritableStreamDefaultWriter`);
}
function defaultWriterLockException(name) {
return new TypeError('Cannot ' + name + ' a stream using a released writer');
}
function defaultWriterClosedPromiseInitialize(writer) {
writer._closedPromise = new Promise((resolve, reject) => {
writer._closedPromise_resolve = resolve;
writer._closedPromise_reject = reject;
writer._closedPromiseState = 'pending';
});
}
function defaultWriterClosedPromiseInitializeAsRejected(writer, reason) {
defaultWriterClosedPromiseInitialize(writer);
defaultWriterClosedPromiseReject(writer, reason);
}
function defaultWriterClosedPromiseInitializeAsResolved(writer) {
defaultWriterClosedPromiseInitialize(writer);
defaultWriterClosedPromiseResolve(writer);
}
function defaultWriterClosedPromiseReject(writer, reason) {
writer._closedPromise.catch(() => { });
writer._closedPromise_reject(reason);
writer._closedPromise_resolve = undefined;
writer._closedPromise_reject = undefined;
writer._closedPromiseState = 'rejected';
}
function defaultWriterClosedPromiseResetToRejected(writer, reason) {
defaultWriterClosedPromiseInitializeAsRejected(writer, reason);
}
function defaultWriterClosedPromiseResolve(writer) {
writer._closedPromise_resolve(undefined);
writer._closedPromise_resolve = undefined;
writer._closedPromise_reject = undefined;
writer._closedPromiseState = 'resolved';
}
function defaultWriterReadyPromiseInitialize(writer) {
writer._readyPromise = new Promise((resolve, reject) => {
writer._readyPromise_resolve = resolve;
writer._readyPromise_reject = reject;
});
writer._readyPromiseState = 'pending';
}
function defaultWriterReadyPromiseInitializeAsRejected(writer, reason) {
defaultWriterReadyPromiseInitialize(writer);
defaultWriterReadyPromiseReject(writer, reason);
}
function defaultWriterReadyPromiseInitializeAsResolved(writer) {
defaultWriterReadyPromiseInitialize(writer);
defaultWriterReadyPromiseResolve(writer);
}
function defaultWriterReadyPromiseReject(writer, reason) {
writer._readyPromise.catch(() => { });
writer._readyPromise_reject(reason);
writer._readyPromise_resolve = undefined;
writer._readyPromise_reject = undefined;
writer._readyPromiseState = 'rejected';
}
function defaultWriterReadyPromiseReset(writer) {
defaultWriterReadyPromiseInitialize(writer);
}
function defaultWriterReadyPromiseResetToRejected(writer, reason) {
defaultWriterReadyPromiseInitializeAsRejected(writer, reason);
}
function defaultWriterReadyPromiseResolve(writer) {
writer._readyPromise_resolve(undefined);
writer._readyPromise_resolve = undefined;
writer._readyPromise_reject = undefined;
writer._readyPromiseState = 'fulfilled';
}
// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number/isInteger#Polyfill
const NumberIsInteger = Number.isInteger || function (value) {
return typeof value === 'number' &&
isFinite(value) &&
Math.floor(value) === value;
};
let AsyncIteratorPrototype;
if (typeof SymbolPolyfill.asyncIterator === 'symbol') {
// We're running inside a ES2018+ environment, but we're compiling to an older syntax.
// We cannot access %AsyncIteratorPrototype% without non-ES2018 syntax, but we can re-create it.
AsyncIteratorPrototype = {
// 25.1.3.1 %AsyncIteratorPrototype% [ @@asyncIterator ] ( )
// https://tc39.github.io/ecma262/#sec-asynciteratorprototype-asynciterator
[SymbolPolyfill.asyncIterator]() {
return this;
}
};
Object.defineProperty(AsyncIteratorPrototype, SymbolPolyfill.asyncIterator, { enumerable: false });
}
const CancelSteps = SymbolPolyfill('[[CancelSteps]]');
const PullSteps = SymbolPolyfill('[[PullSteps]]');
class ReadableStream {
constructor(underlyingSource = {}, strategy = {}) {
InitializeReadableStream(this);
const size = strategy.size;
let highWaterMark = strategy.highWaterMark;
const type = underlyingSource.type;
const typeString = String(type);
if (typeString === 'bytes') {
if (size !== undefined) {
throw new RangeError('The strategy for a byte stream cannot have a size function');
}
if (highWaterMark === undefined) {
highWaterMark = 0;
}
highWaterMark = ValidateAndNormalizeHighWaterMark(highWaterMark);
SetUpReadableByteStreamControllerFromUnderlyingSource(this, underlyingSource, highWaterMark);
}
else if (type === undefined) {
const sizeAlgorithm = MakeSizeAlgorithmFromSizeFunction(size);
if (highWaterMark === undefined) {
highWaterMark = 1;
}
highWaterMark = ValidateAndNormalizeHighWaterMark(highWaterMark);
SetUpReadableStreamDefaultControllerFromUnderlyingSource(this, underlyingSource, highWaterMark, sizeAlgorithm);
}
else {
throw new RangeError('Invalid type is specified');
}
}
get locked() {
if (IsReadableStream(this) === false) {
throw streamBrandCheckException$1('locked');
}
return IsReadableStreamLocked(this);
}
cancel(reason) {
if (IsReadableStream(this) === false) {
return Promise.reject(streamBrandCheckException$1('cancel'));
}
if (IsReadableStreamLocked(this) === true) {
return Promise.reject(new TypeError('Cannot cancel a stream that already has a reader'));
}
return ReadableStreamCancel(this, reason);
}
getReader({ mode } = {}) {
if (IsReadableStream(this) === false) {
throw streamBrandCheckException$1('getReader');
}
if (mode === undefined) {
return AcquireReadableStreamDefaultReader(this, true);
}
mode = String(mode);
if (mode === 'byob') {
return AcquireReadableStreamBYOBReader(this, true);
}
throw new RangeError('Invalid mode is specified');
}
pipeThrough({ writable, readable }, { preventClose, preventAbort, preventCancel, signal } = {}) {
if (IsReadableStream(this) === false) {
throw streamBrandCheckException$1('pipeThrough');
}
if (IsWritableStream(writable) === false) {
throw new TypeError('writable argument to pipeThrough must be a WritableStream');
}
if (IsReadableStream(readable) === false) {
throw new TypeError('readable argument to pipeThrough must be a ReadableStream');
}
preventClose = Boolean(preventClose);
preventAbort = Boolean(preventAbort);
preventCancel = Boolean(preventCancel);
if (signal !== undefined && !isAbortSignal(signal)) {
throw new TypeError('ReadableStream.prototype.pipeThrough\'s signal option must be an AbortSignal');
}
if (IsReadableStreamLocked(this) === true) {
throw new TypeError('ReadableStream.prototype.pipeThrough cannot be used on a locked ReadableStream');
}
if (IsWritableStreamLocked(writable) === true) {
throw new TypeError('ReadableStream.prototype.pipeThrough cannot be used on a locked WritableStream');
}
const promise = ReadableStreamPipeTo(this, writable, preventClose, preventAbort, preventCancel, signal);
promise.catch(() => { });
return readable;
}
pipeTo(dest, { preventClose, preventAbort, preventCancel, signal } = {}) {
if (IsReadableStream(this) === false) {
return Promise.reject(streamBrandCheckException$1('pipeTo'));
}
if (IsWritableStream(dest) === false) {
return Promise.reject(new TypeError('ReadableStream.prototype.pipeTo\'s first argument must be a WritableStream'));
}
preventClose = Boolean(preventClose);
preventAbort = Boolean(preventAbort);
preventCancel = Boolean(preventCancel);
if (signal !== undefined && !isAbortSignal(signal)) {
return Promise.reject(new TypeError('ReadableStream.prototype.pipeTo\'s signal option must be an AbortSignal'));
}
if (IsReadableStreamLocked(this) === true) {
return Promise.reject(new TypeError('ReadableStream.prototype.pipeTo cannot be used on a locked ReadableStream'));
}
if (IsWritableStreamLocked(dest) === true) {
return Promise.reject(new TypeError('ReadableStream.prototype.pipeTo cannot be used on a locked WritableStream'));
}
return ReadableStreamPipeTo(this, dest, preventClose, preventAbort, preventCancel, signal);
}
tee() {
if (IsReadableStream(this) === false) {
throw streamBrandCheckException$1('tee');
}
const branches = ReadableStreamTee(this, false);
return createArrayFromList(branches);
}
getIterator({ preventCancel } = {}) {
if (IsReadableStream(this) === false) {
throw streamBrandCheckException$1('getIterator');
}
const reader = AcquireReadableStreamDefaultReader(this);
const iterator = Object.create(ReadableStreamAsyncIteratorPrototype);
iterator._asyncIteratorReader = reader;
iterator._preventCancel = Boolean(preventCancel);
return iterator;
}
}
const ReadableStreamAsyncIteratorPrototype = {
next() {
if (IsReadableStreamAsyncIterator(this) === false) {
return Promise.reject(streamAsyncIteratorBrandCheckException('next'));
}
const reader = this._asyncIteratorReader;
if (reader._ownerReadableStream === undefined) {
return Promise.reject(readerLockException('iterate'));
}
return ReadableStreamDefaultReaderRead(reader).then(result => {
const done = result.done;
if (done) {
ReadableStreamReaderGenericRelease(reader);
}
const value = result.value;
return ReadableStreamCreateReadResult(value, done, true);
});
},
return(value) {
if (IsReadableStreamAsyncIterator(this) === false) {
return Promise.reject(streamAsyncIteratorBrandCheckException('next'));
}
const reader = this._asyncIteratorReader;
if (reader._ownerReadableStream === undefined) {
return Promise.reject(readerLockException('finish iterating'));
}
if (reader._readRequests.length > 0) {
return Promise.reject(new TypeError('Tried to release a reader lock when that reader has pending read() calls un-settled'));
}
if (this._preventCancel === false) {
const result = ReadableStreamReaderGenericCancel(reader, value);
ReadableStreamReaderGenericRelease(reader);
return result.then(() => ReadableStreamCreateReadResult(value, true, true));
}
ReadableStreamReaderGenericRelease(reader);
return Promise.resolve(ReadableStreamCreateReadResult(value, true, true));
}
};
if (AsyncIteratorPrototype !== undefined) {
Object.setPrototypeOf(ReadableStreamAsyncIteratorPrototype, AsyncIteratorPrototype);
}
Object.defineProperty(ReadableStreamAsyncIteratorPrototype, 'next', { enumerable: false });
Object.defineProperty(ReadableStreamAsyncIteratorPrototype, 'return', { enumerable: false });
if (typeof SymbolPolyfill.asyncIterator === 'symbol') {
Object.defineProperty(ReadableStream.prototype, SymbolPolyfill.asyncIterator, {
value: ReadableStream.prototype.getIterator,
enumerable: false,
writable: true,
configurable: true
});
}
// Abstract operations for the ReadableStream.
function AcquireReadableStreamBYOBReader(stream, forAuthorCode = false) {
const reader = new ReadableStreamBYOBReader(stream);
reader._forAuthorCode = forAuthorCode;
return reader;
}
function AcquireReadableStreamDefaultReader(stream, forAuthorCode = false) {
const reader = new ReadableStreamDefaultReader(stream);
reader._forAuthorCode = forAuthorCode;
return reader;
}
// Throws if and only if startAlgorithm throws.
function CreateReadableStream(startAlgorithm, pullAlgorithm, cancelAlgorithm, highWaterMark = 1, sizeAlgorithm = () => 1) {
const stream = Object.create(ReadableStream.prototype);
InitializeReadableStream(stream);
const controller = Object.create(ReadableStreamDefaultController.prototype);
SetUpReadableStreamDefaultController(stream, controller, startAlgorithm, pullAlgorithm, cancelAlgorithm, highWaterMark, sizeAlgorithm);
return stream;
}
function InitializeReadableStream(stream) {
stream._state = 'readable';
stream._reader = undefined;
stream._storedError = undefined;
stream._disturbed = false;
}
function IsReadableStream(x) {
if (!typeIsObject(x)) {
return false;
}
if (!Object.prototype.hasOwnProperty.call(x, '_readableStreamController')) {
return false;
}
return true;
}
function IsReadableStreamLocked(stream) {
if (stream._reader === undefined) {
return false;
}
return true;
}
function IsReadableStreamAsyncIterator(x) {
if (!typeIsObject(x)) {
return false;
}
if (!Object.prototype.hasOwnProperty.call(x, '_asyncIteratorReader')) {
return false;
}
return true;
}
function ReadableStreamPipeTo(source, dest, preventClose, preventAbort, preventCancel, signal) {
const reader = AcquireReadableStreamDefaultReader(source);
const writer = AcquireWritableStreamDefaultWriter(dest);
let shuttingDown = false;
// This is used to keep track of the spec's requirement that we wait for ongoing writes during shutdown.
let currentWrite = Promise.resolve();
return new Promise((resolve, reject) => {
let abortAlgorithm;
if (signal !== undefined) {
abortAlgorithm = () => {
const error = new DOMException('Aborted', 'AbortError');
const actions = [];
if (preventAbort === false) {
actions.push(() => {
if (dest._state === 'writable') {
return WritableStreamAbort(dest, error);
}
return Promise.resolve();
});
}
if (preventCancel === false) {
actions.push(() => {
if (source._state === 'readable') {
return ReadableStreamCancel(source, error);
}
return Promise.resolve();
});
}
shutdownWithAction(() => WaitForAllPromise(actions.map(action => action()), results => results), true, error);
};
if (signal.aborted === true) {
abortAlgorithm();
return;
}
signal.addEventListener('abort', abortAlgorithm);
}