import type { FastifyDynamicSwaggerOptions, SwaggerTransformObject } from '@fastify/swagger'; import type { onRequestHookHandler, preHandlerHookHandler } from 'fastify'; import { type ChainedApiDocumentationTransform } from './apiDocumentationTransform.js'; import { type DocumentationRouteMatcher } from './documentationRouteMatchers.js'; /** * The `openapi` section of the generated document: `info`, `servers`, * `security`, `tags` and anything else `@fastify/swagger` passes through. */ export type OpenApiDocumentDefinition = NonNullable; /** * Document-level transform, as `@fastify/swagger` calls it. This is where * `fastify-type-provider-zod`'s `jsonSchemaTransformObject` goes. */ export type ChainedApiDocumentationTransformObject = SwaggerTransformObject; export type ApiDocumentationHooks = { onRequest?: onRequestHookHandler; preHandler?: preHandlerHookHandler; }; export type ApiDocumentationPluginOptions = { /** * Document metadata (`info`, `servers`, `security`, `tags`) shared by both * documents. * * Required, and required to be present rather than `undefined`: * `@fastify/swagger` reads the presence of this key as the choice between * OpenAPI 3 and Swagger 2.0, and a Swagger 2.0 document cannot carry the * component references the transforms produce. Passing `{}` is enough to * select OpenAPI 3, though a document with no `info` is not valid OpenAPI. */ openapi: OpenApiDocumentDefinition; /** * Metadata for the internal document. It replaces `openapi` rather than * merging into it, so pass a whole document definition. * * Left out, the internal document reuses `openapi` with `(internal)` * appended to `info.title`, which is what tells the two references apart on * screen. */ internalOpenapi?: OpenApiDocumentDefinition; /** * Where the public API reference is served. The reference itself is at * `/`, the document at `/openapi.json` and * `/openapi.yaml`. * * @default '/documentation' */ publicRoutePrefix?: `/${string}`; /** * Where the internal API reference is served, with the same layout. * * @default '/documentation/internal' */ internalRoutePrefix?: `/${string}`; /** * Whether the internal reference is served at all. Off by default: the * internal document lists every endpoint the public one hides, along with * their schemas, and it carries no authentication of its own, so a service * turns it on once it has decided who may read it. `internalHooks` is * where that check goes. * * Left `false`, neither the internal document nor its routes are created, * so there is nothing to reach. * * @default false */ exposeInternalDocumentation?: boolean; /** * Routes kept out of *both* documents. * * Defaults to {@link DEFAULT_HIDDEN_ROUTES}. Passing a list replaces that * default rather than adding to it, so spread it in to keep it: * `hiddenRoutes: [...DEFAULT_HIDDEN_ROUTES, '/internal-metrics']`. * * Matchers are exact: a string here hides one url, never the routes * registered beneath it. Use a regular expression for a subtree. * * The reference's own routes are excluded on top of whatever this says. * Scalar registers them with `hide: true`, which is indistinguishable from * a contract-derived hide, so without the exclusion the internal document * would document the documentation. */ hiddenRoutes?: readonly DocumentationRouteMatcher[]; /** * Key stamped on internal operations in the internal document so readers * can tell them apart from the public ones. `false` turns it off. * * Must be an `x-` extension key, and must not be `x-internal` or * `x-scalar-ignore`: Scalar reads both as "leave this operation out of the * reference". * * @default 'x-internal-endpoint' */ internalMarkerKey?: string | false; /** * Route-level transform run underneath the audience decision, typically * `jsonSchemaTransform` from `fastify-type-provider-zod`. */ transform?: ChainedApiDocumentationTransform; /** * Document-level transform, typically `jsonSchemaTransformObject` from * `fastify-type-provider-zod`. */ transformObject?: ChainedApiDocumentationTransformObject; /** * Drop `components` entries no operation of the document references. * * Hiding an operation does not remove the schemas behind it: * `jsonSchemaTransformObject` writes the whole Zod registry into * `components.schemas` in one pass over the finished document, and * `app.addSchema` shared schemas land there too. Both UIs render those as * their models panel, so an internal-only response shape is not merely * present in the public JSON, it is on screen with its field names. * * Turn it off only for a document that deliberately publishes a schema * catalogue beyond what its operations reference. * * @default true */ pruneUnreferencedComponents?: boolean; /** * Remove response and request properties marked * `.meta({ visibility: 'internal' })` from the generated documents. * * The marker is audience-aware, matching the route-level split: internal * fields are dropped from the public document and kept in the internal one. * * @default true */ stripInternalFields?: boolean; /** * Drop top-level `tags` no operation of the document references. * * Services share one canonical tag catalogue and register the whole of it on * every document, so a document otherwise advertises tags for operations it * does not serve — and, in the internal-vs-public split, tags only its hidden * operations use. Both UIs render those as empty groups. * * Turn it off only for a document that deliberately advertises tags beyond * what its operations use. * * @default true */ pruneUnreferencedTags?: boolean; /** Passed through to `@scalar/fastify-api-reference` for both references. */ scalarConfiguration?: Record; /** Scalar configuration overrides for the internal reference only. */ internalScalarConfiguration?: Record; /** * Fastify hooks for the reference routes, both the public ones and, unless * `internalHooks` replaces them, the internal ones. */ hooks?: ApiDocumentationHooks; /** * Fastify hooks for the internal reference routes. This is where an * authentication or network check on the internal documentation goes. * * Merged over `hooks` per hook name, the way * `internalScalarConfiguration` merges over `scalarConfiguration`, so a * check that covers the public reference covers the internal one too * unless this replaces it. The internal document is a superset of the * public one, so inheriting is the safe direction. */ internalHooks?: ApiDocumentationHooks; /** Log level for the routes both references register. */ logLevel?: 'fatal' | 'error' | 'warn' | 'info' | 'debug' | 'trace' | 'silent'; /** * Fastify decorator holding the public document. * * @default 'swagger' */ documentDecorator?: string; /** * Fastify decorator holding the internal document. * * @default 'internalSwagger' */ internalDocumentDecorator?: string; }; export declare const apiDocumentationPlugin: import("fastify").FastifyPluginCallback;