@graphql-mesh/hmac-upstream-signature
Version: 
305 lines (295 loc) • 13.7 kB
TypeScript
import { Plugin, YogaInitialContext, Instrumentation as Instrumentation$2, GraphQLParams } from 'graphql-yoga';
import { ExecutionRequest, ExecutionResult, Executor, MaybePromise as MaybePromise$1, Maybe } from '@graphql-tools/utils';
import { GraphQLSchema, OperationTypeNode, GraphQLFieldResolver, GraphQLResolveInfo, GraphQLOutputType, GraphQLError, SelectionSetNode, FragmentDefinitionNode, FieldNode, ExecutionResult as ExecutionResult$1, SelectionNode } from 'graphql';
import { Logger, MeshFetch, MeshPubSub, KeyValueCache, OnFetchHook } from '@graphql-mesh/types';
import DataLoader from 'dataloader';
import { GraphQLResolveInfo as GraphQLResolveInfo$1, GraphQLOutputType as GraphQLOutputType$1 } from 'graphql/type';
import { MaybePromise } from '@whatwg-node/promise-helpers';
import { FetchInstrumentation } from '@graphql-mesh/utils';
interface TransportEntry<Options extends Record<string, any> = Record<string, any>> {
    kind: string;
    subgraph: string;
    location?: string;
    headers?: [string, string][];
    options?: Options;
}
type SchemaTransform<TContext = Record<any, string>> = (originalWrappingSchema: GraphQLSchema, subschemaConfig: SubschemaConfig<any, any, any, TContext>) => GraphQLSchema;
type RequestTransform<T = Record<string, any>, TContext = Record<any, string>> = (originalRequest: ExecutionRequest, delegationContext: DelegationContext<TContext>, transformationContext: T) => ExecutionRequest;
type ResultTransform<T = Record<string, any>, TContext = Record<any, string>> = (originalResult: ExecutionResult, delegationContext: DelegationContext<TContext>, transformationContext: T) => ExecutionResult;
interface Transform<T = any, TContext = Record<string, any>> {
    transformSchema?: SchemaTransform<TContext>;
    transformRequest?: RequestTransform<T, TContext>;
    transformResult?: ResultTransform<T, TContext>;
}
interface DelegationContext<TContext = Record<string, any>> {
    subschema: GraphQLSchema | SubschemaConfig<any, any, any, TContext>;
    subschemaConfig?: SubschemaConfig<any, any, any, TContext>;
    targetSchema: GraphQLSchema;
    operation: OperationTypeNode;
    fieldName: string;
    args?: Record<string, any>;
    context?: TContext;
    info?: GraphQLResolveInfo;
    returnType: GraphQLOutputType;
    onLocatedError?: (originalError: GraphQLError) => GraphQLError;
    rootValue?: any;
    transforms: Array<Transform<any, TContext>>;
    transformedSchema: GraphQLSchema;
    skipTypeMerging: boolean;
}
type DelegationPlanBuilder = (schema: GraphQLSchema, sourceSubschema: Subschema<any, any, any, any>, variableValues: Record<string, any>, fragments: Record<string, FragmentDefinitionNode>, fieldNodes: FieldNode[], context?: any, info?: GraphQLResolveInfo) => Array<Map<Subschema, SelectionSetNode>>;
interface ICreateProxyingResolverOptions<TContext = Record<string, any>> {
    subschemaConfig: SubschemaConfig<any, any, any, TContext>;
    operation?: OperationTypeNode;
    fieldName?: string;
}
type CreateProxyingResolverFn<TContext = Record<string, any>> = (options: ICreateProxyingResolverOptions<TContext>) => GraphQLFieldResolver<any, TContext>;
interface BatchingOptions<K = any, V = any, C = K> {
    extensionsReducer?: (mergedExtensions: Record<string, any>, request: ExecutionRequest) => Record<string, any>;
    dataLoaderOptions?: DataLoader.Options<K, V, C>;
}
interface SubschemaConfig<K = any, V = any, C = K, TContext = Record<string, any>> {
    name?: string;
    schema: GraphQLSchema;
    createProxyingResolver?: CreateProxyingResolverFn<TContext>;
    rootValue?: any;
    transforms?: Array<Transform<any, TContext>>;
    merge?: Record<string, MergedTypeConfig<any, any, TContext>>;
    executor?: Executor<TContext>;
    batch?: boolean;
    batchingOptions?: BatchingOptions<K, V, C>;
}
interface MergedTypeConfig<K = any, V = any, TContext = Record<string, any>> extends MergedTypeEntryPoint<K, V, TContext> {
    entryPoints?: Array<MergedTypeEntryPoint>;
    fields?: Record<string, MergedFieldConfig>;
    canonical?: boolean;
}
interface MergedTypeEntryPoint<K = any, V = any, TContext = Record<string, any>> extends MergedTypeResolverOptions<K, V> {
    selectionSet?: string;
    key?: (originalResult: any) => K | PromiseLike<K>;
    resolve?: MergedTypeResolver<TContext>;
}
interface MergedTypeResolverOptions<K = any, V = any> {
    fieldName?: string;
    args?: (originalResult: any) => Record<string, any>;
    argsFromKeys?: (keys: ReadonlyArray<K>) => Record<string, any>;
    valuesFromResults?: (results: any, keys: ReadonlyArray<K>) => Array<V>;
    dataLoaderOptions?: DataLoader.Options<K, V>;
}
interface MergedFieldConfig {
    selectionSet?: string;
    computed?: boolean;
    canonical?: boolean;
    provides?: SelectionSetNode;
}
type MergedTypeResolver<TContext = Record<string, any>> = (originalResult: any, context: TContext, info: GraphQLResolveInfo, subschema: Subschema<any, any, any, TContext>, selectionSet: SelectionSetNode, key: any | undefined, type: GraphQLOutputType) => any;
interface ISubschema<K = any, V = any, C = K, TContext = Record<string, any>> extends SubschemaConfig<K, V, C, TContext> {
    transformedSchema: GraphQLSchema;
}
declare class Subschema<K = any, V = any, C = K, TContext = Record<string, any>> implements ISubschema<K, V, C, TContext> {
    name?: string;
    schema: GraphQLSchema;
    executor?: Executor<TContext>;
    batch?: boolean;
    batchingOptions?: BatchingOptions<K, V, C>;
    createProxyingResolver?: CreateProxyingResolverFn<TContext>;
    transforms: Array<Transform<any, TContext>>;
    private _transformedSchema;
    merge?: Record<string, MergedTypeConfig<any, any, TContext>>;
    constructor(config: SubschemaConfig<K, V, C, TContext>);
    get transformedSchema(): GraphQLSchema;
    set transformedSchema(value: GraphQLSchema);
}
type Instrumentation$1 = {
    /**
     * Wrap each subgraph execution request. This can happen multiple time for the same graphql operation.
     */
    subgraphExecute?: (payload: {
        executionRequest: ExecutionRequest;
    }, wrapped: () => MaybePromise<void>) => MaybePromise<void>;
};
declare module 'graphql' {
    interface GraphQLResolveInfo {
        executionRequest?: ExecutionRequest;
    }
}
interface UnifiedGraphPlugin<TContext> {
    onSubgraphExecute?: OnSubgraphExecuteHook<TContext>;
    onDelegationPlan?: OnDelegationPlanHook<TContext>;
    onDelegationStageExecute?: OnDelegationStageExecuteHook<TContext>;
}
type OnSubgraphExecuteHook<TContext = any> = (payload: OnSubgraphExecutePayload<TContext>) => MaybePromise$1<Maybe<OnSubgraphExecuteDoneHook | void>>;
interface OnSubgraphExecutePayload<TContext> {
    subgraph: GraphQLSchema;
    subgraphName: string;
    transportEntry?: TransportEntry;
    executionRequest: ExecutionRequest<any, TContext>;
    setExecutionRequest(executionRequest: ExecutionRequest): void;
    executor: Executor;
    setExecutor(executor: Executor): void;
    requestId?: string;
    logger?: Logger;
}
interface OnSubgraphExecuteDonePayload {
    result: AsyncIterable<ExecutionResult$1> | ExecutionResult$1;
    setResult(result: AsyncIterable<ExecutionResult$1> | ExecutionResult$1): void;
}
type OnSubgraphExecuteDoneHook = (payload: OnSubgraphExecuteDonePayload) => MaybePromise$1<Maybe<OnSubgraphExecuteDoneResult | void>>;
type OnSubgraphExecuteDoneResultOnNext = (payload: OnSubgraphExecuteDoneOnNextPayload) => MaybePromise$1<void>;
interface OnSubgraphExecuteDoneOnNextPayload {
    result: ExecutionResult$1;
    setResult(result: ExecutionResult$1): void;
}
type OnSubgraphExecuteDoneResultOnEnd = () => MaybePromise$1<void>;
type OnSubgraphExecuteDoneResult = {
    onNext?: OnSubgraphExecuteDoneResultOnNext;
    onEnd?: OnSubgraphExecuteDoneResultOnEnd;
};
type OnDelegationPlanHook<TContext> = (payload: OnDelegationPlanHookPayload<TContext>) => Maybe<OnDelegationPlanDoneHook | void>;
interface OnDelegationPlanHookPayload<TContext> {
    supergraph: GraphQLSchema;
    subgraph: string;
    sourceSubschema: Subschema<any, any, any, TContext>;
    typeName: string;
    variables: Record<string, any>;
    fragments: Record<string, FragmentDefinitionNode>;
    fieldNodes: SelectionNode[];
    context: TContext;
    requestId?: string;
    logger?: Logger;
    info?: GraphQLResolveInfo$1;
    delegationPlanBuilder: DelegationPlanBuilder;
    setDelegationPlanBuilder(delegationPlanBuilder: DelegationPlanBuilder): void;
}
type OnDelegationPlanDoneHook = (payload: OnDelegationPlanDonePayload) => Maybe<void>;
interface OnDelegationPlanDonePayload {
    delegationPlan: ReturnType<DelegationPlanBuilder>;
    setDelegationPlan: (delegationPlan: ReturnType<DelegationPlanBuilder>) => void;
}
type OnDelegationStageExecuteHook<TContext> = (payload: OnDelegationStageExecutePayload<TContext>) => Maybe<OnDelegationStageExecuteDoneHook>;
interface OnDelegationStageExecutePayload<TContext> {
    object: any;
    context: TContext;
    info: GraphQLResolveInfo$1;
    subgraph: string;
    subschema: Subschema<any, any, any, TContext>;
    selectionSet: SelectionSetNode;
    key?: any;
    type: GraphQLOutputType$1;
    resolver: MergedTypeResolver<TContext>;
    setResolver: (resolver: MergedTypeResolver<TContext>) => void;
    typeName: string;
    requestId?: string;
    logger?: Logger;
}
type OnDelegationStageExecuteDoneHook = (payload: OnDelegationStageExecuteDonePayload) => void;
interface OnDelegationStageExecuteDonePayload {
    result: any;
    setResult: (result: any) => void;
}
interface GatewayConfigContext {
    /**
     * WHATWG compatible Fetch implementation.
     */
    fetch: MeshFetch;
    /**
     * The logger to use throught Mesh and it's plugins.
     */
    logger: Logger;
    /**
     * Current working directory.
     */
    cwd: string;
    /**
     * Event bus for pub/sub.
     */
    pubsub?: MeshPubSub;
    /**
     * Cache Storage
     */
    cache?: KeyValueCache;
}
interface GatewayContext extends GatewayConfigContext, YogaInitialContext {
    /**
     * Environment agnostic HTTP headers provided with the request.
     */
    headers: Record<string, string>;
    /**
     * Runtime context available within WebSocket connections.
     */
    connectionParams: Record<string, string>;
}
type GatewayPlugin<TPluginContext extends Record<string, any> = Record<string, any>, TContext extends Record<string, any> = Record<string, any>> = Plugin<Partial<TPluginContext> & GatewayContext & TContext> & UnifiedGraphPlugin<Partial<TPluginContext> & GatewayContext & TContext> & {
    onFetch?: OnFetchHook<Partial<TPluginContext> & GatewayContext & TContext>;
    onCacheGet?: OnCacheGetHook;
    onCacheSet?: OnCacheSetHook;
    onCacheDelete?: OnCacheDeleteHook;
    /**
     * An Instrumentation instance that will wrap each phases of the request pipeline.
     * This should be used primarily as an observability tool (for monitoring, tracing, etc...).
     *
     * Note: The wrapped functions in instrumentation should always be called. Use hooks to
     *       conditionally skip a phase.
     */
    instrumentation?: Instrumentation<TPluginContext & TContext & GatewayContext>;
};
type OnCacheGetHook = (payload: OnCacheGetHookEventPayload) => MaybePromise$1<OnCacheGetHookResult | void>;
interface OnCacheGetHookEventPayload {
    cache: KeyValueCache;
    key: string;
    ttl?: number;
}
interface OnCacheGetHookResult {
    onCacheHit?: OnCacheHitHook;
    onCacheMiss?: OnCacheMissHook;
    onCacheGetError?: OnCacheErrorHook;
}
type OnCacheErrorHook = (payload: OnCacheErrorHookPayload) => void;
interface OnCacheErrorHookPayload {
    error: Error;
}
type OnCacheHitHook = (payload: OnCacheHitHookEventPayload) => void;
interface OnCacheHitHookEventPayload {
    value: any;
}
type OnCacheMissHook = () => void;
type OnCacheSetHook = (payload: OnCacheSetHookEventPayload) => MaybePromise$1<OnCacheSetHookResult | void>;
interface OnCacheSetHookResult {
    onCacheSetDone?: () => void;
    onCacheSetError?: OnCacheErrorHook;
}
interface OnCacheSetHookEventPayload {
    cache: KeyValueCache;
    key: string;
    value: any;
    ttl?: number;
}
type OnCacheDeleteHook = (payload: OnCacheDeleteHookEventPayload) => MaybePromise$1<OnCacheDeleteHookResult | void>;
interface OnCacheDeleteHookResult {
    onCacheDeleteDone?: () => void;
    onCacheDeleteError?: OnCacheErrorHook;
}
interface OnCacheDeleteHookEventPayload {
    cache: KeyValueCache;
    key: string;
}
type Instrumentation<TContext extends Record<string, any>> = Instrumentation$2<TContext> & Instrumentation$1 & FetchInstrumentation;
declare global {
    var DEBUG: string;
}
type HMACUpstreamSignatureOptions = {
    secret: string;
    shouldSign?: (input: Pick<OnSubgraphExecutePayload<{}>, 'subgraph' | 'subgraphName' | 'executionRequest'>) => boolean;
    extensionName?: string;
    serializeExecutionRequest?: (executionRequest: ExecutionRequest) => string;
};
declare const defaultExecutionRequestSerializer: (executionRequest: ExecutionRequest) => string | undefined;
declare const defaultParamsSerializer: (params: GraphQLParams) => string | undefined;
declare function useHmacUpstreamSignature(options: HMACUpstreamSignatureOptions): GatewayPlugin;
type HMACUpstreamSignatureValidationOptions = {
    secret: string;
    extensionName?: string;
    serializeParams?: (params: GraphQLParams) => string;
};
declare function useHmacSignatureValidation(options: HMACUpstreamSignatureValidationOptions): Plugin;
export { type HMACUpstreamSignatureOptions, type HMACUpstreamSignatureValidationOptions, defaultExecutionRequestSerializer, defaultParamsSerializer, useHmacSignatureValidation, useHmacUpstreamSignature };