Files
2026-05-27 23:29:53 +01:00

2.9 KiB

manifest

(no submodules)

Purpose

Loads and validates plugin manifest files. Every Suaveplan installer plugin ships a manifest.json next to its entry module; this module exposes loadManifest(packagePath) and validateManifest(raw) which both surface schema violations as InstallerError(INSTALLER.PLUGIN_INVALID_MANIFEST) with the underlying Zod error attached as cause. The host calls loadManifest once per plugin during discovery; the result is cached on the DiscoveredPlugin record returned to callers.

Features

  • Backed by PluginManifestSchema (Zod) which enforces required fields: id, semver version, non-empty description, relative entry, engines: Record<string, string>, and assets: string[].
  • Optional peerInstallers: string[] for plugins that depend on other installers being present at runtime.
  • Distinguishes parse errors from schema errors but emits the same code (PLUGIN_INVALID_MANIFEST) so consumers don't have to handle three variants.
  • Pure validator — validateManifest(raw) is synchronous and side-effect free, so plugins can be validated before any disk I/O happens.

Basic Example

import { loadManifest } from "@suaveplan/installer";

const manifest = await loadManifest(
    "/path/to/node_modules/@suaveplan/install-agent-skills"
);
console.log(manifest.id, manifest.version);

Advanced Example

import {
    InstallerError,
    loadManifest,
    validateManifest,
} from "@suaveplan/installer";

async function safeLoad(path: string): Promise<unknown> {
    try {
        return await loadManifest(path);
    } catch (err) {
        if (
            err instanceof InstallerError &&
            err.code === "INSTALLER.PLUGIN_INVALID_MANIFEST"
        ) {
            console.warn(`skipping ${path}: bad manifest`);
            return null;
        }
        throw err;
    }
}

// Standalone validation — no disk I/O:
const valid = validateManifest({
    id: "demo",
    version: "0.1.0",
    description: "demo plugin",
    entry: "dist/index.js",
    engines: { node: ">=20" },
    assets: [],
});

API Reference

  • loadManifest(packagePath: string): Promise<PluginManifest> — reads <packagePath>/manifest.json, parses, and validates.
  • validateManifest(raw: unknown): PluginManifest — pure schema check.
  • PluginManifest — inferred type: { id, version, description, entry, engines, assets, peerInstallers? }.

Implementation Notes

The schema uses a strict semver regex (MAJOR.MINOR.PATCH with optional -prerelease+build) rather than z.string() so prerelease ergonomics are explicit. Failures from JSON.parse are caught and re-thrown as PLUGIN_INVALID_MANIFEST, not as raw SyntaxError, so callers always have a typed InstallerError to switch on. The Zod error issues are attached via context.issues for downstream error reporters that want field-level breakdowns without re-walking the cause chain.