Portable filesystem operations and FileRef construction.
Node, Deno, and Bun use native filesystem implementations. Browser bundles are safe to import: reference construction and lexical operations work, while disk operations throw when called.
import fs from "@rcompat/fs";
import type {
DirectoryOptions, FileInfo, FileRef, FileType, Filter, ListOptions, GlobOptions, LinkOptions, NamedStreamable, Path, RemoveOptions, SpoolOptions, SpoolSnapshot, Streamable, WritableInput,
} from "@rcompat/fs";fs.streamable#
Protocol key for objects that provide a web ReadableStream.
Registered globally as Symbol.for("std:symbol/stream"), preserving
identity across runtimes, separately loaded copies, and the legacy
@rcompat/symbol.stream export.
fs.streamable: unique symbol;fs.ref#
Creates a FileRef for a filesystem path.
Parameters
path— A native path, file URL, or existing reference.
Returns: A FileRef preserving the supplied native path spelling.
Example
const config = fs.ref("config.json");
await config.writeJSON({ enabled: true });
await config.json(); // { enabled: true }fs.isRef#
Checks whether a value is a compatible FileRef.
Parameters
value— The value to inspect.
fs.isRef(value: unknown): value is FileRef;fs.isStream#
Checks whether a value can provide a readable stream.
Parameters
value— The value to inspect.
fs.isStream(value: unknown): value is Streamable;fs.isNamedStream#
Checks whether a streamable value also has a name.
Parameters
value— The value to inspect.
fs.isNamedStream(value: unknown): value is NamedStreamable;fs.cwd#
Returns the current working directory as an absolute reference.
fs.cwd(): FileRef;fs.createDirectory#
Creates a directory.
Parameters
path— Directory path to create.options— Directory creation options.
Default: options.recursive is true.
fs.createDirectory(path: Path, options?: DirectoryOptions): Promise<void>;fs.createFile#
Creates an empty file exclusively, without creating parents.
fs.createFile(path: Path): Promise<void>;fs.createLink#
Creates a symbolic link at linkPath, storing target.
fs.createLink(
linkPath: Path, target: Exclude<Path, URL>, options?: LinkOptions,
): Promise<void>;fs.resolve#
Resolves a path from the current working directory.
Parameters
path— Path to resolve, or the current directory when omitted.
fs.list#
Lists immediate or recursive directory entries.
Parameters
path— Directory to list.options— Recursion and filtering options.
fs.list(path: Path, options?: ListOptions): Promise<FileRef[]>;fs.files#
Lists file entries in a directory.
Parameters
path— Directory to list.options— Recursion and filtering options.
fs.files(path: Path, options?: ListOptions): Promise<FileRef[]>;fs.dirs#
Lists directory entries in a directory.
Parameters
path— Directory to list.options— Recursion and filtering options.
fs.dirs(path: Path, options?: ListOptions): Promise<FileRef[]>;fs.glob#
Lazily yields files matching a portable relative glob pattern.
Supports *, ?, ** path segments, and bracket classes. Brace
expansion and extglobs are not supported. / is always the pattern
separator. Wildcards do not match a leading dot in a path segment unless
that segment starts with .. Symbolic links are not followed or yielded.
Results are absolute references beneath the resolved cwd and retain the
runtime's native directory iteration order. Missing or non-directory roots
produce no results; other filesystem errors reject iteration.
Parameters
pattern— Relative portable glob pattern.options— Root directory and cancellation options.
Throws: A SyntaxError for malformed or unsupported patterns. Iteration
also rejects on cancellation or filesystem errors other than a missing or
non-directory root.
fs.glob(pattern: string, options?: GlobOptions): AsyncIterable<FileRef>;fs.exists#
Checks whether a path exists.
fs.exists(path: Path): Promise<boolean>;fs.empty#
Checks whether a file or directory is empty.
fs.empty(path: Path): Promise<boolean>;fs.arrayBuffer#
Reads a file into an array buffer.
fs.arrayBuffer(path: Path): Promise<ArrayBuffer>;fs.bytes#
Reads a file into an unsigned byte array.
fs.bytes(path: Path): Promise<Uint8Array>;fs.text#
Reads a UTF-8 text file.
fs.text(path: Path): Promise<string>;fs.json#
Reads and parses a JSON file.
fs.stream#
Returns a readable stream for a path or streamable value.
fs.stream(target: Path | Streamable): ReadableStream<unknown>;fs.write#
Writes text, bytes, blobs, responses, or readable streams to a path.
fs.write(path: Path, value: WritableInput): Promise<void>;fs.spool#
Copies a byte stream to a private disposable file while incrementally computing its SHA-256 digest.
This operation uses backpressure and never buffers the complete input.
It resolves only after source EOF, completed file writes, digest
finalization, and optional expectedDigest verification. The returned
snapshot reads the saved bytes rather than the original source.
spool() takes ownership of source while it runs. Abort, source or file
failure, digest-finalization failure, and digest mismatch close resources,
delete the partial file, and reject without returning a snapshot. Without
expectedDigest, the returned digest is computed but not externally
verified. Supply a trusted expected value before using this operation to
gate delivery of an artifact.
The caller owns the result. Its one-shot stream removes the backing file
after EOF or cancellation. Call dispose() if no consumer receives the
stream, or to terminate an active read. Do not dispose immediately after
constructing a streaming Response; allow its body to finish or be
cancelled by the HTTP host. An abandoned, uncancelled body can retain its
snapshot like any other open stream.
Browser bundles remain safe to import, but calling this disk-backed operation in a browser throws a clear unavailable-filesystem error.
Parameters
source— Byte stream to consume exactly once.options— Digest verification and spooling cancellation options.
Throws: On invalid options, abort, source or file I/O failure, digest mismatch, digest finalization failure, or unsupported runtime.
fs.spool(
source: ReadableStream<Uint8Array>,
options?: SpoolOptions,
): Promise<SpoolSnapshot>;Example
const snapshot = await fs.spool(response.body!, {
expectedDigest: trustedDigest,
});
const verified = new Response(snapshot.stream(), {
headers: { "content-length": String(snapshot.size) },
});fs.writeJSON#
Writes a value as indented JSON.
fs.size#
Returns a file's size in bytes.
fs.size(path: Path): Promise<number>;fs.webpath#
Converts a path to forward-slash separators.
fs.webpath(path: Path): string;fs.join#
Joins path segments into a new reference.
fs.normalize#
Lexically normalizes a path without accessing the filesystem.
fs.isAbsolute#
Checks whether a path is absolute in native syntax.
fs.isAbsolute(path: Path): boolean;fs.relativeTo#
Returns a portable lexical path from base to path.
fs.discover#
Walks upward until a directory containing a filename is found.
fs.type#
Returns the filesystem entry type, or null when it is missing.
Types#
DirectoryOptions#
Options for creating a directory.
interface DirectoryOptions {
// Create missing parent directories.
// Default: `true`
recursive?: boolean;
}FileInfo#
Information supplied to directory-entry filters.
This closed data shape remains an object type alias so it is assignable to
consumers accepting Record<string, unknown>.
type FileInfo = {
// Native filesystem path for the entry.
path: string;
// Final path component including extensions.
name: string;
// Last extension including its leading dot.
extension: string;
// All extensions beginning at the first dot.
fullExtension: string;
// Kind of filesystem entry.
type: "file" | "directory" | "link";
};FileRef#
A pathlib-inspired reference to a file or directory.
Construct references through fs.ref() when possible. Methods perform
filesystem work only when called; creating a reference does not access disk.
declare class FileRef {}Constructor#
new FileRef()#
Creates a reference without accessing the filesystem.
constructor(path: Path)Static methods#
FileRef.is()#
Checks whether a value carries the compatible FileRef brand.
static is(x: unknown): x is FileRefInstance properties#
file.path#
The native path spelling used to create this reference.
get path(): stringfile.name#
The final path component including its extension.
get name(): stringfile.base#
The final path component without its last extension.
get base(): stringfile.extension#
The last filename extension including its leading dot.
get extension(): stringfile.fullExtension#
All filename extensions beginning at the first dot.
get fullExtension(): stringfile.directory#
A reference to the parent directory.
get directory(): FileReffile.core#
The final path component without any extension.
get core(): stringInstance methods#
file.join()#
Joins relative segments without lexical normalization. Absolute paths, drive-qualified operands and URLs are not join operands.
file.normalize()#
Explicitly normalizes . and .. into a new reference.
normalize(): FileReffile.isAbsolute()#
Checks whether this reference has an absolute native path.
isAbsolute(): booleanfile.relativeTo()#
Returns a /-separated lexical path from base to this reference.
Returns "." for the same location and rejects incompatible roots.
This is not a containment or filesystem-identity check.
relativeTo(base: Path): stringfile.webpath()#
Converts native separators to forward slashes.
webpath(): stringfile.toURL()#
Converts this filesystem path to a native file: URL.
Relative paths are resolved from the current working directory according
to the running host's pathToFileURL semantics.
toURL(): URLfile.append()#
Appends text directly to the path.
append(suffix: string): FileReffile.bare()#
Removes the final extension and optionally appends text.
bare(append?: string): FileReffile.text()#
Reads the file as UTF-8 text.
text(): Promise<string>file.json()#
Reads and parses the file as JSON.
json<T extends JSONValue>(): Promise<T>file.bytes()#
Reads the file as bytes.
bytes(): Promise<Uint8Array>file.arrayBuffer()#
Reads the file into an array buffer.
arrayBuffer(): Promise<ArrayBuffer>file.stream()#
Opens a readable byte stream for the file.
Wrap the result in a Response and call response.text() to decode UTF-8
text.
stream(): ReadableStream<Uint8Array>file.size()#
Returns the file size in bytes.
size(): Promise<number>file.write()#
Writes supported text, binary, blob, response, or stream input.
write(input: WritableInput): Promise<void>file.writeJSON()#
Writes a value as indented JSON.
writeJSON(input: JSONValue): Promise<void>file.exists()#
Checks whether the referenced path exists.
exists(): Promise<boolean>file.type()#
Returns the entry type, or null when the path is missing.
type(): Promise<FileType>file.modified()#
Returns the modification time as Unix milliseconds.
modified(): Promise<number>file.empty()#
Checks whether a file has zero bytes or a directory has no entries.
empty(): Promise<boolean>file.list()#
Lists immediate or recursive directory entries.
list(options?: ListOptions): Promise<FileRef[]>file.files()#
Lists only file entries.
files(options?: ListOptions): Promise<FileRef[]>file.dirs()#
Lists only directory entries.
dirs(options?: ListOptions): Promise<FileRef[]>file.createDirectory()#
Creates this directory.
Default: options.recursive is true.
createDirectory(options?: DirectoryOptions): Promise<void>file.createFile()#
Exclusively creates an empty file, without creating parents.
createFile(): Promise<void>file.createLink()#
Creates a symbolic link at this reference, storing target unchanged.
A relative target is interpreted from the link's directory when followed.
Existing destinations and missing parents fail; dangling targets are valid.
createLink(
target: Exclude<Path, URL>, options?: LinkOptions,
): Promise<void>file.remove()#
Removes this path.
Default: Missing paths do not fail unless options.fail is true.
remove(options?: RemoveOptions): Promise<void>file.copy()#
Copies this file or directory to another reference.
file.hash()#
Hashes the file contents.
Parameters
algorithm— A Web Crypto digest algorithm.
Default: "SHA-256"
hash(algorithm?: string): Promise<string>file.import()#
Dynamically imports the file, optionally returning one named export.
import(name?: string): Promise<any>file.discover()#
Walks upward to find a directory containing a filename.
discover(filename: string): Promise<FileRef>file.sibling()#
Returns a named reference in the same directory.
sibling(name: string): FileReffile.or()#
Returns this reference when it exists, otherwise a fallback value.
or<T>(fallback: () => T): Promise<this | T>file.toString()#
Returns the normalized path.
toString(): stringProtocol members#
file[Symbol.replace]()#
Replaces this reference's string value inside another string.
[Symbol.replace](
string: string,
replacement: string | StringReplacer,
): stringfile[fs.streamable]()#
Returns the file's stream through fs.streamable.
[fs.streamable](): ReadableStream<Uint8Array>file[util.inspect.custom]()#
Formats the reference for Node-compatible object inspection.
[util.inspect.custom](): stringfile.Name protocol property#
The stable class name used by shared protocols.
get Name(): "FileRef"FileType#
The recognized kind of a filesystem entry, or null when it is missing.
type FileType = "directory" | "file" | "link" | null;Filter#
Selects directory entries synchronously or asynchronously.
Parameters
info— Information about the candidate entry.
type Filter = (info: FileInfo) => MaybePromise<boolean>;ListOptions#
Options for listing directory entries.
This remains an object type alias so options are assignable to broad
Record<string, unknown> consumers. Consumers can still extend the shape
through an interface or intersection.
type ListOptions = {
// Visit entries in nested directories.
// Default: `false`
recursive?: boolean;
// Keep entries accepted by a regular expression or callback.
filter?: RegExp | Filter;
};GlobOptions#
Options for lazy filesystem glob scanning.
This remains an object type alias so options are assignable to broad
Record<string, unknown> consumers. Consumers can still extend the shape
through an interface or intersection.
type GlobOptions = {
// Directory against which the relative pattern is evaluated.
cwd?: string;
// Cancels traversal and causes the iterator to reject.
signal?: AbortSignal;
};LinkOptions#
Options for creating a symbolic link.
type LinkOptions = {
// Only symbolic links are supported.
// Default: `"symbolic"`
type?: "symbolic";
// Windows target-kind hint; ignored by POSIX filesystems.
targetType?: "file" | "directory";
};NamedStreamable#
A streamable value with a filename or other display name.
Type parameters
T— The chunks produced by the stream.
type NamedStreamable<T = unknown> = Streamable<T> & { name: string };Path#
A complete filesystem path accepted by @rcompat/fs operations.
Native path strings and file:// strings are accepted. Strings beginning
with a non-file <scheme>://, such as https://example.com/file.txt, are
rejected before filesystem access. Drive-letter paths, including paths using
doubled forward slashes such as C://Temp/file.txt, and ordinary filenames
containing a colon remain native paths. URL objects must use the file:
protocol. Filesystem helpers never fetch network resources.
APIs for relative path segments, such as FileRef.join(), exclude URL
objects from this complete-path contract.
type Path = FileRef | URL | string;RemoveOptions#
Options for removing a filesystem entry.
interface RemoveOptions extends DirectoryOptions {
// Fail when the entry does not exist.
// Default: `false`
fail?: boolean;
// Remove directory contents recursively.
// Default: `true`
recursive?: boolean;
}SpoolOptions#
Options for creating a disposable streamed file snapshot.
This remains an object type alias so options are assignable to broad
Record<string, unknown> consumers. Consumers can still extend the shape
through an interface or intersection.
type SpoolOptions = {
// Digest algorithm. Only `SHA-256` is currently supported.
algorithm?: "SHA-256";
// Trusted 64-character hexadecimal SHA-256 digest to verify.
expectedDigest?: string;
// Aborts only the spooling phase.
signal?: AbortSignal;
};SpoolSnapshot#
An owned, disposable snapshot created by fs.spool().
type SpoolSnapshot = {
// Lowercase hexadecimal SHA-256 digest of the saved bytes.
readonly digest: string;
// Number of bytes saved.
readonly size: number;
// Opens the snapshot for its single read.
stream(): ReadableStream<Uint8Array>;
// Closes an active read and removes the backing file.
// Safe to call repeatedly, including after stream completion.
dispose(): Promise<void>;
};Streamable#
A value that can provide a web ReadableStream.
Objects can expose streams through fs.streamable.
Type parameters
T— The chunks produced by the stream.
type Streamable<T = unknown> =
| Blob
| ReadableStream<T>
| { [fs.streamable](): ReadableStream<T> }
;WritableInput#
Content accepted by filesystem write operations.
type WritableInput =
| ArrayBuffer
| Uint8Array
| Blob
| ReadableStream
| Response
| string
;