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

2.5 KiB

graphqlSchema

Purpose

Optional GraphQL contribution block. When contributes is true, the host loads the SDL at types (path relative to the package root) and merges the resolvers exported from resolversFrom into the federated schema. The cross-field validator validateOpenApiRequiresGraphqlOrRoutes references this flag.

Features

  • contributes boolean discriminator
  • Optional types path to an SDL file
  • Optional resolversFrom path to a JS/TS module exporting resolvers
  • Composable with routes and openapi blocks

Basic Example

import { graphqlSchema } from "@suaveplan/api-manifest/schema";
graphqlSchema.parse({ contributes: false });

Advanced Example

import { graphqlSchema } from "@suaveplan/api-manifest/schema";
const gql = graphqlSchema.parse({
  contributes: true,
  types: "graphql/types.graphql",
  resolversFrom: "src/graphql.ts",
});

API Reference

  • graphqlSchema: z.ZodObject<{ contributes, types?, resolversFrom? }>
  • GraphqlBlock = z.infer<typeof graphqlSchema>

Implementation Notes

contributes: false is a legal state — it lets a plugin opt out of GraphQL while keeping the block present for tooling that wants a uniform shape. Paths are intentionally strings (not URLs or node:fs-resolved paths) because the host resolves them relative to the package root after install; baking resolution into the schema would couple it to a specific module-resolution strategy.

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.