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

2.6 KiB

routesSchema

Purpose

Validates the declarative HTTP-routes block. Carries the route prefix plus an optional publicRoutes array — routes the host mounts without auth gating. The handler implementations live in the code half of the manifest (definePlugin({ routes })); this block only captures what the host needs to know declaratively to mount + introspect routes before loading code.

Features

  • prefix must start with / — Zod regex rejects unprefixed segments
  • publicRoutes entries must each start with /
  • Public routes are optional — most plugins authenticate every route
  • Inferred type is the same shape api-types exposes via RouteManifest

Basic Example

import { routesSchema } from "@suaveplan/api-manifest/schema";
routesSchema.parse({ prefix: "/billing" });

Advanced Example

import { routesSchema } from "@suaveplan/api-manifest/schema";
const routes = routesSchema.parse({
  prefix: "/billing",
  publicRoutes: ["/webhooks/stripe", "/health"],
});

API Reference

  • routesSchema: z.ZodObject<{ prefix, publicRoutes? }>
  • Routes = z.infer<typeof routesSchema>

Implementation Notes

Public-route paths are matched verbatim by the host's auth middleware; supporting glob patterns is intentionally deferred — the right place for that is the rate-limit / auth plugin, not the manifest. The prefix lives in the manifest rather than the code half so admin tooling can build the canonical URL map without loading any plugin code, which matters for sandboxed plugins where loading code is expensive.

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.