UNPKG

@struktoai/mirage-core

Version:

A Unified Virtual Filesystem For AI Agents

80 lines • 3.39 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 { toIsoZ } from "../../utils/dates.js"; import { DirListing, FileStat, FileType } from "../../types.js"; import { contentTypeForPath } from "../../utils/filetype.js"; import { rstripSlash } from "../../utils/slash.js"; import { getMetadata, getDirectoryMetadata, listDirectoryContents } from "./client.js"; import { isNotFound } from "./errors.js"; import { backendPath } from "./path.js"; import { compareCodePoints } from "../../utils/sort.js"; import { listingError } from "../../errors/fs.js"; async function exists(accessor, probe, key) { try { await probe(accessor, backendPath(accessor.config, key)); } catch (exc) { if (isNotFound(exc)) return false; throw exc; } return true; } /** * A folder's rows, as the Files API lists them; past a walk's `limit` the * API is paged no further, and the listing is partial. Mirrors Python's * `readdir`. * * Throws: * FileNotFoundError: nothing is at the path. * NotADirectoryError: the path, or a folder above it, is a file. */ export async function readdir(accessor, path, limit) { const listPath = path.pattern !== null ? path.dir : path; const remotePath = backendPath(accessor.config, listPath); let entries; try { entries = await listDirectoryContents(accessor, remotePath, limit); } catch (exc) { // The Files API answers 404 for a missing path and for a path under a // file alike, so the errno comes from walking the ancestors: one // metadata request per component, on this failure path only. if (isNotFound(exc)) { throw await listingError(listPath.virtual, listPath.mountPath, (p) => exists(accessor, getMetadata, p), (p) => exists(accessor, getDirectoryMetadata, p)); } throw exc; } const rows = []; for (const entry of [...entries].sort((a, b) => compareCodePoints(a.path, b.path))) { const name = rstripSlash(entry.path).split('/').pop() ?? entry.path; if (entry.isDirectory) { rows.push(new FileStat({ name, type: FileType.DIRECTORY })); continue; } let size = entry.fileSize; size ??= (await getMetadata(accessor, entry.path)).contentLength; rows.push(new FileStat({ name, size, modified: entry.lastModified === null ? null : toIsoZ(new Date(entry.lastModified)), type: FileType.FILE, content: contentTypeForPath(name), })); } if (limit !== undefined && entries.length >= limit) return new DirListing({ entries: rows, partial: true }); return rows; } //# sourceMappingURL=readdir.js.map