Files
suaveplan/packages/api-stack/api/api-manifest/src/schema/identity.md
2026-05-27 23:29:53 +01:00

2.9 KiB

identitySchema

Purpose

Zod schema for the identity fields of a plugin manifest — the keys that uniquely identify a plugin in the registry and pin its semver. Validates name against npm package-name rules and version against strict SemVer 2.0.0. Optional $schema, displayName, description, license fields round out the metadata block.

Features

  • NPM-compatible name regex (@scope/pkg optional, lower-case, hyphen/underscore allowed)
  • Strict SemVer 2.0.0 validation including pre-release and build metadata
  • Optional $schema URL for JSON-Schema-aware editors
  • Optional displayName, description, license carry over to the admin UI

Basic Example

import { identitySchema } from "@suaveplan/api-manifest/schema";

identitySchema.parse({
  name: "@acme/billing-plugin",
  version: "1.4.2",
});

Advanced Example

import { identitySchema } from "@suaveplan/api-manifest/schema";

const result = identitySchema.safeParse({
  name: "acme/billing",
  version: "1.4",
});
if (!result.success) {
  for (const issue of result.error.issues) {
    console.error(issue.path, issue.message);
  }
}

API Reference

  • identitySchema: z.ZodObject<{ $schema?, name, version, displayName?, description?, license? }>
  • IdentityFields = z.infer<typeof identitySchema>

Implementation Notes

Name validation matches the npm registry's regex (lower-case, no leading dot/underscore, optional @scope/ prefix); 214-char max length matches npm's hard limit. Version regex implements SemVer 2.0.0 exactly — MAJOR.MINOR.PATCH[-PRE][+BUILD] — which is what satisfies() in the dep-graph module assumes; loose versions like 1.4 are rejected to keep the dep-graph comparator total. The identity block is merged into pluginManifestSchema rather than nested so the top-level keys match the JSON wire shape from design §3.

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.