Files
skills/docs/devtools/tooling/installer/src/fs/installer-fs.md
2026-05-29 08:20:56 +01:00

2.5 KiB

installer-fs

Purpose

Re-exports the read-only InstallerFs interface from the types module and declares its mutating extension MutableInstallerFs. Plugins receive a read-only InstallerFs through the context — they can describe writes via FileOp[] but cannot perform them directly. The host uses MutableInstallerFs internally to materialise ops with rollback. Keeping the read/write split at the interface level is what makes --dry-run trivially correct: a dry-run never resolves the mutating subset.

Features

  • Single source of truth for filesystem capability boundaries inside the installer.
  • MutableInstallerFs extends InstallerFs with writeFile, deleteFile, mkdir, rename, and writeJson.
  • Both MemoryFs and DiskFs implement MutableInstallerFs, but only the read-only view is ever handed to plugin code.

Basic Example

import { MemoryFs, type InstallerFs } from "@suaveplan/installer";

async function describe(fs: InstallerFs): Promise<number> {
    const entries = await fs.listDir("/");
    return entries.length;
}

const fs = new MemoryFs({ seed: { "/a.txt": "hi" } });
await describe(fs);

Advanced Example

import {
    type MutableInstallerFs,
    MemoryFs,
} from "@suaveplan/installer";

async function backupThenWrite(
    fs: MutableInstallerFs,
    path: string,
    next: Uint8Array
): Promise<void> {
    if (await fs.exists(path)) {
        const prior = await fs.readFile(path);
        await fs.writeFile(`${path}.bak`, prior);
    }
    await fs.writeFile(path, next);
}

await backupThenWrite(new MemoryFs(), "/cfg.json", new Uint8Array([123, 125]));

API Reference

  • interface InstallerFs (re-export from types/installer.types.ts): exists, readFile, readJson, stat, listDir, pathOf.
  • interface MutableInstallerFs extends InstallerFs: writeFile(path, contents, mode?), deleteFile(path), mkdir(path), rename(from, to), writeJson(path, value).

Implementation Notes

MutableInstallerFs is exposed publicly through ./fs so authors who want to write a custom backing store (e.g. an S3-backed installer fs) have a single contract to satisfy. Implementations must honour any AbortSignal they were constructed with — both in-tree implementations call a shared ensureNotAborted(signal) helper at the start of every async operation. The interface deliberately has no chmod or chown operations: per-file mode is carried on the WriteOp itself, and ownership is left to the host filesystem.