UNPKG

@transcend-io/remote-web-streams

Version:

Web streams that work across web workers and iframes.

173 lines (166 loc) 5.93 kB
import { WritableStream as WritableStream$1 } from 'web-streams-polyfill/ponyfill'; var NativeReadableStream = typeof ReadableStream === 'function' ? ReadableStream : undefined; var NativeWritableStream = typeof WritableStream === 'function' ? WritableStream : undefined; var SenderType; (function (SenderType) { SenderType[SenderType["WRITE"] = 0] = "WRITE"; SenderType[SenderType["ABORT"] = 1] = "ABORT"; SenderType[SenderType["CLOSE"] = 2] = "CLOSE"; })(SenderType || (SenderType = {})); var ReceiverType; (function (ReceiverType) { ReceiverType[ReceiverType["PULL"] = 0] = "PULL"; ReceiverType[ReceiverType["ERROR"] = 1] = "ERROR"; })(ReceiverType || (ReceiverType = {})); function fromReadablePort(port) { return new NativeReadableStream(new MessagePortSource(port)); } var MessagePortSource = /** @class */ (function () { function MessagePortSource(_port) { var _this = this; this._port = _port; this._port.onmessage = function (event) { return _this._onMessage(event.data); }; } MessagePortSource.prototype.start = function (controller) { this._controller = controller; }; MessagePortSource.prototype.pull = function (controller) { var message = { type: ReceiverType.PULL }; this._port.postMessage(message); }; MessagePortSource.prototype.cancel = function (reason) { var message = { type: ReceiverType.ERROR, reason: reason }; this._port.postMessage(message); this._port.close(); }; MessagePortSource.prototype._onMessage = function (message) { switch (message.type) { case SenderType.WRITE: // enqueue() will call pull() if needed when there's no backpressure this._controller.enqueue(message.chunk); break; case SenderType.ABORT: this._controller.error(message.reason); this._port.close(); break; case SenderType.CLOSE: this._controller.close(); this._port.close(); break; } }; return MessagePortSource; }()); var WS = (NativeWritableStream || WritableStream$1); function fromWritablePort(port, options) { return new WS(new MessagePortSink(port, options)); } var MessagePortSink = /** @class */ (function () { function MessagePortSink(_port, options) { var _this = this; if (options === void 0) { options = {}; } this._port = _port; this._transferChunk = options.transferChunk; this._resetReady(); this._port.onmessage = function (event) { return _this._onMessage(event.data); }; } MessagePortSink.prototype.start = function (controller) { this._controller = controller; // Apply initial backpressure return this._readyPromise; }; MessagePortSink.prototype.write = function (chunk, controller) { var message = { type: SenderType.WRITE, chunk: chunk, }; // Send chunk, optionally transferring its contents var transferList = this._transferChunk ? this._transferChunk(chunk) : []; if (transferList.length) { this._port.postMessage(message, transferList); } else { this._port.postMessage(message); } // Assume backpressure after every write, until sender pulls this._resetReady(); // Apply backpressure return this._readyPromise; }; MessagePortSink.prototype.close = function () { var message = { type: SenderType.CLOSE, }; this._port.postMessage(message); this._port.close(); }; MessagePortSink.prototype.abort = function (reason) { var message = { type: SenderType.ABORT, reason: reason, }; this._port.postMessage(message); this._port.close(); }; MessagePortSink.prototype._onMessage = function (message) { switch (message.type) { case ReceiverType.PULL: this._resolveReady(); break; case ReceiverType.ERROR: this._onError(message.reason); break; } }; MessagePortSink.prototype._onError = function (reason) { this._controller.error(reason); this._rejectReady(reason); this._port.close(); }; MessagePortSink.prototype._resetReady = function () { var _this = this; this._readyPromise = new Promise(function (resolve, reject) { _this._readyResolve = resolve; _this._readyReject = reject; }); this._readyPending = true; }; MessagePortSink.prototype._resolveReady = function () { this._readyResolve(); this._readyPending = false; }; MessagePortSink.prototype._rejectReady = function (reason) { if (!this._readyPending) { this._resetReady(); } this._readyPromise.catch(function () { }); this._readyReject(reason); this._readyPending = false; }; return MessagePortSink; }()); var RemoteReadableStream = /** @class */ (function () { function RemoteReadableStream() { var channel = new MessageChannel(); this.writablePort = channel.port1; this.readable = fromReadablePort(channel.port2); } return RemoteReadableStream; }()); var RemoteWritableStream = /** @class */ (function () { function RemoteWritableStream(options) { var channel = new MessageChannel(); this.readablePort = channel.port1; this.writable = fromWritablePort(channel.port2, options); } return RemoteWritableStream; }()); export { RemoteReadableStream, RemoteWritableStream, fromReadablePort, fromWritablePort };