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

2.8 KiB

errorsSchema

Purpose

Plugin-error status-map block. Maps PLUGIN.<DOMAIN>.<REASON> codes to HTTP status numbers and optional redaction paths. The host's error middleware consults this map when rendering error envelopes so plugins get a stable wire shape across boot, reload, and version upgrades.

Features

  • Code regex enforces PLUGIN.<UPPER>.<UPPER> template
  • Status codes restricted to 4xx and 5xx
  • Redact entries are dot-paths into the error's context payload
  • Defence-in-depth re-check at the validator layer surfaces every offender in one pass

Basic Example

import { errorsSchema } from "@suaveplan/api-manifest/schema";
errorsSchema.parse({ statusMap: { "PLUGIN.X.Y": 409 } });

Advanced Example

import { errorsSchema } from "@suaveplan/api-manifest/schema";
const errs = errorsSchema.parse({
  statusMap: {
    "PLUGIN.BILLING.SUBSCRIPTION_INACTIVE": 409,
    "PLUGIN.BILLING.STRIPE_API_FAILURE": 502,
  },
  redact: { "PLUGIN.BILLING.STRIPE_API_FAILURE": ["details.stripeKey"] },
});

API Reference

  • errorsSchema: z.ZodObject<{ statusMap?, redact? }>
  • errorCodeRegex, errorPathSegmentRegex — exported for cross-validator reuse.
  • Errors = z.infer<typeof errorsSchema>

Implementation Notes

errorCodeRegex is exported because the cross-field validator validateErrorStatusMapShape needs it too — splitting the regex would risk drift. Status numbers are validated to be integers in [400, 600) so the host can be sure it's safe to set them on the response status line. Redact paths use dot-separated identifiers; each segment is validated to be a valid JS identifier so nested-key lookups don't need to handle quoting.

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.