UNPKG

@struktoai/mirage-core

Version:

A Unified Virtual Filesystem For AI Agents

128 lines • 5.27 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 { currentCaller } from "../context/session_context.js"; import { OutputStream } from "./stream.js"; import { createAsyncContext } from "../utils/async_context.js"; import { rstripSlash } from "../utils/slash.js"; import { runWithNetwork } from "./network.js"; /** * What judges the connections a line or a file op opens: the workspace's * `network` (null for no limit) and its policies, whose preNetwork and * postNetwork each connection answers to. `hooked` settles whether one of * them listens for the session's connections, so each goes through the * gateway, and `listening` holds the answer once it has: the binding starts * the line or the op at once, as a browser's storage must keep its frames in * step, and a connection opened first waits for it. `session` is the * session it runs for (null when unknown), and `op` whether a file op, not a * line, bound it. Mirrors Python's `Egress`. */ export class Egress { rule; policies; session; op; listening = null; hooked; constructor(rule, policies, hooked, session = null, op = false) { this.rule = rule; this.policies = policies; this.session = session; this.op = op; this.hooked = hooked.then((answer) => (this.listening = answer)); } } const egress = createAsyncContext(); async function listens(policies) { if (policies === null) return false; const sessionId = currentCaller().session?.sessionId ?? ''; for (const method of ['preNetwork', 'postNetwork']) { if (policies.wants(method) && (await policies.wantsFor(method, sessionId))) return true; } return false; } /** * `fn` run as a line or a file op of a workspace: every connection it opens * clears `rule`, and passes the gateway when a policy listens for the * session's connections; for `session`, null when unknown, and `op` when * a file op, not a line, binds it. Mirrors * Python's `run_with_egress`. */ export function runWithEgress(rule, policies, fn, session = null, op = false) { const outer = egress.getStore(); const hooked = outer?.policies === policies ? outer.hooked : listens(policies); return runWithNetwork(rule, () => Promise.resolve(egress.run(new Egress(rule, policies, hooked, session, op), fn))); } /** * `it` pulled and closed under the egress bound where it was made: a mount's * stream opens each later connection, whoever pulls it and however late, * under the workspace's rule and policies, as `withCaller` keeps its caller. * Its close reaches the stream even before a first pull. Handed back as it * is where neither limits anything. `owner` names the egress outright where * a browser's storage, which answers its newest frame, could hand another * workspace's. Mirrors Python's `with_egress`. */ export function withEgress(it, owner = egress.getStore() ?? null) { const bound = owner; if (bound === null || (bound.rule === null && (bound.policies === null || bound.listening === false))) { return it; } const under = (fn) => runWithNetwork(bound.rule, () => Promise.resolve(egress.run(bound, fn))); const iterator = it[Symbol.asyncIterator](); async function* pulled() { for (;;) { const step = await under(() => iterator.next()); if (step.done === true) return; yield step.value; } } return new OutputStream(pulled(), async () => { await under(async () => { await iterator.return?.(); }); }); } /** * The egress of every call live in this context: on an isolating runtime the * bound one alone, in a browser every concurrently bound one, since it cannot * tell whose call is opening the connection. Mirrors Python's `live_egress`. */ export function liveEgress() { return egress.liveStores(); } /** * The context a connection to `address` on `port`, opened for `host`, * reports: the command, the mount and the session of the call opening it. * Mirrors Python's `_opened`. */ export function opened(host, address, port) { const caller = currentCaller(); const invocation = caller.invocation; const mount = caller.vfsMount ?? ''; return { host, address, port, command: caller.command ?? '', program: invocation?.program ?? [], words: invocation?.words ?? [], line: invocation?.line ?? '', mount: rstripSlash(mount) || mount, sessionId: caller.session?.sessionId ?? '', }; } //# sourceMappingURL=gateway.js.map