@struktoai/mirage-core
Version:
A Unified Virtual Filesystem For AI Agents
107 lines • 5.1 kB
JavaScript
// ========= 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;
};
import { resolveHome } from "../../config.js";
import { PyodideUnavailableError } from "./errors.js";
import { sealNetwork } from "./network.js";
const noopIo = () => undefined;
const PYODIDE_CDN_VERSION = '314.0.5';
const PYODIDE_CDN_URL = `https://cdn.jsdelivr.net/pyodide/v${PYODIDE_CDN_VERSION}/full/`;
const PYODIDE_HOME_ENV = 'MIRAGE_PYODIDE_HOME';
/** Whether this runs under Node, where pyodide loads from the installed package. */
export function isNode() {
const proc = globalThis.process;
return typeof proc?.versions?.node === 'string';
}
async function resolveNodeIndexURL() {
if (!isNode())
return null;
try {
const nodeModule = await import('node:module');
const nodePath = await import('node:path');
const require = nodeModule.createRequire(import.meta.url);
const entry = require.resolve('pyodide');
const dir = nodePath.dirname(entry);
return `${dir}/`;
}
catch {
return null;
}
}
export async function loadPyodideRuntime(
/** Distribution knobs a deployment can point at its own prebuilt assets. */
options = {}) {
const home = resolveHome(options, PYODIDE_HOME_ENV) ??
(await resolveNodeIndexURL()) ??
(isNode() ? null : PYODIDE_CDN_URL);
// A browser worker starts from a blob (worker/client.ts), where neither
// a bare specifier nor a relative path resolves, so it loads pyodide's
// loader and every other asset from the distribution's absolute URL, a
// path read from the page's origin. The page loads from the same URL, so
// the two always run one release and the page needs no pyodide package.
const origin = isNode()
? undefined
: globalThis.location?.origin;
const resolved = home === null || origin === undefined ? home : new URL(home, `${origin}/`).href;
const indexURL = resolved === null || resolved.endsWith('/') ? resolved : `${resolved}/`;
const distribution = origin === undefined ? null : indexURL;
let mod;
try {
mod = (await (distribution === null
? import('pyodide')
: import(__rewriteRelativeImportExtension(/* @vite-ignore */ `${distribution}pyodide.mjs`))));
}
catch (err) {
throw new PyodideUnavailableError(distribution === null
? 'python3 requires the optional `pyodide` peer dependency. Install it with `npm i pyodide`.'
: `cannot load pyodide from ${distribution}: ${err instanceof Error ? err.message : String(err)}`, { cause: err });
}
// A null-prototype jsglobals empties the guest's `js` module: `import
// js` still resolves, but js.process, js.fetch and the rest of the host
// globalThis are not attributes of it. pyodide's own internals capture
// the globals they need at load time, not through this object.
const opts = {
stdout: noopIo,
stderr: noopIo,
jsglobals: Object.create(null),
};
if (options.packageBaseUrl !== undefined)
opts.packageBaseUrl = options.packageBaseUrl;
if (options.lockFileURL !== undefined)
opts.lockFileURL = options.lockFileURL;
if (options.packages !== undefined && options.packages.length > 0) {
opts.packages = [...options.packages];
}
if (indexURL !== null)
opts.indexURL = indexURL;
try {
const runtime = (await mod.loadPyodide(opts));
// Emscripten's SOCKFS would carry a guest socket over a WebSocket to
// the host; sealNetwork makes it refuse instead. A build it cannot
// seal reports pyodide unavailable, like any failed initialization.
sealNetwork(runtime._module ?? {}, runtime.FS, runtime.ERRNO_CODES);
return runtime;
}
catch (err) {
throw new PyodideUnavailableError(`python3: failed to initialize pyodide runtime: ${err instanceof Error ? err.message : String(err)}`, { cause: err });
}
}
//# sourceMappingURL=loader.js.map