@struktoai/mirage-core
Version:
A Unified Virtual Filesystem For AI Agents
171 lines • 6.66 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;
};
// How much of a file one read or write moves while a tar streams.
const CHUNK = 1024 * 1024;
async function tryLoadFs() {
const g = globalThis;
if (g.process?.versions?.node === undefined)
return null;
try {
const modName = 'node:fs/promises';
const mod = (await import(__rewriteRelativeImportExtension(/* @vite-ignore */ modName)));
return mod;
}
catch {
return null;
}
}
const nodeFs = await tryLoadFs();
export async function readFileBytes(path) {
if (nodeFs === null)
throw new Error('readFileBytes: not available (node:fs unavailable)');
return nodeFs.readFile(path);
}
export async function writeFileBytes(path, data) {
if (nodeFs === null)
throw new Error('writeFileBytes: not available (node:fs unavailable)');
await nodeFs.writeFile(path, data);
}
function requireFs(caller) {
if (nodeFs === null)
throw new Error(`${caller}: not available (node:fs unavailable)`);
return nodeFs;
}
export async function fileSize(path) {
return (await requireFs('fileSize').stat(path)).size;
}
/**
* Open a host file a state named, without following a link. A captured
* file read later is refused when a link or anything but a regular file
* has replaced it since its state named it: O_NOFOLLOW makes the open
* fail on a link (ELOOP), and the handle's own stat refuses a directory,
* FIFO or device, so a swapped file cannot pull a host file from outside
* the mount into a workspace or a snapshot. Mirrors node's openRegular.
*/
async function openRegular(path) {
const fs = requireFs('openRegular');
const handle = await fs.open(path, fs.constants.O_RDONLY | (fs.constants.O_NOFOLLOW ?? 0));
try {
if (!(await handle.stat()).isFile())
throw new Error(`not a regular file: ${path}`);
}
catch (error) {
await handle.close();
throw error;
}
return handle;
}
/** The bytes of a host file a state named, opened as `openRegular` opens it. */
export async function readRegular(path) {
const handle = await openRegular(path);
try {
return await handle.readFile();
}
finally {
await handle.close();
}
}
/** The file at `path`, opened as `openRegular` opens it, a chunk at a time. */
export async function* regularChunks(path) {
yield* chunksOf(await openRegular(path));
}
/** Write `source` to a file at `path`, chunk by chunk; returns the bytes written. */
export async function writeStreamToFile(path, source) {
const fs = requireFs('writeStreamToFile');
const slash = path.lastIndexOf('/');
if (slash > 0)
await fs.mkdir(path.slice(0, slash), { recursive: true });
const handle = await fs.open(path, 'w');
const reader = source.getReader();
let written = 0;
try {
for (;;) {
const { done, value } = await reader.read();
if (done)
break;
let offset = 0;
while (offset < value.byteLength) {
const { bytesWritten } = await handle.write(value, offset, value.byteLength - offset, null);
if (bytesWritten === 0)
throw new Error(`${path}: write made no progress`);
offset += bytesWritten;
}
written += value.byteLength;
}
}
finally {
reader.releaseLock();
await handle.close();
}
return written;
}
/** The file at `path`, a chunk at a time. */
export async function* fileChunks(path) {
yield* chunksOf(await requireFs('fileChunks').open(path, 'r'));
}
/** An open file's bytes a chunk at a time, closing it once read or let go. */
async function* chunksOf(handle) {
try {
for (;;) {
const chunk = new Uint8Array(CHUNK);
const { bytesRead } = await handle.read(chunk, 0, CHUNK, null);
if (bytesRead === 0)
return;
yield chunk.subarray(0, bytesRead);
}
}
finally {
await handle.close();
}
}
/** A fresh directory under the system temp dir, for staging a restore. */
/**
* Where blob `name` is staged under `staging`, its directory made; a name
* landing outside it, as written or through a link, is refused.
*/
export async function stagedPath(staging, name) {
const fs = requireFs('stagedPath');
const modName = 'node:path';
const path = (await import(__rewriteRelativeImportExtension(/* @vite-ignore */ modName)));
const root = await fs.realpath(staging);
const inside = (target) => {
const rel = path.relative(root, target);
return rel !== '' && rel !== '..' && !rel.startsWith(`..${path.sep}`) && !path.isAbsolute(rel);
};
const target = path.resolve(root, name);
if (!inside(target))
throw new Error(`Unsafe blob path: ${name}`);
await fs.mkdir(path.dirname(target), { recursive: true });
const real = path.join(await fs.realpath(path.dirname(target)), path.basename(target));
if (!inside(real))
throw new Error(`Unsafe blob path: ${name}`);
return real;
}
export async function makeStagingDir() {
const modName = 'node:os';
const os = (await import(__rewriteRelativeImportExtension(/* @vite-ignore */ modName)));
return requireFs('makeStagingDir').mkdtemp(`${os.tmpdir()}/mirage-restore-`);
}
export async function removeDir(path) {
await requireFs('removeDir').rm(path, { recursive: true, force: true });
}
//# sourceMappingURL=fs.js.map