@struktoai/mirage-core
Version:
A Unified Virtual Filesystem For AI Agents
70 lines • 2.26 kB
JavaScript
import { ConcurrencyLimiter } from "../concurrency/limiter.js";
import { CHUNK_SIZE } from "./cooperative.js";
import { BytePipe, CAPACITY } from "./pipe.js";
/** One ordered output reader, sharing the byte pipe's capacity and chunks. */
export class OutputPipe {
pipe;
streams = [];
lock = new ConcurrencyLimiter(1);
reading = false;
constructor(capacity = CAPACITY) {
this.pipe = new BytePipe(capacity);
}
get bufferedBytes() {
return this.pipe.bufferedBytes;
}
get closedReader() {
return this.pipe.closedReader;
}
/** Accept one write in order, waiting for byte capacity. Empty writes have no event. */
async write(stream, data) {
const release = await this.lock.acquire();
try {
for (let offset = 0; offset < data.byteLength; offset += CHUNK_SIZE) {
this.streams.push(stream);
try {
await this.pipe.write(data.subarray(offset, offset + CHUNK_SIZE));
}
catch (error) {
this.streams.pop();
throw error;
}
}
}
finally {
release();
}
}
/** End output, preserving accepted events before a late failure. */
end(error) {
this.pipe.end(error);
}
async drain() {
await this.pipe.drain();
}
/** Discard unread output and wake pending readers and writers. */
closeReader() {
this.pipe.closeReader();
this.streams.length = 0;
}
/** Read once; close the reader before closing a pending iterator pull. */
async *events() {
if (this.reading)
throw new Error('output pipe already has a reader');
this.reading = true;
try {
for await (const data of this.pipe.stream()) {
if (this.closedReader)
return;
const stream = this.streams.shift();
if (stream === undefined)
throw new Error('output stream is missing');
yield { stream, data };
}
}
finally {
this.closeReader();
}
}
}
//# sourceMappingURL=output.js.map