Fileserver
Defined in: packages/core/src/kernel/types.ts:528
universal filesystem protocol — any object implementing these methods is a fileserver.
Implement this to mount arbitrary backing storage (memory, overlay, HTTP, proc, etc.) into the namespace. The kernel routes all I/O through this protocol.
Remarks
Section titled “Remarks”The kernel routes all I/O through fileservers via namespace resolution. A fileserver
never sees process-level fd numbers — open() returns an
opaque token that the kernel maps to a process fd. All data on the wire is Uint8Array.
Fileservers are composable: an overlay fileserver layers two fileservers for copy-on-write, union bind stacks multiple fileservers at one mount point. The protocol is small enough that fundamental capabilities (overlay, readonly, proxy) are just more fileservers — see readonlyFS for the simplest example.
Invariant
Section titled “Invariant”Paths arriving at any method are InnerPath — mount-relative, already
normalized by the kernel (no ., .., double slashes, or trailing /).
Invariant
Section titled “Invariant”The fd argument to read / write / close is always a token that this
same server returned from a prior open() — never a kernel fd number and
never a token from a different server.
Invariant
Section titled “Invariant”Errors are reported by throwing an FsError with the appropriate
FsErrorCode. Returning undefined or a sentinel value is not a
protocol-conformant way to signal failure.
Caveat
Section titled “Caveat”checkAccess is opt-in. When present, the kernel calls it INSTEAD of the
default mode-bit check; when absent, the kernel falls back to checking
mode / uid / gid from stat(). A server that implements neither has
no access control.
Example
Section titled “Example”import { memoryFS, type Fileserver } from '@fishnet/core'
// A minimal fileserver that wraps memoryFS() and counts method calls.// Demonstrates the "composability" property — a Fileserver can be any object// satisfying the protocol, not just one produced by a built-in factory.function countingFS(): Fileserver & { calls: ReadonlyMap<string, number> } { const inner = memoryFS() const calls = new Map<string, number>() const track = <T extends unknown[], R>(name: string, fn: (...args: T) => R) => (...args: T): R => { calls.set(name, (calls.get(name) ?? 0) + 1) return fn(...args) } return { type: 'counting', open: track('open', inner.open.bind(inner)), read: track('read', inner.read.bind(inner)), write: track('write', inner.write.bind(inner)), close: track('close', inner.close.bind(inner)), stat: track('stat', inner.stat.bind(inner)), readdir: track('readdir', inner.readdir.bind(inner)), mkdir: track('mkdir', inner.mkdir.bind(inner)), remove: track('remove', inner.remove.bind(inner)), rename: track('rename', inner.rename.bind(inner)), wstat: track('wstat', inner.wstat.bind(inner)), calls, }}Properties
Section titled “Properties”
readonlyoptionaltype?:string
Defined in: packages/core/src/kernel/types.ts:530
Optional human-readable type tag (e.g. ‘memory’, ‘overlay’, ‘proc’).
Methods
Section titled “Methods”checkAccess()?
Section titled “checkAccess()?”
optionalcheckAccess(path,flags,caller):Promise<void>
Defined in: packages/core/src/kernel/types.ts:642
Optional permission override. When present, kernel calls this INSTEAD of the default mode-bit check. Allows synthetic fileservers (procFS, devFS, etc.) to implement custom access control semantics.
Parameters
Section titled “Parameters”InnerPath
OpenFlags
caller
Section titled “caller”Returns
Section titled “Returns”Promise<void>
Invariant
Section titled “Invariant”Throw EACCES / EPERM to deny; resolve void to grant. The return
value of a successful check is ignored — only the throw path matters
Invariant
Section titled “Invariant”Called BEFORE open() on every access — the server must not rely on
open() to re-check permissions
close()
Section titled “close()”close(
fd):Promise<void>
Defined in: packages/core/src/kernel/types.ts:572
Close an open fd token.
Parameters
Section titled “Parameters”unknown
Returns
Section titled “Returns”Promise<void>
mkdir()
Section titled “mkdir()”mkdir(
path):Promise<void>
Defined in: packages/core/src/kernel/types.ts:602
Create a directory. Throws EEXIST if it already exists.
Parameters
Section titled “Parameters”InnerPath
Returns
Section titled “Returns”Promise<void>
Invariant
Section titled “Invariant”Parent directory must exist — the server does not perform mkdir -p;
throw ENOENT when the parent is missing
open()
Section titled “open()”open(
path,flags,pid?):Promise<unknown>
Defined in: packages/core/src/kernel/types.ts:544
Open a file or directory, returning an opaque fd token.
Parameters
Section titled “Parameters”InnerPath
OpenFlags
Returns
Section titled “Returns”Promise<unknown>
Invariant
Section titled “Invariant”path is mount-relative (InnerPath) — the server never sees
absolute paths or .. / . segments
Invariant
Section titled “Invariant”The returned token is opaque to the kernel; it MUST round-trip through
this same server’s read / write / close
Invariant
Section titled “Invariant”Throws ENOENT when the path does not exist and flags.create is not
set — the kernel does not pre-check existence
Invariant
Section titled “Invariant”pid is informational only (for audit / permission scoping); the server
MUST NOT use it as a routing key or trust it for authorization
read()
Section titled “read()”read(
fd,offset,count):Promise<Uint8Array<ArrayBufferLike>>
Defined in: packages/core/src/kernel/types.ts:558
Read up to count bytes from an open fd at the given offset.
Parameters
Section titled “Parameters”unknown
offset
Section titled “offset”number
number
Returns
Section titled “Returns”Promise<Uint8Array<ArrayBufferLike>>
Invariant
Section titled “Invariant”offset is absolute within the file — the kernel tracks the
per-fd cursor and passes the resolved offset on each call; the server
is stateless with respect to position
Invariant
Section titled “Invariant”Return length ≤ count; a short read (including length 0) is how the
server signals EOF — it is NOT an error condition
Invariant
Section titled “Invariant”The returned Uint8Array may be a view into the server’s own backing
storage; callers MUST NOT mutate the buffer or retain it past the next
call on the same fd
readdir()
Section titled “readdir()”readdir(
path):Promise<DirEntry[]>
Defined in: packages/core/src/kernel/types.ts:594
List entries in a directory. Throws ENOTDIR if path is a file.
Parameters
Section titled “Parameters”InnerPath
Returns
Section titled “Returns”Promise<DirEntry[]>
Invariant
Section titled “Invariant”Entry names are basenames, not full paths — the caller joins them with
path when needed
Invariant
Section titled “Invariant”. and .. are NOT included; the kernel synthesizes parent / self
traversal from the namespace, not the server
remove()
Section titled “remove()”remove(
path):Promise<void>
Defined in: packages/core/src/kernel/types.ts:610
Remove a file or empty directory.
Parameters
Section titled “Parameters”InnerPath
Returns
Section titled “Returns”Promise<void>
Invariant
Section titled “Invariant”Throws ENOTEMPTY when removing a non-empty directory — recursive
removal is a caller-level concern, not a server responsibility
rename()
Section titled “rename()”rename(
oldPath,newPath):Promise<void>
Defined in: packages/core/src/kernel/types.ts:620
Rename/move a file or directory.
Parameters
Section titled “Parameters”oldPath
Section titled “oldPath”InnerPath
newPath
Section titled “newPath”InnerPath
Returns
Section titled “Returns”Promise<void>
Invariant
Section titled “Invariant”Both oldPath and newPath resolve to THIS server — cross-mount renames
are rejected by the kernel with EXDEV before reaching here
Invariant
Section titled “Invariant”Rename is atomic from the kernel’s perspective: either both paths are consistent on return, or the call throws and nothing changed
stat()
Section titled “stat()”stat(
path,opts?):Promise<Stat>
Defined in: packages/core/src/kernel/types.ts:584
Return metadata for a path. Throws ENOENT if not found.
When opts.nofollow is true, return the symlink node itself (lstat behavior).
Parameters
Section titled “Parameters”InnerPath
nofollow?
Section titled “nofollow?”boolean
Returns
Section titled “Returns”Promise<Stat>
Invariant
Section titled “Invariant”stat is how the kernel implements the default mode-bit access check —
servers that want to hide nodes from non-privileged callers should
implement checkAccess rather than lying in stat
Invariant
Section titled “Invariant”Stat.size is bytes for files, implementation-defined for directories
and streams (commonly 0); do not rely on it for stream-like nodes
write()
Section titled “write()”write(
fd,offset,data):Promise<number>
Defined in: packages/core/src/kernel/types.ts:569
Write data at the given offset, returning bytes written.
Parameters
Section titled “Parameters”unknown
offset
Section titled “offset”number
Uint8Array
Returns
Section titled “Returns”Promise<number>
Invariant
Section titled “Invariant”Return value is bytes actually written; a short write is legal and the
kernel will retry from offset + written — do not throw on partial writes
Invariant
Section titled “Invariant”The server MUST NOT retain data past the returned promise — the kernel
may reuse the buffer once the promise settles
Invariant
Section titled “Invariant”Throws EPERM on a read-only server rather than silently dropping data
wstat()
Section titled “wstat()”wstat(
path,changes):Promise<void>
Defined in: packages/core/src/kernel/types.ts:630
Update metadata fields (mode, uid, gid, mtime, size).
Parameters
Section titled “Parameters”InnerPath
changes
Section titled “changes”Partial<StatChanges>
Returns
Section titled “Returns”Promise<void>
Invariant
Section titled “Invariant”Only fields present in changes are modified — absent fields are
preserved; passing {} is a valid no-op
Invariant
Section titled “Invariant”size changes implement truncate / extend semantics on file content;
extending beyond current size zero-fills