Overview
Complete specification for the FileSystemBridge interface
FS Bridge Specification
This document describes the complete specification for the FileSystemBridge interface, including all operations, capabilities, hooks, and types.
FileSystemBridge Interface
The FileSystemBridge interface is the core contract that all bridge implementations must satisfy. It extends the file system operations and adds metadata, capabilities tracking, and hooks.
interface FileSystemBridge extends FileSystemBridgeOperations {
/**
* The capabilities of this file system bridge.
*/
optionalCapabilities: HasOptionalCapabilityMap;
/**
* Metadata about this file system bridge.
*/
meta: FileSystemBridgeMetadata;
/**
* Hook system for listening to file system events.
*/
hook: HookableCore<FileSystemBridgeHooks>["hook"];
}Required Operations
All bridges must implement these three operations:
read
Reads the contents of a file as a string.
read(path: string): Promise<string>Parameters:
path(string): The path to the file to read
Returns: Promise that resolves to the file contents as a string
Example:
const content = await bridge.read("file.txt");exists
Checks if a file or directory exists.
exists(path: string): Promise<boolean>Parameters:
path(string): The path to check for existence
Returns: Promise that resolves to true if the path exists, false otherwise
Example:
const exists = await bridge.exists("file.txt");
if (exists) {
// File exists
}listdir
Lists the contents of a directory.
listdir(path: string, recursive?: boolean): Promise<FSEntry[]>Parameters:
path(string): The path to the directory to listrecursive(boolean, optional): Iftrue, lists files in subdirectories as well. Defaults tofalse.
Returns: Promise that resolves to an array of FSEntry objects
Example:
// List top-level contents
const entries = await bridge.listdir("directory");
// List recursively
const allEntries = await bridge.listdir("directory", true);Optional Operations
Bridges may optionally implement these operations. If not implemented, attempting to use them will throw a BridgeUnsupportedOperation error.
write
Writes data to a file.
write(path: string, data: string | Uint8Array, encoding?: BufferEncoding): Promise<void>Parameters:
path(string): The path to the file to writedata(string | Uint8Array): The data to write to the fileencoding(BufferEncoding, optional): Encoding for string data. Defaults to'utf8'.
Returns: Promise that resolves when the write operation is complete
Example:
await bridge.write("file.txt", "Hello World");
await bridge.write("file.bin", new Uint8Array([1, 2, 3]));mkdir
Creates a directory.
mkdir(path: string): Promise<void>Parameters:
path(string): The path of the directory to create
Returns: Promise that resolves when the directory is created
Example:
await bridge.mkdir("new/directory");rm
Removes a file or directory.
rm(path: string, options?: FileSystemBridgeRmOptions): Promise<void>Parameters:
path(string): The path to removeoptions(FileSystemBridgeRmOptions, optional): Configuration for removalrecursive(boolean): Iftrue, removes directories and their contents recursivelyforce(boolean): Iftrue, ignores errors if the path doesn't exist
Returns: Promise that resolves when the removal is complete
Example:
// Remove a file
await bridge.rm("file.txt");
// Remove a directory recursively
await bridge.rm("directory", { recursive: true, force: true });Capabilities System
Bridges automatically detect which optional operations they support. For complete documentation on checking and asserting capabilities, see the Capabilities documentation.
Hooks System
Bridges provide a hook system for listening to file system events. The hook property on a bridge instance allows you to register listeners for operation events.
interface FileSystemBridge {
// ...
hook: HookableCore<FileSystemBridgeHooks>["hook"];
}All bridges support hooks for monitoring, debugging, and logging. For complete documentation on available hooks, payload types, and usage examples, see the Hooks documentation.
FileSystemBridgeObject
When defining a custom bridge, you provide a FileSystemBridgeObject:
interface FileSystemBridgeObject<
TOptionsSchema extends z.ZodType = z.ZodNever,
TState extends Record<string, unknown> = Record<string, unknown>,
> {
/**
* Metadata about the file system bridge
*/
meta: FileSystemBridgeMetadata;
/**
* Zod schema for validating bridge options
*/
optionsSchema?: TOptionsSchema;
/**
* Optional state object for the file system bridge
*/
state?: TState;
/**
* Setup function that receives options and state
* and returns the filesystem operations implementation
*/
setup: FileSystemBridgeSetupFn<TOptionsSchema, TState>;
}Metadata
interface FileSystemBridgeMetadata {
name: string;
description: string;
}Setup Function
The setup function receives a context object and returns the operations:
type FileSystemBridgeSetupFn<
TOptionsSchema extends z.ZodType,
TState extends Record<string, unknown> = Record<string, unknown>,
> = (ctx: {
options: z.infer<TOptionsSchema>;
state: TState;
resolveSafePath: ResolveSafePathFn;
}) => FileSystemBridgeOperations;The resolveSafePath function helps prevent path traversal attacks by resolving paths relative to a base path safely.
defineFileSystemBridge
The defineFileSystemBridge function creates a bridge factory from a FileSystemBridgeObject:
function defineFileSystemBridge<
TOptionsSchema extends z.ZodType = z.ZodNever,
TState extends Record<string, unknown> = Record<string, unknown>,
>(
fsBridge: FileSystemBridgeObject<TOptionsSchema, TState>,
): FileSystemBridgeFactory<TOptionsSchema>Example:
const MyBridge = defineFileSystemBridge({
meta: {
name: "My Bridge",
description: "Custom bridge implementation"
},
optionsSchema: z.object({
basePath: z.string()
}),
setup({ options, resolveSafePath }) {
return {
async read(path) {
const resolved = resolveSafePath(options.basePath, path);
// ... implementation
},
// ... other operations
};
}
});
// Create an instance
const bridge = MyBridge({ basePath: "/path/to/base" });FSEntry Type
The listdir operation returns an array of FSEntry objects:
type FSEntry =
| {
type: "file";
name: string;
path: string;
}
| {
type: "directory";
name: string;
path: string;
children: FSEntry[];
};Example:
const entries = await bridge.listdir("directory");
for (const entry of entries) {
if (entry.type === "file") {
console.log(`File: ${entry.name} at ${entry.path}`);
} else {
console.log(`Directory: ${entry.name} with ${entry.children.length} children`);
}
}Error Handling
The bridge system defines several error types for different error scenarios. For complete documentation on error types and error handling patterns, see the Errors documentation.
Type Safety
The bridge system is fully type-safe. TypeScript will:
- Infer optional capabilities based on what operations are implemented
- Narrow types when using
hasCapabilityorassertCapability - Validate options using Zod schemas
- Provide autocomplete for all operations and hooks
Best Practices
-
Always use
resolveSafePath: When implementing custom bridges, use the providedresolveSafePathfunction to prevent path traversal attacks. -
Check capabilities before use: Use
hasCapabilityorassertCapabilitybefore calling optional operations. -
Handle errors gracefully: Bridge operations may throw errors. Always wrap calls in try-catch blocks or handle errors appropriately.
-
Use hooks for debugging: The hook system is excellent for monitoring bridge operations during development.
-
Validate options: Always provide an
optionsSchemawhen defining bridges to ensure type-safe configuration.