UNPKG

@struktoai/mirage-core

Version:

A Unified Virtual Filesystem For AI Agents

103 lines • 3.49 kB
// ========= Copyright 2026 @ Strukto.AI All Rights Reserved. ========= // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // ========= Copyright 2026 @ Strukto.AI All Rights Reserved. ========= import { KeyLock } from "../cache/lock.js"; /** Work in flight on one resource, awaited before it is released. */ export class Activity { count = 0; waiters = []; acquire() { this.count++; let released = false; return () => { if (released) return; released = true; this.count--; if (this.count === 0) { for (const resolve of this.waiters.splice(0)) resolve(); } }; } wait() { if (this.count === 0) return Promise.resolve(); return new Promise((resolve) => { this.waiters.push(resolve); }); } /** Count `source` in flight until it ends or is closed. */ hold(source) { if (source instanceof Uint8Array) return source; return new ActivityStream(source, this.acquire()); } } /** Explicit return releases even a stream that was never pulled. */ class ActivityStream { release; source; pullLock = new KeyLock(); closing; constructor(source, release) { this.release = release; this.source = source[Symbol.asyncIterator](); } [Symbol.asyncIterator]() { return this; } isClosing() { return this.closing !== undefined; } next() { return this.pullLock.withLock('', async () => { if (this.isClosing()) return { done: true, value: undefined }; try { const step = await this.source.next(); if (step.done === true && this.closing === undefined) this.release(); return step; } catch (error) { if (this.closing === undefined) this.release(); throw error; } }); } return() { this.closing ??= this.finish(); return this.closing; } async finish() { // A pull can wait on a source that only yields when something lands (a // follow), so the source is told to close before the pull ends, not // after: its own close is what ends that wait. const closing = Promise.resolve().then(() => this.source.return?.()); // Handled here so a failed close is not unhandled while the pull ends; // awaiting it below still hands the failure to the caller. void closing.catch(() => undefined); return this.pullLock.withLock('', async () => { try { await closing; return { done: true, value: undefined }; } finally { this.release(); } }); } } //# sourceMappingURL=activity.js.map