# `directives` _(no submodules)_ ## Purpose Host-supplied GraphQL directive descriptors that engine adapters install at schema-build time. The contract layer ships two: `@auth(scope: String!)` for per-field authorisation and `@rateLimit(rpm: Int!)` for per-field rate limiting. Plugins reference them in SDL; engines wire the descriptor's `handler` into the resolver pipeline. Keeping the descriptors here (rather than in each engine adapter) means a plugin author writes one piece of SDL and gets the same enforcement semantics from every concrete engine. Engine adapters install the SDL via the directive `sdl` string and dispatch to the descriptor's `handler` from their resolver wrapper. ## Features - `authDirective` — checks `ctx.principal.scopes` against the declared scope and throws when missing. Locations: `FIELD_DEFINITION`. - `rateLimitDirective` — validates the `rpm` integer bound; the actual rate-limit accounting is the engine adapter's responsibility (the contract body asserts the argument shape). - `HOST_DIRECTIVES` — frozen map keyed by directive name for engine adapter consumption. ## Usage: Basic ```ts import { authDirective } from "@suaveplan/api-graphql/directives"; // SDL declaration: // directive @auth(scope: String!) on FIELD_DEFINITION // // Used in a plugin's typeDefs: // type Query { invoices: [Invoice!]! @auth(scope: "billing:read") } console.log(authDirective.sdl); ``` ## Usage: Advanced Engine adapters install every host directive in one pass: ```ts import { HOST_DIRECTIVES } from "@suaveplan/api-graphql/directives"; for (const directive of Object.values(HOST_DIRECTIVES)) { schemaBuilder.addDirective({ name: directive.name, sdl: directive.sdl, run: directive.handler, }); } ``` The `handler` is the contract-layer enforcement body. The `@auth` handler reads `ctx.principal.scopes` (the typed `readonly Scope[]`) and raises a plain `Error` when the required scope is absent — engine adapters wrap that in the engine's GraphQL error type before returning it on the wire. ## API Reference - `authDirective: DirectiveDescriptor<{ scope: string }>` — descriptor for `@auth`. - `rateLimitDirective: DirectiveDescriptor<{ rpm: number }>` — descriptor for `@rateLimit`. - `HOST_DIRECTIVES` — frozen `{ auth, rateLimit }` lookup. ## Implementation Notes The descriptors carry **contract bodies**, not full implementations. A production engine adapter wraps each resolver in a check that runs the handler before invoking the resolver. For `@rateLimit`, the engine adapter also wires the per-tenant counter; the contract-layer handler only enforces the `rpm > 0` invariant so a misconfigured directive surfaces early. Adding a new host directive: add a `DirectiveDescriptor`, append it to `HOST_DIRECTIVES`, and document the SDL in the package README. The `api-graphql-yoga` and `api-graphql-apollo` packages pick up new descriptors automatically through the frozen map.