import type { EventEmitter } from "eventemitter3"; import type { Middleware } from "graphile-config"; import type { ASTNode, ExecutionArgs, FragmentDefinitionNode, GraphQLArgs, GraphQLArgument, GraphQLArgumentConfig, GraphQLEnumValue, GraphQLField, GraphQLFieldConfig, GraphQLInputField, GraphQLInputFieldConfig, GraphQLInputObjectType, GraphQLInputType, GraphQLInterfaceType, GraphQLObjectType, GraphQLOutputType, GraphQLScalarType, GraphQLSchema, GraphQLUnionType, OperationDefinitionNode, Source, ValueNode, VariableNode } from "graphql"; import type { ObjMap } from "graphql/jsutils/ObjMap.js"; import type { $$streamMore, $$timeout, $$ts, ExecutionEntryFlags } from "./constants.ts"; import type { Constraint } from "./constraints.ts"; import type { LayerPlanReasonListItemStream } from "./engine/LayerPlan.ts"; import type { OperationPlan } from "./engine/OperationPlan.ts"; import type { FlaggedValue, SafeError } from "./error.ts"; import type { GrafastOperationOptions } from "./prepare.ts"; import type { Step } from "./step.ts"; import type { __InputDefaultStep } from "./steps/__inputDefault.ts"; import type { __InputDynamicScalarStep } from "./steps/__inputDynamicScalar.ts"; import type { ApplyableStep } from "./steps/applyInput.ts"; import type { __InputListStep, __InputObjectStepWithDollars, __InputStaticLeafStep, __TrackedValueStepWithDollars, ConstantStep, ObjectStep } from "./steps/index.ts"; export type { ExecutionEntryFlags }; export interface GrafastTimeouts { /** * How many milliseconds should we allow for planning. Remember: planning is * synchronous, so whilst it is happening the event loop is blocked. */ planning?: number; /** * How many milliseconds should we allow for execution. We will only check * this immediately before triggering the execution of an asynchronous step, * and if it is exceeded it will only prevent the execution of asynchronous * steps, not synchronous ones. * * IMPORTANT: since we only check this _before_ an asynchronous step * executes, there's nothing to stop an asynchronous step from continuing to * execute long after the timeout has expired - therefore it's the * responsibility of each step to abort itself if it goes over the allocated * time budget (which is detailed in `ExecutionExtra.stopTime`). */ execution?: number; } export type Fragments = { [key: string]: FragmentDefinitionNode; }; export interface IEstablishOperationPlanResult { variableValuesConstraints: Constraint[]; contextConstraints: Constraint[]; rootValueConstraints: Constraint[]; errorBehavior: ErrorBehavior; } export interface EstablishOperationPlanResultSuccess extends IEstablishOperationPlanResult { error?: never; operationPlan: OperationPlan; } export interface EstablishOperationPlanResultError extends IEstablishOperationPlanResult { error: Error | SafeError<{ [$$timeout]: number; [$$ts]: number; } | { [$$timeout]?: undefined; [$$ts]?: undefined; } | undefined>; operationPlan?: never; } export type EstablishOperationPlanResult = EstablishOperationPlanResultSuccess | EstablishOperationPlanResultError; /** * This represents the list of possible operationPlans for a specific document. * * @remarks * * It also includes the fragments for validation, but generally we trust that * if the OperationDefinitionNode is the same then the request is equivalent. */ export interface CacheByOperationEntry { /** * Implemented as a linked list so the hot operationPlans can be kept at the top of the * list, and if the list grows beyond a maximum size we can drop the last * element. */ possibleOperationPlans: LinkedList | null; fragments: Fragments; } export interface LinkedList { value: T; next: LinkedList | null; } export interface IndexByListItemStepId { [listItemStepId: number]: number; } export type GrafastValuesList = ReadonlyArray; export type PromiseOrDirect = PromiseLike | T; export type ExecutionResultValue = T | FlaggedValue | FlaggedValue; export type GrafastResultsList = ReadonlyArray>>; export type GrafastResultStreamList = ReadonlyArray>>> | PromiseLike>; export type AwaitedExecutionResults = ReadonlyArray | AsyncIterable ? UStreamItem : never>>>>>; export type ExecutionResults = PromiseOrDirect> | PromiseLike; export type BaseGraphQLRootValue = any; export interface BaseGraphQLVariables { [key: string]: unknown; } export interface BaseGraphQLArguments { [key: string]: unknown; } export type FieldArgs = { /** @deprecated Use bakedInput() step instead. */ get?: never; getRaw(path: TKey): Step; getRaw(path?: ReadonlyArray): AnyInputStep | ObjectStep<{ [argName: string]: AnyInputStep; }>; getBaked(path: TKey): Step; getBaked(path: ReadonlyArray): Step; typeAt(path: keyof TObj & string): GraphQLInputType; typeAt(path: ReadonlyArray): GraphQLInputType; /** This also works (without path) to apply each list entry against $target */ apply($target: ApplyableStep, path: keyof TObj & string, getTargetFromParent?: (parent: TArg, inputValue: any) => object | undefined): void; apply($target: ApplyableStep, path?: ReadonlyArray, getTargetFromParent?: (parent: TArg, inputValue: any) => object | undefined): void; apply($target: ApplyableStep, getTargetFromParent: (parent: TArg, inputValue: any) => object | undefined, justTargetFromParent?: never): void; /** * Applies the arguments to $target if they haven't already been applied. * Called automatically by the system once the `plan()` returns, but may be * called manually (e.g. by a plan wrapper) to ensure args are applied at any * point. */ autoApply($target: Step): void; } & { [key in keyof TObj & string as `$${key}`]: Step & ([unknown] extends [TObj[key]] ? { [subkey in string as `$${subkey}`]: Step; } : TObj[key] extends Record ? { [subkey in keyof TObj[key] & string as `$${subkey}`]: Step; } : unknown); }; export type FieldArg = { /** @deprecated Use bakedInput() step instead. */ get?: never; getRaw(path: TKey): Step; getRaw(path?: string | ReadonlyArray): AnyInputStep; typeAt(path: string | ReadonlyArray): GraphQLInputType; /** This also works (without path) to apply each list entry against $target */ apply($target: ApplyableStep, path?: ReadonlyArray, getTargetFromParent?: (parent: TArg, inputValue: any) => object | undefined): void; apply($target: ApplyableStep, getTargetFromParent: (parent: TArg, inputValue: any) => object | undefined, justTargetFromParent?: never): void; }; export type AnyInputStep = __TrackedValueStepWithDollars | __InputListStep | __InputStaticLeafStep | __InputDynamicScalarStep | __InputObjectStepWithDollars | __InputDefaultStep | ConstantStep; export type AnyInputStepWithDollars = AnyInputStep & AnyInputStepDollars; /** * Lies to make it easier to write TypeScript code like * `{ $input: { $user: { $username } } }` without having to pass loads of * generics. */ export type AnyInputStepDollars = { [key in string as `$${key}`]: AnyInputStepWithDollars; }; export interface FieldInfo { fieldName: string; field: GraphQLField; schema: GraphQLSchema; } /** * Step resolvers are like regular resolvers except they're called beforehand, * they return plans rather than values, and they only run once for lists * rather than for each item in the list. * * The idea is that the plan resolver returns a plan object which later will * process the data and feed that into the actual resolver functions * (preferably using the default resolver function?). * * They are stored onto `.extensions.grafast.plan` * * @returns a plan for this field. * * @remarks * We're using `TrackedObject<...>` so we can later consider caching these * executions. */ export type FieldPlanResolver = ($source: TSourceStep, fieldArgs: FieldArgs, info: FieldInfo) => TResultStep | null; export type InputObjectFieldApplyResolver = (target: TParent, input: TData, // Don't use unknown here, otherwise users can't easily cast it info: { schema: GraphQLSchema; fieldName: string; field: GraphQLInputField; scope: TScope; }) => any; export type InputObjectTypeBakedInfo = { schema: GraphQLSchema; type: GraphQLInputObjectType; applyChildren(val: any): void; }; export type InputObjectTypeBakedResolver = (input: Record, info: InputObjectTypeBakedInfo) => any; export type ArgumentApplyPlanResolver = ($parentPlan: TSource, $fieldPlan: TFieldStep, input: FieldArg, info: { schema: GraphQLSchema; arg: GraphQLArgument; argName: string; }) => void; /** * GraphQLScalarTypes can have plans, these are passed the field plan and must * return an executable plan. */ export type ScalarPlanResolver = ($source: TSourceStep, info: { schema: GraphQLSchema; }) => TResultStep; /** * GraphQLScalarTypes can have plans, these are passed the field plan and must * return an executable plan. */ export type ScalarInputPlanResolver = ($inputValue: AnyInputStep, info: { schema: GraphQLSchema; type: GraphQLScalarType; }) => TResultStep; /** * EXPERIMENTAL! * * NOTE: this is an `any` because we want to allow users to specify * subclasses of ExecutableStep but TypeScript only wants to allow * superclasses. * * @experimental */ export type EnumValueApplyResolver = (parent: TParent, info: { value: GraphQLEnumValue; scope: TScope; }) => void; /** * Basically GraphQLFieldConfig but with an easy to access `plan` method. */ export type GrafastFieldConfig = Omit, "args" | "type"> & { type: GraphQLOutputType; plan?: FieldPlanResolver; subscribePlan?: FieldPlanResolver; args?: GrafastFieldConfigArgumentMap; }; /** * Basically GraphQLFieldConfigArgumentMap but allowing for args to have plans. */ export type GrafastFieldConfigArgumentMap = { [argName: string]: GrafastArgumentConfig; }; /** * Basically GraphQLArgumentConfig but allowing for a plan. */ export type GrafastArgumentConfig = Omit & { type: GraphQLInputType; applyPlan?: ArgumentApplyPlanResolver; applySubscribePlan?: ArgumentApplyPlanResolver; inputPlan?: never; autoApplyAfterParentPlan?: never; autoApplyAfterParentSubscribePlan?: never; }; /** * Basically GraphQLInputFieldConfig but allowing for the field to have a plan. */ export type GrafastInputFieldConfig = Omit & { type: GraphQLInputType; apply?: InputObjectFieldApplyResolver; inputPlan?: never; applyPlan?: never; autoApplyAfterParentInputPlan?: never; autoApplyAfterParentApplyPlan?: never; }; /** * The args passed to a field plan resolver, the values are plans. */ export type TrackedArguments = { [TKey in keyof TArgs & string]: AnyInputStep; }; /** * `@stream` directive meta. */ export interface StepStreamOptions extends LayerPlanReasonListItemStream { } /** * Additional details about the planning for a field; currently only relates to * the `@stream` directive. */ export interface StepOptions { /** * Details for the `@stream` directive. * * object - `@stream` details * * true - no stream directive, but is inside a subscription field * * null - no stream directive */ stream: StepStreamOptions | true | null; /** * Should we walk an iterable if presented. This is important because we * don't want to walk things like Map/Set except if we're doing it as part of * a list step. */ walkIterable: boolean; } /** * Options passed to the `optimize` method of a plan to give more context. */ export interface StepOptimizeOptions { /** * If null, this step will not stream. If non-null, this step _might_ stream, * but it's not guaranteed - it may be dependent on user variables, e.g. the * `if` parameter. */ stream: null | {}; meta: Record | undefined; } /** * A subscriber provides realtime data, a SubscribeStep can subscribe to a * given topic (string) and will receive an AsyncIterableIterator with messages * published to that topic (standard pub/sub semantics). */ export type GrafastSubscriber = { subscribe(topic: TTopic): PromiseOrDirect>; release?(): PromiseOrDirect; }; /** * Specifically relates to the stringification of NodeIDs, e.g. `["User", 1]` * to/from `WyJVc2VyIiwgMV0=` */ export interface NodeIdCodec { name: string; encode(value: T): string | null; decode(value: string): T; } /** * Determines if a NodeID relates to a given object type, and also relates to * encoding the NodeID for that type. */ export type NodeIdHandler = NodeIdCodec, TNodeStep extends Step = Step, TSpec = any> = { /** * The name of the object type this handler is for. */ typeName: string; /** * Which codec are we using to encode/decode the NodeID string? */ codec: TCodec; /** * Returns true if the given decoded Node ID value represents this type. */ match(specifier: TCodec extends NodeIdCodec ? U : any): boolean; /** * Returns the underlying identifiers extracted from the decoded NodeID * value. */ getIdentifiers(value: TCodec extends NodeIdCodec ? U : any): TIdentifiers; /** * Returns a plan that returns the value ready to be encoded. When the result * of this plan is fed into `match`, it should return `true`. */ plan($thing: TNodeStep): Step ? U : any>; /** * Returns a specification based on the Node ID, this can be in any format * you like. It is intended to then be fed into `get` or handled in your own * code as you see fit. (When used directly, it's primarily useful for * referencing a node without actually fetching it - e.g. allowing you to * delete a node by its ID without first fetching it.) */ getSpec(plan: Step ? U : any>): TSpec; /** * Combined with `getSpec`, this forms the recprocal of `plan`; i.e. * `get(getSpec( plan(node) ))` should return a plan that results in the * original node. */ get(spec: TSpec): TNodeStep; deprecationReason?: string; }; export type BaseEventMap = Record; export type EventMapKey = string & keyof TEventMap; export type EventCallback = (params: TPayload) => void; export interface TypedEventEmitter extends EventEmitter { addListener>(eventName: TEventName, callback: EventCallback): this; on>(eventName: TEventName, callback: EventCallback): this; once>(eventName: TEventName, callback: EventCallback): this; removeListener>(eventName: TEventName, callback: EventCallback): this; off>(eventName: TEventName, callback: EventCallback): this; emit>(eventName: TEventName, params: TEventMap[TEventName]): boolean; } export type ExecutionEventMap = { /** * Something that can be added to the * ExecutionResult.extensions.explain.operations list. */ explainOperation: { operation: Record & { type: string; title: string; }; }; }; export type ExecutionEventEmitter = TypedEventEmitter; export interface ExecutionExtraBase { /** The `performance.now()` at which your step should stop executing */ stopTime: number | null; /** If you have set a `metaKey` on your step, the relevant meta object which you can write into (e.g. for caching) */ meta: Record | undefined; eventEmitter: ExecutionEventEmitter | undefined; } export interface ExecutionExtra extends ExecutionExtraBase { } export interface UnbatchedExecutionExtra extends ExecutionExtraBase { stream: ExecutionDetailsStream | null; } export type ExecutionValue = BatchExecutionValue | UnaryExecutionValue; interface ExecutionValueBase { /** Data at index in the batch (`0 <= batchIndex < count`) */ at(i: number): TData; /** `false` for unary execution values, `true` otherwise */ isBatch: boolean; /** Returns the value for a unary execution value; throws if non-unary */ unaryValue(): TData; } export interface BatchExecutionValue extends ExecutionValueBase { isBatch: true; entries: ReadonlyArray; /** Always throws, since this should only be called on unary execution values */ unaryValue(): never; } export interface UnaryExecutionValue extends ExecutionValueBase { isBatch: false; value: TData; /** Same as getting .value */ unaryValue(): TData; } export type IndexMap = (callback: (i: number) => T) => ReadonlyArray; export type IndexForEach = (callback: (i: number) => any) => void; export interface ExecutionDetailsStream { initialCount: number; } export interface ExecutionDetails { /** The size of the batch being processed */ count: number; /** An "execution value" for each dependency of the step */ values: { [DepIdx in keyof TDeps]: ExecutionValue; } & { length: TDeps["length"]; map: ReadonlyArray>["map"]; }; /** Helper; makes array from `callback(batchIndex)` for each `0 <= batchIndex < count` */ indexMap: IndexMap; /** Helper; calls `callback` for each batchIndex in the batch; no return value */ indexForEach: IndexForEach; /** * If this step is expected to return a stream (e.g. because it's a * `subscription`, or because of the `@stream` incremental delivery * directive) then an object with details of the stream, such as how many * records were requested up front (`initialCount`). For subscriptions, * `initialCount` will always be `0`. */ stream: ExecutionDetailsStream | null; /** Currently experimental, use it at your own risk (and see the source for docs) */ extra: ExecutionExtra; } export interface LocationDetails { node: ASTNode | readonly ASTNode[]; /** This should only be null for the root selection */ parentTypeName: string | null; /** This should only be null for the root selection */ fieldName: string | null; } export type UnwrapPlanTuple = { [Index in keyof TIn]: DataFromStep; }; export type NotVariableValueNode = Exclude; export type StreamMaybeMoreableArray = Array & { [$$streamMore]?: AsyncIterator | Iterator; }; export type StreamMoreableArray = Array & { [$$streamMore]: AsyncIterator | Iterator; }; export interface GrafastArgs extends GraphQLArgs { onError?: ErrorBehavior; extensions?: Record; resolvedPreset?: GraphileConfig.ResolvedPreset; requestContext?: Partial; middleware?: Middleware | null; } export type Maybe = T | null | undefined; export type * from "./planJSONInterfaces.ts"; export interface BaseDependencyOptions { step: TStep; skipDeduplication?: boolean; /** @defaultValue `FLAG_NULL` */ acceptFlags?: ExecutionEntryFlags; onReject?: Maybe; } export interface AddDependencyOptions extends BaseDependencyOptions { nonUnaryMessage?: never; dataOnly?: boolean; } export interface AddUnaryDependencyOptions extends BaseDependencyOptions { nonUnaryMessage?: ($dependent: Step, $dependency: Step) => string; dataOnly?: never; } export interface DependencyOptions { step: TStep; acceptFlags: ExecutionEntryFlags; onReject: Maybe; dataOnly: boolean; } export type DataFromStep = TStep extends Step ? TData : never; export interface GrafastExecutionArgs extends ExecutionArgs { onError?: ErrorBehavior; extensions?: Record; resolvedPreset?: GraphileConfig.ResolvedPreset; middleware?: Middleware | null; requestContext?: Partial; outputDataAsString?: boolean; } export interface ValidateSchemaEvent { resolvedPreset: GraphileConfig.ResolvedPreset; schema: GraphQLSchema; } export interface ParseAndValidateEvent { resolvedPreset: GraphileConfig.ResolvedPreset; schema: GraphQLSchema; source: string | Source; } export interface PrepareArgsEvent { args: Grafast.ExecutionArgs; } export interface ExecuteEvent { args: GrafastExecutionArgs; } export interface SubscribeEvent { args: GrafastExecutionArgs; } export interface EstablishOperationPlanEvent { schema: GraphQLSchema; operation: OperationDefinitionNode; fragments: ObjMap; variableValues: Record; context: any; rootValue: any; onError: ErrorBehavior; args: GrafastExecutionArgs; options: GrafastOperationOptions; } export interface ExecuteStepEvent { args: GrafastExecutionArgs; step: Step; executeDetails: ExecutionDetails; } export interface PlanTypeInfo { abstractType: GraphQLUnionType | GraphQLInterfaceType; /** * If this polymorphic position was represented by exactly one source step, * this will be that step and you may use it to implement a more optimal * planType. If more than one step was combined as input to this * polymorphism, this will be null. */ $original: TOriginalStep | null; } /** * When planning an abstract type, an interface or union, it should have a * `extensions.grafast.planType` method which accepts an incoming step * representing the polymorphic data (we call this the `$specifier`) and will * return a AbstractTypePlanner object. This object has a key `$__typename` * whose value must be a step that represents the GraphQL type name to use for * the given $specifier, and a method `planForType` that should return the step * to use for a specific object type within the interface/union. */ export interface AbstractTypePlanner { /** * Must be a step representing the name of the object type associated with * the given `$specifier`, or `null` if no such type could be determined. */ $__typename: Step; /** * If not provided, will call `t.planType($specifier)` */ planForType?(t: GraphQLObjectType): Step | null; } export type Thunk = T | (() => T); /** * GraphQL error behavior, as per https://github.com/graphql/graphql-spec/pull/1163 */ export type ErrorBehavior = "PROPAGATE" | "NULL" | "HALT"; //# sourceMappingURL=interfaces.d.ts.map