UNPKG

@struktoai/mirage-core

Version:

A Unified Virtual Filesystem For AI Agents

88 lines • 3.07 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 { hasAborted, makeAbortError } from "../utils/abort.js"; export class KeyLock { queues = new Map(); async withLock(key, fn, signal) { if (hasAborted(signal)) throw makeAbortError(signal); const entered = this.enter(key, signal); let queue = entered instanceof Set ? entered : await entered; try { // Admission may have transferred immediately before cancellation. if (hasAborted(signal)) throw makeAbortError(signal); return await fn({ released: async (body) => { this.leave(key, queue); try { return await body(); } finally { const back = this.enter(key); queue = back instanceof Set ? back : await back; } }, }); } finally { this.leave(key, queue); } } /** Whether someone holds the key now. */ held(key) { return this.queues.has(key); } discard(key) { this.queues.delete(key); } clear() { this.queues.clear(); } /** The key's queue: taken at once when the key is free, else once its * holder hands it over. */ enter(key, signal) { const queue = this.queues.get(key); if (queue === undefined) { const held = new Set(); this.queues.set(key, held); return held; } return new Promise((resolve, reject) => { const waiter = { enter: () => { signal?.removeEventListener('abort', onAbort); resolve(queue); }, }; const onAbort = () => { queue.delete(waiter); reject(makeAbortError(signal)); }; queue.add(waiter); signal?.addEventListener('abort', onAbort, { once: true }); }); } leave(key, queue) { const next = queue.values().next().value; if (next !== undefined) { queue.delete(next); next.enter(); } else if (this.queues.get(key) === queue) { this.queues.delete(key); } } } //# sourceMappingURL=lock.js.map