@struktoai/mirage-core
Version:
A Unified Virtual Filesystem For AI Agents
167 lines • 6.19 kB
JavaScript
import { z } from 'zod';
import { compiledModule } from "../rs/stream.js";
import { abortable, makeAbortError } from "../utils/abort.js";
const Reply = z.object({ ok: z.boolean(), value: z.unknown() });
async function createPort(done, failed) {
const node = globalThis.process?.versions
?.node;
if (node !== undefined) {
const { Worker: NodeWorker } = await import('node:worker_threads');
const url = new URL(import.meta.url.endsWith('.ts') ? './worker_entry.ts' : './worker_entry.js', import.meta.url);
const worker = new NodeWorker(url, {
execArgv: url.pathname.endsWith('.ts')
? ['--experimental-transform-types', '--disable-warning=ExperimentalWarning']
: [],
});
worker.on('message', (raw) => {
const reply = Reply.safeParse(raw);
if (reply.success)
done(reply.data);
else
failed(new Error('invalid computation worker reply', { cause: reply.error }));
});
worker.on('messageerror', failed);
worker.on('error', failed);
worker.on('exit', (code) => {
failed(new Error(`computation worker exited (${String(code)})`));
});
return {
post: (data) => {
worker.postMessage(data);
},
close: async () => {
await worker.terminate();
},
};
}
// The worker starts from the bundle core embeds, not from worker_entry.js:
// a bundler that moves this module (Vite's dependency pre-bundling) leaves
// no file where a relative URL would look.
const { default: source } = await import("../generated/computation_worker.js");
const wasm = await compiledModule();
const url = URL.createObjectURL(new Blob([source], { type: 'text/javascript' }));
const { Worker } = globalThis;
const worker = new Worker(url, { type: 'module' });
worker.onmessage = (event) => {
const reply = Reply.safeParse(event.data);
if (reply.success)
done(reply.data);
else
failed(new Error('invalid computation worker reply', { cause: reply.error }));
};
worker.onmessageerror = () => {
failed(new Error('cannot decode computation worker reply'));
};
worker.onerror = (event) => {
// A script the page refuses to start carries no message.
failed(new Error(event.message || 'computation worker did not start'));
};
return {
post: (data) => {
worker.postMessage({ ...data, wasm });
},
close: () => {
worker.terminate();
URL.revokeObjectURL(url);
return Promise.resolve();
},
};
}
/** An invocation-owned worker for computations that cannot yield inside their engine. */
export class Worker {
port;
closing;
closeSettled = false;
closeFailed = false;
terminal;
waiting = [];
async call(name, args, signal) {
try {
signal?.throwIfAborted();
if (this.terminal !== undefined)
throw this.terminal;
if (this.closeSettled && !this.closeFailed && this.port === undefined) {
this.closing = undefined;
this.closeSettled = false;
}
if (this.closing !== undefined)
throw new Error('computation worker is closing');
const port = (this.port ??= this.open());
const ready = await abortable(port, signal);
this.checkReady(port, signal);
const reply = new Promise((resolve, reject) => {
this.waiting.push({ resolve, reject });
try {
ready.post({ name, args });
}
catch (error) {
reject(error instanceof Error ? error : new Error('cannot post computation', { cause: error }));
}
});
const { ok, value } = await abortable(reply, signal);
if (!ok)
throw value instanceof Error ? value : new Error('Computation failed', { cause: value });
return value;
}
catch (error) {
try {
await this.close();
}
catch (cleanup) {
throw new AggregateError([error, cleanup], 'computation worker failed to stop');
}
throw error;
}
}
close(retry = false) {
if (retry && this.closeSettled && this.closeFailed) {
this.closing = undefined;
this.closeSettled = false;
this.closeFailed = false;
}
if (this.closing !== undefined)
return this.closing;
for (const waiter of this.waiting.splice(0))
waiter.reject(makeAbortError());
const port = this.port;
const stopping = Promise.resolve().then(async () => {
if (port !== undefined) {
let ready;
try {
ready = await port;
}
catch {
this.port = undefined;
return;
}
await ready.close();
if (this.port === port)
this.port = undefined;
}
});
this.closing = stopping;
void stopping.then(() => {
this.closeSettled = true;
}, () => {
this.closeSettled = true;
this.closeFailed = true;
});
return stopping;
}
checkReady(port, signal) {
if (port !== this.port || this.closing !== undefined)
throw makeAbortError(signal);
if (this.terminal !== undefined)
throw this.terminal;
}
open() {
return createPort((reply) => this.waiting.shift()?.resolve(reply), (error) => {
if (this.closing !== undefined)
return;
this.terminal = error;
for (const waiter of this.waiting.splice(0))
waiter.reject(error);
});
}
}
//# sourceMappingURL=worker.js.map