This guide provides practical examples for using @photostructure/fs-metadata.
import { getVolumeMountPoints } from "@photostructure/fs-metadata";
const mountPoints = await getVolumeMountPoints();
// Example output on Windows:
// [
// { mountPoint: 'C:\\', status: 'healthy' },
// { mountPoint: 'D:\\', status: 'healthy' },
// { mountPoint: 'E:\\', status: 'unavailable' }
// ]
// Example output on Linux:
// [
// { mountPoint: '/', status: 'healthy' },
// { mountPoint: '/home', status: 'healthy' },
// { mountPoint: '/mnt/nas', status: 'timeout' }
// ]
import { getVolumeMetadata } from "@photostructure/fs-metadata";
const metadata = await getVolumeMetadata("/");
// Example output:
// {
// mountPoint: '/',
// mountFrom: '/dev/sda1',
// fstype: 'ext4',
// size: 500107862016,
// used: 234567890123,
// available: 239539971893,
// status: 'healthy'
// }
import { getAllVolumeMetadata } from "@photostructure/fs-metadata";
// Get all volumes including system volumes
const allVolumes = await getAllVolumeMetadata({ includeSystemVolumes: true });
// Filter healthy volumes only
const healthyVolumes = allVolumes.filter((v) => v.status === "healthy");
// Calculate total storage
const totalStorage = healthyVolumes.reduce((sum, v) => sum + v.size, 0);
const totalUsed = healthyVolumes.reduce((sum, v) => sum + v.used, 0);
import { watchVolumeMountPoints } from "@photostructure/fs-metadata";
const watcher = watchVolumeMountPoints(
{ pollIntervalMs: 60_000 },
({ added, removed }) => {
for (const volume of added) console.log("mounted:", volume.mountPoint);
for (const volume of removed) console.log("unmounted:", volume.mountPoint);
},
);
console.log("initial mounts:", await watcher.ready);
watcher.on("error", (error) => console.warn("mount poll failed:", error));
// Later, when observation is no longer needed:
watcher.close();
The watcher observes state at the requested interval. A complete mount and
unmount between two polls may not be seen. Polls do not query volume capacity
or report accessibility health. On Linux, each newly observed local path gets
one directory probe so file bind-mount targets remain omitted; remote paths are
never probed. On Windows, the watcher sees logical drive roots, not
directory-mounted volume paths, and rejects a custom systemFsTypes filter
because shallow drive enumeration does not fetch filesystem types. Windows
snapshot and change records contain only mountPoint and the TypeScript-derived
isSystemVolume; fields that require touching the drive, including fstype and
isReadOnly, are omitted.
import { watchAvailableSpace } from "@photostructure/fs-metadata";
const watcher = watchAvailableSpace(
"/var/lib/photos",
{
minimumAvailableBytes: 20 * 1024 ** 3,
hysteresisBytes: 2 * 1024 ** 3,
pollIntervalMs: 60_000,
},
({ current }) => {
console.log(current.state, current.availableBytes);
},
);
console.log("initial space state:", await watcher.ready);
watcher.close();
Hysteresis means that after dropping below 20 GiB, the watcher reports recovery only after available space reaches 22 GiB. Errors and timeouts are not treated as zero available bytes.
import { isHidden } from "@photostructure/fs-metadata";
// Simple check
const hidden = await isHidden("/path/to/file.txt");
// Check with timeout
const hidden2 = await isHidden("/mnt/slow-network/file.txt", {
timeoutMs: 5000,
});
import { setHidden } from "@photostructure/fs-metadata";
// Hide a file
await setHidden("/path/to/file.txt", true);
// Unhide a file
await setHidden("/path/to/.hidden-file", false);
// Note: On POSIX systems (Linux/macOS), this will rename the file
// to add/remove a leading dot. On Windows, it sets the hidden attribute.
import { isHiddenRecursive } from "@photostructure/fs-metadata";
// Check if file or any parent directory is hidden
const hidden = await isHiddenRecursive("/home/user/.config/app/settings.json");
// Returns true because .config is hidden
// Works with Windows hidden attributes too
const hidden2 = await isHiddenRecursive("C:\\Users\\Public\\Desktop\\file.txt");
import { getHiddenMetadata } from "@photostructure/fs-metadata";
const metadata = await getHiddenMetadata("/path/to/file");
// Example output:
// {
// hidden: true,
// hiddenByAncestor: false,
// localSupport: 'native', // or 'posix' or 'none'
// exists: true
// }
const {
getVolumeMountPoints,
getVolumeMetadata,
isHidden,
setHidden,
} = require("@photostructure/fs-metadata");
async function main() {
const mountPoints = await getVolumeMountPoints();
console.log("Mount points:", mountPoints);
const metadata = await getVolumeMetadata(mountPoints[0].mountPoint);
console.log("Volume metadata:", metadata);
}
main().catch(console.error);
import {
getVolumeMetadata,
VolumeMountPointNotAccessibleError,
TimeoutError,
} from "@photostructure/fs-metadata";
try {
const metadata = await getVolumeMetadata("/mnt/network-drive", {
timeoutMs: 10000, // 10 second timeout
});
} catch (error) {
if (error instanceof TimeoutError) {
console.error("Operation timed out - network drive may be unreachable");
} else if (error instanceof VolumeMountPointNotAccessibleError) {
console.error("Volume is not accessible:", error.message);
} else {
console.error("Unexpected error:", error);
}
}
import {
getVolumeMountPoints,
getVolumeMetadata,
} from "@photostructure/fs-metadata";
// Network volumes may timeout or be unavailable
const mountPoints = await getVolumeMountPoints({ timeoutMs: 30000 });
// Filter out unhealthy volumes
const availableVolumes = mountPoints.filter((mp) => mp.status === "healthy");
// Get metadata with extended timeout for network drives
for (const mp of availableVolumes) {
try {
const metadata = await getVolumeMetadata(mp.mountPoint, {
timeoutMs: 20000, // 20 seconds for network volumes
});
console.log(
`${mp.mountPoint}: ${metadata.used} of ${metadata.size} bytes used`,
);
} catch (error) {
console.error(
`Failed to get metadata for ${mp.mountPoint}:`,
error.message,
);
}
}
import { getVolumeMountPoints } from "@photostructure/fs-metadata";
const volumes = await getVolumeMountPoints();
const driveLetters = volumes
.filter((v) => v.status === "healthy")
.map((v) => v.mountPoint)
.filter((mp) => /^[A-Z]:\\$/.test(mp))
.sort();
console.log("Available drives:", driveLetters);
// Output: ["C:\\", "D:\\", "E:\\"]
import { getAllVolumeMetadata } from "@photostructure/fs-metadata";
// Get only user-accessible volumes (excludes /proc, /sys, etc.)
const userVolumes = await getAllVolumeMetadata({
includeSystemVolumes: false,
});
// Custom filtering for specific filesystem types
const dataVolumes = userVolumes.filter((v) =>
["ext4", "xfs", "btrfs", "zfs"].includes(v.fstype),
);
import { getAllVolumeMetadata } from "@photostructure/fs-metadata";
const volumes = await getAllVolumeMetadata();
// Find APFS volumes
const apfsVolumes = volumes.filter((v) => v.fstype === "apfs");
// APFS containers share space, so available space might be the same
const containers = new Map();
for (const vol of apfsVolumes) {
const key = `${vol.size}-${vol.available}`;
if (!containers.has(key)) {
containers.set(key, []);
}
containers.get(key).push(vol.mountPoint);
}
// Enable debug logging before importing
process.env.NODE_DEBUG = "fs-meta";
import { getVolumeMetadata } from "@photostructure/fs-metadata";
// Now operations will log debug information to stderr
const metadata = await getVolumeMetadata("/");
// Debug output includes native code operations and timing information