UNPKG

@struktoai/mirage-core

Version:

A Unified Virtual Filesystem For AI Agents

168 lines • 6.15 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. ========= var __rewriteRelativeImportExtension = (this && this.__rewriteRelativeImportExtension) || function (path, preserveJsx) { if (typeof path === "string" && /^\.\.?\//.test(path)) { return path.replace(/\.(tsx)$|((?:\.d)?)((?:\.[^./]+?)?)\.([cm]?)ts$/i, function (m, tsx, d, ext, cm) { return tsx ? preserveJsx ? ".jsx" : ".js" : d && (!ext || !cm) ? m : (d + ext + "." + cm.toLowerCase() + "js"); }); } return path; }; /** * The browser storage: no task isolation, one frame stack per storage. * * `getStore` answers the newest live frame, so a read that interleaves * with another task's bind can still see that task's store — only real * isolation fixes that, which is what `liveStores` exists to route * around. What the stack does fix is the slot's two worse failures: a * settle removes its own frame rather than blind-restoring a saved * value, so an out-of-order settle can neither wipe a binding that is * still live nor strand a stale one after every run has finished. * * Exported for the fallback-mode tests, which mock `createAsyncContext` * with this class so the browser branch runs under node's test runner. */ export class FallbackStorage { frames = []; run(s, fn) { return this.withFrame(s, fn); } withFrame(s, fn) { const frame = { store: s }; this.frames.push(frame); const drop = () => { const at = this.frames.indexOf(frame); if (at >= 0) this.frames.splice(at, 1); }; try { const result = fn(); if (result instanceof Promise) { return result.finally(drop); } drop(); return result; } catch (err) { drop(); throw err; } } getStore() { return this.frames.length === 0 ? undefined : this.frames[this.frames.length - 1]?.store; } liveStores() { return this.frames .map((frame) => frame.store) .filter((store) => store !== undefined); } capture() { const frames = this.frames.length === 0 ? [undefined] : this.frames.map((frame) => frame.store); return (fn) => { const enter = (at) => at === frames.length ? fn() : this.withFrame(frames[at], () => enter(at + 1)); return enter(0); }; } } class IsolatedStorage { tasks; constructor(ctor) { this.tasks = new ctor(); } run(store, fn) { return this.tasks.run(store, fn); } getStore() { return this.tasks.getStore(); } liveStores() { const store = this.tasks.getStore(); return store === undefined ? [] : [store]; } capture() { const store = this.tasks.getStore(); return (fn) => this.tasks.run(store, fn); } } async function resolveCtor() { const g = globalThis; if (g.AsyncLocalStorage !== undefined) return g.AsyncLocalStorage; if (g.process?.versions?.node !== undefined) { try { const modName = 'node:async_hooks'; const mod = (await import(__rewriteRelativeImportExtension(/* @vite-ignore */ modName))); return mod.AsyncLocalStorage; } catch { return null; } } return null; } /** * Whether `ctor` actually isolates overlapping tasks. * * Constructor identity is not proof: a bundler's `AsyncLocalStorage` * shim on `globalThis` is typically a single slot, and trusting it * would disarm every fallback hardening while behaving exactly like * the fallback. So the claim is tested: two runs overlap across a * microtask and each must read back its own store. A ctor that throws * anywhere in the probe is answering the same question. */ async function isolates(ctor) { try { const probe = new ctor(); const reads = await Promise.all([ probe.run(1, async () => { await Promise.resolve(); return probe.getStore(); }), probe.run(2, async () => { await Promise.resolve(); return probe.getStore(); }), ]); return reads[0] === 1 && reads[1] === 2; } catch { return false; } } const resolved = await resolveCtor(); /** * Whether the storage isolates concurrent tasks, verified behaviorally * at module load rather than assumed from where the constructor came * from. * * `AsyncLocalStorage` gives every task its own store. The fallback is * one frame stack whose top a concurrent task can shadow, so a caller * that binds a store for concurrent work has to know which it got. */ export const asyncContextIsolatesTasks = resolved !== null && (await isolates(resolved)); const verifiedCtor = asyncContextIsolatesTasks ? resolved : null; const unbound = verifiedCtor?.snapshot?.() ?? null; /** * Run `fn` with no store bound, as this module loaded: for work a line * starts that outlives it and must not carry the line's state, such as * a sandbox's SFTP server. Without task isolation there is nothing to * leave, so `fn` runs as called. */ export function runDetached(fn) { return unbound === null ? fn() : unbound(fn); } export function createAsyncContext() { return verifiedCtor === null ? new FallbackStorage() : new IsolatedStorage(verifiedCtor); } //# sourceMappingURL=async_context.js.map