FsAdapter

The FsAdapter interface defines the contract between a layer and its backing filesystem. Every adapter must implement this interface. The layer delegates read operations to the adapter when no overlay entry exists, and writes changes through the adapter when apply() is called.

Import

import type { FsAdapter } from "@catmint-fs/core";

Signature

interface FsAdapter {
  readFile(path: string): Promise<Uint8Array>;
  createReadStream(path: string): ReadableStream<Uint8Array>;
  readdir(path: string): Promise<DirentEntry[]>;
  stat(path: string): Promise<StatResult>;
  lstat(path: string): Promise<StatResult>;
  readlink(path: string): Promise<string>;
  exists(path: string): Promise<boolean>;
  writeFile(path: string, data: Uint8Array, options?: WriteOptions): Promise<void>;
  mkdir(path: string, options?: MkdirOptions): Promise<void>;
  rm(path: string, options?: RmOptions): Promise<void>;
  rmdir(path: string): Promise<void>;
  rename(from: string, to: string): Promise<void>;
  symlink(target: string, path: string): Promise<void>;
  chmod(path: string, mode: number): Promise<void>;
  chown(path: string, uid: number, gid: number): Promise<void>;
  lchown(path: string, uid: number, gid: number): Promise<void>;
  checkPermission(path: string, op: PermissionOp): Promise<void>;
  capabilities(): AdapterCapabilities;
  initialize?(root: string): Promise<void>;
}

Methods

Reading

MethodParametersReturnDescription
readFilepath: stringPromise<Uint8Array>Read the full contents of a file
createReadStreampath: stringReadableStream<Uint8Array>Create a readable stream for a file
readdirpath: stringPromise<DirentEntry[]>List directory entries
statpath: stringPromise<StatResult>Get file metadata (follows symlinks)
lstatpath: stringPromise<StatResult>Get file metadata (does not follow symlinks)
readlinkpath: stringPromise<string>Read the target of a symlink
existspath: stringPromise<boolean>Check if a path exists

Writing

MethodParametersReturnDescription
writeFilepath: string, data: Uint8Array, options?: WriteOptionsPromise<void>Write data to a file
mkdirpath: string, options?: MkdirOptionsPromise<void>Create a directory
rmpath: string, options?: RmOptionsPromise<void>Remove a file or directory
rmdirpath: stringPromise<void>Remove an empty directory
renamefrom: string, to: stringPromise<void>Rename or move an entry
symlinktarget: string, path: stringPromise<void>Create a symbolic link

Permissions

MethodParametersReturnDescription
chmodpath: string, mode: numberPromise<void>Change file permission mode
chownpath: string, uid: number, gid: numberPromise<void>Change file ownership
lchownpath: string, uid: number, gid: numberPromise<void>Change symlink ownership
checkPermissionpath: string, op: PermissionOpPromise<void>Validate that an operation is permitted

Metadata

MethodParametersReturnDescription
capabilitiesAdapterCapabilitiesDeclare adapter feature support
initializeroot: stringPromise<void>(Optional) One-time setup with the layer root

AdapterCapabilities

interface AdapterCapabilities {
  permissions: boolean;
  symlinks: boolean;
  caseSensitive: boolean;
}
FieldTypeDescription
permissionsbooleanWhether chmod, chown, and lchown are supported
symlinksbooleanWhether symlink and readlink are supported
caseSensitivebooleanWhether the filesystem treats paths as case-sensitive

Examples

Implementing a minimal adapter

import type {
  FsAdapter,
  AdapterCapabilities,
  StatResult,
  DirentEntry,
  PermissionOp,
} from "@catmint-fs/core";

class MyAdapter implements FsAdapter {
  async readFile(path: string): Promise<Uint8Array> {
    // Fetch file contents from your storage
  }

  createReadStream(path: string): ReadableStream<Uint8Array> {
    // Return a ReadableStream for the file
  }

  async readdir(path: string): Promise<DirentEntry[]> {
    // List directory contents
  }

  async stat(path: string): Promise<StatResult> {
    // Return file metadata, following symlinks
  }

  async lstat(path: string): Promise<StatResult> {
    // Return file metadata, not following symlinks
  }

  async readlink(path: string): Promise<string> {
    throw new Error("Symlinks not supported");
  }

  async exists(path: string): Promise<boolean> {
    // Check if path exists
  }

  async writeFile(path: string, data: Uint8Array): Promise<void> {
    // Write file data
  }

  async mkdir(path: string): Promise<void> {
    // Create a directory
  }

  async rm(path: string): Promise<void> {
    // Remove a file or directory
  }

  async rmdir(path: string): Promise<void> {
    // Remove an empty directory
  }

  async rename(from: string, to: string): Promise<void> {
    // Move/rename an entry
  }

  async symlink(target: string, path: string): Promise<void> {
    throw new Error("Symlinks not supported");
  }

  async chmod(path: string, mode: number): Promise<void> {
    throw new Error("Permissions not supported");
  }

  async chown(path: string, uid: number, gid: number): Promise<void> {
    throw new Error("Permissions not supported");
  }

  async lchown(path: string, uid: number, gid: number): Promise<void> {
    throw new Error("Permissions not supported");
  }

  async checkPermission(path: string, op: PermissionOp): Promise<void> {
    // No-op: allow all operations
  }

  capabilities(): AdapterCapabilities {
    return {
      permissions: false,
      symlinks: false,
      caseSensitive: true,
    };
  }
}

Using a custom adapter

import { createLayer } from "@catmint-fs/core";

const adapter = new MyAdapter();
const layer = createLayer({ root: "/", adapter });

See Also