UNPKG

@struktoai/mirage-core

Version:

A Unified Virtual Filesystem For AI Agents

98 lines • 4.1 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 { concat } from "../utils/bytes.js"; import { abortable, hasAborted, makeAbortError } from "../utils/abort.js"; import { YieldBudget } from "./yield_budget.js"; export const CHUNK_SIZE = 16 * 1024; /** * Split even a single RAM/cache blob; an abort closes the producer and wins * over a stalled pull. Unless `split`, each pull passes through whole, as its * producer wrote it. `check` runs with the budget (a deadline). */ export async function* chunks(source, signal, split = true, check) { const budget = new YieldBudget(signal, check); const piece = split ? CHUNK_SIZE : Number.POSITIVE_INFINITY; if (source instanceof Uint8Array) { for (let offset = 0; offset < source.byteLength; offset += piece) { const pending = budget.run(); if (pending !== undefined) await pending; yield source.subarray(offset, offset + piece); } return; } // Pulled by hand rather than for-await: a pull that stays pending (a // stalled body) has to lose the race to the abort, which for-await // cannot express. const iterator = source[Symbol.asyncIterator](); let finished = false; let pulling = false; try { for (;;) { // Before the pull, not only around it: a lazy source starts its // request on the first `next()`, which an abort must never reach. if (hasAborted(signal)) throw makeAbortError(signal); pulling = true; const result = await abortable(iterator.next(), signal); pulling = false; if (result.done === true) { finished = true; break; } const data = result.value; // Once per pull as well as per chunk: a run of empty chunks that // resolve at once would otherwise never reach a yield, and a // microtask chain with no yield starves the timer an abort rides. const pulled = budget.run(); if (pulled !== undefined) await pulled; for (let offset = 0; offset < data.byteLength; offset += piece) { const pending = budget.run(); if (pending !== undefined) await pending; yield data.subarray(offset, offset + piece); } } } finally { // What for-await did implicitly: close a producer left mid-stream, // whether the consumer stopped early or an abort landed. A return // queued behind a pull that never settles would hang, so that one // is not awaited. if (!finished) { const closing = iterator.return?.(); if (closing !== undefined) { if (pulling) void closing.catch(() => undefined); else await closing; } } } } /** Read at most count bytes, closing the source when the limit is reached. */ export async function readPrefix(source, count, signal) { if (count <= 0) return new Uint8Array(); const parts = []; for await (const part of chunks(source, signal)) { parts.push(part.subarray(0, count)); count -= part.length; if (count <= 0) break; } return concat(parts); } //# sourceMappingURL=cooperative.js.map