fake-service-worker
Version:
Fake service worker implementation for testing developer edge applications
209 lines • 5.9 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.EdgeReadableStream = void 0;
class EdgeReadableStream {
_internals;
constructor(underlyingSource, strategy) {
this._internals = new StreamInternals(underlyingSource, strategy || {});
}
get locked() {
return this._internals.locked;
}
cancel(reason) {
return this._internals.cancel(reason);
}
getReader({ mode } = {}) {
if (mode) {
throw new TypeError('ReadableStream modes other than default are not supported');
}
this._internals.acquireLock();
return new EdgeReadableStreamDefaultReader(this._internals);
}
pipeThrough(_transform, _options) {
throw new Error('pipeThrough not yet implemented');
}
pipeTo(_dest, _options) {
throw new Error('pipeTo not yet implemented');
}
tee() {
return this._internals.tee();
}
}
exports.EdgeReadableStream = EdgeReadableStream;
class StreamInternals {
_source;
_chunks;
_controller;
_on_done_resolvers = new Set();
_closed = false;
_done = false;
_error = null;
_locked = false;
_start_promise = null;
_highWaterMark;
constructor(source, { highWaterMark, size } = {}) {
this._source = source;
if (source?.type) {
throw new Error('UnderlyingSource.type is not yet supported');
}
this._highWaterMark = highWaterMark || 10;
if (size) {
throw new Error('TODO call size');
}
this._chunks = [];
this._controller = new EdgeReadableStreamDefaultController(this);
if (this._source?.start) {
this._start_promise = this._source.start(this._controller);
}
}
cancel(_reason) {
this._chunks.length = 0;
this._closed = true;
if (this._source?.cancel) {
this._source?.cancel(this._controller);
}
return new Promise(resolve => {
this.addResolver(resolve);
});
}
get locked() {
return this._locked;
}
acquireLock() {
if (this._locked) {
throw new Error('ReadableStream already locked');
}
this._locked = true;
}
releaseLock() {
this._locked = false;
}
close() {
this._closed = true;
}
enqueue(chunk) {
this._chunks.push(chunk);
}
error(e) {
this._error = e || true;
}
addResolver(resolver) {
this._on_done_resolvers.add(resolver);
}
done() {
for (const resolve of this._on_done_resolvers) {
resolve();
}
this._done = true;
return { done: true, value: undefined };
}
async read() {
if (this._done) {
return { done: true, value: undefined };
}
if (this._start_promise) {
await this._start_promise;
this._start_promise = null;
}
if (!this._closed && this._chunks.length < this._highWaterMark && this._source?.pull) {
if (this._error) {
throw this._error;
}
else {
await Promise.resolve(this._source.pull(this._controller));
}
}
const value = this._chunks.shift();
if (value == undefined) {
return this.done();
}
else {
return { done: false, value };
}
}
tee() {
this.acquireLock();
const chunks1 = [...this._chunks];
const chunks2 = [...this._chunks];
const start = async () => {
const p = this._start_promise;
if (p) {
this._start_promise = null;
await p;
}
};
const pull = async (controller, which) => {
const { value } = await this.read();
if (value) {
chunks1.push(value);
chunks2.push(value);
}
const chunks = which == 1 ? chunks1 : chunks2;
const next = chunks.shift();
if (next == undefined) {
controller.close();
}
else {
controller.enqueue(next);
}
};
const cancel = async (controller) => {
this.cancel();
const c = this._source?.cancel;
if (c) {
delete this._source?.cancel;
await c(controller);
}
};
const source1 = {
start: () => start(),
pull: controller => pull(controller, 1),
cancel: controller => cancel(controller),
};
const source2 = {
start: () => start(),
pull: controller => pull(controller, 2),
cancel: controller => cancel(controller),
};
return [new EdgeReadableStream(source1), new EdgeReadableStream(source2)];
}
}
class EdgeReadableStreamDefaultController {
desiredSize = null;
_internals;
constructor(internals) {
this._internals = internals;
}
close() {
this._internals.close();
}
enqueue(chunk) {
this._internals.enqueue(chunk);
}
error(e) {
this._internals.error(e);
}
}
class EdgeReadableStreamDefaultReader {
_internals;
_closed_promise;
constructor(internals) {
this._internals = internals;
this._closed_promise = new Promise(resolve => {
internals.addResolver(() => resolve(undefined));
});
}
get closed() {
return this._closed_promise;
}
async read() {
return this._internals.read();
}
cancel(reason) {
return this._internals.cancel(reason);
}
releaseLock() {
this._internals.releaseLock();
}
}
//# sourceMappingURL=ReadableStream.js.map