# `guards/depth-and-complexity` — query-shape rejection _(no submodules)_ ## Purpose `depth-and-complexity` walks a parsed `DocumentNode` and computes two coarse static metrics — the maximum selection-set nesting depth and the total field-count cost. The engine consults both before handing the document to Apollo Server; queries that exceed `maxQueryDepth` or `maxQueryComplexity` are rejected with the corresponding `GRAPHQL_APOLLO.DEPTH_EXCEEDED` / `COMPLEXITY_EXCEEDED` codes. The walk follows fragment spreads through their definitions and includes inline-fragment subselections, so a clever query that hides depth or cost behind a deeply nested fragment cannot bypass the guards. The heuristic matches the Yoga sibling so the two engines reject the same query set under identical limits. ## Features - Depth counter increments per nested `selectionSet`, never on fragment spreads or inline fragments themselves (matches conventional depth-limiter implementations). - Complexity counter adds 1 per selected field, plus the recursive cost of its subselection, plus the expansion of fragment spreads. Missing fragment spreads contribute zero. - `assertDepthAndComplexity` evaluates depth first; the more localised failure wins so operators see the rule they triggered. - Pure-functional — no instance state, no `this`. Safe to call from any request lifecycle phase. ## Usage: Basic ```ts import { parse } from "graphql"; import { assertDepthAndComplexity } from "@suaveplan/api-graphql-apollo/guards"; const doc = parse("{ a { b { c } } }"); assertDepthAndComplexity(doc, { maxDepth: 10, maxComplexity: 1000 }); ``` ## Usage: Advanced Run the metrics in isolation to feed an OTel histogram before the engine even routes the document: ```ts import { parse } from "graphql"; import { maxQueryDepth, queryComplexity, } from "@suaveplan/api-graphql-apollo/guards"; const doc = parse(req.body.query); metrics.histogram("graphql.depth").record(maxQueryDepth(doc)); metrics.histogram("graphql.complexity").record(queryComplexity(doc)); ``` ## API Reference - `maxQueryDepth(doc: DocumentNode): number` - `queryComplexity(doc: DocumentNode): number` - `assertDepthAndComplexity(doc, { maxDepth, maxComplexity }): void` — throws `GraphqlApolloError` on first violation. ## Implementation Notes Fragment definitions are collected up-front into a `Map` so spread resolution is O(1). Inline fragments share the parent depth — they do not add a level. The complexity heuristic intentionally undercounts list multiplicity; production deployments wire a richer estimator via a host-supplied `costExtension` (out of scope for the foundation engine).