@photostructure/fs-metadata
    Preparing search index...

    Examples

    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