import { devAssert } from '../jsutils/devAssert' ; import { inspect } from '../jsutils/inspect' ; import { isAsyncIterable } from '../jsutils/isAsyncIterable' ; import type { Maybe } from '../jsutils/Maybe' ; import { addPath , pathToArray } from '../jsutils/Path' ; import { GraphQLError } from '../error/GraphQLError' ; import { locatedError } from '../error/locatedError' ; import type { DocumentNode } from '../language/ast' ; import type { GraphQLFieldResolver } from '../type/definition' ; import type { GraphQLSchema } from '../type/schema' ; import { collectFields } from './collectFields' ; import type { ExecutionArgs , ExecutionContext , ExecutionResult , } from './execute' ; import { assertValidExecutionArguments , buildExecutionContext , buildResolveInfo , execute , getFieldDef , } from './execute' ; import { mapAsyncIterator } from './mapAsyncIterator' ; import { getArgumentValues } from './values' ; /**
 * Implements the "Subscribe" algorithm described in the GraphQL specification.
 *
 * Returns a Promise which resolves to either an AsyncIterator (if successful)
 * or an ExecutionResult (error). The promise will be rejected if the schema or
 * other arguments to this function are invalid, or if the resolved event stream
 * is not an async iterable.
 *
 * If the client-provided arguments to this function do not result in a
 * compliant subscription, a GraphQL Response (ExecutionResult) with
 * descriptive errors and no data will be returned.
 *
 * If the source stream could not be created due to faulty subscription
 * resolver logic or underlying systems, the promise will resolve to a single
 * ExecutionResult containing `errors` and no `data`.
 *
 * If the operation succeeded, the promise resolves to an AsyncIterator, which
 * yields a stream of ExecutionResults representing the response stream.
 *
 * Accepts either an object with named arguments, or individual arguments.
 */ export async function subscribe ( args ) { devAssert ( arguments . length < 2 , 'graphql@16 dropped long-deprecated support for positional arguments, please pass an object instead.' ) ; const { schema , document , rootValue , contextValue , variableValues , operationName , fieldResolver , subscribeFieldResolver , } = args ; const resultOrStream = await createSourceEventStream ( schema , document , rootValue , contextValue , variableValues , operationName , subscribeFieldResolver ) ; if ( ! isAsyncIterable ( resultOrStream ) ) { return resultOrStream ; } const mapSourceToResponse = ( payload ) => execute ( { schema , document , rootValue : payload , contextValue , variableValues , operationName , fieldResolver , } ) ; return mapAsyncIterator ( resultOrStream , mapSourceToResponse ) ; } /**
 * Implements the "CreateSourceEventStream" algorithm described in the
 * GraphQL specification, resolving the subscription source event stream.
 *
 * Returns a Promise which resolves to either an AsyncIterable (if successful)
 * or an ExecutionResult (error). The promise will be rejected if the schema or
 * other arguments to this function are invalid, or if the resolved event stream
 * is not an async iterable.
 *
 * If the client-provided arguments to this function do not result in a
 * compliant subscription, a GraphQL Response (ExecutionResult) with
 * descriptive errors and no data will be returned.
 *
 * If the the source stream could not be created due to faulty subscription
 * resolver logic or underlying systems, the promise will resolve to a single
 * ExecutionResult containing `errors` and no `data`.
 *
 * If the operation succeeded, the promise resolves to the AsyncIterable for the
 * event stream returned by the resolver.
 *
 * A Source Event Stream represents a sequence of events, each of which triggers
 * a GraphQL execution for that event.
 *
 * This may be useful when hosting the stateful subscription service in a
 * different process or machine than the stateless GraphQL execution engine,
 * or otherwise separating these two steps. For more on this, see the
 * "Supporting Subscriptions at Scale" information in the GraphQL specification.
 */ export async function createSourceEventStream ( schema , document , rootValue ? , contextValue ? , variableValues ? , operationName ? , subscribeFieldResolver ? ) { assertValidExecutionArguments ( schema , document , variableValues ) ; const exeContext = buildExecutionContext ( { schema , document , rootValue , contextValue , variableValues , operationName , subscribeFieldResolver , } ) ; if ( ! ( 'schema' in exeContext ) ) { return { errors : exeContext } ; } try { const eventStream = await executeSubscription ( exeContext ) ; if ( ! isAsyncIterable ( eventStream ) ) { throw new Error ( 'Subscription field must return Async Iterable. ' + `Received: ${ inspect ( eventStream ) }.` ) ; } return eventStream ; } catch ( error ) { if ( error instanceof GraphQLError ) { return { errors : [ error ] } ; } throw error ; } } async function executeSubscription ( exeContext ) { const { schema , fragments , operation , variableValues , rootValue } = exeContext ; const rootType = schema . getSubscriptionType ( ) ; if ( rootType == null ) { throw new GraphQLError ( 'Schema is not configured to execute subscription operation.' , operation ) ; } const rootFields = collectFields ( schema , fragments , variableValues , rootType , operation . selectionSet ) ; const [ responseName , fieldNodes ] = [ ... rootFields . entries ( ) ] [ 0 ] ; const fieldDef = getFieldDef ( schema , rootType , fieldNodes [ 0 ] ) ; if ( ! fieldDef ) { const fieldName = fieldNodes [ 0 ] . name . value ; throw new GraphQLError ( `The subscription field "${ fieldName }" is not defined.` , fieldNodes ) ; } const path = addPath ( undefined , responseName , rootType . name ) ; const info = buildResolveInfo ( exeContext , fieldDef , fieldNodes , rootType , path ) ; try { const args = getArgumentValues ( fieldDef , fieldNodes [ 0 ] , variableValues ) ; const contextValue = exeContext . contextValue ; const resolveFn = fieldDef . subscribe ?? exeContext . subscribeFieldResolver ; const eventStream = await resolveFn ( rootValue , args , contextValue , info ) ; if ( eventStream instanceof Error ) { throw eventStream ; } return eventStream ; } catch ( error ) { throw locatedError ( error , fieldNodes , pathToArray ( path ) ) ; } }