diff --git a/index.d.ts b/index.d.ts index 0826a4a8..b209c1bd 100644 --- a/index.d.ts +++ b/index.d.ts @@ -16,487 +16,595 @@ import { ParseOptions, } from "graphql"; import { SocketStream } from "@fastify/websocket" -import { IncomingMessage, IncomingHttpHeaders, OutgoingHttpHeaders } from "http"; +import { IncomingMessage, OutgoingHttpHeaders } from "http"; import { Readable } from "stream"; -export interface PubSub { - subscribe(topics: string | string[]): Promise>; - publish(event: { topic: string; payload: TResult }, callback?: () => void): void; -} - -export interface MercuriusContext { - app: FastifyInstance; - reply: FastifyReply; - operationsCount?: number; - operationId?: number; - __currentQuery: string; - /** - * __Caution__: Only available if `subscriptions` are enabled - */ - pubsub: PubSub; -} - -export interface MercuriusError extends FastifyError { - errors?: TError[] -} - -export interface Loader< - TObj extends Record = any, - TParams extends Record = any, - TContext extends Record = MercuriusContext -> { - ( - queries: Array<{ - obj: TObj; - params: TParams; - }>, - context: TContext & { - reply: FastifyReply; - } - ): any; -} +type Mercurius = typeof mercurius -export interface MercuriusLoaders = MercuriusContext> { - [root: string]: { - [field: string]: - | Loader - | { - loader: Loader; - opts?: { - cache?: boolean; +declare namespace mercurius { + export interface PubSub { + subscribe(topics: string | string[]): Promise>; + publish(event: { topic: string; payload: TResult }, callback?: () => void): void; + } + + export interface MercuriusContext { + app: FastifyInstance; + reply: FastifyReply; + operationsCount?: number; + operationId?: number; + __currentQuery: string; + /** + * __Caution__: Only available if `subscriptions` are enabled + */ + pubsub: PubSub; + } + + export interface MercuriusError extends FastifyError { + errors?: TError[] + } + + export interface Loader< + TObj extends Record = any, + TParams extends Record = any, + TContext extends Record = MercuriusContext + > { + ( + queries: Array<{ + obj: TObj; + params: TParams; + }>, + context: TContext & { + reply: FastifyReply; + } + ): any; + } + + export interface MercuriusLoaders = MercuriusContext> { + [root: string]: { + [field: string]: + | Loader + | { + loader: Loader; + opts?: { + cache?: boolean; + }; }; - }; - }; -} - -// ------------------------ -// Request Lifecycle hooks -// ------------------------ - -/** - * `preParsing` is the first hook to be executed in the GraphQL request lifecycle. The next hook will be `preValidation`. - */ -export interface preParsingHookHandler { - ( - schema: GraphQLSchema, - source: string, - context: TContext, - ): Promise | void; -} - -/** - * `preValidation` is the second hook to be executed in the GraphQL request lifecycle. The previous hook was `preParsing`, the next hook will be `preExecution`. - */ -export interface preValidationHookHandler { - ( - schema: GraphQLSchema, - source: DocumentNode, - context: TContext, - ): Promise | void; -} - -/** - * `preExecution` is the third hook to be executed in the GraphQL request lifecycle. The previous hook was `preValidation`. - * Notice: in the `preExecution` hook, you can modify the following items by returning them in the hook definition: - * - `schema` - * - `document` - * - `errors` - * - `variables` - */ -export interface preExecutionHookHandler { - ( - schema: GraphQLSchema, - source: DocumentNode, - context: TContext, - variables: Record, - ): Promise | void> | PreExecutionHookResponse | void; -} - -/** - * `onResolution` is the fifth and final hook to be executed in the GraphQL request lifecycle. The previous hook was `preExecution`. - */ -export interface onResolutionHookHandler = Record, TContext = MercuriusContext> { - ( - execution: ExecutionResult, - context: TContext, - ): Promise | void; -} - -// ----------------------------- -// Subscription Lifecycle hooks -// ----------------------------- - -/** - * `preSubscriptionParsing` is the first hook to be executed in the GraphQL subscription lifecycle. The next hook will be `preSubscriptionExecution`. - * This hook will only be triggered when subscriptions are enabled. - */ -export interface preSubscriptionParsingHookHandler { - ( - schema: GraphQLSchema, - source: string, - context: TContext, - ): Promise | void; -} - -/** - * `preSubscriptionExecution` is the second hook to be executed in the GraphQL subscription lifecycle. The previous hook was `preSubscriptionParsing`. - * This hook will only be triggered when subscriptions are enabled. - */ -export interface preSubscriptionExecutionHookHandler { - ( - schema: GraphQLSchema, - source: DocumentNode, - context: TContext, - ): Promise | void; -} - -/** - * `onSubscriptionResolution` is the fourth hook to be executed in the GraphQL subscription lifecycle. The next hook will be `onSubscriptionEnd`. - * This hook will only be triggered when subscriptions are enabled. - */ -export interface onSubscriptionResolutionHookHandler = Record, TContext = MercuriusContext> { - ( - execution: ExecutionResult, - context: TContext, - ): Promise | void; -} - -/** - * `onSubscriptionEnd` is the fifth and final hook to be executed in the GraphQL subscription lifecycle. The previous hook was `onSubscriptionResolution`. - * This hook will only be triggered when subscriptions are enabled. - */ -export interface onSubscriptionEndHookHandler { - ( - context: TContext, - id: string | number, - ): Promise | void; -} - -// ---------------------------- -// Application Lifecycle hooks -// ---------------------------- - -export interface onExtendSchemaHandler { - ( - schema: GraphQLSchema, - context: TContext, - ): Promise | void; -} - -interface ServiceConfig { - setSchema: (schema: string) => ServiceConfig; -} - -export interface MercuriusPlugin { - < - TData extends Record = Record, - TVariables extends Record = Record - >( - source: string, - context?: Record, - variables?: TVariables, - operationName?: string - ): Promise>; - /** - * Replace existing schema - * @param schema graphql schema - */ - replaceSchema(schema: GraphQLSchema): void; - /** - * Extend existing schema - * @param schema graphql schema - */ - extendSchema(schema: string | Source | DocumentNode): Promise | void; - /** - * Define additional resolvers - * @param resolvers object with resolver functions - */ - defineResolvers = MercuriusContext>(resolvers: IResolvers): void; - /** - * Define data loaders - * @param loaders object with data loader functions - */ - defineLoaders = MercuriusContext>(loaders: MercuriusLoaders): void; - /** - * Transform the existing schema - */ - transformSchema: ( - schemaTransforms: - | ((schema: GraphQLSchema) => GraphQLSchema) - | Array<(schema: GraphQLSchema) => GraphQLSchema> - ) => void; - /** - * __Caution__: Only available if `subscriptions` are enabled - */ - pubsub: PubSub; - /** - * Managed GraphQL schema object for doing custom execution with. Will reflect changes made via `extendSchema`, `defineResolvers`, etc. - */ - schema: GraphQLSchema; - - // addHook: overloads - - // Request lifecycle addHooks - + }; + } + + // ------------------------ + // Request Lifecycle hooks + // ------------------------ + /** * `preParsing` is the first hook to be executed in the GraphQL request lifecycle. The next hook will be `preValidation`. */ - addHook(name: 'preParsing', hook: preParsingHookHandler): void; - + export interface preParsingHookHandler { + ( + schema: GraphQLSchema, + source: string, + context: TContext, + ): Promise | void; + } + /** * `preValidation` is the second hook to be executed in the GraphQL request lifecycle. The previous hook was `preParsing`, the next hook will be `preExecution`. */ - addHook(name: 'preValidation', hook: preValidationHookHandler): void; - + export interface preValidationHookHandler { + ( + schema: GraphQLSchema, + source: DocumentNode, + context: TContext, + ): Promise | void; + } + /** * `preExecution` is the third hook to be executed in the GraphQL request lifecycle. The previous hook was `preValidation`. * Notice: in the `preExecution` hook, you can modify the following items by returning them in the hook definition: + * - `schema` * - `document` * - `errors` + * - `variables` */ - addHook(name: 'preExecution', hook: preExecutionHookHandler): void; - + export interface preExecutionHookHandler { + ( + schema: GraphQLSchema, + source: DocumentNode, + context: TContext, + variables: Record, + ): Promise | void> | PreExecutionHookResponse | void; + } + /** * `onResolution` is the fifth and final hook to be executed in the GraphQL request lifecycle. The previous hook was `preExecution`. */ - addHook = Record, TContext = MercuriusContext>(name: 'onResolution', hook: onResolutionHookHandler): void; - - // Subscription lifecycle addHooks - + export interface onResolutionHookHandler = Record, TContext = MercuriusContext> { + ( + execution: ExecutionResult, + context: TContext, + ): Promise | void; + } + + // ----------------------------- + // Subscription Lifecycle hooks + // ----------------------------- + /** * `preSubscriptionParsing` is the first hook to be executed in the GraphQL subscription lifecycle. The next hook will be `preSubscriptionExecution`. * This hook will only be triggered when subscriptions are enabled. */ - addHook(name: 'preSubscriptionParsing', hook: preSubscriptionParsingHookHandler): void; - + export interface preSubscriptionParsingHookHandler { + ( + schema: GraphQLSchema, + source: string, + context: TContext, + ): Promise | void; + } + /** * `preSubscriptionExecution` is the second hook to be executed in the GraphQL subscription lifecycle. The previous hook was `preSubscriptionParsing`. * This hook will only be triggered when subscriptions are enabled. */ - addHook(name: 'preSubscriptionExecution', hook: preSubscriptionExecutionHookHandler): void; - + export interface preSubscriptionExecutionHookHandler { + ( + schema: GraphQLSchema, + source: DocumentNode, + context: TContext, + ): Promise | void; + } + /** - * `onSubscriptionResolution` is the fourth and final hook to be executed in the GraphQL subscription lifecycle. + * `onSubscriptionResolution` is the fourth hook to be executed in the GraphQL subscription lifecycle. The next hook will be `onSubscriptionEnd`. * This hook will only be triggered when subscriptions are enabled. */ - addHook = Record, TContext = MercuriusContext>(name: 'onSubscriptionResolution', hook: onSubscriptionResolutionHookHandler): void; - + export interface onSubscriptionResolutionHookHandler = Record, TContext = MercuriusContext> { + ( + execution: ExecutionResult, + context: TContext, + ): Promise | void; + } + /** * `onSubscriptionEnd` is the fifth and final hook to be executed in the GraphQL subscription lifecycle. The previous hook was `onSubscriptionResolution`. * This hook will only be triggered when subscriptions are enabled. */ - addHook(name: 'onSubscriptionEnd', hook: onSubscriptionEndHookHandler): void; - - // Application lifecycle addHooks - addHook(name: 'onExtendSchema', hook: onExtendSchemaHandler): void; -} - -interface QueryRequest { - operationName?: string; - query: string; - variables?: object; - extensions?: object; -} - -interface WsConnectionParams { - connectionInitPayload?: - | (() => Record | Promise>) - | Record; - reconnect?: boolean; - maxReconnectAttempts?: number; - connectionCallback?: () => void; - failedConnectionCallback?: (err: { message: string }) => void | Promise; - failedReconnectCallback?: () => void; - rewriteConnectionInitPayload?: (payload: Record | undefined, context: TContext) => Record; -} - -export interface MercuriusSchemaOptions { - /** - * The GraphQL schema. String schema will be parsed - */ - schema?: GraphQLSchema | string | string[]; - /** - * Object with resolver functions - */ - resolvers?: IResolvers; - /** - * Object with data loader functions - */ - loaders?: MercuriusLoaders; - /** - * Schema transformation function or an array of schema transformation functions - */ - schemaTransforms?: ((originalSchema: GraphQLSchema) => GraphQLSchema) | Array<(originalSchema: GraphQLSchema) => GraphQLSchema>; -} - -export interface MercuriusGraphiQLOptions { - /** - * Expose the graphiql app, default `true` - */ - enabled?: boolean; - /** - * The list of plugin to add to GraphiQL - */ - plugins?: Array<{ + export interface onSubscriptionEndHookHandler { + ( + context: TContext, + id: string | number, + ): Promise | void; + } + + // ---------------------------- + // Application Lifecycle hooks + // ---------------------------- + + export interface onExtendSchemaHandler { + ( + schema: GraphQLSchema, + context: TContext, + ): Promise | void; + } + + interface ServiceConfig { + setSchema: (schema: string) => ServiceConfig; + } + + export interface MercuriusPlugin { + < + TData extends Record = Record, + TVariables extends Record = Record + >( + source: string, + context?: Record, + variables?: TVariables, + operationName?: string + ): Promise>; /** - * The name of the plugin, it should be the same exported in the `umd` + * Replace existing schema + * @param schema graphql schema */ - name: string; + replaceSchema(schema: GraphQLSchema): void; /** - * The props to be passed to the plugin + * Extend existing schema + * @param schema graphql schema */ - props?: Object; + extendSchema(schema: string | Source | DocumentNode): Promise | void; /** - * The urls of the plugin, it's downloaded at runtime. (eg. https://unpkg.com/myplugin/....) + * Define additional resolvers + * @param resolvers object with resolver functions */ - umdUrl: string; + defineResolvers = MercuriusContext>(resolvers: IResolvers): void; /** - * A function name exported by the plugin to read/enrich the fetch response + * Define data loaders + * @param loaders object with data loader functions */ - fetcherWrapper?: string; - }> -} - -export interface GrapQLValidateOptions { - maxErrors?: number; -} - -export interface MercuriusGraphQLOptions { - parseOptions?: ParseOptions, - validateOptions?: GrapQLValidateOptions -} - -export interface MercuriusCommonOptions { - /** - * Serve GraphiQL on /graphiql if true or 'graphiql' and if routes is true - */ - graphiql?: boolean | 'graphiql' | MercuriusGraphiQLOptions; - ide?: boolean | 'graphiql' | MercuriusGraphiQLOptions; - /** - * The minimum number of execution a query needs to be executed before being jit'ed. - * @default 0 - disabled - */ - jit?: number; - /** - * A graphql endpoint is exposed at /graphql when true - * @default true - */ - routes?: boolean; - /** - * Define if the plugin can cache the responses. - * @default true - */ - cache?: boolean | number; - /** - * An endpoint for graphql if routes is true - * @default '/graphql' - */ - path?: string; - /** - * Change the route prefix of the graphql endpoint if set - */ - prefix?: string; - /** - * Add the empty Mutation definition if schema is not defined - * @default false - */ - defineMutation?: boolean; - /** - * Change the default error handler (Default: true). - * If a custom error handler is defined, it should send the standardized response format according to [GraphQL spec](https://graphql.org/learn/serving-over-http/#response) using `reply.send`. - * @default true - */ - errorHandler?: - | boolean - | ((error: MercuriusError, request: FastifyRequest, reply: FastifyReply) => void | Promise); - /** - * Change the default error formatter. - */ - errorFormatter?: ( - execution: ExecutionResult & Required>, - context: TContext - ) => { - statusCode: number; - response: ExecutionResult | FormattedExecutionResult; + defineLoaders = MercuriusContext>(loaders: MercuriusLoaders): void; + /** + * Transform the existing schema + */ + transformSchema: ( + schemaTransforms: + | ((schema: GraphQLSchema) => GraphQLSchema) + | Array<(schema: GraphQLSchema) => GraphQLSchema> + ) => void; + /** + * __Caution__: Only available if `subscriptions` are enabled + */ + pubsub: PubSub; + /** + * Managed GraphQL schema object for doing custom execution with. Will reflect changes made via `extendSchema`, `defineResolvers`, etc. + */ + schema: GraphQLSchema; + + // addHook: overloads + + // Request lifecycle addHooks + + /** + * `preParsing` is the first hook to be executed in the GraphQL request lifecycle. The next hook will be `preValidation`. + */ + addHook(name: 'preParsing', hook: preParsingHookHandler): void; + + /** + * `preValidation` is the second hook to be executed in the GraphQL request lifecycle. The previous hook was `preParsing`, the next hook will be `preExecution`. + */ + addHook(name: 'preValidation', hook: preValidationHookHandler): void; + + /** + * `preExecution` is the third hook to be executed in the GraphQL request lifecycle. The previous hook was `preValidation`. + * Notice: in the `preExecution` hook, you can modify the following items by returning them in the hook definition: + * - `document` + * - `errors` + */ + addHook(name: 'preExecution', hook: preExecutionHookHandler): void; + + /** + * `onResolution` is the fifth and final hook to be executed in the GraphQL request lifecycle. The previous hook was `preExecution`. + */ + addHook = Record, TContext = MercuriusContext>(name: 'onResolution', hook: onResolutionHookHandler): void; + + // Subscription lifecycle addHooks + + /** + * `preSubscriptionParsing` is the first hook to be executed in the GraphQL subscription lifecycle. The next hook will be `preSubscriptionExecution`. + * This hook will only be triggered when subscriptions are enabled. + */ + addHook(name: 'preSubscriptionParsing', hook: preSubscriptionParsingHookHandler): void; + + /** + * `preSubscriptionExecution` is the second hook to be executed in the GraphQL subscription lifecycle. The previous hook was `preSubscriptionParsing`. + * This hook will only be triggered when subscriptions are enabled. + */ + addHook(name: 'preSubscriptionExecution', hook: preSubscriptionExecutionHookHandler): void; + + /** + * `onSubscriptionResolution` is the fourth and final hook to be executed in the GraphQL subscription lifecycle. + * This hook will only be triggered when subscriptions are enabled. + */ + addHook = Record, TContext = MercuriusContext>(name: 'onSubscriptionResolution', hook: onSubscriptionResolutionHookHandler): void; + + /** + * `onSubscriptionEnd` is the fifth and final hook to be executed in the GraphQL subscription lifecycle. The previous hook was `onSubscriptionResolution`. + * This hook will only be triggered when subscriptions are enabled. + */ + addHook(name: 'onSubscriptionEnd', hook: onSubscriptionEndHookHandler): void; + + // Application lifecycle addHooks + addHook(name: 'onExtendSchema', hook: onExtendSchemaHandler): void; + } + + interface QueryRequest { + operationName?: string; + query: string; + variables?: object; + extensions?: object; + } + + interface WsConnectionParams { + connectionInitPayload?: + | (() => Record | Promise>) + | Record; + reconnect?: boolean; + maxReconnectAttempts?: number; + connectionCallback?: () => void; + failedConnectionCallback?: (err: { message: string }) => void | Promise; + failedReconnectCallback?: () => void; + rewriteConnectionInitPayload?: (payload: Record | undefined, context: TContext) => Record; + } + + export interface MercuriusSchemaOptions { + /** + * The GraphQL schema. String schema will be parsed + */ + schema?: GraphQLSchema | string | string[]; + /** + * Object with resolver functions + */ + resolvers?: IResolvers; + /** + * Object with data loader functions + */ + loaders?: MercuriusLoaders; + /** + * Schema transformation function or an array of schema transformation functions + */ + schemaTransforms?: ((originalSchema: GraphQLSchema) => GraphQLSchema) | Array<(originalSchema: GraphQLSchema) => GraphQLSchema>; + } + + export interface MercuriusGraphiQLOptions { + /** + * Expose the graphiql app, default `true` + */ + enabled?: boolean; + /** + * The list of plugin to add to GraphiQL + */ + plugins?: Array<{ + /** + * The name of the plugin, it should be the same exported in the `umd` + */ + name: string; + /** + * The props to be passed to the plugin + */ + props?: Object; + /** + * The urls of the plugin, it's downloaded at runtime. (eg. https://unpkg.com/myplugin/....) + */ + umdUrl: string; + /** + * A function name exported by the plugin to read/enrich the fetch response + */ + fetcherWrapper?: string; + }> + } + + export interface GrapQLValidateOptions { + maxErrors?: number; + } + + export interface MercuriusGraphQLOptions { + parseOptions?: ParseOptions, + validateOptions?: GrapQLValidateOptions + } + + export interface MercuriusCommonOptions { + /** + * Serve GraphiQL on /graphiql if true or 'graphiql' and if routes is true + */ + graphiql?: boolean | 'graphiql' | MercuriusGraphiQLOptions; + ide?: boolean | 'graphiql' | MercuriusGraphiQLOptions; + /** + * The minimum number of execution a query needs to be executed before being jit'ed. + * @default 0 - disabled + */ + jit?: number; + /** + * A graphql endpoint is exposed at /graphql when true + * @default true + */ + routes?: boolean; + /** + * Define if the plugin can cache the responses. + * @default true + */ + cache?: boolean | number; + /** + * An endpoint for graphql if routes is true + * @default '/graphql' + */ + path?: string; + /** + * Change the route prefix of the graphql endpoint if set + */ + prefix?: string; + /** + * Add the empty Mutation definition if schema is not defined + * @default false + */ + defineMutation?: boolean; + /** + * Change the default error handler (Default: true). + * If a custom error handler is defined, it should send the standardized response format according to [GraphQL spec](https://graphql.org/learn/serving-over-http/#response) using `reply.send`. + * @default true + */ + errorHandler?: + | boolean + | ((error: MercuriusError, request: FastifyRequest, reply: FastifyReply) => void | Promise); + /** + * Change the default error formatter. + */ + errorFormatter?: ( + execution: ExecutionResult & Required>, + context: TContext + ) => { + statusCode: number; + response: ExecutionResult | FormattedExecutionResult; + }; + /** + * The maximum depth allowed for a single query. + */ + queryDepth?: number; + /** + * GraphQL function optional option overrides + */ + graphql?: MercuriusGraphQLOptions, + context?: ( + request: FastifyRequest, + reply: FastifyReply + ) => Promise> | Record; + /** + * Optional additional validation rules. + * Queries must satisfy these rules in addition to those defined by the GraphQL specification. + */ + validationRules?: ValidationRules; + /** + * Enable subscription support when options are provided. [`emitter`](https://github.com/mcollina/mqemitter) property is required when subscriptions is an object. (Default false) + */ + subscription?: + | boolean + | { + emitter?: object; + pubsub?: any; // FIXME: Technically this should be the PubSub type. But PubSub is now typed as SubscriptionContext. + verifyClient?: ( + info: { origin: string; secure: boolean; req: IncomingMessage }, + next: ( + result: boolean, + code?: number, + message?: string, + headers?: OutgoingHttpHeaders + ) => void + ) => void; + context?: ( + connection: SocketStream, + request: FastifyRequest + ) => Record | Promise>; + onConnect?: (data: { + type: 'connection_init'; + payload: any; + }) => any; + onDisconnect?: (context: MercuriusContext) => void | Promise; + keepAlive?: number, + fullWsTransport?: boolean, + }; + /** + * Persisted queries, overrides persistedQueryProvider. + */ + persistedQueries?: Record; + /** + * Only allow persisted queries. Required persistedQueries, overrides persistedQueryProvider. + */ + onlyPersisted?: boolean; + /** + * Settings for enabling persisted queries. + */ + persistedQueryProvider?: PersistedQueryProvider; + + /** + * Enable support for batched queries (POST requests only). + * Batched query support allows clients to send an array of queries and + * receive an array of responses within a single request. + */ + allowBatchedQueries?: boolean; + } + + export type MercuriusOptions = MercuriusCommonOptions & (MercuriusSchemaOptions) + + export interface IResolvers { + [key: string]: + | (() => any) + | IResolverObject + | IResolverOptions + | GraphQLScalarType + | IEnumResolver + | undefined; + } + + export type IResolverObject = { + [key: string]: + | IFieldResolver + | IResolverOptions + | IResolverObject + | undefined; + } + + export interface IResolverOptions { + fragment?: string; + resolve?: IFieldResolver; + subscribe?: IFieldResolver; + } + + type IEnumResolver = { + [key: string]: string | number; }; - /** - * The maximum depth allowed for a single query. - */ - queryDepth?: number; - /** - * GraphQL function optional option overrides - */ - graphql?: MercuriusGraphQLOptions, - context?: ( - request: FastifyRequest, - reply: FastifyReply - ) => Promise> | Record; - /** - * Optional additional validation rules. - * Queries must satisfy these rules in addition to those defined by the GraphQL specification. - */ - validationRules?: ValidationRules; - /** - * Enable subscription support when options are provided. [`emitter`](https://github.com/mcollina/mqemitter) property is required when subscriptions is an object. (Default false) - */ - subscription?: - | boolean - | { - emitter?: object; - pubsub?: any; // FIXME: Technically this should be the PubSub type. But PubSub is now typed as SubscriptionContext. - verifyClient?: ( - info: { origin: string; secure: boolean; req: IncomingMessage }, - next: ( - result: boolean, - code?: number, - message?: string, - headers?: OutgoingHttpHeaders - ) => void - ) => void; - context?: ( - connection: SocketStream, - request: FastifyRequest - ) => Record | Promise>; - onConnect?: (data: { - type: 'connection_init'; - payload: any; - }) => any; - onDisconnect?: (context: MercuriusContext) => void | Promise; - keepAlive?: number, - fullWsTransport?: boolean, - }; - /** - * Persisted queries, overrides persistedQueryProvider. - */ - persistedQueries?: Record; - /** - * Only allow persisted queries. Required persistedQueries, overrides persistedQueryProvider. - */ - onlyPersisted?: boolean; - /** - * Settings for enabling persisted queries. - */ - persistedQueryProvider?: mercurius.PersistedQueryProvider; - - /** - * Enable support for batched queries (POST requests only). - * Batched query support allows clients to send an array of queries and - * receive an array of responses within a single request. - */ - allowBatchedQueries?: boolean; -} - -export type MercuriusOptions = MercuriusCommonOptions & (MercuriusSchemaOptions) - -declare function mercurius - ( - instance: FastifyInstance, - opts: MercuriusOptions - ): void; - + + export interface IFieldResolver> { + ( + source: TSource, + args: TArgs, + context: TContext, + info: GraphQLResolveInfo & { + mergeInfo?: MergeInfo; + } + ): any; + } + + type MergeInfo = { + delegate: ( + type: "query" | "mutation" | "subscription", + fieldName: string, + args: { + [key: string]: any; + }, + context: { + [key: string]: any; + }, + info: GraphQLResolveInfo, + transforms?: Array + ) => any; + delegateToSchema(options: IDelegateToSchemaOptions): any; + fragments: Array<{ + field: string; + fragment: string; + }>; + }; + + type Transform = { + transformSchema?: (schema: GraphQLSchema) => GraphQLSchema; + transformRequest?: (originalRequest: Request) => Request; + transformResult?: (result: Result) => Result; + }; + + interface IDelegateToSchemaOptions< + TContext = { + [key: string]: any; + } + > { + schema: GraphQLSchema; + operation: Operation; + fieldName: string; + args?: { + [key: string]: any; + }; + context: TContext; + info: IGraphQLToolsResolveInfo; + transforms?: Array; + skipValidation?: boolean; + } + + type Operation = "query" | "mutation" | "subscription"; + + type Result = ExecutionResult & { + extensions?: Record; + }; + + interface IGraphQLToolsResolveInfo extends GraphQLResolveInfo { + mergeInfo?: MergeInfo; + } + + type Request = { + document: DocumentNode; + variables: Record; + extensions?: Record; + }; + + type ValidationRules = + | ValidationRule[] + | ((params: { + source: string; + variables?: Record; + operationName?: string; + }) => ValidationRule[]); + + export interface PreExecutionHookResponse { + schema?: GraphQLSchema + document?: DocumentNode + errors?: TError[], + variables?: Record, + } -declare namespace mercurius { - interface PersistedQueryProvider { + export interface PersistedQueryProvider { /** * Return true if a given request matches the desired persisted query format. */ @@ -530,12 +638,12 @@ declare namespace mercurius { /** * @deprecated Use `PersistedQueryProvider` */ - interface PeristedQueryProvider extends PersistedQueryProvider {} + export interface PeristedQueryProvider extends PersistedQueryProvider {} /** * Extended errors for adding additional information in error responses */ - class ErrorWithProps extends Error { + export class ErrorWithProps extends Error { constructor(message: string, extensions?: object, statusCode?: number); /** * Custom additional properties of this error @@ -547,7 +655,7 @@ declare namespace mercurius { /** * Default options for persisted queries. */ - const persistedQueryDefaults: { + export const persistedQueryDefaults: { prepared: (persistedQueries: object) => PersistedQueryProvider; preparedOnly: (persistedQueries: object) => PersistedQueryProvider; automatic: (maxSize?: number) => PersistedQueryProvider; @@ -556,7 +664,7 @@ declare namespace mercurius { /** * Default error formatter. */ - const defaultErrorFormatter: ( + export const defaultErrorFormatter: ( execution: ExecutionResult & Required>, context: MercuriusContext ) => { statusCode: number; response: FormattedExecutionResult }; @@ -564,7 +672,7 @@ declare namespace mercurius { /** * Subscriptions with filter functionality */ - const withFilter: < + export const withFilter: < TPayload = any, TSource = any, TContext = MercuriusContext, @@ -587,16 +695,22 @@ declare namespace mercurius { mergeInfo?: MergeInfo } ) => AsyncGenerator -} -export default mercurius; + // named export + // import { mercurius } from 'mercurius' + // const { mercurius } = require('mercurius') + export const mercurius: Mercurius + // default export + // import mercurius from 'mercurius' + export { mercurius as default } +} declare module "fastify" { interface FastifyInstance { /** * GraphQL plugin */ - graphql: MercuriusPlugin; + graphql: mercurius.MercuriusPlugin; } interface FastifyReply { @@ -618,115 +732,19 @@ declare module "fastify" { } } -export interface IResolvers { - [key: string]: - | (() => any) - | IResolverObject - | IResolverOptions - | GraphQLScalarType - | IEnumResolver - | undefined; -} - -export type IResolverObject = { - [key: string]: - | IFieldResolver - | IResolverOptions - | IResolverObject - | undefined; -} - -export interface IResolverOptions { - fragment?: string; - resolve?: IFieldResolver; - subscribe?: IFieldResolver; -} - -type IEnumResolver = { - [key: string]: string | number; -}; - -export interface IFieldResolver> { +/** + * Mercurius GraphQL adapter function for a Fastify server instance. + * + * @param instance Fastify server instance + * @param opts Mercurius options + */ +declare function mercurius ( - source: TSource, - args: TArgs, - context: TContext, - info: GraphQLResolveInfo & { - mergeInfo?: MergeInfo; - } - ): any; -} - -type MergeInfo = { - delegate: ( - type: "query" | "mutation" | "subscription", - fieldName: string, - args: { - [key: string]: any; - }, - context: { - [key: string]: any; - }, - info: GraphQLResolveInfo, - transforms?: Array - ) => any; - delegateToSchema(options: IDelegateToSchemaOptions): any; - fragments: Array<{ - field: string; - fragment: string; - }>; -}; - -type Transform = { - transformSchema?: (schema: GraphQLSchema) => GraphQLSchema; - transformRequest?: (originalRequest: Request) => Request; - transformResult?: (result: Result) => Result; -}; - -interface IDelegateToSchemaOptions< - TContext = { - [key: string]: any; - } -> { - schema: GraphQLSchema; - operation: Operation; - fieldName: string; - args?: { - [key: string]: any; - }; - context: TContext; - info: IGraphQLToolsResolveInfo; - transforms?: Array; - skipValidation?: boolean; -} - -type Operation = "query" | "mutation" | "subscription"; - -type Result = ExecutionResult & { - extensions?: Record; -}; - -interface IGraphQLToolsResolveInfo extends GraphQLResolveInfo { - mergeInfo?: MergeInfo; -} - -type Request = { - document: DocumentNode; - variables: Record; - extensions?: Record; -}; + instance: FastifyInstance, + opts: mercurius.MercuriusOptions + ): void; -type ValidationRules = - | ValidationRule[] - | ((params: { - source: string; - variables?: Record; - operationName?: string; - }) => ValidationRule[]); -export interface PreExecutionHookResponse { - schema?: GraphQLSchema - document?: DocumentNode - errors?: TError[], - variables?: Record, -} +// CJS export +// const mercurius = require('mercurius') +export = mercurius; diff --git a/index.js b/index.js index 00ea743c..e1b89de0 100644 --- a/index.js +++ b/index.js @@ -66,7 +66,7 @@ function buildCache (opts) { return LRU(1024) } -const plugin = fp(async function (app, opts) { +const mercurius = fp(async function (app, opts) { const lru = buildCache(opts) const lruErrors = buildCache(opts) @@ -584,9 +584,22 @@ const plugin = fp(async function (app, opts) { fastify: '4.x' }) -plugin.ErrorWithProps = ErrorWithProps -plugin.defaultErrorFormatter = defaultErrorFormatter -plugin.persistedQueryDefaults = persistedQueryDefaults -plugin.withFilter = withFilter - -module.exports = plugin +mercurius.ErrorWithProps = ErrorWithProps +mercurius.defaultErrorFormatter = defaultErrorFormatter +mercurius.persistedQueryDefaults = persistedQueryDefaults +mercurius.withFilter = withFilter + +/** + * These export configurations enable JS and TS developers + * to consume mercurius in whatever way best suits their needs. + * Some examples of supported import syntax includes: + * - `const mercurius = require('mercurius')` + * - `const { mercurius } = require('mercurius')` + * - `import * as mercurius from 'mercurius'` + * - `import { mercurius, TS_definition } from 'mercurius'` + * - `import mercurius from 'mercurius'` + * - `import mercurius, { TS_definition } from 'mercurius'` + */ +module.exports = mercurius +module.exports.mercurius = mercurius +module.exports.default = mercurius diff --git a/test/types/index.ts b/test/types/index.ts index f81bd1c2..341a9ea0 100644 --- a/test/types/index.ts +++ b/test/types/index.ts @@ -6,7 +6,13 @@ import Fastify, { FastifyRequest } from 'fastify' // eslint-disable-next-line no-unused-vars import { Readable } from 'stream' // eslint-disable-next-line no-unused-vars +import * as mercuriusNamespaceImport from '../..' import mercurius, { + mercurius as mercuriusNamedImport, + ErrorWithProps, + defaultErrorFormatter, + persistedQueryDefaults, + withFilter, MercuriusOptions, IResolvers, MercuriusContext, @@ -61,6 +67,10 @@ declare module '../../' { } } +expectType(mercuriusNamedImport) +expectType(mercuriusNamespaceImport.default) +expectType(mercuriusNamespaceImport.mercurius) + app.register(mercurius, { schema, resolvers, @@ -635,3 +645,8 @@ expectAssignable>({ } } }) + +expectType(ErrorWithProps) +expectType(defaultErrorFormatter) +expectType(persistedQueryDefaults) +expectType(withFilter)