@envelop/core
Advanced tools
Comparing version 0.1.4 to 0.1.5-alpha-89abc0f.0
@@ -1,7 +0,4 @@ | ||
import { GraphQLSchema } from 'graphql'; | ||
import { Envelop, Plugin } from '@envelop/types'; | ||
export declare function envelop(options: { | ||
export declare function envelop({ plugins }: { | ||
plugins: Plugin[]; | ||
extends?: Envelop[]; | ||
initialSchema?: GraphQLSchema; | ||
}): Envelop; |
667
index.cjs.js
@@ -8,9 +8,167 @@ 'use strict'; | ||
// In ES2015 (or a polyfilled) environment, this will be Symbol.iterator | ||
// istanbul ignore next (See: 'https://github.com/graphql/graphql-js/issues/2317') | ||
var SYMBOL_ASYNC_ITERATOR = typeof Symbol === 'function' && Symbol.asyncIterator != null ? Symbol.asyncIterator : '@@asyncIterator'; // istanbul ignore next (See: 'https://github.com/graphql/graphql-js/issues/2317') | ||
/** | ||
* Returns true if the provided object implements the AsyncIterator protocol via | ||
* either implementing a `Symbol.asyncIterator` or `"@@asyncIterator"` method. | ||
*/ | ||
// eslint-disable-next-line no-redeclare | ||
function isAsyncIterable(maybeAsyncIterable) { | ||
return typeof (maybeAsyncIterable === null || maybeAsyncIterable === void 0 ? void 0 : maybeAsyncIterable[SYMBOL_ASYNC_ITERATOR]) === 'function'; | ||
} | ||
function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; } | ||
/** | ||
* Given an AsyncIterable and a callback function, return an AsyncIterator | ||
* which produces values mapped via calling the callback function. | ||
*/ | ||
function mapAsyncIterator(iterable, callback, rejectCallback) { | ||
// $FlowFixMe[prop-missing] | ||
var iteratorMethod = iterable[SYMBOL_ASYNC_ITERATOR]; | ||
var iterator = iteratorMethod.call(iterable); | ||
var $return; | ||
var abruptClose; | ||
if (typeof iterator.return === 'function') { | ||
$return = iterator.return; | ||
abruptClose = function abruptClose(error) { | ||
var rethrow = function rethrow() { | ||
return Promise.reject(error); | ||
}; | ||
return $return.call(iterator).then(rethrow, rethrow); | ||
}; | ||
} | ||
function mapResult(result) { | ||
return result.done ? result : asyncMapValue(result.value, callback).then(iteratorResult, abruptClose); | ||
} | ||
var mapReject; | ||
if (rejectCallback) { | ||
// Capture rejectCallback to ensure it cannot be null. | ||
var reject = rejectCallback; | ||
mapReject = function mapReject(error) { | ||
return asyncMapValue(error, reject).then(iteratorResult, abruptClose); | ||
}; | ||
} | ||
/* TODO: Flow doesn't support symbols as keys: | ||
https://github.com/facebook/flow/issues/3258 */ | ||
return _defineProperty({ | ||
next: function next() { | ||
return iterator.next().then(mapResult, mapReject); | ||
}, | ||
return: function _return() { | ||
return $return ? $return.call(iterator).then(mapResult, mapReject) : Promise.resolve({ | ||
value: undefined, | ||
done: true | ||
}); | ||
}, | ||
throw: function _throw(error) { | ||
if (typeof iterator.throw === 'function') { | ||
return iterator.throw(error).then(mapResult, mapReject); | ||
} | ||
return Promise.reject(error).catch(abruptClose); | ||
} | ||
}, SYMBOL_ASYNC_ITERATOR, function () { | ||
return this; | ||
}); | ||
} | ||
function asyncMapValue(value, callback) { | ||
return new Promise(function (resolve) { | ||
return resolve(callback(value)); | ||
}); | ||
} | ||
function iteratorResult(value) { | ||
return { | ||
value: value, | ||
done: false | ||
}; | ||
} | ||
function getExecuteArgs(args) { | ||
return args.length === 1 | ||
? args[0] | ||
: { | ||
schema: args[0], | ||
document: args[1], | ||
rootValue: args[2], | ||
contextValue: args[3], | ||
variableValues: args[4], | ||
operationName: args[5], | ||
fieldResolver: args[6], | ||
typeResolver: args[7], | ||
}; | ||
} | ||
/** | ||
* Utility function for making a execute function that handles polymorphic arguments. | ||
*/ | ||
const makeExecute = (subscribeFn) => (...polyArgs) => subscribeFn(getExecuteArgs(polyArgs)); | ||
function getSubscribeArgs(args) { | ||
return args.length === 1 | ||
? args[0] | ||
: { | ||
schema: args[0], | ||
document: args[1], | ||
rootValue: args[2], | ||
contextValue: args[3], | ||
variableValues: args[4], | ||
operationName: args[5], | ||
fieldResolver: args[6], | ||
subscribeFieldResolver: args[7], | ||
execute: args[8], | ||
}; | ||
} | ||
/** | ||
* Utility function for making a subscribe function that handles polymorphic arguments. | ||
*/ | ||
const makeSubscribe = (subscribeFn) => (...polyArgs) => subscribeFn(getSubscribeArgs(polyArgs)); | ||
/** | ||
* This is a almost identical port from graphql-js subscribe. | ||
* The only difference is that a custom `execute` function can be injected as an additional argument. | ||
*/ | ||
const subscribe = makeSubscribe(async (args) => { | ||
const { schema, document, rootValue, contextValue, variableValues, operationName, fieldResolver, subscribeFieldResolver, execute = graphql.execute, } = args; | ||
const resultOrStream = await graphql.createSourceEventStream(schema, document, rootValue, contextValue, variableValues !== null && variableValues !== void 0 ? variableValues : undefined, operationName, subscribeFieldResolver); | ||
if (!isAsyncIterable(resultOrStream)) { | ||
return resultOrStream; | ||
} | ||
// For each payload yielded from a subscription, map it over the normal | ||
// GraphQL `execute` function, with `payload` as the rootValue. | ||
// This implements the "MapSourceToResponseEvent" algorithm described in | ||
// the GraphQL specification. The `execute` function provides the | ||
// "ExecuteSubscriptionEvent" algorithm, as it is nearly identical to the | ||
// "ExecuteQuery" algorithm, for which `execute` is also used. | ||
const mapSourceToResponse = async (payload) => execute({ | ||
schema, | ||
document, | ||
rootValue: payload, | ||
contextValue, | ||
variableValues, | ||
operationName, | ||
fieldResolver, | ||
}); | ||
// Map every source value to a ExecutionResult value as described above. | ||
return mapAsyncIterator(resultOrStream, mapSourceToResponse); | ||
}); | ||
const trackedSchemaSymbol = Symbol('TRACKED_SCHEMA'); | ||
const resolversHooksSymbol = Symbol('RESOLVERS_HOOKS'); | ||
function envelop(options) { | ||
let schema = options.initialSchema; | ||
function envelop({ plugins }) { | ||
let schema = null; | ||
let initDone = false; | ||
const childPlugins = (options.extends || []).reduce((prev, child) => [...prev, ...child._plugins], []); | ||
const plugins = [...childPlugins, ...options.plugins]; | ||
const replaceSchema = (newSchema, ignorePluginIndex = -1) => { | ||
@@ -35,12 +193,28 @@ schema = newSchema; | ||
plugin.onPluginInit({ | ||
plugins, | ||
addPlugin: newPlugin => { | ||
plugins.push(newPlugin); | ||
}, | ||
setSchema: modifiedSchema => replaceSchema(modifiedSchema, i), | ||
}); | ||
} | ||
const customParse = (source, parseOptions) => { | ||
let result = null; | ||
let parseFn = graphql.parse; | ||
const afterCalls = []; | ||
for (const plugin of plugins) { | ||
const afterFn = plugin.onParse && | ||
plugin.onParse({ | ||
const onContextBuildingCbs = []; | ||
const onExecuteCbs = []; | ||
const onParseCbs = []; | ||
const onSubscribeCbs = []; | ||
const onValidateCbs = []; | ||
for (const { onContextBuilding, onExecute, onParse, onSubscribe, onValidate } of plugins) { | ||
onContextBuilding && onContextBuildingCbs.push(onContextBuilding); | ||
onExecute && onExecuteCbs.push(onExecute); | ||
onParse && onParseCbs.push(onParse); | ||
onSubscribe && onSubscribeCbs.push(onSubscribe); | ||
onValidate && onValidateCbs.push(onValidate); | ||
} | ||
const customParse = onParseCbs.length | ||
? (source, parseOptions) => { | ||
let result = null; | ||
let parseFn = graphql.parse; | ||
const afterCalls = []; | ||
for (const onParse of onParseCbs) { | ||
const afterFn = onParse({ | ||
params: { source, options: parseOptions }, | ||
@@ -55,33 +229,37 @@ parseFn, | ||
}); | ||
afterFn && afterCalls.push(afterFn); | ||
} | ||
if (result === null) { | ||
try { | ||
result = parseFn(source, parseOptions); | ||
afterFn && afterCalls.push(afterFn); | ||
} | ||
catch (e) { | ||
result = e; | ||
if (result === null) { | ||
try { | ||
result = parseFn(source, parseOptions); | ||
} | ||
catch (e) { | ||
result = e; | ||
} | ||
} | ||
for (const afterCb of afterCalls) { | ||
afterCb({ | ||
replaceParseResult: newResult => { | ||
result = newResult; | ||
}, | ||
result, | ||
}); | ||
} | ||
if (result === null) { | ||
throw new Error(`Failed to parse document.`); | ||
} | ||
if (result instanceof Error) { | ||
throw result; | ||
} | ||
return result; | ||
} | ||
for (const afterCb of afterCalls) { | ||
afterCb({ | ||
replaceParseResult: newResult => { | ||
result = newResult; | ||
}, | ||
result, | ||
}); | ||
} | ||
if (result instanceof Error) { | ||
throw result; | ||
} | ||
return result; | ||
}; | ||
const customValidate = (schema, documentAST, rules, typeInfo, validationOptions) => { | ||
let actualRules = rules ? [...rules] : undefined; | ||
let validateFn = graphql.validate; | ||
let result = null; | ||
const afterCalls = []; | ||
for (const plugin of plugins) { | ||
const afterFn = plugin.onValidate && | ||
plugin.onValidate({ | ||
: graphql.parse; | ||
const customValidate = onValidateCbs.length | ||
? (schema, documentAST, rules, typeInfo, validationOptions) => { | ||
let actualRules = rules ? [...rules] : undefined; | ||
let validateFn = graphql.validate; | ||
let result = null; | ||
const afterCalls = []; | ||
for (const onValidate of onValidateCbs) { | ||
const afterFn = onValidate({ | ||
params: { | ||
@@ -108,19 +286,20 @@ schema, | ||
}); | ||
afterFn && afterCalls.push(afterFn); | ||
afterFn && afterCalls.push(afterFn); | ||
} | ||
if (!result) { | ||
result = validateFn(schema, documentAST, actualRules, typeInfo, validationOptions); | ||
} | ||
const valid = result.length === 0; | ||
for (const afterCb of afterCalls) { | ||
afterCb({ valid, result }); | ||
} | ||
return result; | ||
} | ||
if (result === null) { | ||
result = validateFn(schema, documentAST, actualRules, typeInfo, validationOptions); | ||
} | ||
const valid = result.length === 0; | ||
for (const afterCb of afterCalls) { | ||
afterCb({ valid, result }); | ||
} | ||
return result; | ||
}; | ||
const customContextFactory = async (initialContext) => { | ||
let context = initialContext; | ||
const afterCalls = []; | ||
for (const plugin of plugins) { | ||
const afterFn = plugin.onContextBuilding && | ||
(await plugin.onContextBuilding({ | ||
: graphql.validate; | ||
const customContextFactory = onContextBuildingCbs.length | ||
? async (initialContext) => { | ||
let context = initialContext; | ||
const afterCalls = []; | ||
for (const onContext of onContextBuildingCbs) { | ||
const afterFn = await onContext({ | ||
context, | ||
@@ -138,31 +317,20 @@ extendContext: extension => { | ||
}, | ||
})); | ||
afterFn && afterCalls.push(afterFn); | ||
}); | ||
afterFn && afterCalls.push(afterFn); | ||
} | ||
for (const afterCb of afterCalls) { | ||
afterCb({ context }); | ||
} | ||
return context; | ||
} | ||
for (const afterCb of afterCalls) { | ||
afterCb({ context }); | ||
} | ||
return context; | ||
}; | ||
const beforeExecuteCalls = plugins.filter(p => p.onExecute); | ||
const beforeSubscribeCalls = plugins.filter(p => p.onSubscribe); | ||
const customSubscribe = async (argsOrSchema, document, rootValue, contextValue, variableValues, operationName, fieldResolver, subscribeFieldResolver) => { | ||
const args = argsOrSchema instanceof graphql.GraphQLSchema | ||
? { | ||
schema: argsOrSchema, | ||
document, | ||
rootValue, | ||
contextValue, | ||
variableValues, | ||
operationName, | ||
fieldResolver, | ||
subscribeFieldResolver, | ||
} | ||
: argsOrSchema; | ||
: (ctx) => ctx; | ||
const customSubscribe = makeSubscribe(async (args) => { | ||
var _a; | ||
const onResolversHandlers = []; | ||
let subscribeFn = graphql.subscribe; | ||
let subscribeFn = subscribe; | ||
const afterCalls = []; | ||
const beforeExecuteSubscriptionHandlers = []; | ||
let context = args.contextValue; | ||
for (const plugin of beforeSubscribeCalls) { | ||
const after = plugin.onSubscribe({ | ||
for (const onSubscribe of onSubscribeCbs) { | ||
const after = onSubscribe({ | ||
subscribeFn, | ||
@@ -192,2 +360,5 @@ setSubscribeFn: newSubscribeFn => { | ||
} | ||
if (after.onExecuteSubscriptionEvent) { | ||
beforeExecuteSubscriptionHandlers.push(after.onExecuteSubscriptionEvent); | ||
} | ||
} | ||
@@ -198,5 +369,67 @@ } | ||
} | ||
const subscribeExecute = beforeExecuteSubscriptionHandlers.length | ||
? makeExecute(async (args) => { | ||
const onResolversHandlers = []; | ||
let executeFn = graphql.execute; | ||
let result; | ||
const afterCalls = []; | ||
let context = args.contextValue; | ||
for (const onExecute of beforeExecuteSubscriptionHandlers) { | ||
let stopCalled = false; | ||
const after = onExecute({ | ||
executeFn, | ||
setExecuteFn: newExecuteFn => { | ||
executeFn = newExecuteFn; | ||
}, | ||
setResultAndStopExecution: stopResult => { | ||
stopCalled = true; | ||
result = stopResult; | ||
}, | ||
extendContext: extension => { | ||
if (typeof extension === 'object') { | ||
context = { | ||
...(context || {}), | ||
...extension, | ||
}; | ||
} | ||
else { | ||
throw new Error(`Invalid context extension provided! Expected "object", got: "${JSON.stringify(extension)}" (${typeof extension})`); | ||
} | ||
}, | ||
args, | ||
}); | ||
if (stopCalled) { | ||
return result; | ||
} | ||
if (after) { | ||
if (after.onExecuteDone) { | ||
afterCalls.push(after.onExecuteDone); | ||
} | ||
if (after.onResolverCalled) { | ||
onResolversHandlers.push(after.onResolverCalled); | ||
} | ||
} | ||
} | ||
if (onResolversHandlers.length) { | ||
context[resolversHooksSymbol] = onResolversHandlers; | ||
} | ||
result = await executeFn({ | ||
...args, | ||
contextValue: context, | ||
}); | ||
for (const afterCb of afterCalls) { | ||
afterCb({ | ||
result, | ||
setResult: newResult => { | ||
result = newResult; | ||
}, | ||
}); | ||
} | ||
return result; | ||
}) | ||
: ((_a = args.execute) !== null && _a !== void 0 ? _a : graphql.execute); | ||
let result = await subscribeFn({ | ||
...args, | ||
contextValue: context, | ||
execute: subscribeExecute, | ||
}); | ||
@@ -212,76 +445,66 @@ for (const afterCb of afterCalls) { | ||
return result; | ||
}; | ||
const customExecute = async (argsOrSchema, document, rootValue, contextValue, variableValues, operationName, fieldResolver, typeResolver) => { | ||
const args = argsOrSchema instanceof graphql.GraphQLSchema | ||
? { | ||
schema: argsOrSchema, | ||
document, | ||
rootValue, | ||
contextValue, | ||
variableValues, | ||
operationName, | ||
fieldResolver, | ||
typeResolver, | ||
} | ||
: argsOrSchema; | ||
const onResolversHandlers = []; | ||
let executeFn = graphql.execute; | ||
let result; | ||
const afterCalls = []; | ||
let context = args.contextValue; | ||
for (const plugin of beforeExecuteCalls) { | ||
let stopCalled = false; | ||
const after = plugin.onExecute({ | ||
executeFn, | ||
setExecuteFn: newExecuteFn => { | ||
executeFn = newExecuteFn; | ||
}, | ||
setResultAndStopExecution: stopResult => { | ||
stopCalled = true; | ||
result = stopResult; | ||
}, | ||
extendContext: extension => { | ||
if (typeof extension === 'object') { | ||
context = { | ||
...(context || {}), | ||
...extension, | ||
}; | ||
}); | ||
const customExecute = (onExecuteCbs.length | ||
? makeExecute(async (args) => { | ||
const onResolversHandlers = []; | ||
let executeFn = graphql.execute; | ||
let result; | ||
const afterCalls = []; | ||
let context = args.contextValue; | ||
for (const onExecute of onExecuteCbs) { | ||
let stopCalled = false; | ||
const after = onExecute({ | ||
executeFn, | ||
setExecuteFn: newExecuteFn => { | ||
executeFn = newExecuteFn; | ||
}, | ||
setResultAndStopExecution: stopResult => { | ||
stopCalled = true; | ||
result = stopResult; | ||
}, | ||
extendContext: extension => { | ||
if (typeof extension === 'object') { | ||
context = { | ||
...(context || {}), | ||
...extension, | ||
}; | ||
} | ||
else { | ||
throw new Error(`Invalid context extension provided! Expected "object", got: "${JSON.stringify(extension)}" (${typeof extension})`); | ||
} | ||
}, | ||
args, | ||
}); | ||
if (stopCalled) { | ||
return result; | ||
} | ||
if (after) { | ||
if (after.onExecuteDone) { | ||
afterCalls.push(after.onExecuteDone); | ||
} | ||
else { | ||
throw new Error(`Invalid context extension provided! Expected "object", got: "${JSON.stringify(extension)}" (${typeof extension})`); | ||
if (after.onResolverCalled) { | ||
onResolversHandlers.push(after.onResolverCalled); | ||
} | ||
}, | ||
args, | ||
}); | ||
if (stopCalled) { | ||
return result; | ||
} | ||
if (after) { | ||
if (after.onExecuteDone) { | ||
afterCalls.push(after.onExecuteDone); | ||
} | ||
if (after.onResolverCalled) { | ||
onResolversHandlers.push(after.onResolverCalled); | ||
} | ||
} | ||
} | ||
if (onResolversHandlers.length) { | ||
context[resolversHooksSymbol] = onResolversHandlers; | ||
} | ||
result = await executeFn({ | ||
...args, | ||
contextValue: context, | ||
}); | ||
for (const afterCb of afterCalls) { | ||
afterCb({ | ||
result, | ||
setResult: newResult => { | ||
result = newResult; | ||
}, | ||
if (onResolversHandlers.length) { | ||
context[resolversHooksSymbol] = onResolversHandlers; | ||
} | ||
result = await executeFn({ | ||
...args, | ||
contextValue: context, | ||
}); | ||
} | ||
return result; | ||
}; | ||
for (const afterCb of afterCalls) { | ||
afterCb({ | ||
result, | ||
setResult: newResult => { | ||
result = newResult; | ||
}, | ||
}); | ||
} | ||
return result; | ||
}) | ||
: graphql.execute); | ||
function prepareSchema() { | ||
if (schema[trackedSchemaSymbol]) { | ||
if (!schema || schema[trackedSchemaSymbol]) { | ||
return; | ||
@@ -419,4 +642,5 @@ } | ||
}; | ||
return { | ||
onContextBuilding() { | ||
const result = {}; | ||
if (options.onContextBuildingMeasurement) { | ||
result.onContextBuilding = () => { | ||
const contextStartTime = process.hrtime(); | ||
@@ -426,4 +650,6 @@ return () => { | ||
}; | ||
}, | ||
onParse({ params }) { | ||
}; | ||
} | ||
if (options.onParsingMeasurement) { | ||
result.onParse = ({ params }) => { | ||
const parseStartTime = process.hrtime(); | ||
@@ -433,4 +659,6 @@ return () => { | ||
}; | ||
}, | ||
onValidate({ params }) { | ||
}; | ||
} | ||
if (options.onValidationMeasurement) { | ||
result.onValidate = ({ params }) => { | ||
const validateStartTime = process.hrtime(); | ||
@@ -440,32 +668,61 @@ return () => { | ||
}; | ||
}, | ||
onExecute({ args }) { | ||
const executeStartTime = process.hrtime(); | ||
return { | ||
onExecuteDone: () => { | ||
options.onExecutionMeasurement(args, deltaFrom(executeStartTime)); | ||
}, | ||
onResolverCalled: ({ info }) => { | ||
const resolverStartTime = process.hrtime(); | ||
return () => { | ||
options.onResolverMeasurement(info, deltaFrom(resolverStartTime)); | ||
}; | ||
}, | ||
}; | ||
} | ||
if (options.onExecutionMeasurement) { | ||
if (options.onResolverMeasurement) { | ||
result.onExecute = ({ args }) => { | ||
const executeStartTime = process.hrtime(); | ||
return { | ||
onExecuteDone: () => { | ||
options.onExecutionMeasurement(args, deltaFrom(executeStartTime)); | ||
}, | ||
onResolverCalled: ({ info }) => { | ||
const resolverStartTime = process.hrtime(); | ||
return () => { | ||
options.onResolverMeasurement(info, deltaFrom(resolverStartTime)); | ||
}; | ||
}, | ||
}; | ||
}; | ||
}, | ||
onSubscribe({ args }) { | ||
const subscribeStartTime = process.hrtime(); | ||
return { | ||
onSubscribeResult: () => { | ||
options.onSubscriptionMeasurement(args, deltaFrom(subscribeStartTime)); | ||
}, | ||
onResolverCalled: ({ info }) => { | ||
const resolverStartTime = process.hrtime(); | ||
return () => { | ||
options.onResolverMeasurement(info, deltaFrom(resolverStartTime)); | ||
}; | ||
}, | ||
} | ||
else { | ||
result.onExecute = ({ args }) => { | ||
const executeStartTime = process.hrtime(); | ||
return { | ||
onExecuteDone: () => { | ||
options.onExecutionMeasurement(args, deltaFrom(executeStartTime)); | ||
}, | ||
}; | ||
}; | ||
}, | ||
}; | ||
} | ||
} | ||
if (options.onSubscriptionMeasurement) { | ||
if (options.onResolverMeasurement) { | ||
result.onSubscribe = ({ args }) => { | ||
const subscribeStartTime = process.hrtime(); | ||
return { | ||
onSubscribeResult: () => { | ||
options.onSubscriptionMeasurement && options.onSubscriptionMeasurement(args, deltaFrom(subscribeStartTime)); | ||
}, | ||
onResolverCalled: ({ info }) => { | ||
const resolverStartTime = process.hrtime(); | ||
return () => { | ||
options.onResolverMeasurement && options.onResolverMeasurement(info, deltaFrom(resolverStartTime)); | ||
}; | ||
}, | ||
}; | ||
}; | ||
} | ||
else { | ||
result.onSubscribe = ({ args }) => { | ||
const subscribeStartTime = process.hrtime(); | ||
return { | ||
onSubscribeResult: () => { | ||
options.onSubscriptionMeasurement && options.onSubscriptionMeasurement(args, deltaFrom(subscribeStartTime)); | ||
}, | ||
}; | ||
}; | ||
} | ||
} | ||
return result; | ||
}; | ||
@@ -486,3 +743,3 @@ | ||
var _a; | ||
if (((_a = result.errors) === null || _a === void 0 ? void 0 : _a.length) > 0) { | ||
if ((_a = result.errors) === null || _a === void 0 ? void 0 : _a.length) { | ||
errorHandler(result.errors); | ||
@@ -514,11 +771,43 @@ } | ||
const useCreateContextPerSubscriptionEvent = (createContext) => { | ||
return { | ||
onSubscribe({ args }) { | ||
return { | ||
onExecuteSubscriptionEvent({ executeFn, setExecuteFn }) { | ||
const newExecute = async (..._executionArgs) => { | ||
const executionArgs = getExecuteArgs(_executionArgs); | ||
const context = await createContext({ args }); | ||
try { | ||
return executeFn({ | ||
...executionArgs, | ||
contextValue: context ? context.contextValue : executionArgs.contextValue, | ||
}); | ||
} | ||
finally { | ||
if (context && context.onEnd) { | ||
context.onEnd(); | ||
} | ||
} | ||
}; | ||
setExecuteFn(newExecute); | ||
}, | ||
}; | ||
}, | ||
}; | ||
}; | ||
Object.keys(types).forEach(function (k) { | ||
if (k !== 'default') Object.defineProperty(exports, k, { | ||
enumerable: true, | ||
get: function () { | ||
return types[k]; | ||
} | ||
}); | ||
if (k !== 'default') Object.defineProperty(exports, k, { | ||
enumerable: true, | ||
get: function () { | ||
return types[k]; | ||
} | ||
}); | ||
}); | ||
exports.envelop = envelop; | ||
exports.getExecuteArgs = getExecuteArgs; | ||
exports.getSubscribeArgs = getSubscribeArgs; | ||
exports.makeExecute = makeExecute; | ||
exports.makeSubscribe = makeSubscribe; | ||
exports.useCreateContextPerSubscriptionEvent = useCreateContextPerSubscriptionEvent; | ||
exports.useErrorHandler = useErrorHandler; | ||
@@ -525,0 +814,0 @@ exports.useExtendContext = useExtendContext; |
export * from '@envelop/types'; | ||
export * from './create'; | ||
export * from './util'; | ||
export * from './plugins/use-logger'; | ||
@@ -9,1 +10,2 @@ export * from './plugins/use-timing'; | ||
export * from './plugins/use-payload-formatter'; | ||
export * from './plugins/use-context-per-subscription-event'; |
652
index.esm.js
export * from '@envelop/types'; | ||
import { specifiedRules, isIntrospectionType, isObjectType, defaultFieldResolver, parse, validate, GraphQLSchema, subscribe, execute, getOperationAST } from 'graphql'; | ||
import { createSourceEventStream, execute, parse, specifiedRules, validate, isIntrospectionType, isObjectType, defaultFieldResolver, getOperationAST } from 'graphql'; | ||
// In ES2015 (or a polyfilled) environment, this will be Symbol.iterator | ||
// istanbul ignore next (See: 'https://github.com/graphql/graphql-js/issues/2317') | ||
var SYMBOL_ASYNC_ITERATOR = typeof Symbol === 'function' && Symbol.asyncIterator != null ? Symbol.asyncIterator : '@@asyncIterator'; // istanbul ignore next (See: 'https://github.com/graphql/graphql-js/issues/2317') | ||
/** | ||
* Returns true if the provided object implements the AsyncIterator protocol via | ||
* either implementing a `Symbol.asyncIterator` or `"@@asyncIterator"` method. | ||
*/ | ||
// eslint-disable-next-line no-redeclare | ||
function isAsyncIterable(maybeAsyncIterable) { | ||
return typeof (maybeAsyncIterable === null || maybeAsyncIterable === void 0 ? void 0 : maybeAsyncIterable[SYMBOL_ASYNC_ITERATOR]) === 'function'; | ||
} | ||
function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; } | ||
/** | ||
* Given an AsyncIterable and a callback function, return an AsyncIterator | ||
* which produces values mapped via calling the callback function. | ||
*/ | ||
function mapAsyncIterator(iterable, callback, rejectCallback) { | ||
// $FlowFixMe[prop-missing] | ||
var iteratorMethod = iterable[SYMBOL_ASYNC_ITERATOR]; | ||
var iterator = iteratorMethod.call(iterable); | ||
var $return; | ||
var abruptClose; | ||
if (typeof iterator.return === 'function') { | ||
$return = iterator.return; | ||
abruptClose = function abruptClose(error) { | ||
var rethrow = function rethrow() { | ||
return Promise.reject(error); | ||
}; | ||
return $return.call(iterator).then(rethrow, rethrow); | ||
}; | ||
} | ||
function mapResult(result) { | ||
return result.done ? result : asyncMapValue(result.value, callback).then(iteratorResult, abruptClose); | ||
} | ||
var mapReject; | ||
if (rejectCallback) { | ||
// Capture rejectCallback to ensure it cannot be null. | ||
var reject = rejectCallback; | ||
mapReject = function mapReject(error) { | ||
return asyncMapValue(error, reject).then(iteratorResult, abruptClose); | ||
}; | ||
} | ||
/* TODO: Flow doesn't support symbols as keys: | ||
https://github.com/facebook/flow/issues/3258 */ | ||
return _defineProperty({ | ||
next: function next() { | ||
return iterator.next().then(mapResult, mapReject); | ||
}, | ||
return: function _return() { | ||
return $return ? $return.call(iterator).then(mapResult, mapReject) : Promise.resolve({ | ||
value: undefined, | ||
done: true | ||
}); | ||
}, | ||
throw: function _throw(error) { | ||
if (typeof iterator.throw === 'function') { | ||
return iterator.throw(error).then(mapResult, mapReject); | ||
} | ||
return Promise.reject(error).catch(abruptClose); | ||
} | ||
}, SYMBOL_ASYNC_ITERATOR, function () { | ||
return this; | ||
}); | ||
} | ||
function asyncMapValue(value, callback) { | ||
return new Promise(function (resolve) { | ||
return resolve(callback(value)); | ||
}); | ||
} | ||
function iteratorResult(value) { | ||
return { | ||
value: value, | ||
done: false | ||
}; | ||
} | ||
function getExecuteArgs(args) { | ||
return args.length === 1 | ||
? args[0] | ||
: { | ||
schema: args[0], | ||
document: args[1], | ||
rootValue: args[2], | ||
contextValue: args[3], | ||
variableValues: args[4], | ||
operationName: args[5], | ||
fieldResolver: args[6], | ||
typeResolver: args[7], | ||
}; | ||
} | ||
/** | ||
* Utility function for making a execute function that handles polymorphic arguments. | ||
*/ | ||
const makeExecute = (subscribeFn) => (...polyArgs) => subscribeFn(getExecuteArgs(polyArgs)); | ||
function getSubscribeArgs(args) { | ||
return args.length === 1 | ||
? args[0] | ||
: { | ||
schema: args[0], | ||
document: args[1], | ||
rootValue: args[2], | ||
contextValue: args[3], | ||
variableValues: args[4], | ||
operationName: args[5], | ||
fieldResolver: args[6], | ||
subscribeFieldResolver: args[7], | ||
execute: args[8], | ||
}; | ||
} | ||
/** | ||
* Utility function for making a subscribe function that handles polymorphic arguments. | ||
*/ | ||
const makeSubscribe = (subscribeFn) => (...polyArgs) => subscribeFn(getSubscribeArgs(polyArgs)); | ||
/** | ||
* This is a almost identical port from graphql-js subscribe. | ||
* The only difference is that a custom `execute` function can be injected as an additional argument. | ||
*/ | ||
const subscribe = makeSubscribe(async (args) => { | ||
const { schema, document, rootValue, contextValue, variableValues, operationName, fieldResolver, subscribeFieldResolver, execute: execute$1 = execute, } = args; | ||
const resultOrStream = await createSourceEventStream(schema, document, rootValue, contextValue, variableValues !== null && variableValues !== void 0 ? variableValues : undefined, operationName, subscribeFieldResolver); | ||
if (!isAsyncIterable(resultOrStream)) { | ||
return resultOrStream; | ||
} | ||
// For each payload yielded from a subscription, map it over the normal | ||
// GraphQL `execute` function, with `payload` as the rootValue. | ||
// This implements the "MapSourceToResponseEvent" algorithm described in | ||
// the GraphQL specification. The `execute` function provides the | ||
// "ExecuteSubscriptionEvent" algorithm, as it is nearly identical to the | ||
// "ExecuteQuery" algorithm, for which `execute` is also used. | ||
const mapSourceToResponse = async (payload) => execute$1({ | ||
schema, | ||
document, | ||
rootValue: payload, | ||
contextValue, | ||
variableValues, | ||
operationName, | ||
fieldResolver, | ||
}); | ||
// Map every source value to a ExecutionResult value as described above. | ||
return mapAsyncIterator(resultOrStream, mapSourceToResponse); | ||
}); | ||
const trackedSchemaSymbol = Symbol('TRACKED_SCHEMA'); | ||
const resolversHooksSymbol = Symbol('RESOLVERS_HOOKS'); | ||
function envelop(options) { | ||
let schema = options.initialSchema; | ||
function envelop({ plugins }) { | ||
let schema = null; | ||
let initDone = false; | ||
const childPlugins = (options.extends || []).reduce((prev, child) => [...prev, ...child._plugins], []); | ||
const plugins = [...childPlugins, ...options.plugins]; | ||
const replaceSchema = (newSchema, ignorePluginIndex = -1) => { | ||
@@ -30,12 +188,28 @@ schema = newSchema; | ||
plugin.onPluginInit({ | ||
plugins, | ||
addPlugin: newPlugin => { | ||
plugins.push(newPlugin); | ||
}, | ||
setSchema: modifiedSchema => replaceSchema(modifiedSchema, i), | ||
}); | ||
} | ||
const customParse = (source, parseOptions) => { | ||
let result = null; | ||
let parseFn = parse; | ||
const afterCalls = []; | ||
for (const plugin of plugins) { | ||
const afterFn = plugin.onParse && | ||
plugin.onParse({ | ||
const onContextBuildingCbs = []; | ||
const onExecuteCbs = []; | ||
const onParseCbs = []; | ||
const onSubscribeCbs = []; | ||
const onValidateCbs = []; | ||
for (const { onContextBuilding, onExecute, onParse, onSubscribe, onValidate } of plugins) { | ||
onContextBuilding && onContextBuildingCbs.push(onContextBuilding); | ||
onExecute && onExecuteCbs.push(onExecute); | ||
onParse && onParseCbs.push(onParse); | ||
onSubscribe && onSubscribeCbs.push(onSubscribe); | ||
onValidate && onValidateCbs.push(onValidate); | ||
} | ||
const customParse = onParseCbs.length | ||
? (source, parseOptions) => { | ||
let result = null; | ||
let parseFn = parse; | ||
const afterCalls = []; | ||
for (const onParse of onParseCbs) { | ||
const afterFn = onParse({ | ||
params: { source, options: parseOptions }, | ||
@@ -50,33 +224,37 @@ parseFn, | ||
}); | ||
afterFn && afterCalls.push(afterFn); | ||
} | ||
if (result === null) { | ||
try { | ||
result = parseFn(source, parseOptions); | ||
afterFn && afterCalls.push(afterFn); | ||
} | ||
catch (e) { | ||
result = e; | ||
if (result === null) { | ||
try { | ||
result = parseFn(source, parseOptions); | ||
} | ||
catch (e) { | ||
result = e; | ||
} | ||
} | ||
for (const afterCb of afterCalls) { | ||
afterCb({ | ||
replaceParseResult: newResult => { | ||
result = newResult; | ||
}, | ||
result, | ||
}); | ||
} | ||
if (result === null) { | ||
throw new Error(`Failed to parse document.`); | ||
} | ||
if (result instanceof Error) { | ||
throw result; | ||
} | ||
return result; | ||
} | ||
for (const afterCb of afterCalls) { | ||
afterCb({ | ||
replaceParseResult: newResult => { | ||
result = newResult; | ||
}, | ||
result, | ||
}); | ||
} | ||
if (result instanceof Error) { | ||
throw result; | ||
} | ||
return result; | ||
}; | ||
const customValidate = (schema, documentAST, rules, typeInfo, validationOptions) => { | ||
let actualRules = rules ? [...rules] : undefined; | ||
let validateFn = validate; | ||
let result = null; | ||
const afterCalls = []; | ||
for (const plugin of plugins) { | ||
const afterFn = plugin.onValidate && | ||
plugin.onValidate({ | ||
: parse; | ||
const customValidate = onValidateCbs.length | ||
? (schema, documentAST, rules, typeInfo, validationOptions) => { | ||
let actualRules = rules ? [...rules] : undefined; | ||
let validateFn = validate; | ||
let result = null; | ||
const afterCalls = []; | ||
for (const onValidate of onValidateCbs) { | ||
const afterFn = onValidate({ | ||
params: { | ||
@@ -103,19 +281,20 @@ schema, | ||
}); | ||
afterFn && afterCalls.push(afterFn); | ||
afterFn && afterCalls.push(afterFn); | ||
} | ||
if (!result) { | ||
result = validateFn(schema, documentAST, actualRules, typeInfo, validationOptions); | ||
} | ||
const valid = result.length === 0; | ||
for (const afterCb of afterCalls) { | ||
afterCb({ valid, result }); | ||
} | ||
return result; | ||
} | ||
if (result === null) { | ||
result = validateFn(schema, documentAST, actualRules, typeInfo, validationOptions); | ||
} | ||
const valid = result.length === 0; | ||
for (const afterCb of afterCalls) { | ||
afterCb({ valid, result }); | ||
} | ||
return result; | ||
}; | ||
const customContextFactory = async (initialContext) => { | ||
let context = initialContext; | ||
const afterCalls = []; | ||
for (const plugin of plugins) { | ||
const afterFn = plugin.onContextBuilding && | ||
(await plugin.onContextBuilding({ | ||
: validate; | ||
const customContextFactory = onContextBuildingCbs.length | ||
? async (initialContext) => { | ||
let context = initialContext; | ||
const afterCalls = []; | ||
for (const onContext of onContextBuildingCbs) { | ||
const afterFn = await onContext({ | ||
context, | ||
@@ -133,31 +312,20 @@ extendContext: extension => { | ||
}, | ||
})); | ||
afterFn && afterCalls.push(afterFn); | ||
}); | ||
afterFn && afterCalls.push(afterFn); | ||
} | ||
for (const afterCb of afterCalls) { | ||
afterCb({ context }); | ||
} | ||
return context; | ||
} | ||
for (const afterCb of afterCalls) { | ||
afterCb({ context }); | ||
} | ||
return context; | ||
}; | ||
const beforeExecuteCalls = plugins.filter(p => p.onExecute); | ||
const beforeSubscribeCalls = plugins.filter(p => p.onSubscribe); | ||
const customSubscribe = async (argsOrSchema, document, rootValue, contextValue, variableValues, operationName, fieldResolver, subscribeFieldResolver) => { | ||
const args = argsOrSchema instanceof GraphQLSchema | ||
? { | ||
schema: argsOrSchema, | ||
document, | ||
rootValue, | ||
contextValue, | ||
variableValues, | ||
operationName, | ||
fieldResolver, | ||
subscribeFieldResolver, | ||
} | ||
: argsOrSchema; | ||
: (ctx) => ctx; | ||
const customSubscribe = makeSubscribe(async (args) => { | ||
var _a; | ||
const onResolversHandlers = []; | ||
let subscribeFn = subscribe; | ||
const afterCalls = []; | ||
const beforeExecuteSubscriptionHandlers = []; | ||
let context = args.contextValue; | ||
for (const plugin of beforeSubscribeCalls) { | ||
const after = plugin.onSubscribe({ | ||
for (const onSubscribe of onSubscribeCbs) { | ||
const after = onSubscribe({ | ||
subscribeFn, | ||
@@ -187,2 +355,5 @@ setSubscribeFn: newSubscribeFn => { | ||
} | ||
if (after.onExecuteSubscriptionEvent) { | ||
beforeExecuteSubscriptionHandlers.push(after.onExecuteSubscriptionEvent); | ||
} | ||
} | ||
@@ -193,5 +364,67 @@ } | ||
} | ||
const subscribeExecute = beforeExecuteSubscriptionHandlers.length | ||
? makeExecute(async (args) => { | ||
const onResolversHandlers = []; | ||
let executeFn = execute; | ||
let result; | ||
const afterCalls = []; | ||
let context = args.contextValue; | ||
for (const onExecute of beforeExecuteSubscriptionHandlers) { | ||
let stopCalled = false; | ||
const after = onExecute({ | ||
executeFn, | ||
setExecuteFn: newExecuteFn => { | ||
executeFn = newExecuteFn; | ||
}, | ||
setResultAndStopExecution: stopResult => { | ||
stopCalled = true; | ||
result = stopResult; | ||
}, | ||
extendContext: extension => { | ||
if (typeof extension === 'object') { | ||
context = { | ||
...(context || {}), | ||
...extension, | ||
}; | ||
} | ||
else { | ||
throw new Error(`Invalid context extension provided! Expected "object", got: "${JSON.stringify(extension)}" (${typeof extension})`); | ||
} | ||
}, | ||
args, | ||
}); | ||
if (stopCalled) { | ||
return result; | ||
} | ||
if (after) { | ||
if (after.onExecuteDone) { | ||
afterCalls.push(after.onExecuteDone); | ||
} | ||
if (after.onResolverCalled) { | ||
onResolversHandlers.push(after.onResolverCalled); | ||
} | ||
} | ||
} | ||
if (onResolversHandlers.length) { | ||
context[resolversHooksSymbol] = onResolversHandlers; | ||
} | ||
result = await executeFn({ | ||
...args, | ||
contextValue: context, | ||
}); | ||
for (const afterCb of afterCalls) { | ||
afterCb({ | ||
result, | ||
setResult: newResult => { | ||
result = newResult; | ||
}, | ||
}); | ||
} | ||
return result; | ||
}) | ||
: ((_a = args.execute) !== null && _a !== void 0 ? _a : execute); | ||
let result = await subscribeFn({ | ||
...args, | ||
contextValue: context, | ||
execute: subscribeExecute, | ||
}); | ||
@@ -207,76 +440,66 @@ for (const afterCb of afterCalls) { | ||
return result; | ||
}; | ||
const customExecute = async (argsOrSchema, document, rootValue, contextValue, variableValues, operationName, fieldResolver, typeResolver) => { | ||
const args = argsOrSchema instanceof GraphQLSchema | ||
? { | ||
schema: argsOrSchema, | ||
document, | ||
rootValue, | ||
contextValue, | ||
variableValues, | ||
operationName, | ||
fieldResolver, | ||
typeResolver, | ||
} | ||
: argsOrSchema; | ||
const onResolversHandlers = []; | ||
let executeFn = execute; | ||
let result; | ||
const afterCalls = []; | ||
let context = args.contextValue; | ||
for (const plugin of beforeExecuteCalls) { | ||
let stopCalled = false; | ||
const after = plugin.onExecute({ | ||
executeFn, | ||
setExecuteFn: newExecuteFn => { | ||
executeFn = newExecuteFn; | ||
}, | ||
setResultAndStopExecution: stopResult => { | ||
stopCalled = true; | ||
result = stopResult; | ||
}, | ||
extendContext: extension => { | ||
if (typeof extension === 'object') { | ||
context = { | ||
...(context || {}), | ||
...extension, | ||
}; | ||
}); | ||
const customExecute = (onExecuteCbs.length | ||
? makeExecute(async (args) => { | ||
const onResolversHandlers = []; | ||
let executeFn = execute; | ||
let result; | ||
const afterCalls = []; | ||
let context = args.contextValue; | ||
for (const onExecute of onExecuteCbs) { | ||
let stopCalled = false; | ||
const after = onExecute({ | ||
executeFn, | ||
setExecuteFn: newExecuteFn => { | ||
executeFn = newExecuteFn; | ||
}, | ||
setResultAndStopExecution: stopResult => { | ||
stopCalled = true; | ||
result = stopResult; | ||
}, | ||
extendContext: extension => { | ||
if (typeof extension === 'object') { | ||
context = { | ||
...(context || {}), | ||
...extension, | ||
}; | ||
} | ||
else { | ||
throw new Error(`Invalid context extension provided! Expected "object", got: "${JSON.stringify(extension)}" (${typeof extension})`); | ||
} | ||
}, | ||
args, | ||
}); | ||
if (stopCalled) { | ||
return result; | ||
} | ||
if (after) { | ||
if (after.onExecuteDone) { | ||
afterCalls.push(after.onExecuteDone); | ||
} | ||
else { | ||
throw new Error(`Invalid context extension provided! Expected "object", got: "${JSON.stringify(extension)}" (${typeof extension})`); | ||
if (after.onResolverCalled) { | ||
onResolversHandlers.push(after.onResolverCalled); | ||
} | ||
}, | ||
args, | ||
}); | ||
if (stopCalled) { | ||
return result; | ||
} | ||
if (after) { | ||
if (after.onExecuteDone) { | ||
afterCalls.push(after.onExecuteDone); | ||
} | ||
if (after.onResolverCalled) { | ||
onResolversHandlers.push(after.onResolverCalled); | ||
} | ||
} | ||
} | ||
if (onResolversHandlers.length) { | ||
context[resolversHooksSymbol] = onResolversHandlers; | ||
} | ||
result = await executeFn({ | ||
...args, | ||
contextValue: context, | ||
}); | ||
for (const afterCb of afterCalls) { | ||
afterCb({ | ||
result, | ||
setResult: newResult => { | ||
result = newResult; | ||
}, | ||
if (onResolversHandlers.length) { | ||
context[resolversHooksSymbol] = onResolversHandlers; | ||
} | ||
result = await executeFn({ | ||
...args, | ||
contextValue: context, | ||
}); | ||
} | ||
return result; | ||
}; | ||
for (const afterCb of afterCalls) { | ||
afterCb({ | ||
result, | ||
setResult: newResult => { | ||
result = newResult; | ||
}, | ||
}); | ||
} | ||
return result; | ||
}) | ||
: execute); | ||
function prepareSchema() { | ||
if (schema[trackedSchemaSymbol]) { | ||
if (!schema || schema[trackedSchemaSymbol]) { | ||
return; | ||
@@ -414,4 +637,5 @@ } | ||
}; | ||
return { | ||
onContextBuilding() { | ||
const result = {}; | ||
if (options.onContextBuildingMeasurement) { | ||
result.onContextBuilding = () => { | ||
const contextStartTime = process.hrtime(); | ||
@@ -421,4 +645,6 @@ return () => { | ||
}; | ||
}, | ||
onParse({ params }) { | ||
}; | ||
} | ||
if (options.onParsingMeasurement) { | ||
result.onParse = ({ params }) => { | ||
const parseStartTime = process.hrtime(); | ||
@@ -428,4 +654,6 @@ return () => { | ||
}; | ||
}, | ||
onValidate({ params }) { | ||
}; | ||
} | ||
if (options.onValidationMeasurement) { | ||
result.onValidate = ({ params }) => { | ||
const validateStartTime = process.hrtime(); | ||
@@ -435,32 +663,61 @@ return () => { | ||
}; | ||
}, | ||
onExecute({ args }) { | ||
const executeStartTime = process.hrtime(); | ||
return { | ||
onExecuteDone: () => { | ||
options.onExecutionMeasurement(args, deltaFrom(executeStartTime)); | ||
}, | ||
onResolverCalled: ({ info }) => { | ||
const resolverStartTime = process.hrtime(); | ||
return () => { | ||
options.onResolverMeasurement(info, deltaFrom(resolverStartTime)); | ||
}; | ||
}, | ||
}; | ||
} | ||
if (options.onExecutionMeasurement) { | ||
if (options.onResolverMeasurement) { | ||
result.onExecute = ({ args }) => { | ||
const executeStartTime = process.hrtime(); | ||
return { | ||
onExecuteDone: () => { | ||
options.onExecutionMeasurement(args, deltaFrom(executeStartTime)); | ||
}, | ||
onResolverCalled: ({ info }) => { | ||
const resolverStartTime = process.hrtime(); | ||
return () => { | ||
options.onResolverMeasurement(info, deltaFrom(resolverStartTime)); | ||
}; | ||
}, | ||
}; | ||
}; | ||
}, | ||
onSubscribe({ args }) { | ||
const subscribeStartTime = process.hrtime(); | ||
return { | ||
onSubscribeResult: () => { | ||
options.onSubscriptionMeasurement(args, deltaFrom(subscribeStartTime)); | ||
}, | ||
onResolverCalled: ({ info }) => { | ||
const resolverStartTime = process.hrtime(); | ||
return () => { | ||
options.onResolverMeasurement(info, deltaFrom(resolverStartTime)); | ||
}; | ||
}, | ||
} | ||
else { | ||
result.onExecute = ({ args }) => { | ||
const executeStartTime = process.hrtime(); | ||
return { | ||
onExecuteDone: () => { | ||
options.onExecutionMeasurement(args, deltaFrom(executeStartTime)); | ||
}, | ||
}; | ||
}; | ||
}, | ||
}; | ||
} | ||
} | ||
if (options.onSubscriptionMeasurement) { | ||
if (options.onResolverMeasurement) { | ||
result.onSubscribe = ({ args }) => { | ||
const subscribeStartTime = process.hrtime(); | ||
return { | ||
onSubscribeResult: () => { | ||
options.onSubscriptionMeasurement && options.onSubscriptionMeasurement(args, deltaFrom(subscribeStartTime)); | ||
}, | ||
onResolverCalled: ({ info }) => { | ||
const resolverStartTime = process.hrtime(); | ||
return () => { | ||
options.onResolverMeasurement && options.onResolverMeasurement(info, deltaFrom(resolverStartTime)); | ||
}; | ||
}, | ||
}; | ||
}; | ||
} | ||
else { | ||
result.onSubscribe = ({ args }) => { | ||
const subscribeStartTime = process.hrtime(); | ||
return { | ||
onSubscribeResult: () => { | ||
options.onSubscriptionMeasurement && options.onSubscriptionMeasurement(args, deltaFrom(subscribeStartTime)); | ||
}, | ||
}; | ||
}; | ||
} | ||
} | ||
return result; | ||
}; | ||
@@ -481,3 +738,3 @@ | ||
var _a; | ||
if (((_a = result.errors) === null || _a === void 0 ? void 0 : _a.length) > 0) { | ||
if ((_a = result.errors) === null || _a === void 0 ? void 0 : _a.length) { | ||
errorHandler(result.errors); | ||
@@ -509,3 +766,30 @@ } | ||
export { envelop, useErrorHandler, useExtendContext, useLogger, usePayloadFormatter, useSchema, useTiming }; | ||
const useCreateContextPerSubscriptionEvent = (createContext) => { | ||
return { | ||
onSubscribe({ args }) { | ||
return { | ||
onExecuteSubscriptionEvent({ executeFn, setExecuteFn }) { | ||
const newExecute = async (..._executionArgs) => { | ||
const executionArgs = getExecuteArgs(_executionArgs); | ||
const context = await createContext({ args }); | ||
try { | ||
return executeFn({ | ||
...executionArgs, | ||
contextValue: context ? context.contextValue : executionArgs.contextValue, | ||
}); | ||
} | ||
finally { | ||
if (context && context.onEnd) { | ||
context.onEnd(); | ||
} | ||
} | ||
}; | ||
setExecuteFn(newExecute); | ||
}, | ||
}; | ||
}, | ||
}; | ||
}; | ||
export { envelop, getExecuteArgs, getSubscribeArgs, makeExecute, makeSubscribe, useCreateContextPerSubscriptionEvent, useErrorHandler, useExtendContext, useLogger, usePayloadFormatter, useSchema, useTiming }; | ||
//# sourceMappingURL=index.esm.js.map |
{ | ||
"name": "@envelop/core", | ||
"version": "0.1.4", | ||
"version": "0.1.5-alpha-89abc0f.0", | ||
"sideEffects": false, | ||
@@ -9,3 +9,3 @@ "peerDependencies": { | ||
"dependencies": { | ||
"@envelop/types": "0.1.4" | ||
"@envelop/types": "0.1.5-alpha-89abc0f.0" | ||
}, | ||
@@ -12,0 +12,0 @@ "repository": { |
@@ -15,2 +15,2 @@ import { Plugin } from '@envelop/types'; | ||
}; | ||
export declare const useTiming: (rawOptions?: TimingPluginOptions) => Plugin; | ||
export declare const useTiming: (rawOptions?: TimingPluginOptions | undefined) => Plugin; |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
183273
18
1618
+ Added@envelop/types@0.1.5-alpha-89abc0f.0(transitive)
- Removed@envelop/types@0.1.4(transitive)