From c27091969e8b84ae6dd7a6bc1bde17aa1746726b Mon Sep 17 00:00:00 2001 From: Saihajpreet Singh Date: Thu, 22 Sep 2022 13:08:53 -0400 Subject: [PATCH 1/3] feat: use engine plugin --- .changeset/hip-ravens-serve.md | 24 ++++++++++++ packages/core/README.md | 1 + packages/core/docs/use-engine.md | 22 +++++++++++ packages/core/src/index.ts | 1 + packages/core/src/plugins/use-engine.ts | 33 ++++++++++++++++ packages/core/test/plugins/use-engine.spec.ts | 38 +++++++++++++++++++ website/docs/core.mdx | 23 +++++++++++ website/src/lib/plugins.ts | 11 ++++++ 8 files changed, 153 insertions(+) create mode 100644 .changeset/hip-ravens-serve.md create mode 100644 packages/core/docs/use-engine.md create mode 100644 packages/core/src/plugins/use-engine.ts create mode 100644 packages/core/test/plugins/use-engine.spec.ts diff --git a/.changeset/hip-ravens-serve.md b/.changeset/hip-ravens-serve.md new file mode 100644 index 000000000..6bbae9177 --- /dev/null +++ b/.changeset/hip-ravens-serve.md @@ -0,0 +1,24 @@ +--- +'@envelop/core': minor +--- + +A new plugin that can be used to customize the GraphQL Engine. + +```ts +import { envelop, useEngine } from '@envelop/core' +import { parse, validate, execute, subscribe } from 'graphql' +import { parser } from 'my-custom-graphql-parser' + +const getEnveloped = envelop({ + parse, + validate, + execute, + subscribe, + plugins: [ + useEngine({ + // Now your envelop will use the custom parser instead of the default one provided. + parse: parser + }) + ] +}) +``` diff --git a/packages/core/README.md b/packages/core/README.md index e35719ce8..37a8132f1 100644 --- a/packages/core/README.md +++ b/packages/core/README.md @@ -11,3 +11,4 @@ This is the core package for Envelop. You can find a complete documentation here - [`useLogger`](./docs/use-logger.md) - [`useMaskedErrors`](./docs/use-masked-errors.md) - [`usePayloadFormatter`](./docs/use-payload-formatter.md) +- [`useEngine`](./docs/use-engine.md) diff --git a/packages/core/docs/use-engine.md b/packages/core/docs/use-engine.md new file mode 100644 index 000000000..bd9ce10f4 --- /dev/null +++ b/packages/core/docs/use-engine.md @@ -0,0 +1,22 @@ +#### `useEngine` + +This plugin can be used to customize the GraphQL Engine. + +```ts +import { envelop, useEngine } from '@envelop/core' +import { parse, validate, execute, subscribe } from 'graphql' +import { parser } from 'my-custom-graphql-parser' + +const getEnveloped = envelop({ + parse, + validate, + execute, + subscribe, + plugins: [ + useEngine({ + // Now your envelop will use the custom parser instead of the default one provided. + parse: parser + }) + ] +}) +``` diff --git a/packages/core/src/index.ts b/packages/core/src/index.ts index 3a03fc795..131064c4e 100644 --- a/packages/core/src/index.ts +++ b/packages/core/src/index.ts @@ -8,3 +8,4 @@ export * from './plugins/use-error-handler.js'; export * from './plugins/use-extend-context.js'; export * from './plugins/use-payload-formatter.js'; export * from './plugins/use-masked-errors.js'; +export * from './plugins/use-engine.js'; diff --git a/packages/core/src/plugins/use-engine.ts b/packages/core/src/plugins/use-engine.ts new file mode 100644 index 000000000..896ace0f7 --- /dev/null +++ b/packages/core/src/plugins/use-engine.ts @@ -0,0 +1,33 @@ +import { ExecuteFunction, ParseFunction, Plugin, SubscribeFunction, ValidateFunction } from '@envelop/types'; + +type UseEngineOptions = { + execute?: ExecuteFunction; + parse?: ParseFunction; + validate?: ValidateFunction; + subscribe?: SubscribeFunction; +}; + +export const useEngine = (engine: UseEngineOptions): Plugin => { + return { + onExecute: ({ setExecuteFn }) => { + if (engine.execute) { + setExecuteFn(engine.execute); + } + }, + onParse: ({ setParseFn }) => { + if (engine.parse) { + setParseFn(engine.parse); + } + }, + onValidate: ({ setValidationFn }) => { + if (engine.validate) { + setValidationFn(engine.validate); + } + }, + onSubscribe: ({ setSubscribeFn }) => { + if (engine.subscribe) { + setSubscribeFn(engine.subscribe); + } + }, + }; +}; diff --git a/packages/core/test/plugins/use-engine.spec.ts b/packages/core/test/plugins/use-engine.spec.ts new file mode 100644 index 000000000..846c71fd2 --- /dev/null +++ b/packages/core/test/plugins/use-engine.spec.ts @@ -0,0 +1,38 @@ +import { createTestkit } from '@envelop/testing'; +import { query, schema, subscriptionOperationString } from '../common.js'; +import { useEngine } from '@envelop/core'; +import { parse, validate } from 'graphql'; + +describe('useEngine', () => { + it('should invoke custom execute', async () => { + expect.assertions(1); + const custom = jest.fn(); + const testInstance = createTestkit([useEngine({ execute: custom })], schema); + await testInstance.execute(query); + expect(custom).toHaveBeenCalledTimes(1); + }); + + it('should invoke custom subscribe', async () => { + expect.assertions(1); + const custom = jest.fn(); + const testInstance = createTestkit([useEngine({ subscribe: custom })], schema); + await testInstance.execute(subscriptionOperationString); + expect(custom).toHaveBeenCalledTimes(1); + }); + + it('should invoke custom validate', async () => { + expect.assertions(1); + const custom = jest.fn(validate); + const testInstance = createTestkit([useEngine({ validate: custom })], schema); + await testInstance.execute(query); + expect(custom).toHaveBeenCalledTimes(1); + }); + + it('should invoke custom parse', async () => { + expect.assertions(1); + const custom = jest.fn(parse); + const testInstance = createTestkit([useEngine({ parse: custom })], schema); + await testInstance.execute(query); + expect(custom).toHaveBeenCalledTimes(1); + }); +}); diff --git a/website/docs/core.mdx b/website/docs/core.mdx index d1532842c..3bfbe9bb5 100644 --- a/website/docs/core.mdx +++ b/website/docs/core.mdx @@ -127,3 +127,26 @@ const getEnveloped = envelop({ ] }) ``` + +#### `useEngine` + +This plugin can be used to customize the GraphQL Engine. + +```ts +import { envelop, useEngine } from '@envelop/core' +import { parse, validate, execute, subscribe } from 'graphql' +import { parser } from 'my-custom-graphql-parser' + +const getEnveloped = envelop({ + parse, + validate, + execute, + subscribe, + plugins: [ + useEngine({ + // Now your envelop will use the custom parser instead of the default one provided. + parse: parser + }) + ] +}) +``` diff --git a/website/src/lib/plugins.ts b/website/src/lib/plugins.ts index de1d2ae14..3dd95fc96 100644 --- a/website/src/lib/plugins.ts +++ b/website/src/lib/plugins.ts @@ -79,6 +79,17 @@ export const pluginsArr: Package[] = [ iconUrl: '/logo.png', tags: ['core', 'errors', 'security'], }, + { + identifier: 'use-engine', + title: 'useEngine', + githubReadme: { + repo: 'n1ru4l/envelop', + path: 'packages/core/docs/use-engine.md', + }, + npmPackage: '@envelop/core', + iconUrl: '/logo.png', + tags: ['core', 'utilities'], + }, { identifier: 'use-extend-context', title: 'useExtendContext', From b8f5d71ae609021202a5362e3b81f25c57721092 Mon Sep 17 00:00:00 2001 From: Saihajpreet Singh Date: Fri, 23 Sep 2022 10:18:26 -0400 Subject: [PATCH 2/3] remove assertion --- packages/core/test/plugins/use-engine.spec.ts | 4 ---- 1 file changed, 4 deletions(-) diff --git a/packages/core/test/plugins/use-engine.spec.ts b/packages/core/test/plugins/use-engine.spec.ts index 846c71fd2..a482f0418 100644 --- a/packages/core/test/plugins/use-engine.spec.ts +++ b/packages/core/test/plugins/use-engine.spec.ts @@ -5,7 +5,6 @@ import { parse, validate } from 'graphql'; describe('useEngine', () => { it('should invoke custom execute', async () => { - expect.assertions(1); const custom = jest.fn(); const testInstance = createTestkit([useEngine({ execute: custom })], schema); await testInstance.execute(query); @@ -13,7 +12,6 @@ describe('useEngine', () => { }); it('should invoke custom subscribe', async () => { - expect.assertions(1); const custom = jest.fn(); const testInstance = createTestkit([useEngine({ subscribe: custom })], schema); await testInstance.execute(subscriptionOperationString); @@ -21,7 +19,6 @@ describe('useEngine', () => { }); it('should invoke custom validate', async () => { - expect.assertions(1); const custom = jest.fn(validate); const testInstance = createTestkit([useEngine({ validate: custom })], schema); await testInstance.execute(query); @@ -29,7 +26,6 @@ describe('useEngine', () => { }); it('should invoke custom parse', async () => { - expect.assertions(1); const custom = jest.fn(parse); const testInstance = createTestkit([useEngine({ parse: custom })], schema); await testInstance.execute(query); From 99d06a4d06497c4a4c6edc641b493eabfb1735f5 Mon Sep 17 00:00:00 2001 From: Saihajpreet Singh Date: Mon, 26 Sep 2022 09:23:38 -0400 Subject: [PATCH 3/3] make useEngine plugin the only way to pass engine functions (#1536) * make useEngine plugin the only way to pass engine fns * update types * update docs * Update packages/plugins/apollo-datasources/README.md Co-authored-by: Arda TANRIKULU * prettier: Co-authored-by: Arda TANRIKULU --- packages/core/docs/use-engine.md | 11 +-- packages/core/docs/use-error-handler.md | 7 +- packages/core/docs/use-extend-context.md | 7 +- packages/core/docs/use-logger.md | 7 +- packages/core/docs/use-masked-errors.md | 25 +++++-- packages/core/docs/use-payload-formatter.md | 7 +- packages/core/docs/use-schema-by-context.md | 7 +- packages/core/docs/use-schema.md | 7 +- packages/core/src/create.ts | 8 -- packages/core/src/orchestrator.ts | 17 +++-- packages/core/test/extends.spec.ts | 15 +--- packages/plugins/apollo-datasources/README.md | 7 +- packages/plugins/apollo-federation/README.md | 7 +- .../plugins/apollo-server-errors/README.md | 7 +- .../test/apollo-server-errors.spec.ts | 9 +-- packages/plugins/apollo-tracing/README.md | 7 +- packages/plugins/auth0/README.md | 7 +- packages/plugins/dataloader/README.md | 7 +- packages/plugins/depth-limit/README.md | 7 +- .../plugins/disable-introspection/README.md | 8 +- .../execute-subscription-event/README.md | 11 ++- .../plugins/extended-validation/README.md | 12 +-- .../test/extended-validation.spec.ts | 5 -- .../plugins/filter-operation-type/README.md | 8 +- packages/plugins/fragment-arguments/README.md | 7 +- .../test/use-fragment-arguments.spec.ts | 8 +- packages/plugins/generic-auth/README.md | 15 ++-- packages/plugins/graphql-jit/README.md | 15 ++-- packages/plugins/graphql-middleware/README.md | 7 +- packages/plugins/graphql-modules/README.md | 7 +- .../plugins/immediate-introspection/README.md | 11 ++- packages/plugins/live-query/README.md | 7 +- packages/plugins/newrelic/README.md | 7 +- packages/plugins/on-resolve/README.md | 8 +- packages/plugins/opentelemetry/README.md | 14 +--- .../operation-field-permissions/README.md | 7 +- packages/plugins/parser-cache/README.md | 7 +- .../plugins/persisted-operations/README.md | 21 ++---- packages/plugins/preload-assets/README.md | 8 +- packages/plugins/prometheus/README.md | 21 ++---- packages/plugins/rate-limiter/README.md | 7 +- .../plugins/resource-limitations/README.md | 7 +- .../plugins/response-cache-redis/README.md | 14 +--- packages/plugins/response-cache/README.md | 21 ++---- packages/plugins/sentry/README.md | 7 +- packages/plugins/statsd/README.md | 7 +- packages/plugins/validation-cache/README.md | 7 +- packages/testing/src/index.ts | 24 +++--- website/docs/composing-envelop.mdx | 15 +++- website/docs/core.mdx | 45 ++++-------- website/docs/getting-started.mdx | 15 +--- .../adding-a-graphql-response-cache.mdx | 30 ++++---- .../adding-authentication-with-auth0.mdx | 14 +++- .../docs/guides/integrating-with-databases.md | 8 +- .../docs/guides/migrating-from-v2-to-v3.mdx | 27 +++---- .../docs/guides/monitoring-and-tracing.mdx | 21 ++---- ...ubscription-data-loader-caching-issues.mdx | 7 +- .../docs/guides/securing-your-graphql-api.mdx | 73 +++++-------------- ...using-graphql-features-from-the-future.mdx | 8 +- website/docs/plugins/custom-plugin.mdx | 10 +-- website/docs/plugins/lifecycle.mdx | 7 +- website/docs/plugins/typescript.mdx | 9 +++ website/docs/tracing.mdx | 4 + 63 files changed, 294 insertions(+), 483 deletions(-) diff --git a/packages/core/docs/use-engine.md b/packages/core/docs/use-engine.md index bd9ce10f4..1840a6a24 100644 --- a/packages/core/docs/use-engine.md +++ b/packages/core/docs/use-engine.md @@ -5,17 +5,14 @@ This plugin can be used to customize the GraphQL Engine. ```ts import { envelop, useEngine } from '@envelop/core' import { parse, validate, execute, subscribe } from 'graphql' -import { parser } from 'my-custom-graphql-parser' const getEnveloped = envelop({ - parse, - validate, - execute, - subscribe, plugins: [ useEngine({ - // Now your envelop will use the custom parser instead of the default one provided. - parse: parser + parse, + validate, + execute, + subscribe }) ] }) diff --git a/packages/core/docs/use-error-handler.md b/packages/core/docs/use-error-handler.md index 739b59c6c..060e24953 100644 --- a/packages/core/docs/use-error-handler.md +++ b/packages/core/docs/use-error-handler.md @@ -3,15 +3,12 @@ This plugin triggers a custom function when execution encounters an error. ```ts -import { envelop, useErrorHandler } from '@envelop/core' +import { envelop, useEngine, useErrorHandler } from '@envelop/core' import { parse, validate, execute, subscribe } from 'graphql' const getEnveloped = envelop({ - parse, - validate, - execute, - subscribe, plugins: [ + useEngine({ parse, validate, execute, subscribe }), useErrorHandler((errors, args) => { // This callback is called once, containing all GraphQLError emitted during execution phase }) diff --git a/packages/core/docs/use-extend-context.md b/packages/core/docs/use-extend-context.md index 5267cbddc..9a8137b8f 100644 --- a/packages/core/docs/use-extend-context.md +++ b/packages/core/docs/use-extend-context.md @@ -3,15 +3,12 @@ Easily extends the context with custom fields. ```ts -import { envelop, useExtendContext } from '@envelop/core' +import { envelop, useEngine, useExtendContext } from '@envelop/core' import { parse, validate, execute, subscribe } from 'graphql' const getEnveloped = envelop({ - parse, - validate, - execute, - subscribe, plugins: [ + useEngine({ parse, validate, execute, subscribe }), useExtendContext(async contextSoFar => { return { myCustomField: { diff --git a/packages/core/docs/use-logger.md b/packages/core/docs/use-logger.md index 39a44e15d..87a3b6eca 100644 --- a/packages/core/docs/use-logger.md +++ b/packages/core/docs/use-logger.md @@ -3,15 +3,12 @@ Logs parameters and information about the execution phases. You can easily plug your custom logger. ```ts -import { envelop, useLogger } from '@envelop/core' +import { envelop, useEngine, useLogger } from '@envelop/core' import { parse, validate, execute, subscribe } from 'graphql' const getEnveloped = envelop({ - parse, - validate, - execute, - subscribe, plugins: [ + useEngine({ parse, validate, execute, subscribe }), useLogger({ logFn: (eventName, args) => { // Event could be `execute-start` / `execute-end` / `subscribe-start` / `subscribe-end` diff --git a/packages/core/docs/use-masked-errors.md b/packages/core/docs/use-masked-errors.md index 0bb09e383..4579c386b 100644 --- a/packages/core/docs/use-masked-errors.md +++ b/packages/core/docs/use-masked-errors.md @@ -3,8 +3,8 @@ Prevent unexpected error messages from leaking to the GraphQL clients. ```ts -import { envelop, useSchema, useMaskedErrors } from '@envelop/core' -import { makeExecutableSchema, GraphQLError } from 'graphql' +import { envelop, useSchema, useMaskedErrors, useEngine } from '@envelop/core' +import { makeExecutableSchema, GraphQLError, parse, validate, execute, subscribe } from 'graphql' const schema = makeExecutableSchema({ typeDefs: /* GraphQL */ ` @@ -33,22 +33,31 @@ const schema = makeExecutableSchema({ }) const getEnveloped = envelop({ - plugins: [useSchema(schema), useMaskedErrors()] + plugins: [useEngine({ parse, validate, execute, subscribe }), useSchema(schema), useMaskedErrors()] }) ``` You may customize the default error message `Unexpected error.` with your own `errorMessage`: ```ts +import { envelop, useSchema, useMaskedErrors, useEngine } from '@envelop/core' +import { parse, validate, execute, subscribe } from 'graphql' +import { schema } from './schema' + const getEnveloped = envelop({ - plugins: [useSchema(schema), useMaskedErrors({ errorMessage: 'Something went wrong.' })] + plugins: [ + useEngine({ parse, validate, execute, subscribe }), + useSchema(schema), + useMaskedErrors({ errorMessage: 'Something went wrong.' }) + ] }) ``` Or provide a custom formatter when masking the output: ```ts -import { isGraphQLError, MaskError } from '@envelop/core' +import { isGraphQLError, MaskError, useEngine } from '@envelop/core' +import { parse, validate, execute, subscribe, GraphQLError } from 'graphql' export const customFormatError: MaskError = err => { if (isGraphQLError(err)) { @@ -59,6 +68,10 @@ export const customFormatError: MaskError = err => { } const getEnveloped = envelop({ - plugins: [useSchema(schema), useMaskedErrors({ maskErrorFn: customFormatError })] + plugins: [ + useEngine({ parse, validate, execute, subscribe }), + useSchema(schema), + useMaskedErrors({ maskErrorFn: customFormatError }) + ] }) ``` diff --git a/packages/core/docs/use-payload-formatter.md b/packages/core/docs/use-payload-formatter.md index b83748ec5..afaa1dd11 100644 --- a/packages/core/docs/use-payload-formatter.md +++ b/packages/core/docs/use-payload-formatter.md @@ -5,15 +5,12 @@ Allow you to format/modify execution result payload before returning it to your The second argument `executionArgs` provides additional information for your formatter. It consists of contextValue, variableValues, document, operationName, and other properties. ```ts -import { envelop, usePayloadFormatter } from '@envelop/core' +import { envelop, usePayloadFormatter, useEngine } from '@envelop/core' import { parse, validate, execute, subscribe } from 'graphql' const getEnveloped = envelop({ - parse, - validate, - execute, - subscribe, plugins: [ + useEngine({ parse, validate, execute, subscribe }), usePayloadFormatter((result, executionArgs) => { // Return a modified result here, // Or `false`y value to keep it as-is. diff --git a/packages/core/docs/use-schema-by-context.md b/packages/core/docs/use-schema-by-context.md index cff850017..d7a13890e 100644 --- a/packages/core/docs/use-schema-by-context.md +++ b/packages/core/docs/use-schema-by-context.md @@ -3,7 +3,7 @@ This plugin is the simplest plugin for specifying your GraphQL schema. You can specify a schema created from any tool that emits `GraphQLSchema` object, and you can choose to load the schema based on the initial context (or the incoming request). ```ts -import { envelop, useSchemaByContext } from '@envelop/core' +import { envelop, useSchemaByContext, useEngine } from '@envelop/core' import { parse, validate, execute, subscribe } from 'graphql' async function getSchema({ req }): GraphQLSchema { @@ -15,11 +15,8 @@ async function getSchema({ req }): GraphQLSchema { } const getEnveloped = envelop({ - parse, - validate, - execute, - subscribe, plugins: [ + useEngine({ parse, validate, execute, subscribe }), useSchemaByContext(getSchema) // ... other plugins ... ] diff --git a/packages/core/docs/use-schema.md b/packages/core/docs/use-schema.md index 4671d3781..112a19a06 100644 --- a/packages/core/docs/use-schema.md +++ b/packages/core/docs/use-schema.md @@ -3,17 +3,14 @@ This plugin is the simplest plugin for specifying your GraphQL schema. You can specify a schema created from any tool that emits `GraphQLSchema` object. ```ts -import { envelop, useSchema } from '@envelop/core' +import { envelop, useSchema, useEngine } from '@envelop/core' import { parse, validate, execute, subscribe } from 'graphql' const mySchema = buildSchema(/* ... */) const getEnveloped = envelop({ - parse, - validate, - execute, - subscribe, plugins: [ + useEngine({ parse, validate, execute, subscribe }), useSchema(mySchema) // ... other plugins ... ] diff --git a/packages/core/src/create.ts b/packages/core/src/create.ts index 498a3c499..bb99506ff 100644 --- a/packages/core/src/create.ts +++ b/packages/core/src/create.ts @@ -20,18 +20,10 @@ function notEmpty(value: Optional): value is T { export function envelop>[]>(options: { plugins: PluginsType; enableInternalTracing?: boolean; - parse: ParseFunction; - execute: ExecuteFunction; - validate: ValidateFunction; - subscribe: SubscribeFunction; }): GetEnvelopedFn>> { const plugins = options.plugins.filter(notEmpty); const orchestrator = createEnvelopOrchestrator>>({ plugins, - parse: options.parse, - execute: options.execute, - validate: options.validate, - subscribe: options.subscribe, }); const getEnveloped = ( diff --git a/packages/core/src/orchestrator.ts b/packages/core/src/orchestrator.ts index f3a7f2a9a..070600d5b 100644 --- a/packages/core/src/orchestrator.ts +++ b/packages/core/src/orchestrator.ts @@ -55,22 +55,23 @@ export type EnvelopOrchestrator< type EnvelopOrchestratorOptions = { plugins: Plugin[]; - parse: ParseFunction; - execute: ExecuteFunction; - subscribe: SubscribeFunction; - validate: ValidateFunction; }; +function throwEngineFunctionError(name: string) { + throw Error(`No \`${name}\` function found! Register it using "useEngine" plugin.`); +} + export function createEnvelopOrchestrator({ plugins, - parse, - execute, - subscribe, - validate, }: EnvelopOrchestratorOptions): EnvelopOrchestrator { let schema: any | undefined | null = null; let initDone = false; + const parse: ParseFunction = () => throwEngineFunctionError('parse'); + const validate: ValidateFunction = () => throwEngineFunctionError('validate'); + const execute: ExecuteFunction = () => throwEngineFunctionError('execute'); + const subscribe: SubscribeFunction = () => throwEngineFunctionError('subscribe'); + // Define the initial method for replacing the GraphQL schema, this is needed in order // to allow setting the schema from the onPluginInit callback. We also need to make sure // here not to call the same plugin that initiated the schema switch. diff --git a/packages/core/test/extends.spec.ts b/packages/core/test/extends.spec.ts index d325e7f52..77630af1a 100644 --- a/packages/core/test/extends.spec.ts +++ b/packages/core/test/extends.spec.ts @@ -1,19 +1,14 @@ -import { createSpiedPlugin, createTestkit } from '@envelop/testing'; -import { envelop, useExtendContext, useLogger, useSchema } from '../src/index.js'; +import { createSpiedPlugin, createTestkit, useGraphQLJSEngine } from '@envelop/testing'; +import { envelop, useLogger, useSchema } from '../src/index.js'; import { useEnvelop } from '../src/plugins/use-envelop.js'; import { schema, query } from './common.js'; -import { parse, execute, validate, subscribe } from 'graphql'; describe('extending envelops', () => { it('should allow to extend envelops', async () => { const spiedPlugin = createSpiedPlugin(); const baseEnvelop = envelop({ - plugins: [useLogger(), spiedPlugin.plugin], - parse, - execute, - validate, - subscribe, + plugins: [useGraphQLJSEngine(), useLogger(), spiedPlugin.plugin], }); const onExecuteChildSpy = jest.fn(); @@ -26,10 +21,6 @@ describe('extending envelops', () => { onExecute: onExecuteChildSpy, }, ], - parse, - execute, - validate, - subscribe, }); const teskit = createTestkit(instance); diff --git a/packages/plugins/apollo-datasources/README.md b/packages/plugins/apollo-datasources/README.md index 2debde017..936c91b9a 100644 --- a/packages/plugins/apollo-datasources/README.md +++ b/packages/plugins/apollo-datasources/README.md @@ -12,7 +12,7 @@ yarn add @envelop/apollo-datasources ```ts import { parse, validate, execute, subscribe } from 'graphql' -import { envelop } from '@envelop/core' +import { envelop, useEngine } from '@envelop/core' import { useApolloDataSources } from '@envelop/apollo-datasources' import { RESTDataSource } from 'apollo-datasource-rest' @@ -36,11 +36,8 @@ class MoviesAPI extends RESTDataSource { } const getEnveloped = envelop({ - parse, - validate, - execute, - subscribe, plugins: [ + useEngine({ parse, validate, execute, subscribe }), // ... other plugins ... useApolloDataSources({ dataSources() { diff --git a/packages/plugins/apollo-federation/README.md b/packages/plugins/apollo-federation/README.md index 45a015c36..85b9dbd06 100644 --- a/packages/plugins/apollo-federation/README.md +++ b/packages/plugins/apollo-federation/README.md @@ -11,7 +11,7 @@ yarn add @envelop/apollo-federation ## Usage Example ```ts -import { envelop } from '@envelop/core' +import { envelop, useEngine } from '@envelop/core' import { parse, validate, execute, subscribe } from 'graphql' import { ApolloGateway } from '@apollo/gateway' import { useApolloFederation } from '@envelop/apollo-federation' @@ -30,11 +30,8 @@ await gateway.load() // Then pass it to the plugin configuration const getEnveloped = envelop({ - parse, - validate, - execute, - subscribe, plugins: [ + useEngine({ parse, validate, execute, subscribe }), // ... other plugins ... useApolloFederation({ gateway }) ] diff --git a/packages/plugins/apollo-server-errors/README.md b/packages/plugins/apollo-server-errors/README.md index e82b24f7a..05a3ec159 100644 --- a/packages/plugins/apollo-server-errors/README.md +++ b/packages/plugins/apollo-server-errors/README.md @@ -12,15 +12,12 @@ yarn add @envelop/apollo-server-errors ```ts import { parse, validate, execute, subscribe } from 'graphql' -import { envelop } from '@envelop/core' +import { envelop, useEngine } from '@envelop/core' import { useApolloServerErrors } from '@envelop/apollo-server-errors' const getEnveloped = envelop({ - parse, - validate, - execute, - subscribe, plugins: [ + useEngine({ parse, validate, execute, subscribe }), // ... other plugins ... useApolloServerErrors({ // All fields are optional, and should match what you pass today to ApolloServer diff --git a/packages/plugins/apollo-server-errors/test/apollo-server-errors.spec.ts b/packages/plugins/apollo-server-errors/test/apollo-server-errors.spec.ts index c7a2c36af..a35be5cec 100644 --- a/packages/plugins/apollo-server-errors/test/apollo-server-errors.spec.ts +++ b/packages/plugins/apollo-server-errors/test/apollo-server-errors.spec.ts @@ -3,8 +3,7 @@ import { ApolloServerBase } from 'apollo-server-core'; import { GraphQLSchema } from 'graphql'; import { envelop, useSchema } from '@envelop/core'; import { useApolloServerErrors } from '../src/index.js'; -import { assertSingleExecutionValue } from '@envelop/testing'; -import { parse, execute, validate, subscribe } from 'graphql'; +import { assertSingleExecutionValue, useGraphQLJSEngine } from '@envelop/testing'; // Fix compat by mocking broken function // we can remove this once apollo fixed legacy usages of execute(schema, ...args) @@ -17,11 +16,7 @@ describe('useApolloServerErrors', () => { const executeBoth = async (schema: GraphQLSchema, query: string, debug: boolean) => { const apolloServer = new ApolloServerBase({ schema, debug }); const envelopRuntime = envelop({ - plugins: [useSchema(schema), useApolloServerErrors({ debug })], - parse, - execute, - validate, - subscribe, + plugins: [useGraphQLJSEngine(), useSchema(schema), useApolloServerErrors({ debug })], })({}); return { diff --git a/packages/plugins/apollo-tracing/README.md b/packages/plugins/apollo-tracing/README.md index 969af079f..ef5adba0e 100644 --- a/packages/plugins/apollo-tracing/README.md +++ b/packages/plugins/apollo-tracing/README.md @@ -18,15 +18,12 @@ yarn add @envelop/apollo-tracing ```ts import { parse, validate, execute, subscribe } from 'graphql' -import { envelop } from '@envelop/core' +import { envelop, useEngine } from '@envelop/core' import { useApolloTracing } from '@envelop/apollo-tracing' const getEnveloped = envelop({ - parse, - validate, - execute, - subscribe, plugins: [ + useEngine({ parse, validate, execute, subscribe }), // ... other plugins ... useApolloTracing() ] diff --git a/packages/plugins/auth0/README.md b/packages/plugins/auth0/README.md index c87789787..2af1b6a5c 100644 --- a/packages/plugins/auth0/README.md +++ b/packages/plugins/auth0/README.md @@ -15,15 +15,12 @@ We recommend using the [Adding Authentication with Auth0 guide](https://www.enve ```ts import { parse, validate, execute, subscribe } from 'graphql' -import { envelop } from '@envelop/core' +import { envelop, useEngine } from '@envelop/core' import { useAuth0 } from '@envelop/auth0' const getEnveloped = envelop({ - parse, - validate, - execute, - subscribe, plugins: [ + useEngine({ parse, validate, execute, subscribe }), // ... other plugins ... useAuth0({ onError: e => {}, // In case of an error, you can override it and customize the error your client will get. diff --git a/packages/plugins/dataloader/README.md b/packages/plugins/dataloader/README.md index 5c4102246..4bf3dc01d 100644 --- a/packages/plugins/dataloader/README.md +++ b/packages/plugins/dataloader/README.md @@ -12,16 +12,13 @@ yarn add dataloader @envelop/dataloader ```ts import { parse, validate, execute, subscribe } from 'graphql' -import { envelop } from '@envelop/core' +import { envelop, useEngine } from '@envelop/core' import DataLoader from 'dataloader' import { useDataLoader } from '@envelop/dataloader' const getEnveloped = envelop({ - parse, - validate, - execute, - subscribe, plugins: [ + useEngine({ parse, validate, execute, subscribe }), // ... other plugins ... useDataLoader('users', context => new DataLoader(keys => myBatchGetUsers(keys))) ] diff --git a/packages/plugins/depth-limit/README.md b/packages/plugins/depth-limit/README.md index 589ac67e4..ca846df4d 100644 --- a/packages/plugins/depth-limit/README.md +++ b/packages/plugins/depth-limit/README.md @@ -12,15 +12,12 @@ yarn add @envelop/depth-limit ```ts import { parse, validate, execute, subscribe } from 'graphql' -import { envelop } from '@envelop/core' +import { envelop, useEngine } from '@envelop/core' import { useDepthLimit } from '@envelop/depth-limit' const getEnveloped = envelop({ - parse, - validate, - execute, - subscribe, plugins: [ + useEngine({ parse, validate, execute, subscribe }), // ... other plugins ... useDepthLimit({ maxDepth: 10 diff --git a/packages/plugins/disable-introspection/README.md b/packages/plugins/disable-introspection/README.md index 9cbe9c5b7..dccc4e6b6 100644 --- a/packages/plugins/disable-introspection/README.md +++ b/packages/plugins/disable-introspection/README.md @@ -12,15 +12,11 @@ yarn add @envelop/disable-introspection ```ts import { parse, validate, execute, subscribe } from 'graphql' -import { envelop } from '@envelop/core' +import { envelop, useEngine } from '@envelop/core' import { useDisableIntrospection } from '@envelop/disable-introspection' const getEnveloped = envelop({ - parse, - validate, - execute, - subscribe, - plugins: [useDisableIntrospection()] + plugins: [useEngine({ parse, validate, execute, subscribe }), useDisableIntrospection()] }) ``` diff --git a/packages/plugins/execute-subscription-event/README.md b/packages/plugins/execute-subscription-event/README.md index 715f06d42..ec1192315 100644 --- a/packages/plugins/execute-subscription-event/README.md +++ b/packages/plugins/execute-subscription-event/README.md @@ -8,16 +8,13 @@ Create a new context object per `ExecuteSubscriptionEvent` phase, allowing to by ```ts import { parse, validate, execute, subscribe } from 'graphql' -import { envelop } from '@envelop/core' +import { envelop, useEngine } from '@envelop/core' import { useContextValuePerExecuteSubscriptionEvent } from '@envelop/execute-subscription-event' import { createContext, createDataLoaders } from './context' const getEnveloped = envelop({ - parse, - validate, - execute, - subscribe, plugins: [ + useEngine({ parse, validate, execute, subscribe }), useContext(() => createContext()), useContextValuePerExecuteSubscriptionEvent(() => ({ // Existing context is merged with this context partial @@ -34,12 +31,14 @@ const getEnveloped = envelop({ Alternatively, you can also provide a callback that is invoked after each [`ExecuteSubscriptionEvent`]() phase. ```ts -import { envelop } from '@envelop/core' +import { parse, validate, execute, subscribe } from 'graphql' +import { envelop, useEngine } from '@envelop/core' import { useContextValuePerExecuteSubscriptionEvent } from '@envelop/execute-subscription-event' import { createContext, createDataLoaders } from './context' const getEnveloped = envelop({ plugins: [ + useEngine({ parse, validate, execute, subscribe }), useContext(() => createContext()), useContextValuePerExecuteSubscriptionEvent(({ args }) => ({ onEnd: () => { diff --git a/packages/plugins/extended-validation/README.md b/packages/plugins/extended-validation/README.md index fbaded9ab..3630bdcd1 100644 --- a/packages/plugins/extended-validation/README.md +++ b/packages/plugins/extended-validation/README.md @@ -18,15 +18,12 @@ Then, use the plugin with your validation rules: ```ts import { parse, validate, execute, subscribe } from 'graphql' -import { envelop } from '@envelop/core' +import { envelop, useEngine } from '@envelop/core' import { useExtendedValidation } from '@envelop/extended-validation' const getEnveloped = envelop({ - parse, - validate, - execute, - subscribe, plugins: [ + useEngine({ parse, validate, execute, subscribe }), useExtendedValidation({ rules: [ /* ... your rules here */ @@ -65,10 +62,13 @@ You can use union inputs either via a the SDL flow, by annotating types and fiel First, make sure to add that rule to your plugin usage: ```ts +import { parse, validate, execute, subscribe } from 'graphql' +import { envelop, useEngine } from '@envelop/core' import { useExtendedValidation, OneOfInputObjectsRule } from '@envelop/extended-validation' -const getEnveloped = evelop({ +const getEnveloped = envelop({ plugins: [ + useEngine({ parse, validate, execute, subscribe }), useExtendedValidation({ rules: [OneOfInputObjectsRule] }) diff --git a/packages/plugins/extended-validation/test/extended-validation.spec.ts b/packages/plugins/extended-validation/test/extended-validation.spec.ts index 7cf58c041..e99f74039 100644 --- a/packages/plugins/extended-validation/test/extended-validation.spec.ts +++ b/packages/plugins/extended-validation/test/extended-validation.spec.ts @@ -3,7 +3,6 @@ import { assertSingleExecutionValue, createTestkit } from '@envelop/testing'; import { makeExecutableSchema } from '@graphql-tools/schema'; import { buildSchema, GraphQLError, parse } from 'graphql'; import { useExtendedValidation } from '../src/index.js'; -import { parse as gqlParse, execute as gqlExecute, validate as gqlValidate, subscribe as gqlSubscribe } from 'graphql'; describe('useExtendedValidation', () => { it('supports usage of multiple useExtendedValidation in different plugins', async () => { @@ -115,10 +114,6 @@ describe('useExtendedValidation', () => { rules: [() => ({})], }), ], - parse: gqlParse, - execute: gqlExecute, - validate: gqlValidate, - subscribe: gqlSubscribe, })(); await expect( execute({ diff --git a/packages/plugins/filter-operation-type/README.md b/packages/plugins/filter-operation-type/README.md index eb02bddb1..3fb5b03ec 100644 --- a/packages/plugins/filter-operation-type/README.md +++ b/packages/plugins/filter-operation-type/README.md @@ -12,15 +12,11 @@ yarn add @envelop/filter-operation-type ```ts import { parse, validate, execute, subscribe } from 'graphql' -import { envelop } from '@envelop/core' +import { envelop, useEngine } from '@envelop/core' import { useFilterAllowedOperations } from '@envelop/filter-operation-type' const getEnveloped = envelop({ - parse, - validate, - execute, - subscribe, // only allow execution of subscription operations - plugins: [useFilterAllowedOperations(['subscription'])] + plugins: [useEngine({ parse, validate, execute, subscribe }), useFilterAllowedOperations(['subscription'])] }) ``` diff --git a/packages/plugins/fragment-arguments/README.md b/packages/plugins/fragment-arguments/README.md index ed8ce1e90..16af0bb60 100644 --- a/packages/plugins/fragment-arguments/README.md +++ b/packages/plugins/fragment-arguments/README.md @@ -16,15 +16,12 @@ yarn add @envelop/fragment-arguments ```ts import { parse, validate, execute, subscribe } from 'graphql' -import { envelop } from '@envelop/core' +import { envelop, useEngine } from '@envelop/core' import { useFragmentArguments } from '@envelop/fragment-arguments' const getEnveloped = envelop({ - parse, - validate, - execute, - subscribe, plugins: [ + useEngine({ parse, validate, execute, subscribe }), // ... other plugins ... useFragmentArguments() ] diff --git a/packages/plugins/fragment-arguments/test/use-fragment-arguments.spec.ts b/packages/plugins/fragment-arguments/test/use-fragment-arguments.spec.ts index 4149932d9..f1065ec6b 100644 --- a/packages/plugins/fragment-arguments/test/use-fragment-arguments.spec.ts +++ b/packages/plugins/fragment-arguments/test/use-fragment-arguments.spec.ts @@ -3,7 +3,7 @@ import { oneLine, stripIndent } from 'common-tags'; import { diff } from 'jest-diff'; import { envelop, useSchema } from '@envelop/core'; import { useFragmentArguments } from '../src/index.js'; -import { parse as gqlParse, execute as gqlExecute, validate as gqlValidate, subscribe as gqlSubscribe } from 'graphql'; +import { useGraphQLJSEngine } from '@envelop/testing'; function compareStrings(a: string, b: string): boolean { return a.includes(b); @@ -68,11 +68,7 @@ describe('useFragmentArguments', () => { `); test('can inline fragment with argument', () => { const { parse } = envelop({ - plugins: [useFragmentArguments(), useSchema(schema)], - parse: gqlParse, - execute: gqlExecute, - validate: gqlValidate, - subscribe: gqlSubscribe, + plugins: [useGraphQLJSEngine(), useFragmentArguments(), useSchema(schema)], })({}); const result = parse(/* GraphQL */ ` fragment TestFragment($c: String) on Query { diff --git a/packages/plugins/generic-auth/README.md b/packages/plugins/generic-auth/README.md index ba31b6341..dec8620df 100644 --- a/packages/plugins/generic-auth/README.md +++ b/packages/plugins/generic-auth/README.md @@ -79,7 +79,7 @@ To setup this mode, use the following config: ```ts import { parse, validate, execute, subscribe } from 'graphql' -import { envelop } from '@envelop/core' +import { envelop, useEngine } from '@envelop/core' import { useGenericAuth, ResolveUserFn, ValidateUserFn } from '@envelop/generic-auth' type UserType = { @@ -93,11 +93,8 @@ const validateUser: ValidateUserFn = params => { } const getEnveloped = envelop({ - parse, - validate, - execute, - subscribe, plugins: [ + useEngine({ parse, validate, execute, subscribe }), // ... other plugins ... useGenericAuth({ resolveUserFn, @@ -152,7 +149,8 @@ const GraphQLQueryType = new GraphQLObjectType({ This mode uses the plugin to inject the authenticated user into the `context`, and later you can verify it in your resolvers. ```ts -import { envelop } from '@envelop/core' +import { parse, validate, execute, subscribe } from 'graphql' +import { envelop, useEngine } from '@envelop/core' import { useGenericAuth, ResolveUserFn, ValidateUserFn } from '@envelop/generic-auth' type UserType = { @@ -167,6 +165,7 @@ const validateUser: ValidateUserFn = async params => { const getEnveloped = envelop({ plugins: [ + useEngine({ parse, validate, execute, subscribe }), // ... other plugins ... useGenericAuth({ resolveUserFn, @@ -197,7 +196,8 @@ const resolvers = { This mode is similar to option #2, but it uses the `@auth` SDL directive or `auth` field extension for protecting specific GraphQL fields. ```ts -import { envelop } from '@envelop/core' +import { parse, validate, execute, subscribe } from 'graphql' +import { envelop, useEngine } from '@envelop/core' import { useGenericAuth, ResolveUserFn, ValidateUserFn } from '@envelop/generic-auth' type UserType = { @@ -212,6 +212,7 @@ const validateUser: ValidateUserFn = params => { const getEnveloped = envelop({ plugins: [ + useEngine({ parse, validate, execute, subscribe }), // ... other plugins ... useGenericAuth({ resolveUserFn, diff --git a/packages/plugins/graphql-jit/README.md b/packages/plugins/graphql-jit/README.md index 45ec30327..e6eef37fe 100644 --- a/packages/plugins/graphql-jit/README.md +++ b/packages/plugins/graphql-jit/README.md @@ -12,15 +12,12 @@ yarn add @envelop/graphql-jit ```ts import { parse, validate, execute, subscribe } from 'graphql' -import { envelop } from '@envelop/core' +import { envelop, useEngine } from '@envelop/core' import { useGraphQlJit } from '@envelop/graphql-jit' const getEnveloped = envelop({ - parse, - validate, - execute, - subscribe, plugins: [ + useEngine({ parse, validate, execute, subscribe }), // ... other plugins ... useGraphQlJit( { @@ -39,11 +36,13 @@ const getEnveloped = envelop({ If you wish to conditionally use the JIT executor based on the incoming request, you can use `enableIf` config flag and return a `boolean` based on the `ExecutionArgs`: ```ts -import { envelop } from '@envelop/core' +import { parse, validate, execute, subscribe } from 'graphql' +import { envelop, useEngine } from '@envelop/core' import { useGraphQlJit } from '@envelop/graphql-jit' const getEnveloped = envelop({ plugins: [ + useEngine({ parse, validate, execute, subscribe }), // ... other plugins ... useGraphQlJit( { @@ -62,11 +61,13 @@ const getEnveloped = envelop({ You can configure the JIT cache with the following options: ```ts -import { envelop } from '@envelop/core' +import { parse, validate, execute, subscribe } from 'graphql' +import { envelop, useEngine } from '@envelop/core' import { useGraphQlJit } from '@envelop/graphql-jit' const getEnveloped = envelop({ plugins: [ + useEngine({ parse, validate, execute, subscribe }), // ... other plugins ... useGraphQlJit( { diff --git a/packages/plugins/graphql-middleware/README.md b/packages/plugins/graphql-middleware/README.md index 85c750370..76a3c44ec 100644 --- a/packages/plugins/graphql-middleware/README.md +++ b/packages/plugins/graphql-middleware/README.md @@ -16,7 +16,7 @@ You can use any type of middleware defined for `graphql-middleware`, here's an e ```ts import { parse, validate, execute, subscribe } from 'graphql' -import { envelop } from '@envelop/core' +import { envelop, useEngine } from '@envelop/core' import { useGraphQLMiddleware } from '@envelop/graphql-middleware' import { rule, shield, and, or, not } from 'graphql-shield' @@ -36,11 +36,8 @@ const permissions = shield({ }) const getEnveloped = envelop({ - parse, - validate, - execute, - subscribe, plugins: [ + useEngine({ parse, validate, execute, subscribe }), // ... other plugins ... useSchema(mySchema), useGraphQLMiddleware([permissions]) diff --git a/packages/plugins/graphql-modules/README.md b/packages/plugins/graphql-modules/README.md index fe3c256a2..584a12a90 100644 --- a/packages/plugins/graphql-modules/README.md +++ b/packages/plugins/graphql-modules/README.md @@ -14,7 +14,7 @@ yarn add @envelop/graphql-modules ```ts import { parse, validate, execute, subscribe } from 'graphql' -import { envelop } from '@envelop/core' +import { envelop, useEngine } from '@envelop/core' import { createApplication } from 'graphql-modules' import { useGraphQLModules } from '@envelop/graphql-modules' @@ -25,11 +25,8 @@ const myApp = createApplication({ }) const getEnveloped = envelop({ - parse, - validate, - execute, - subscribe, plugins: [ + useEngine({ parse, validate, execute, subscribe }), // ... other plugins ... useGraphQLModules(myApp) ] diff --git a/packages/plugins/immediate-introspection/README.md b/packages/plugins/immediate-introspection/README.md index 5f3d0f1d0..38b0223e2 100644 --- a/packages/plugins/immediate-introspection/README.md +++ b/packages/plugins/immediate-introspection/README.md @@ -15,15 +15,12 @@ The `useImmediateIntrospection` can be used to short circuit any further context ```ts import { parse, validate, execute, subscribe } from 'graphql' -import { envelop, useImmediateIntrospection } from '@envelop/core' +import { envelop, useImmediateIntrospection, useEngine } from '@envelop/core' import { schema } from './schema' const getEnveloped = envelop({ - parse, - validate, - execute, - subscribe, plugins: [ + useEngine({ parse, validate, execute, subscribe }), useSchema(schema), useImmediateIntrospection() // additional plugins @@ -34,12 +31,14 @@ const getEnveloped = envelop({ In case you want to authorize that an user is authenticated before allowing introspection the plugin must be placed in front of the `useImmediateIntrospection()` call. ```ts -import { envelop, useImmediateIntrospection } from '@envelop/core' +import { parse, validate, execute, subscribe } from 'graphql' +import { envelop, useImmediateIntrospection, useEngine } from '@envelop/core' import { schema } from './schema' import { useAuthorization } from './useAuthorization' const getEnveloped = envelop({ plugins: [ + useEngine({ parse, validate, execute, subscribe }), useSchema(schema), useAuthorization(), // place this before useImmediateIntrospection() diff --git a/packages/plugins/live-query/README.md b/packages/plugins/live-query/README.md index 3ba0688d7..5cb239f71 100644 --- a/packages/plugins/live-query/README.md +++ b/packages/plugins/live-query/README.md @@ -28,7 +28,7 @@ yarn add @envelop/live-query @n1ru4l/in-memory-live-query-store ```ts import { parse, validate, execute, subscribe } from 'graphql' -import { envelop, useSchema, useExtendContext } from '@envelop/core' +import { envelop, useSchema, useExtendContext, useEngine } from '@envelop/core' import { useLiveQuery } from '@envelop/live-query' import { InMemoryLiveQueryStore } from '@n1ru4l/in-memory-live-query-store' import { makeExecutableSchema } from '@graphql-tools/schema' @@ -60,11 +60,8 @@ setInterval(() => { }, 1000) const getEnveloped = envelop({ - parse, - validate, - execute, - subscribe, plugins: [ + useEngine({ parse, validate, execute, subscribe }), useSchema(schema), useLiveQuery({ liveQueryStore }), useExtendContext(() => ({ greetings })) diff --git a/packages/plugins/newrelic/README.md b/packages/plugins/newrelic/README.md index 75867c60c..a5ba910ef 100644 --- a/packages/plugins/newrelic/README.md +++ b/packages/plugins/newrelic/README.md @@ -32,15 +32,12 @@ yarn add newrelic @envelop/newrelic ```ts import { parse, validate, execute, subscribe } from 'graphql' -import { envelop } from '@envelop/core' +import { envelop, useEngine } from '@envelop/core' import { useNewRelic } from '@envelop/newrelic' const getEnveloped = envelop({ - parse, - validate, - execute, - subscribe, plugins: [ + useEngine({ parse, validate, execute, subscribe }), // ... other plugins ... useNewRelic({ includeOperationDocument: true, // default `false`. When set to `true`, includes the GraphQL document defining the operations and fragments diff --git a/packages/plugins/on-resolve/README.md b/packages/plugins/on-resolve/README.md index 326065b65..dd271e1c0 100644 --- a/packages/plugins/on-resolve/README.md +++ b/packages/plugins/on-resolve/README.md @@ -15,12 +15,14 @@ yarn add @envelop/on-resolve ### Custom field resolutions ```ts -import { envelop } from '@envelop/core' +import { parse, validate, execute, subscribe } from 'graphql' +import { envelop, useEngine } from '@envelop/core' import { useOnResolve } from '@envelop/on-resolve' import { specialResolver } from './my-resolvers' const getEnveloped = envelop({ plugins: [ + useEngine({ parse, validate, execute, subscribe }), // ... other plugins ... useOnResolve(async function onResolve({ context, root, args, info, replaceResolver }) { // replace special field's resolver @@ -42,7 +44,8 @@ const getEnveloped = envelop({ ### Tracing ```ts -import { envelop, Plugin } from '@envelop/core' +import { parse, validate, execute, subscribe } from 'graphql' +import { envelop, useEngine, Plugin } from '@envelop/core' import { useOnResolve } from '@envelop/on-resolve' interface FieldTracingPluginContext { @@ -91,6 +94,7 @@ function useFieldTracing() { const getEnveloped = envelop({ plugins: [ + useEngine({ parse, validate, execute, subscribe }), // ... other plugins ... useSpecialResolve() ] diff --git a/packages/plugins/opentelemetry/README.md b/packages/plugins/opentelemetry/README.md index f46a3ec18..d4f1ebd47 100644 --- a/packages/plugins/opentelemetry/README.md +++ b/packages/plugins/opentelemetry/README.md @@ -16,15 +16,12 @@ By default, this plugin prints the collected telemetry to the console: ```ts import { parse, validate, execute, subscribe } from 'graphql' -import { envelop } from '@envelop/core' +import { envelop, useEngine } from '@envelop/core' import { useOpenTelemetry } from '@envelop/opentelemetry' const getEnveloped = envelop({ - parse, - validate, - execute, - subscribe, plugins: [ + useEngine({ parse, validate, execute, subscribe }), // ... other plugins ... useOpenTelemetry({ resolvers: true, // Tracks resolvers calls, and tracks resolvers thrown errors @@ -39,7 +36,7 @@ If you wish to use custom tracer/exporter, create it and pass it. This example i ```ts import { parse, validate, execute, subscribe } from 'graphql' -import { envelop } from '@envelop/core' +import { envelop, useEngine } from '@envelop/core' import { useOpenTelemetry } from '@envelop/opentelemetry' import { JaegerExporter } from '@opentelemetry/exporter-jaeger' import { SimpleSpanProcessor, BasicTracerProvider } from '@opentelemetry/tracing' @@ -53,11 +50,8 @@ provider.addSpanProcessor(new SimpleSpanProcessor(exporter)) provider.register() const getEnveloped = envelop({ - parse, - validate, - execute, - subscribe, plugins: [ + useEngine({ parse, validate, execute, subscribe }), // ... other plugins ... useOpenTelemetry( { diff --git a/packages/plugins/operation-field-permissions/README.md b/packages/plugins/operation-field-permissions/README.md index 05066c887..81d21ec1d 100644 --- a/packages/plugins/operation-field-permissions/README.md +++ b/packages/plugins/operation-field-permissions/README.md @@ -14,15 +14,12 @@ yarn add @envelop/operation-field-permissions ```ts import { parse, validate, execute, subscribe } from 'graphql' -import { envelop, useSchema } from '@envelop/core' +import { envelop, useSchema, useEngine } from '@envelop/core' import { useOperationFieldPermissions } from '@envelop/operation-field-permissions' const getEnveloped = envelop({ - parse, - validate, - execute, - subscribe, plugins: [ + useEngine({ parse, validate, execute, subscribe }), useSchema(schema), useOperationFieldPermissions({ // we can access graphql context here diff --git a/packages/plugins/parser-cache/README.md b/packages/plugins/parser-cache/README.md index d39cab4b6..624121de9 100644 --- a/packages/plugins/parser-cache/README.md +++ b/packages/plugins/parser-cache/README.md @@ -14,15 +14,12 @@ yarn add @envelop/parser-cache ```ts import { parse, validate, execute, subscribe } from 'graphql' -import { envelop } from '@envelop/core' +import { envelop, useEngine } from '@envelop/core' import { useParserCache } from '@envelop/parser-cache' const getEnveloped = envelop({ - parse, - validate, - execute, - subscribe, plugins: [ + useEngine({ parse, validate, execute, subscribe }), // ... other plugins ... useParserCache({ // options goes here diff --git a/packages/plugins/persisted-operations/README.md b/packages/plugins/persisted-operations/README.md index 9536163f7..042f7d861 100644 --- a/packages/plugins/persisted-operations/README.md +++ b/packages/plugins/persisted-operations/README.md @@ -16,7 +16,7 @@ The most basic implementation can use an in-memory JS `Map` wrapper with a `Stor ```ts import { parse, validate, execute, subscribe } from 'graphql' -import { envelop } from '@envelop/core' +import { envelop, useEngine } from '@envelop/core' import { usePersistedOperations, InMemoryStore } from '@envelop/persisted-operations' // You can retrieve the store in any way (e.g. from a remote source) and implement it with a simple Map / Key->Value @@ -29,11 +29,8 @@ const store = new InMemoryStore({ }) const getEnveloped = envelop({ - parse, - validate, - execute, - subscribe, plugins: [ + useEngine({ parse, validate, execute, subscribe }), // ... other plugins ... usePersistedOperations({ store: myStore @@ -64,7 +61,7 @@ usePersistedOperations({ ```ts import { parse, validate, execute, subscribe } from 'graphql' -import { envelop } from '@envelop/core' +import { envelop, useEngine } from '@envelop/core' import { usePersistedOperations, JsonFileStore } from '@envelop/persisted-operations' const persistedOperationsStore = new JsonFilesStore() @@ -77,11 +74,8 @@ persistedOperationsStore.loadFromFileSync(filePath) // load and parse persisted- await persistedOperationsStore.loadFromFile(filePath) // load and parse persisted-operations files const getEnveloped = envelop({ - parse, - validate, - execute, - subscribe, plugins: [ + useEngine({ parse, validate, execute, subscribe }), // ... other plugins ... usePersistedOperations({ store: persistedOperationsStore @@ -96,14 +90,11 @@ The `store` parameter accepts both a `Store` instance, or a function. If you nee ```ts import { parse, validate, execute, subscribe } from 'graphql' -import { envelop } from '@envelop/core' +import { envelop, useEngine } from '@envelop/core' const getEnveloped = envelop({ - parse, - validate, - execute, - subscribe, plugins: [ + useEngine({ parse, validate, execute, subscribe }), // ... other plugins ... usePersistedOperations({ store: context => { diff --git a/packages/plugins/preload-assets/README.md b/packages/plugins/preload-assets/README.md index 50fd86665..43bfed6a9 100644 --- a/packages/plugins/preload-assets/README.md +++ b/packages/plugins/preload-assets/README.md @@ -13,7 +13,7 @@ yarn add @envelop/preload-assets ```ts import { parse, validate, execute, subscribe } from 'graphql' -import { envelop } from '@envelop/core' +import { envelop, useEngine } from '@envelop/core' import { usePreloadAssets } from '@envelop/preload-asset' import { makeExecutableSchema } from 'graphql' @@ -35,11 +35,7 @@ const schema = makeExecutableSchema({ }) const getEnveloped = envelop({ - parse, - validate, - execute, - subscribe, - plugins: [usePreloadAssets()] + plugins: [useEngine({ parse, validate, execute, subscribe }), usePreloadAssets()] }) ``` diff --git a/packages/plugins/prometheus/README.md b/packages/plugins/prometheus/README.md index 6583158ec..e2f01c526 100644 --- a/packages/plugins/prometheus/README.md +++ b/packages/plugins/prometheus/README.md @@ -27,15 +27,12 @@ yarn add prom-client @envelop/prometheus ```ts import { parse, validate, execute, subscribe } from 'graphql' -import { envelop } from '@envelop/core' +import { envelop, useEngine } from '@envelop/core' import { usePrometheus } from '@envelop/prometheus' const getEnveloped = envelop({ - parse, - validate, - execute, - subscribe, plugins: [ + useEngine({ parse, validate, execute, subscribe }), // ... other plugins ... usePrometheus({ // all optional, and by default, all set to false, please opt-in to the metrics you wish to get @@ -63,17 +60,14 @@ You can customize the `prom-client` `Registry` object if you are using a custom ```ts import { parse, validate, execute, subscribe } from 'graphql' -import { envelop } from '@envelop/core' +import { envelop, useEngine } from '@envelop/core' import { Registry } from 'prom-client' const myRegistry = new Registry() const getEnveloped = envelop({ - parse, - validate, - execute, - subscribe, plugins: [ + useEngine({ parse, validate, execute, subscribe }), // ... other plugins ... usePrometheus({ // ... config ... @@ -96,15 +90,12 @@ Each tracing field supports custom `prom-client` objects, and custom `labels` a ```ts import { parse, validate, execute, subscribe } from 'graphql' import { Histogram } from 'prom-client' -import { envelop } from '@envelop/core' +import { envelop, useEngine } from '@envelop/core' import { createHistogram, usePrometheus } from '@envelop/prometheus' const getEnveloped = envelop({ - parse, - validate, - execute, - subscribe, plugins: [ + useEngine({ parse, validate, execute, subscribe }), // ... other plugins ... usePrometheus({ // all optional, and by default, all set to false, please opt-in to the metrics you wish to get diff --git a/packages/plugins/rate-limiter/README.md b/packages/plugins/rate-limiter/README.md index 4cb201849..bcd66b293 100644 --- a/packages/plugins/rate-limiter/README.md +++ b/packages/plugins/rate-limiter/README.md @@ -12,7 +12,7 @@ yarn add @envelop/rate-limiter ```ts import { parse, validate, execute, subscribe } from 'graphql' -import { envelop } from '@envelop/core' +import { envelop, useEngine } from '@envelop/core' import { useRateLimiter, IdentifyFn } from '@envelop/rate-limiter' const identifyFn: IdentifyFn = async context => { @@ -20,11 +20,8 @@ const identifyFn: IdentifyFn = async context => { } const getEnveloped = envelop({ - parse, - validate, - execute, - subscribe, plugins: [ + useEngine({ parse, validate, execute, subscribe }), // ... other plugins ... useRateLimiter({ identifyFn diff --git a/packages/plugins/resource-limitations/README.md b/packages/plugins/resource-limitations/README.md index 8e72088da..c1c418c9c 100644 --- a/packages/plugins/resource-limitations/README.md +++ b/packages/plugins/resource-limitations/README.md @@ -12,15 +12,12 @@ yarn add @envelop/resource-limitations ```ts import { parse, validate, execute, subscribe } from 'graphql' -import { envelop } from '@envelop/core' +import { envelop, useEngine } from '@envelop/core' import { useResourceLimitations } from '@envelop/resource-limitations' const getEnveloped = envelop({ - parse, - validate, - execute, - subscribe, plugins: [ + useEngine({ parse, validate, execute, subscribe }), // ... other plugins ... useResourceLimitations({ nodeCostLimit: 500000, // optional, default to 500000 diff --git a/packages/plugins/response-cache-redis/README.md b/packages/plugins/response-cache-redis/README.md index 62844e05d..af284623f 100644 --- a/packages/plugins/response-cache-redis/README.md +++ b/packages/plugins/response-cache-redis/README.md @@ -23,7 +23,7 @@ In order to use the Redis cache, you need to: ```ts import { parse, validate, execute, subscribe } from 'graphql' -import { envelop } from '@envelop/core' +import { envelop, useEngine } from '@envelop/core' import { useResponseCache } from '@envelop/response-cache' import { createRedisCache } from '@envelop/response-cache-redis' import Redis from 'ioredis' @@ -45,11 +45,8 @@ const redis = new Redis('rediss://:1234567890@my-redis-db.example.com:30652') const cache = createRedisCache({ redis }) const getEnveloped = envelop({ - parse, - validate, - execute, - subscribe, plugins: [ + useEngine({ parse, validate, execute, subscribe }), // ... other plugins ... useResponseCache({ cache }) ] @@ -60,7 +57,7 @@ const getEnveloped = envelop({ ```ts import { parse, validate, execute, subscribe } from 'graphql' -import { envelop } from '@envelop/core' +import { envelop, useEngine } from '@envelop/core' import { useResponseCache } from '@envelop/response-cache' import { createRedisCache } from '@envelop/response-cache-redis' @@ -72,11 +69,8 @@ const redis = new Redis('rediss://:1234567890@my-redis-db.example.com:30652') const cache = createRedisCache({ redis }) const getEnveloped = envelop({ - parse, - validate, - execute, - subscribe, plugins: [ + useEngine({ parse, validate, execute, subscribe }), // ... other plugins ... useResponseCache({ ttl: 2000, diff --git a/packages/plugins/response-cache/README.md b/packages/plugins/response-cache/README.md index 145b1ee60..d738adbc3 100644 --- a/packages/plugins/response-cache/README.md +++ b/packages/plugins/response-cache/README.md @@ -39,15 +39,12 @@ The in-memory LRU cache is used by default. ```ts import { parse, validate, execute, subscribe } from 'graphql' -import { envelop } from '@envelop/core' +import { envelop, useEngine } from '@envelop/core' import { useResponseCache } from '@envelop/response-cache' const getEnveloped = envelop({ - parse, - validate, - execute, - subscribe, plugins: [ + useEngine({ parse, validate, execute, subscribe }), // ... other plugins ... useResponseCache({ // use global cache for all operations @@ -61,17 +58,14 @@ Or, you may create the in-memory LRU cache explicitly. ```ts import { parse, validate, execute, subscribe } from 'graphql' -import { envelop } from '@envelop/core' +import { envelop, useEngine } from '@envelop/core' import { useResponseCache, createInMemoryCache } from '@envelop/response-cache' const cache = createInMemoryCache() const getEnveloped = envelop({ - parse, - validate, - execute, - subscribe, plugins: [ + useEngine({ parse, validate, execute, subscribe }), // ... other plugins ... useResponseCache({ cache, @@ -87,15 +81,12 @@ const getEnveloped = envelop({ ```ts import { parse, validate, execute, subscribe } from 'graphql' -import { envelop } from '@envelop/core' +import { envelop, useEngine } from '@envelop/core' import { useResponseCache } from '@envelop/response-cache' const getEnveloped = envelop({ - parse, - validate, - execute, - subscribe, plugins: [ + useEngine({ parse, validate, execute, subscribe }), // ... other plugins ... useResponseCache({ ttl: 2000, diff --git a/packages/plugins/sentry/README.md b/packages/plugins/sentry/README.md index c7f882b77..cb6f8c3e0 100644 --- a/packages/plugins/sentry/README.md +++ b/packages/plugins/sentry/README.md @@ -31,17 +31,14 @@ yarn add @sentry/node @sentry/tracing @envelop/sentry ```ts import { parse, validate, execute, subscribe } from 'graphql' -import { envelop } from '@envelop/core' +import { envelop, useEngine } from '@envelop/core' import { useSentry } from '@envelop/sentry' // do this only once in you entry file. import '@sentry/tracing' const getEnveloped = envelop({ - parse, - validate, - execute, - subscribe, plugins: [ + useEngine({ parse, validate, execute, subscribe }), // ... other plugins ... useSentry({ includeRawResult: false, // set to `true` in order to include the execution result in the metadata collected diff --git a/packages/plugins/statsd/README.md b/packages/plugins/statsd/README.md index 581545dd9..056b2f40e 100644 --- a/packages/plugins/statsd/README.md +++ b/packages/plugins/statsd/README.md @@ -26,7 +26,7 @@ yarn add hot-shots @envelop/stats ```ts import { parse, validate, execute, subscribe } from 'graphql' -import { envelop } from '@envelop/core' +import { envelop, useEngine } from '@envelop/core' import { useStatsD } from '@envelop/statsd' import StatsD from 'hot-shots' @@ -36,11 +36,8 @@ const client = new StatsD({ }) const getEnveloped = envelop({ - parse, - validate, - execute, - subscribe, plugins: [ + useEngine({ parse, validate, execute, subscribe }), // ... other plugins ... useStatsD({ client, diff --git a/packages/plugins/validation-cache/README.md b/packages/plugins/validation-cache/README.md index db52e73d0..42d37dd20 100644 --- a/packages/plugins/validation-cache/README.md +++ b/packages/plugins/validation-cache/README.md @@ -14,15 +14,12 @@ yarn add @envelop/validation-cache ```ts import { parse, validate, execute, subscribe } from 'graphql' -import { envelop } from '@envelop/core' +import { envelop, useEngine } from '@envelop/core' import { useValidationCache } from '@envelop/validation-cache' const getEnveloped = envelop({ - parse, - validate, - execute, - subscribe, plugins: [ + useEngine({ parse, validate, execute, subscribe }), // ... other plugins ... useValidationCache({ // options goes here diff --git a/packages/testing/src/index.ts b/packages/testing/src/index.ts index ffcec3835..ee1d9b3d8 100644 --- a/packages/testing/src/index.ts +++ b/packages/testing/src/index.ts @@ -10,10 +10,14 @@ import { subscribe, validate, } from 'graphql'; -import { useSchema, envelop, isAsyncIterable } from '@envelop/core'; +import { useSchema, envelop, isAsyncIterable, useEngine } from '@envelop/core'; import { GetEnvelopedFn, Plugin } from '@envelop/types'; import { mapSchema as cloneSchema, isDocumentNode } from '@graphql-tools/utils'; +export const useGraphQLJSEngine = () => { + return useEngine({ parse, validate, execute, subscribe }); +}; + export type ModifyPluginsFn = (plugins: Plugin[]) => Plugin[]; export type PhaseReplacementParams = | { @@ -109,22 +113,20 @@ export function createTestkit( const phasesReplacements: PhaseReplacementParams[] = []; let getEnveloped = Array.isArray(pluginsOrEnvelop) ? envelop({ - plugins: [...(schema ? [useSchema(cloneSchema(schema))] : []), ...pluginsOrEnvelop], - parse, - execute, - validate, - subscribe, + plugins: [ + ...(schema ? [useGraphQLJSEngine(), useSchema(cloneSchema(schema))] : [useGraphQLJSEngine()]), + ...pluginsOrEnvelop, + ], }) : pluginsOrEnvelop; return { modifyPlugins(modifyPluginsFn: ModifyPluginsFn) { getEnveloped = envelop({ - plugins: [...(schema ? [useSchema(cloneSchema(schema))] : []), ...modifyPluginsFn(getEnveloped._plugins)], - parse, - execute, - validate, - subscribe, + plugins: [ + ...(schema ? [useGraphQLJSEngine(), useSchema(cloneSchema(schema))] : [useGraphQLJSEngine()]), + ...modifyPluginsFn(getEnveloped._plugins), + ], }); }, mockPhase(phaseReplacement: PhaseReplacementParams) { diff --git a/website/docs/composing-envelop.mdx b/website/docs/composing-envelop.mdx index f5e1276b3..9cf29e863 100644 --- a/website/docs/composing-envelop.mdx +++ b/website/docs/composing-envelop.mdx @@ -10,7 +10,8 @@ This allows writing shareable pieces that can be used Here's a small example for sharing envelops: ```ts -import { envelop, useEnvelop, useSchema } from '@envelop/core' +import { parse, validate, execute, subscribe } from 'graphql' +import { envelop, useEnvelop, useSchema, useEngine } from '@envelop/core' // Somewhere where you wish to create the basics of what you wish to share // This defined the base plugins you wish to use as base. @@ -21,7 +22,17 @@ const myBaseEnvelop = envelop({ // Later, when you create your own Envelop, you can extend that and add custom plugins. // You can also specify the schema only at this point const myEnvelop = envelop({ - plugins: [useEnvelop(myBaseEnvelop), useSchema(myServerSchema), useMyCustomPlugin()] + plugins: [ + useEngine({ + parse, + validate, + execute, + subscribe + }), + useEnvelop(myBaseEnvelop), + useSchema(myServerSchema), + useMyCustomPlugin() + ] }) ``` diff --git a/website/docs/core.mdx b/website/docs/core.mdx index 3bfbe9bb5..7261e54a8 100644 --- a/website/docs/core.mdx +++ b/website/docs/core.mdx @@ -11,17 +11,14 @@ This is the core package for `envelop`, it comes with the execution pipeline wra This plugin is the simplest plugin for specifying your GraphQL schema. You can specify a schema created from any tool that emits `GraphQLSchema` object. ```ts -import { envelop, useSchema } from '@envelop/core' +import { envelop, useSchema, useEngine } from '@envelop/core' import { parse, validate, execute, subscribe } from 'graphql' const mySchema = buildSchema(/* ... */) const getEnveloped = envelop({ - parse, - validate, - execute, - subscribe, plugins: [ + useEngine({ parse, validate, execute, subscribe }), useSchema(mySchema) // ... other plugins ... ] @@ -33,15 +30,12 @@ const getEnveloped = envelop({ This plugin invokes a custom function with the every time execution encounters an error. ```ts -import { envelop, useErrorHandler } from '@envelop/core' +import { envelop, useErrorHandler, useEngine } from '@envelop/core' import { parse, validate, execute, subscribe } from 'graphql' const getEnveloped = envelop({ - parse, - validate, - execute, - subscribe, plugins: [ + useEngine({ parse, validate, execute, subscribe }), useErrorHandler(error => { // This callback is called per each GraphQLError emitted during execution phase }) @@ -57,15 +51,12 @@ const getEnveloped = envelop({ Easily extends the context with custom fields. ```ts -import { envelop, useExtendContext } from '@envelop/core' +import { envelop, useExtendContext, useEngine } from '@envelop/core' import { parse, validate, execute, subscribe } from 'graphql' const getEnveloped = envelop({ - parse, - validate, - execute, - subscribe, plugins: [ + useEngine({ parse, validate, execute, subscribe }), useExtendContext(async contextSoFar => { return { myCustomField: { @@ -83,15 +74,12 @@ const getEnveloped = envelop({ Logs parameters and information about the execution phases. You can easily plug in your custom logger. ```ts -import { envelop, useLogger } from '@envelop/core' +import { envelop, useLogger, useEngine } from '@envelop/core' import { parse, validate, execute, subscribe } from 'graphql' const getEnveloped = envelop({ - parse, - validate, - execute, - subscribe, plugins: [ + useEngine({ parse, validate, execute, subscribe }), useLogger({ logFn: (eventName, args) => { // Event could be `execute-start` / `execute-end` / `subscribe-start` / `subscribe-end` @@ -110,15 +98,12 @@ Allow you to format/modify the execution result payload before returning it to y The second argument `executionArgs` provides additional information for your formatter. It consists of contextValue, variableValues, document, operationName, and other properties. ```ts -import { envelop, usePayloadFormatter } from '@envelop/core' +import { envelop, usePayloadFormatter, useEngine } from '@envelop/core' import { parse, validate, execute, subscribe } from 'graphql' const getEnveloped = envelop({ - parse, - validate, - execute, - subscribe, plugins: [ + useEngine({ parse, validate, execute, subscribe }), usePayloadFormatter((result, executionArgs) => { // Return a modified result here, // Or `false`y value to keep it as-is. @@ -138,14 +123,12 @@ import { parse, validate, execute, subscribe } from 'graphql' import { parser } from 'my-custom-graphql-parser' const getEnveloped = envelop({ - parse, - validate, - execute, - subscribe, plugins: [ useEngine({ - // Now your envelop will use the custom parser instead of the default one provided. - parse: parser + parse, + validate, + execute, + subscribe }) ] }) diff --git a/website/docs/getting-started.mdx b/website/docs/getting-started.mdx index cc5df19dd..b6abadef3 100644 --- a/website/docs/getting-started.mdx +++ b/website/docs/getting-started.mdx @@ -18,7 +18,7 @@ After installing the `@envelop/core` package, you can use the `envelop` function ```ts import { parse, validate, execute, subcribe } from 'graphql' -import { envelop, useSchema } from '@envelop/core' +import { envelop, useSchema, useEngine } from '@envelop/core' import { buildSchema } from 'graphql' const schema = buildSchema(/* GraphQL */ ` @@ -28,11 +28,7 @@ const schema = buildSchema(/* GraphQL */ ` `) export const getEnveloped = envelop({ - parse, - validate, - execute, - subcribe, - plugins: [useSchema(schema)] + plugins: [useEngine({ parse, validate, execute, subscribe }), useSchema(schema)] }) ``` @@ -64,7 +60,7 @@ Let's add a parser and validation cache, so sending the same operation string se ```ts import { parse, validate, execute, subcribe } from 'graphql' -import { envelop, useSchema } from '@envelop/core' +import { envelop, useSchema, useEngine } from '@envelop/core' import { buildSchema } from 'graphql' import { useParserCache } from '@envelop/parser-cache' import { useValidationCache } from '@envelop/validation-cache' @@ -76,11 +72,8 @@ const schema = buildSchema(/* GraphQL */ ` `) const getEnveloped = envelop({ - parse, - validate, - execute, - subcribe, plugins: [ + useEngine({ parse, validate, execute, subscribe }), // all enabled plugins useSchema(schema), useParserCache(), diff --git a/website/docs/guides/adding-a-graphql-response-cache.mdx b/website/docs/guides/adding-a-graphql-response-cache.mdx index 3dc8ec2e0..7283b0dd2 100644 --- a/website/docs/guides/adding-a-graphql-response-cache.mdx +++ b/website/docs/guides/adding-a-graphql-response-cache.mdx @@ -211,11 +211,13 @@ The goal of the response cache plugin is to educate how such mechanisms are impl Adding a response cache to an existing envelop GraphQL server setup is as easy as adding the plugin: ```ts -import { envelop } from '@envelop/core' +import { parse, validate, execute, subscribe } from 'graphql' +import { envelop, useEngine } from '@envelop/core' import { useResponseCache } from '@envelop/response-cache' const getEnveloped = envelop({ plugins: [ + useEngine({ parse, validate, execute, subscribe }), // ... other plugins ... useResponseCache() ] @@ -225,7 +227,8 @@ const getEnveloped = envelop({ If you need to imperatively invalidate you can do that by providing the cache to the plugin: ```ts -import { envelop } from '@envelop/core' +import { parse, validate, execute, subscribe } from 'graphql' +import { envelop, useEngine } from '@envelop/core' import { useResponseCache, createInMemoryCache } from '@envelop/response-cache' import { emitter } from './event-emitter' @@ -242,6 +245,7 @@ emitter.on('invalidate', entity => { const getEnveloped = envelop({ plugins: [ + useEngine({ parse, validate, execute, subscribe }), // ... other plugins ... useResponseCache({ cache }) ] @@ -251,11 +255,13 @@ const getEnveloped = envelop({ The caching behavior can be fully customized. A TTL can be provided global or more granular per type or schema coordinate. ```ts -import { envelop } from '@envelop/core' +import { parse, validate, execute, subscribe } from 'graphql' +import { envelop, useEngine } from '@envelop/core' import { useResponseCache } from '@envelop/response-cache' const getEnveloped = envelop({ plugins: [ + useEngine({ parse, validate, execute, subscribe }), // ... other plugins ... useResponseCache({ // cache operations for 1 hour by default @@ -278,11 +284,13 @@ const getEnveloped = envelop({ Need to cache based on the user? No problem. ```ts -import { envelop } from '@envelop/core' +import { parse, validate, execute, subscribe } from 'graphql' +import { envelop, useEngine } from '@envelop/core' import { useResponseCache } from '@envelop/response-cache' const getEnveloped = envelop({ plugins: [ + useEngine({ parse, validate, execute, subscribe }), // ... other plugins ... useResponseCache({ // context is the GraphQL context that would be used for execution @@ -298,15 +306,12 @@ Don't want to automatically invalidate based on mutations? Also configurable! ```ts import { parse, validate, execute, subscribe } from 'graphql' -import { envelop } from '@envelop/core' +import { envelop, useEngine } from '@envelop/core' import { useResponseCache } from '@envelop/response-cache' const getEnveloped = envelop({ - parse, - validate, - execute, - subscribe, plugins: [ + useEngine({ parse, validate, execute, subscribe }), // ... other plugins ... useResponseCache({ // some might prefer invalidating only based on a database write log @@ -332,7 +337,7 @@ Here's an example: ```ts import { parse, validate, execute, subscribe } from 'graphql' -import { envelop } from '@envelop/core' +import { envelop, useEngine } from '@envelop/core' import { useResponseCache } from '@envelop/response-cache' import { createRedisCache } from '@envelop/response-cache-redis' import Redis from 'ioredis' @@ -348,11 +353,8 @@ const redis = new Redis('rediss://:1234567890@my-redis-db.example.com:30652') const cache = createRedisCache({ redis }) const getEnveloped = envelop({ - parse, - validate, - execute, - subscribe, plugins: [ + useEngine({ parse, validate, execute, subscribe }), // ... other plugins ... useResponseCache({ cache }) ] diff --git a/website/docs/guides/adding-authentication-with-auth0.mdx b/website/docs/guides/adding-authentication-with-auth0.mdx index cec80c009..5ca4b7314 100644 --- a/website/docs/guides/adding-authentication-with-auth0.mdx +++ b/website/docs/guides/adding-authentication-with-auth0.mdx @@ -23,17 +23,15 @@ import { PackageInstall } from '@guild-docs/client' ## Adding the Auth0 Plugin to the Envelop setup ```ts +import { engine, useSchema, useEngine } from '@envelop/core' import { useAuth0 } from '@envelop/auth0' import { parse, execute, subcribe, validate } from 'graphql' // ... other imports and code const getEnveloped = envelop({ - parse, - execute, - subcribe, - validate, plugins: [ + useEngine({ parse, validate, execute, subscribe }), useSchema(schema), useAuth0({ domain: 'TODO', @@ -90,12 +88,15 @@ This is our `domain` configuration value. Let's quickly add this information to our envelop setup. ```ts +import { envelop, useEngine, useSchema } from '@envelop/core' +import { parse, execute, subcribe, validate } from 'graphql' import { useAuth0 } from '@envelop/auth0' // ... other imports and code const getEnveloped = envelop({ plugins: [ + useEngine({ parse, validate, execute, subscribe }), useSchema(schema), useAuth0({ domain: '{account_name}.{region}.auth0.com', @@ -273,8 +274,13 @@ In the GraphQL schema of this guide we only re-expose the auth0 authentication i A full user object could be loaded when building the context via the [`useExtendContext` plugin](https://www.envelop.dev/plugins/use-extend-context). ```ts +import { parse, execute, subcribe, validate } from 'graphql' +import { envelop, useEngine, useSchema, useExtendContext } from '@envelop/core' +import { useAuth0 } from '@envelop/auth0' + const getEnveloped = envelop({ plugins: [ + useEngine({ parse, validate, execute, subscribe }), useSchema(schema), useAuth0(auth0Config), useExtendContext(async context => { diff --git a/website/docs/guides/integrating-with-databases.md b/website/docs/guides/integrating-with-databases.md index 908ed8f4c..289d1f023 100644 --- a/website/docs/guides/integrating-with-databases.md +++ b/website/docs/guides/integrating-with-databases.md @@ -47,7 +47,7 @@ a plugin which adds a client to the context add release it at the end of the req ```ts import { parse, validate, execute, subscribe } from 'graphql' -import { isAsyncIterable } from '@envelop/core' +import { isAsyncIterable, useEngine } from '@envelop/core' import { useSchema } from './use-schema' const pool = new Pool({ maxClients: 10 }) @@ -74,11 +74,7 @@ const resolvers = { } const getEnvelop = envelop({ - parse, - validate, - execute, - subscribe, - plugins: [useSchema(/*...*/), databaseClientPlugin] + plugins: [useEngine({ parse, validate, execute, subscribe }), useSchema(/*...*/), databaseClientPlugin] }) ``` diff --git a/website/docs/guides/migrating-from-v2-to-v3.mdx b/website/docs/guides/migrating-from-v2-to-v3.mdx index 4388b0462..d852d8058 100644 --- a/website/docs/guides/migrating-from-v2-to-v3.mdx +++ b/website/docs/guides/migrating-from-v2-to-v3.mdx @@ -7,11 +7,12 @@ With [new major version](https://github.com/n1ru4l/envelop/pull/1487) comes brea We have designed the new `envelop` to be engine agnostic. This allows you to use any GraphQL engine you want. This means that `graphql` is no longer a peer dependency and `envelop` simply just wraps the `parse`, `validate`, `execute` and `subscribe` functions that you provide. ```diff -import { envelop } from '@envelop/core'; +- import { envelop } from '@envelop/core'; ++ import { envelop, useEngine } from '@envelop/core'; + import { parse, validate, execute, subscribe } from 'graphql'; - const getEnveloped = envelop([ ... ]) -+ const getEnveloped = envelop({ parse, validate, execute, subscribe, plugins: [ ... ] }) ++ const getEnveloped = envelop({ plugins: [ useEngine({ parse, validate, execute, subscribe }), ... ] }) ``` ### 2. Removed orchestrator tracing @@ -24,7 +25,7 @@ We decided to drop this and instead [provide a new plugin](https://github.com/n1 ```diff import { parse, validate, execute, subscribe } from 'graphql' -import { envelop, Plugin } from '@envelop/core' +import { envelop, Plugin, useEngine } from '@envelop/core' + import { useOnResolve } from '@envelop/on-resolve' import { onResolverCalled } from './my-resolver' @@ -39,11 +40,8 @@ function useResolve(): Plugin { } const getEnveloped = envelop({ - parse, - validate, - execute, - subscribe, plugins: [ + useEngine({ parse, validate, execute, subscribe }), // ... other plugins ... useResolve(), ], @@ -73,18 +71,14 @@ This was a mistake from beginning as we cannot asynchronously `validate` and `pa You should first load your schema and then create the envelop instance and pass the schema to it. ```ts -import { envelop, useSchema } from '@envelop/core' +import { envelop, useSchema, useEngine } from '@envelop/core' import { parse, validate, execute, subscribe } from 'graphql' // this assume you are running latest node js version where top-level await is supported const schema = await loadSchema() const getEnveloped = envelop({ - parse, - validate, - execute, - subscribe, - plugins: [useSchema(schema)] + plugins: [useEngine({ parse, validate, execute, subscribe }), useSchema(schema)] }) ``` @@ -98,17 +92,14 @@ This utility was used to enable plugins conditionally. For a better developer ex ```diff - import { envelop, useMaskedErrors, enableIf } from '@envelop/core' -+ import { envelop, useMaskedErrors } from '@envelop/core' ++ import { envelop, useMaskedErrors, useEngine } from '@envelop/core' import { parse, validate, execute, subscribe } from 'graphql' const isProd = process.env.NODE_ENV === 'production' const getEnveloped = envelop({ - parse, - validate, - execute, - subscribe, plugins: [ + useEngine({ parse, validate, execute, subscribe }), // This plugin is enabled only in production - enableIf(isProd, useMaskedErrors()) + isProd && useMaskedErrors() diff --git a/website/docs/guides/monitoring-and-tracing.mdx b/website/docs/guides/monitoring-and-tracing.mdx index 3775ffc01..d32bb0cef 100644 --- a/website/docs/guides/monitoring-and-tracing.mdx +++ b/website/docs/guides/monitoring-and-tracing.mdx @@ -18,15 +18,12 @@ As with any other envelop plugin the setup is straight forward! ```ts import { parse, validate, execute, subscribe } from 'graphql' -import { envelop } from '@envelop/core' +import { envelop, useEngine } from '@envelop/core' import { useSentry } from '@envelop/sentry' const getEnveloped = envelop({ - parse, - validate, - execute, - subscribe, plugins: [ + useEngine({ parse, validate, execute, subscribe }), // ... other plugins ... useSentry() ] @@ -59,15 +56,12 @@ As with any other envelop plugin the setup is straight forward! ```ts import { parse, validate, execute, subscribe } from 'graphql' -import { envelop } from '@envelop/core' +import { envelop, useEngine } from '@envelop/core' import { useNewRelic } from '@envelop/newrelic' const getEnveloped = envelop({ - parse, - validate, - execute, - subscribe, plugins: [ + useEngine({ parse, validate, execute, subscribe }), // ... other plugins ... useNewRelic({ // ... @@ -84,15 +78,12 @@ Apollo introduced the apollo-tracing specification and implemented it in apollo- ```ts import { parse, validate, execute, subscribe } from 'graphql' -import { envelop } from '@envelop/core' +import { envelop, useEngine } from '@envelop/core' import { useApolloTracing } from '@envelop/apollo-tracing' const getEnveloped = envelop({ - parse, - validate, - execute, - subscribe, plugins: [ + useEngine({ parse, validate, execute, subscribe }), // ... other plugins ... useApolloTracing() ] diff --git a/website/docs/guides/resolving-subscription-data-loader-caching-issues.mdx b/website/docs/guides/resolving-subscription-data-loader-caching-issues.mdx index cf50e67bb..c3926e855 100644 --- a/website/docs/guides/resolving-subscription-data-loader-caching-issues.mdx +++ b/website/docs/guides/resolving-subscription-data-loader-caching-issues.mdx @@ -52,16 +52,13 @@ As your project scales this, however, can become a tedious task. With the `useCo ```ts import { parse, validate, execute, subscribe } from 'graphql' -import { envelop } from '@envelop/core' +import { envelop, useEngine } from '@envelop/core' import { useContextValuePerExecuteSubscriptionEvent } from '@envelop/execute-subscription-event' import { createContext, createDataLoaders } from './context' const getEnveloped = envelop({ - parse, - validate, - execute, - subscribe, plugins: [ + useEngine({ parse, validate, execute, subscribe }), // ... other plugins ... useContext(() => createContext()), useContextValuePerExecuteSubscriptionEvent(() => ({ diff --git a/website/docs/guides/securing-your-graphql-api.mdx b/website/docs/guides/securing-your-graphql-api.mdx index d81b566f4..9b8ad3caa 100644 --- a/website/docs/guides/securing-your-graphql-api.mdx +++ b/website/docs/guides/securing-your-graphql-api.mdx @@ -75,7 +75,7 @@ With the [`usePersistedOperations`](/plugins/use-persisted-operations) plugin su ```ts import { parse, validate, execute, subscribe } from 'graphql' -import { envelop } from '@envelop/core' +import { envelop, useEngine } from '@envelop/core' import { usePersistedOperations, PersistedOperationsStore } from '@envelop/persisted-operations' import persistedOperations from './codegen-artifact' @@ -85,11 +85,8 @@ const store: PersistedOperationsStore = { } const getEnveloped = envelop({ - parse, - validate, - execute, - subscribe, plugins: [ + useEngine({ parse, validate, execute, subscribe }), // ... other plugins ... usePersistedOperations({ store: myStore, @@ -135,15 +132,12 @@ You can limit the amount of allowed tokens per operation and automatically abort ```ts import { parse, validate, execute, subscribe } from 'graphql' -import { envelop } from '@envelop/core' +import { envelop, useEngine } from '@envelop/core' import { maxTokensPlugin } from '@escape.tech/graphql-armor-max-tokens' const getEnveloped = envelop({ - parse, - validate, - execute, - subscribe, plugins: [ + useEngine({ parse, validate, execute, subscribe }), // ... other plugins ... maxTokensPlugin({ maxTokenCount: 1000 // Number of tokens allowed in a document @@ -161,15 +155,12 @@ The [`maxDepthPlugin`](/plugins/graphql-armor-max-depth) allows a maximum nestin ```ts import { parse, validate, execute, subscribe } from 'graphql' -import { envelop } from '@envelop/core' +import { envelop, useEngine } from '@envelop/core' import { maxDepthPlugin } from '@escape.tech/graphql-armor-max-depth' const getEnveloped = envelop({ - parse, - validate, - execute, - subscribe, plugins: [ + useEngine({ parse, validate, execute, subscribe }), // ... other plugins ... maxDepthPlugin({ n: 10 // Number of depth allowed @@ -192,15 +183,12 @@ The [`useRateLimiter`](/plugins/use-rate-limiter) to limit access to resources, ```ts import { parse, validate, execute, subscribe } from 'graphql' -import { envelop } from '@envelop/core' +import { envelop, useEngine } from '@envelop/core' import { useRateLimiter } from '@envelop/rate-limiter' const getEnveloped = envelop({ - parse, - validate, - execute, - subscribe, plugins: [ + useEngine({ parse, validate, execute, subscribe }), // ... other plugins ... useRateLimiter({ /// ... @@ -232,17 +220,14 @@ We recommend using an existing third-party service such as [Auth0](https://auth0 With the `@envelop/auth0` plugin, you can simply bootstrap the authorization process. ```tsx -import { envelop, useExtendContext } from '@envelop/core' +import { envelop, useExtendContext, useSchema, useEngine } from '@envelop/core' import { parse, validate, execute, subscribe } from 'graphql' import { useAuth0 } from '@envelop/auth0' import { schema } from './schema' const getEnveloped = envelop({ - parse, - validate, - execute, - subscribe, plugins: [ + useEngine({ parse, validate, execute, subscribe }), useSchema(schema), useAuth0({ domain: 'YOUR_AUTH0_DOMAIN_HERE', @@ -295,15 +280,12 @@ Libraries such as [`graphql-public-schema-filter`](https://github.com/n1ru4l/gra ```ts import { parse, validate, execute, subscribe } from 'graphql' -import { envelop, useSchemaByContext } from '@envelop/core' +import { envelop, useSchemaByContext, useEngine } from '@envelop/core' import { privateSchema, publicSchema } from './schema' const getEnveloped = envelop({ - parse, - validate, - execute, - subscrib, plugins: [ + useEngine({ parse, validate, execute, subscribe }), // ... other plugins (e.g. useAuth0) useSchemaByContext(context => (context.isPrivateApiUser ? privateSchema : publicSchema)) ] @@ -318,16 +300,13 @@ This plugin is perfect for use-cases where you want the whole schema being intro ```ts import { parse, validate, execute, subscribe } from 'graphql' -import { envelop, useSchema } from '@envelop/core' +import { envelop, useSchema, useEngine } from '@envelop/core' import { useOperationFieldPermissions } from '@envelop/operation-field-permissions' import { schema } from './schema' const getEnveloped = envelop({ - parse, - validate, - execute, - subscribe, plugins: [ + useEngine({ parse, validate, execute, subscribe }), // ... other plugins (e.g. useAuth0) useSchema(schema), useOperationFieldPermissions({ @@ -374,7 +353,7 @@ would result in the following error: In most GraphQL servers any thrown error or rejected promise will result in the original error leaking to the outside world. Some frameworks have custom logic for catching unexpected errors and mapping them to an unexpected error instead. With envelop this abstraction is now possible with any server! Just add the [`useMaskedErrors`](https://www.envelop.dev/plugins/use-masked-errors) plugin and throw `EnvelopError` instances for expected errors that should leak to the outside world. You can also add custom extension fields that will also be sent to the clients. ```tsx -import { envelop, useSchema, useMaskedErrors, EnvelopError } from '@envelop/core' +import { envelop, useSchema, useMaskedErrors, EnvelopError, useEngine } from '@envelop/core' import { parse, validate, execute, subscribe } from 'graphql' import { makeExecutableSchema } from '@graphql-tools/schema' @@ -405,11 +384,7 @@ const schema = makeExecutableSchema({ }) const getEnveloped = envelop({ - parse, - validate, - execute, - subscribe, - plugins: [useSchema(schema), useMaskedErrors()] + plugins: [useEngine({ parse, validate, execute, subscribe }), useSchema(schema), useMaskedErrors()] }) ``` @@ -420,16 +395,12 @@ For people migrating from apollo-server the [`useApolloServerErrors`](/plugins/u If your schema includes sensitive information that you want to hide from the outside world, disabling the schema introspection is a possible solution. The [`useDisableIntrospection`](/plugins/use-disable-introspection) plugin solves that in a single line of code! ```ts -import { envelop } from '@envelop/core' +import { envelop, useEngine } from '@envelop/core' import { parse, validate, execute, subscribe } from 'graphql' import { useDisableIntrospection } from '@envelop/disable-introspection' const getEnveloped = envelop({ - parse, - validate, - execute, - subscribe, - plugins: [useDisableIntrospection()] + plugins: [useEngine({ parse, validate, execute, subscribe }), useDisableIntrospection()] }) ``` @@ -442,16 +413,12 @@ Thus we rather recommend using persisted operations instead of disabling schema If you disabled schema introspection, you should also disable field suggestions as these allow reverse-engineering a GraphQL schema. ```ts -import { envelop } from '@envelop/core' +import { envelop, useEngine } from '@envelop/core' import { parse, validate, execute, subscribe } from 'graphql' import { useRateLimiter } from '@envelop/rate-limiter' import { blockFieldSuggestions } from '@escape.tech/graphql-armor-block-field-suggestions' const getEnveloped = envelop({ - parse, - validate, - execute, - subscribe, - plugins: [blockFieldSuggestions()] + plugins: [useEngine({ parse, validate, execute, subscribe }), blockFieldSuggestions()] }) ``` diff --git a/website/docs/guides/using-graphql-features-from-the-future.mdx b/website/docs/guides/using-graphql-features-from-the-future.mdx index dc84de9b2..23ca2aabc 100644 --- a/website/docs/guides/using-graphql-features-from-the-future.mdx +++ b/website/docs/guides/using-graphql-features-from-the-future.mdx @@ -144,11 +144,13 @@ While the following input would be invalid and not pass the validation phase: Adding support to the existing envelop setup is straight-forward: ```ts -import { envelop } from '@envelop/core' +import { parse, validate, execute, subscribe } from 'graphql' +import { envelop, useEngine } from '@envelop/core' import { useExtendedValidation, OneOfInputObjectsRule } from '@envelop/extended-validation' const getEnveloped = envelop({ plugins: [ + useEngine({ parse, validate, execute, subscribe }), // ... other plugins useExtendedValidation({ rules: [OneOfInputObjectsRule] @@ -286,11 +288,13 @@ There is a [pr for graphql.js](https://github.com/graphql/graphql-js/pull/3152) Envelop already allows using fragment arguments by extending the GraphQL parser. We don't recommend using this for production usage! Please only use it for research or learning purposes! ```ts -import { envelop } from '@envelop/core' +import { parse, validate, execute, subscribe } from 'graphql' +import { envelop, useEngine } from '@envelop/core' import { useFragmentArguments } from '@envelop/fragment-arguments' const getEnveloped = envelop({ plugins: [ + useEngine({ parse, validate, execute, subscribe }), // ... other plugins ... useFragmentArguments() ] diff --git a/website/docs/plugins/custom-plugin.mdx b/website/docs/plugins/custom-plugin.mdx index 58288be6e..be38410a6 100644 --- a/website/docs/plugins/custom-plugin.mdx +++ b/website/docs/plugins/custom-plugin.mdx @@ -22,6 +22,8 @@ https://github.com/n1ru4l/envelop/blob/main/packages/types/src/plugin.ts Here's a simple example that allows you to print the execution and parsing parameter. ```ts +import { parse, validate, execute, subscribe } from 'graphql' +import { useEngine } from '@envelop/core' import type { Plugin } from '@envelop/core' const myPlugin: Plugin = { @@ -45,6 +47,7 @@ const myPlugin: Plugin = { const getEnveloped = envelop({ plugins: [ + useEngine({ parse, validate, execute, subscribe }), /// ... other plugins ..., myPlugin ] @@ -56,7 +59,7 @@ const getEnveloped = envelop({ Often plugins require additional configurartion. A common pattern for doing this is by creating a factor function that returns a `Plugin`. ```ts -import { envelop } from '@envelop/core' +import { envelop, useEngine } from '@envelop/core' import { parse, validate, subscribe, execute } from 'graphql' const myPlugin = (shouldPrintResult: boolean): Plugin => { @@ -76,11 +79,8 @@ const myPlugin = (shouldPrintResult: boolean): Plugin => { } const getEnveloped = envelop({ - parse, - validate, - subscribe, - execute, plugins: [ + useEngine({ parse, validate, execute, subscribe }), /// ... other plugins ..., myPlugin(true) ] diff --git a/website/docs/plugins/lifecycle.mdx b/website/docs/plugins/lifecycle.mdx index a9fce2f09..076d39d05 100644 --- a/website/docs/plugins/lifecycle.mdx +++ b/website/docs/plugins/lifecycle.mdx @@ -37,15 +37,12 @@ While calling `getEnveloped` function (the result of `envelop({ plugins: [ ... ] In most cases, you'll pass the incoming HTTP request (or, just the relevant parts of it) to make it available for the plugins you use: ```ts -import { envelop } from '@envelop/core' +import { envelop, useEngine } from '@envelop/core' import { parse, validate, execute, subscribe } from 'graphql' const getEnveloped = envelop({ - parse, - validate, - execute, - subscribe, plugins: [ + useEngine({ parse, validate, execute, subscribe }) /* ... plugins ... */ ] }) diff --git a/website/docs/plugins/typescript.mdx b/website/docs/plugins/typescript.mdx index 23fd613fb..2a9c65c37 100644 --- a/website/docs/plugins/typescript.mdx +++ b/website/docs/plugins/typescript.mdx @@ -27,9 +27,18 @@ export const useMyPlugin = (): Plugin<{ myContext: string }> => { As a user of a plugin, you get type-inference based on the plugins that you use, for example: ```ts +import { parse, validate, execute, subscribe } from 'graphql' +import { envelop, useEngine } from '@envelop/core' + // At this point, the context known to envelop is `{ pluginA: string, pluginB: string }` const getEnveloped = envelop({ plugins: [ + useEngine({ + parse, + validate, + execute, + subscribe + }), usePluginA(), // Defined with Plugin<{ pluginA: string }> usePluginB() // Defined with Plugin<{ pluginB: string }> ] diff --git a/website/docs/tracing.mdx b/website/docs/tracing.mdx index d883ba35f..0f44b8a5f 100644 --- a/website/docs/tracing.mdx +++ b/website/docs/tracing.mdx @@ -7,8 +7,12 @@ title: Tracing If you wish to enable it, pass `enableInternalTracing: true` to your envelop instance: ```ts +import { parse, validate, execute, subscribe } from 'graphql' +import { envelop, useEngine } from '@envelop/core' + const getEnveloped = envelop({ plugins: [ + useEngine({ parse, validate, execute, subscribe }) // ... ], enableInternalTracing: true