UCD.js Docs

FS Backend

Architecture notes for @ucdjs/fs-backend

@ucdjs/fs-backend is the filesystem abstraction layer used across the storage stack.

Role

  • Defines the common backend contract used by ucd-store, lockfile, and test helpers.
  • Lets higher-level storage code work against one capability model instead of hard-coding Node or HTTP.
  • Centralizes path safety, feature detection, and backend-specific error normalization.

Mental Model

fs-backend has three layers:

  • defineBackend() turns a small backend definition into a full FileSystemBackend
  • built-in backends implement the actual operations
  • consumers branch on features instead of checking environment type directly

The important distinction is capability, not platform:

  • Node backend: mutable, directory-aware, sandboxed to a base path
  • HTTP backend: read-only, request-based, safe-path constrained to a base URL
  • custom backends: anything that can satisfy the contract

Method Flows

defineBackend()

HookableCorebackend.setup()optionsSchemadefineBackend()HookableCorebackend.setup()optionsSchemadefineBackend()alt[setup throws][setup succeeds]alt[invalid options][valid options]Callerfactory(options)safeParse(options)parse errorthrow invalid options errorparsed optionssetup(parsed options)errorBackendSetupErroroperationscreate hook registryinfer features from implemented operationswrap read/list/stat/write/... with hooksFileSystemBackendCaller

Node backend read and write flow

symlink guardnode:fs/promisesresolveSandboxedPath()Node backendsymlink guardnode:fs/promisesresolveSandboxedPath()Node backendalt[read][write]alt[traversal or symlink escape][safe path]Callerread(path) or write(path, data)resolveSafePath(basePath, path)assert real path stays inside sandboxPathTraversalErrorthrowreadFile(resolvedPath)content or ENOENT/EISDIRcontent or normalized backend errormkdir(parent, recursive)writeFile(resolvedPath, data)successCaller

HTTP backend read and list flow

BackendEntryListSchemafetch()resolveSafePath()HTTP backendBackendEntryListSchemafetch()resolveSafePath()HTTP backendalt[404][non-ok][ok]alt[invalid schema][recursive=false][recursive=true]alt[read][list]Callerread(path) or list(path)resolve request path under baseUrlGET file URLresponseBackendFileNotFoundgeneric remote read errorresponse text/bytesGET directory URL with Accept: application/jsonJSON responsevalidate entry listvalidation errorinvalid response errornormalized entriesrecursively list child directoriestree-shaped entriesCaller

Design Notes

  • Feature detection is inferred from the operations actually implemented, which keeps custom backends honest.
  • The Node backend applies both lexical path checks and real-path symlink checks.
  • The HTTP backend is intentionally read-only and uses headers to infer stat() information.
  • ucd-store should branch on features and isHttpBackend() rather than directly inspecting backend names.

Testing Use

The highest-value backend tests map to these buckets:

  • invalid factory options and setup failures
  • traversal protection and symlink escape rejection
  • Node error normalization for missing files vs wrong entry type
  • HTTP read, list, exists, and stat behavior with 404 and schema failures
  • feature inference and hook wrapping for custom backends

On this page