Files
skills/docs/api-stack/api/api-manifest/src/schema/plugin-manifest.md
2026-05-29 08:20:56 +01:00

2.9 KiB

pluginManifestSchema and PluginManifest

Purpose

Composite Zod schema joining every per-key sub-schema into a single strict-mode object. The inferred PluginManifest type is structurally assignable to the api-types view of the same shape — AssignableToApiTypes is a compile-time fence that the type-system enforces during typecheck.

Features

  • Strict mode at the top level — unknown keys are rejected
  • Every documented field from design §3 is covered
  • Type-level fence to @suaveplan/api-types/manifest PluginManifest
  • Single import point for the entire manifest contract

Basic Example

import { pluginManifestSchema } from "@suaveplan/api-manifest/schema";
pluginManifestSchema.parse({ name: "x", version: "0.1.0", apiHost: "^1", isolation: "isolated", trustLevel: "first-party" });

Advanced Example

import { pluginManifestSchema, type PluginManifest, type AssignableToApiTypes } from "@suaveplan/api-manifest/schema";
import type { PluginManifest as ApiTypesPluginManifest } from "@suaveplan/api-types/manifest";

const _fence: AssignableToApiTypes = true;
function asApiTypes(m: PluginManifest): ApiTypesPluginManifest { return m; }

API Reference

  • pluginManifestSchema: z.ZodObject<...>.strict()
  • PluginManifest = z.infer<typeof pluginManifestSchema>
  • AssignableToApiTypes — compile-time fence type.

Implementation Notes

Strict mode at the top level is the host's drift-detection surface: any unknown top-level key (typoed displayname instead of displayName, or a future v2 field) is rejected with a MANIFEST.PARSE_FAILED error pointing at the offending path. Sub-objects use the Zod default (.passthrough() not applied, but no .strict() either) so future additive expansion inside a block remains possible without breaking existing consumers.

Cross-package Notes

This module is part of the @suaveplan/api-manifest Stage-1 contract package. It sits beneath every Stage-2 consumer (api-host, api-loader, the admin CLI, the IDE plugin) and above the foundation packages (@suaveplan/error, @suaveplan/types). The strict-mode top-level rejection of unknown keys means upgrading from manifest v1 to v2 is an OpenSpec-driven event: a new key landing in a consumer manifest is a parse failure rather than a silent drift, which is exactly the contract this stage exists to guarantee.

When the host reloads a plugin without a full restart, every manifest field this module validates is compared against the install-time manifestHash. A mismatch triggers a hard rollback via the RollbackJournal because the host's invariants (route mounts, registered capabilities, declared scopes) are derived from these exact bytes. Treat the schemas and validators here as the contract surface, not just an input filter — downstream code reads manifest.foo.bar and relies on those keys being present, well-typed, and non-undefined in the documented optionality regions.