Skip to content

SymlinkCapable

Defined in: packages/core/src/kernel/types.ts:1666

A fileserver that supports symbolic link creation, reading, and resolution.

Implement on a Fileserver to participate in cross-mount symlink resolution — the kernel delegates the walk so absolute targets and .. escapes can cross mount boundaries.

Fileservers that are NOT SymlinkCapable are treated as having no symlink semantics: readlink() fails with ENOSYS, stat(..., { nofollow: true }) behaves like plain stat, paths within them return verbatim.

resolve() is a pure walk invoked by the kernel BEFORE dispatching the actual op; it may escape this fileserver entirely (see WalkResult). open() / stat() etc. are only invoked with a 'node' result.

import type { SymlinkCapable } from '@fishnet/core'
const links = new Map<string, string>()
const ops: Pick<SymlinkCapable, 'symlink' | 'readlink'> = {
async symlink(target, path) { links.set(path, target) },
async readlink(path) {
const t = links.get(path); if (t === undefined) throw new Error('ENOENT'); return t
},
}

readlink(path): Promise<string>

Defined in: packages/core/src/kernel/types.ts:1682

Read the target of a symlink.

InnerPath

Promise<string>

Returns the raw stored target string — relative targets are NOT expanded; callers join relative targets against the symlink’s directory themselves


resolve(path, opts): Promise<WalkResult>

Defined in: packages/core/src/kernel/types.ts:1693

Resolve a path with symlink following.

InnerPath

ResolutionOpts

Promise<WalkResult>

Returns { kind: 'node' } when resolution stays within this server, or an escape variant when the walk crosses this server’s root — the kernel re-resolves escapes through the namespace

Must decrement opts.depthRemaining for each symlink traversed; depthConsumed on escapes tells the kernel how many steps to subtract from its own budget


symlink(target, path): Promise<void>

Defined in: packages/core/src/kernel/types.ts:1674

Create a symbolic link at path pointing to target.

string

InnerPath

Promise<void>

target is stored verbatim — the server does NOT resolve it at creation time. Target resolution happens on every traversal via the kernel’s walk loop