nfs
@noy-db/to-nfs·pnpm add @noy-db/to-nfsSame layout asto-file, plus NFS mount diagnostics.
| Shape | record |
| Atomic CAS | ✗ |
| Locality | remote |
| Speed | slow |
| Persistence | durable |
What it does
Uses the same JSON-file indexed layout as file for a pre-mounted
NFS path, with pre-flight checks that flag mount options known to silently break
versioning guarantees on stock NFS mounts: nolock (POSIX locks disabled →
silent concurrent-write corruption), stale attribute caching (noac), and wrong
filesystem type.
Notes
casAtomic: false— no CAS primitive; the pre-flight checks exist precisely because concurrent writers on a misconfigured mount can corrupt data silently.- Record shape, one file per record. Exposes a
diagnostics()method returning{ risks, info }for the mount. - Factory:
toNfs(options: NfsStoreOptions).
The mount is cross-checked against the address
From 0.6.0-pre.1 the store compares the server:/export it was told about
against the device string of the mount it actually opened — for an NFS mount the
device is server:/export, and the detector was already parsing it out of
/proc/mounts and discarding it. A pod claiming nas.local:/exports/vaults
resolved against a mountPath pointing somewhere else no longer writes to the
wrong export silently: diagnostics() adds a risk on mismatch.
onDeviceMismatch: 'warn' | 'error' on both NfsStoreOptions and
NfsDescriptorOptions picks what happens, and defaults to 'warn' — an
existing consumer whose descriptor is merely imprecise must not break on upgrade.
Set 'error' when the address is meant to be authoritative.
The check is gated on both address halves and a device from the detector, so a
detector that cannot report one (every pre-0.6.0-pre.1 implementation, including
an injected test double) never manufactures a mismatch. Only trailing slashes are
normalized; host case is left alone. This changes diagnostics() output — assert
against risks by predicate, not by position.
Store-locator descriptor
See store-locator descriptors for the general model.
kind: 'nfs', class: 'lan'. address is { server?, export? }, the
logical server:/export identity. It still does not select the mount —
binding.mountPath is what the store actually opens, and is required, since
where an export is mounted is device-local and never travels in a descriptor —
but from 0.6.0-pre.1 the factory forwards both halves and the store
cross-checks them against the real mount.
options is { onNolock?, onDeviceMismatch? }. binding.mountDetector? carries
the existing test-injection seam through unchanged.
import { nfsStoreDescriptor, registerNfsStore } from '@noy-db/to-nfs'
const descriptor = nfsStoreDescriptor({ server: 'nas.local', export: '/vaults' })
// later: locator.resolve(descriptor, { binding: { mountPath: '/mnt/nas' } })