MemoryFileSystem.ts overview
Provides an in-memory implementation of Effect's FileSystem service.
The service uses @effect-vfs/core for filesystem state and exposes that
state through Effect's path-based FileSystem interface. It is intended for
tests, build tools, and programs that need filesystem behavior without host
filesystem I/O.
Since v0.1.0
constructors
bind
Creates a FileSystem.FileSystem service backed by an existing core volume.
Details
The binding creates its own root caller and file-descriptor table. It does not
add /tmp or otherwise modify the volume. Use this when an adapter and direct
core callers must share filesystem state. Bindings share namespace and content
changes, but keep independent caller state, descriptors, and file cursors.
The caller defaults to a privileged uid and gid of 0 with umask 0. Invalid
caller options fail with a VfsError whose code is InvalidArgument and whose field names the option.
Filesystem operations translate core failures to Effect PlatformError values.
Example
import * as NodeCrypto from "@effect/platform-node-shared/NodeCrypto"
import { VirtualFileSystem as Vfs } from "@effect-vfs/core"
import { MemoryFileSystem } from "@effect-vfs/memory"
import { Effect, FileSystem, Layer } from "effect"
const encoder = new TextEncoder()
// A volume seeded with a fixture, exposed through Effect's `FileSystem`.
const seeded = Layer.effect(
FileSystem.FileSystem,
Effect.gen(function* () {
const volume = yield* Vfs.fromFixture({
entries: [
{ kind: "directory", path: "/project" },
{
kind: "file",
path: "/project/package.json",
bytes: encoder.encode(`{"version":"1.2.3"}`)
}
]
})
return yield* MemoryFileSystem.bind(volume)
})
)
const program = Effect.gen(function* () {
const fs = yield* FileSystem.FileSystem
return yield* fs.readFileString("/project/package.json")
})
Effect.runPromise(program.pipe(Effect.provide(seeded), Effect.provide(NodeCrypto.layer))).then(console.log)
// {"version":"1.2.3"}See
makefor a service backed by a fresh volume with/tmp.
Signature
declare const bind: {
(options?: Vfs.RootCallerOptions): (volume: Vfs.Volume) => Effect.Effect<FileSystem.FileSystem, Vfs.VfsError>
(volume: Vfs.Volume, options?: Vfs.RootCallerOptions): Effect.Effect<FileSystem.FileSystem, Vfs.VfsError>
}Since v0.1.0
bindCaller
Creates a FileSystem service that borrows an existing caller.
Preserves the caller's root, working directory, credentials, and umask. The
binding neither closes the caller nor creates /tmp; file and watch resources
retain their own scoped lifetimes.
Example
import * as NodeCrypto from "@effect/platform-node-shared/NodeCrypto"
import { VirtualFileSystem as Vfs } from "@effect-vfs/core"
import { MemoryFileSystem } from "@effect-vfs/memory"
import { Effect } from "effect"
const program = Effect.gen(function* () {
const volume = yield* Vfs.make()
const owner = yield* volume.caller()
yield* owner.mkdir("/agent")
const caller = yield* owner.withRoot("/agent")
const fs = yield* MemoryFileSystem.bindCaller(caller)
yield* fs.writeFileString("/output.txt", "done")
return yield* fs.readFileString("/output.txt")
}).pipe(Effect.scoped)
Effect.runPromise(program.pipe(Effect.provide(NodeCrypto.layer))).then(console.log)
// doneSignature
declare const bindCaller: (caller: Vfs.Caller) => Effect.Effect<FileSystem.FileSystem>Since v0.9.0
make
Creates a FileSystem.FileSystem service backed by a fresh in-memory volume.
When to use
Use when you need the service value directly. The volume
starts with an empty /tmp directory and uses / as its working directory.
Example
import * as NodeCrypto from "@effect/platform-node-shared/NodeCrypto"
import { MemoryFileSystem } from "@effect-vfs/memory"
import { Effect } from "effect"
const program = Effect.gen(function* () {
const fs = yield* MemoryFileSystem.make
yield* fs.writeFileString("/tmp/greeting.txt", "hello")
return yield* fs.readFileString("/tmp/greeting.txt")
})
Effect.runPromise(program.pipe(Effect.provide(NodeCrypto.layer))).then(console.log)
// helloSee
layerfor a Layer,bindfor an existing volume.Crypto.Cryptofor the required secure random-byte service.
Signature
declare const make: Effect.Effect<FileSystem.FileSystem, never, Crypto.Crypto>Since v0.1.0
guards
isWatchOverflow
Identifies a watch stream failure caused by lost events. Open a new watch before rescanning its path, and repeat if the new watch also overflows.
Example
import { MemoryFileSystem } from "@effect-vfs/memory"
import * as PlatformError from "effect/PlatformError"
const error = PlatformError.systemError({
_tag: "Unknown",
module: "FileSystem",
method: "watch",
description: "WatchOverflow"
})
console.log(MemoryFileSystem.isWatchOverflow(error))
// trueSignature
declare const isWatchOverflow: (error: PlatformError.PlatformError) => booleanSince v0.4.0
layers
layer
Provides a FileSystem.FileSystem backed by a fresh in-memory volume.
When to use
Use when you need to replace the host filesystem in an Effect program.
Gotchas
Reusing this layer value within a single layer graph shares one volume through
layer memoization. Wrap it with Layer.fresh when each use needs separate
state. Separate graphs, such as one per test, already get separate volumes.
Provide Crypto.Crypto to build the underlying volume.
Example
import * as NodeCrypto from "@effect/platform-node-shared/NodeCrypto"
import { MemoryFileSystem } from "@effect-vfs/memory"
import { Effect, FileSystem } from "effect"
const writeManifest = Effect.gen(function* () {
const fs = yield* FileSystem.FileSystem
yield* fs.makeDirectory("/dist", { recursive: true })
yield* fs.writeFileString("/dist/manifest.json", `{"version":"1.2.3"}`)
return yield* fs.readFileString("/dist/manifest.json")
})
Effect.runPromise(writeManifest.pipe(Effect.provide(MemoryFileSystem.layer), Effect.provide(NodeCrypto.layer))).then(
console.log
)
// {"version":"1.2.3"}Example
import * as NodeCrypto from "@effect/platform-node-shared/NodeCrypto"
import { MemoryFileSystem } from "@effect-vfs/memory"
import { Effect, FileSystem, Layer } from "effect"
const write = Effect.gen(function* () {
const fs = yield* FileSystem.FileSystem
yield* fs.writeFileString("/shared.txt", "written")
})
const exists = Effect.gen(function* () {
const fs = yield* FileSystem.FileSystem
return yield* fs.exists("/shared.txt")
})
const program = Effect.gen(function* () {
// One layer value in one graph is memoized, so both effects share a volume.
const shared = yield* Effect.andThen(write, exists).pipe(Effect.provide(MemoryFileSystem.layer))
// `Layer.fresh` builds the layer again, giving each use its own volume.
const isolated = yield* Effect.andThen(
write.pipe(Effect.provide(Layer.fresh(MemoryFileSystem.layer))),
exists.pipe(Effect.provide(Layer.fresh(MemoryFileSystem.layer)))
)
return [shared, isolated]
})
Effect.runPromise(program.pipe(Effect.provide(NodeCrypto.layer))).then(console.log)
// [ true, false ]See
makefor the service directly,bindfor an existing volume.- The testing guide at
/guides/testing-with-an-isolated-filesystem.
Signature
declare const layer: Layer.Layer<FileSystem.FileSystem, never, Crypto.Crypto>Since v0.1.0
layerFromFixture
Provides a FileSystem.FileSystem backed by a fresh fixture volume.
Volume limits and caller options use the existing core types. Invalid fixtures
and options remain typed VfsError construction failures. Provide Crypto.Crypto
to build the volume. This layer adds no entries; include /tmp in the fixture
when temporary-file operations need it.
Separate builds get separate volumes. Reusing one layer value within a single
layer graph shares its volume. Use Layer.fresh for independent state in that
graph. Merge with Path.layer when a consumer also needs POSIX paths.
Example
import * as NodeCrypto from "@effect/platform-node-shared/NodeCrypto"
import { MemoryFileSystem } from "@effect-vfs/memory"
import { Effect, FileSystem, Layer, Path } from "effect"
const seeded = MemoryFileSystem.layerFromFixture({
entries: [{ kind: "file", path: "/greeting.txt", bytes: new TextEncoder().encode("hello") }]
})
const services = Layer.merge(seeded, Path.layer)
const program = Effect.gen(function* () {
const fs = yield* FileSystem.FileSystem
const path = yield* Path.Path
return yield* fs.readFileString(path.join("/", "greeting.txt"))
})
Effect.runPromise(program.pipe(Effect.provide(services), Effect.provide(NodeCrypto.layer))).then(console.log)
// helloSee
bindwhen direct core callers must share the volume.
Signature
declare const layerFromFixture: {
(
volumeOptions?: Vfs.VolumeOptions,
callerOptions?: Vfs.RootCallerOptions
): (fixture: Vfs.Fixture) => Layer.Layer<FileSystem.FileSystem, Vfs.VfsError, Crypto.Crypto>
(
fixture: Vfs.Fixture,
volumeOptions?: Vfs.VolumeOptions,
callerOptions?: Vfs.RootCallerOptions
): Layer.Layer<FileSystem.FileSystem, Vfs.VfsError, Crypto.Crypto>
}Since v0.8.0