@context-fs/core
v0.1.4
Published
Virtual filesystem core - tree router and path-based APIs
Downloads
1,122
Readme
@context-fs/core
Virtual filesystem core library with a tree-based router for defining path-based APIs. Browser-safe with full TypeScript inference.
Installation
npm install @context-fs/coreQuick Start
import { createFileSystem, read, list } from "@context-fs/core";
const vfs = createFileSystem({
"config.json": {
[read]: (c) => c.json({ version: "1.0.0" }),
},
users: {
":userId": {
[list]: () => [{ userId: "alice" }, { userId: "bob" }],
"profile.json": {
[read]: (c) => c.json({ id: c.params.userId }),
},
},
},
});
// Read files
const config = await vfs.readText("/config.json");
const profile = await vfs.readText("/users/alice/profile.json");
// List directories
const users = await vfs.ls("/users"); // ["alice", "bob"]Concepts
Tree Structure
Define your filesystem as a nested object. Each key is a path segment, and leaf nodes contain handler symbols.
const tree = {
// Static file
"readme.txt": {
[read]: () => "Hello, world!",
},
// Directory with nested content
docs: {
"guide.md": {
[read]: (c) => c.markdown("# Guide\n\nWelcome!"),
},
},
};Dynamic Path Segments
Use :param syntax for dynamic segments. Parameters are fully typed and available via c.params.
const tree = {
// Simple param
":id": {
[read]: (c) => c.params.id, // { id: string }
},
// Param with suffix
":slug.md": {
[read]: (c) => c.params.slug, // { slug: string }
},
// Param with prefix
"issue-:num": {
[read]: (c) => c.params.num, // { num: string }
},
// Multiple params
":year-:month-:day.json": {
[read]: (c) => c.params, // { year, month, day: string }
},
};Handler Symbols
read - File Content
Return file content when read. Use context helpers for common formats.
import { read } from "@context-fs/core";
{
[read]: (c) => "plain text",
[read]: (c) => new Uint8Array([...]),
[read]: (c) => c.json({ key: "value" }),
[read]: (c) => c.text("text content"),
[read]: (c) => c.markdown("# Heading"),
}write - File Writes
Handle file writes. Return { error: string } to reject.
import { write } from "@context-fs/core";
{
[read]: (c) => currentValue,
[write]: (c, data) => {
const text = new TextDecoder().decode(data);
// Process write...
return {}; // Success
// return { error: "Write failed" }; // Failure
},
}list - Directory Enumeration
Return an array of parameter objects for dynamic directories.
import { list } from "@context-fs/core";
{
":userId": {
[list]: async () => {
const users = await fetchUsers();
return users.map((u) => ({ userId: u.id }));
},
"profile.json": {
[read]: (c) => c.json({ id: c.params.userId }),
},
},
}link - Symlinks
Create symbolic links to other paths.
import { link } from "@context-fs/core";
{
"latest.json": {
[link]: () => "/versions/v2.0.0.json",
},
// Dynamic symlink
":alias": {
[link]: (c) => `/targets/${c.params.alias}`,
},
}exists - Validation
Control whether a dynamic path exists. Useful for open-ended patterns.
import { exists } from "@context-fs/core";
{
":slug": {
[exists]: async (c) => {
return await isValidSlug(c.params.slug);
},
[read]: (c) => getContent(c.params.slug),
},
}stats - Custom File Stats
Override default file statistics.
import { stats } from "@context-fs/core";
{
"data.bin": {
[stats]: () => ({
size: 1024,
mtime: new Date("2024-01-01"),
mode: 0o644,
}),
[read]: () => getData(),
},
}Mounting Subtrees
Use withParams() to create reusable filesystem fragments with inherited parameters.
import { createFileSystem, withParams, read, list } from "@context-fs/core";
// Reusable subtree factory
const createUserFiles = withParams<{ userId: string }>()({
"profile.json": {
[read]: (c) => c.json({ id: c.params.userId }),
},
"settings.json": {
[read]: (c) => c.json({ theme: "dark" }),
},
});
// Mount in main tree
const vfs = createFileSystem({
users: {
":userId": {
[list]: () => [{ userId: "alice" }],
...createUserFiles(),
},
},
});API Reference
createFileSystem(tree)
Creates a VirtualFileSystem from a tree definition.
const vfs = createFileSystem(tree);VirtualFileSystem
Reading
// List directory contents
const entries: string[] = await vfs.ls("/path");
// Read as Uint8Array
const data: Uint8Array = await vfs.read("/file.bin");
// Read as string
const text: string = await vfs.readText("/file.txt");
// Check existence
const exists: boolean = await vfs.exists("/path");
// Get file stats
const stat: VfsStat = await vfs.stat("/path");
const lstat: VfsStat = await vfs.lstat("/symlink"); // Don't follow symlinksWriting
// Write file (if handler supports it)
const result = await vfs.write("/file.txt", new Uint8Array([...]));
if (result.error) {
console.error(result.error);
}
// Check if path is writable
const writable: boolean = await vfs.isWritable("/path");Symlinks
// Read symlink target
const target: string = await vfs.readlink("/symlink");
// Resolve path (follows symlinks)
const resolved: string = await vfs.resolve("/path/../other/./file");Types
type FileContent = string | Uint8Array;
interface FileStats {
size?: number;
mtime?: Date;
ctime?: Date;
mode?: number;
}
interface VfsStat {
type: "file" | "directory" | "symlink";
mode: number;
size: number;
mtime: Date;
ctime: Date;
atime: Date;
}
interface WriteResult {
error?: string;
}Browser Compatibility
This package is browser-safe and doesn't depend on Node.js APIs. It can be used in any JavaScript environment.
Related Packages
@context-fs/nfs- Mount as NFS server@context-fs/cli- CLI framework for VFS tools@context-fs/just-bash- just-bash adapter
License
MIT
