From 219c41e5e465614ffecd0c79fdb4d909f163a68b Mon Sep 17 00:00:00 2001 From: Laurin Quast Date: Mon, 26 Apr 2021 09:54:35 +0200 Subject: [PATCH] feat: add @envelop/filter-operation-type package (#131) * feat: add @envelop/filter-operation-type package * update readme Co-authored-by: Dotan Simha --- .changeset/orange-bananas-rhyme.md | 5 +++ README.md | 45 ++++++++++--------- .../plugins/filter-operation-type/README.md | 20 +++++++++ .../filter-operation-type/package.json | 38 ++++++++++++++++ .../src/filter-operation-type-rule.ts | 14 ++++++ .../filter-operation-type/src/index.ts | 12 +++++ 6 files changed, 112 insertions(+), 22 deletions(-) create mode 100644 .changeset/orange-bananas-rhyme.md create mode 100644 packages/plugins/filter-operation-type/README.md create mode 100644 packages/plugins/filter-operation-type/package.json create mode 100644 packages/plugins/filter-operation-type/src/filter-operation-type-rule.ts create mode 100644 packages/plugins/filter-operation-type/src/index.ts diff --git a/.changeset/orange-bananas-rhyme.md b/.changeset/orange-bananas-rhyme.md new file mode 100644 index 0000000000..5fa1b5b6b0 --- /dev/null +++ b/.changeset/orange-bananas-rhyme.md @@ -0,0 +1,5 @@ +--- +'@envelop/filter-operation-type': patch +--- + +Initial implementation of the plugin. diff --git a/README.md b/README.md index ef1ce857b9..182a44152b 100644 --- a/README.md +++ b/README.md @@ -108,28 +108,29 @@ Here's a list of integrations and examples: We provide a few built-in plugins within the `@envelop/core`, and many more plugins as standalone packages. -| Name | Package | Description | -| ----------------------- | ---------------------------------------------------------------------------- | ------------------------------------------------------------------------------ | -| useSchema | [`@envelop/core`](./packages/core#useschema) | Simplest plugin to provide your GraphQL schema. | -| useErrorHandler | [`@envelop/core`](./packages/core#useerrorhandler) | Get notified when any execution error occurs. | -| useExtendContext | [`@envelop/core`](./packages/core#useextendcontext) | Extend execution context based on your needs. | -| useLogger | [`@envelop/core`](./packages/core#uselogger) | Simple, yet powerful logging for GraphQL execution. | -| usePayloadFormatter | [`@envelop/core`](./packages/core#usepayloadformatter) | Format, clean and customize execution result. | -| useTiming | [`@envelop/core`](./packages/core#usetiming) | Simple timing/tracing mechanism for your execution. | -| useGraphQLJit | [`@envelop/graphql-jit`](./packages/plugins/graphql-jit) | Custom executor based on GraphQL-JIT. | -| useParserCache | [`@envelop/parser-cache`](./packages/plugins/parser-cache) | Simple LRU for caching `parse` results. | -| useValidationCache | [`@envelop/validation-cache`](./packages/plugins/validation-cache) | Simple LRU for caching `validate` results. | -| useDepthLimit | [`@envelop/depth-limit`](./packages/plugins/depth-limit) | Limits the depth of your GraphQL selection sets. | -| useDataLoader | [`@envelop/dataloader`](./packages/plugins/dataloader) | Simply injects a DataLoader instance into your context. | -| useApolloTracing | [`@envelop/apollo-tracing`](./packages/plugins/apollo-tracing) | Integrates timing with Apollo-Tracing format (for GraphQL Playground) | -| useSentry | [`@envelop/sentry`](./packages/plugins/sentry) | Tracks performance, timing and errors and reports it to Sentry. | -| useOpenTelemetry | [`@envelop/opentelemetry`](./packages/plugins/opentelemetry) | Tracks performance, timing and errors and reports in OpenTelemetry structure. | -| useGenericAuth | [`@envelop/generic-auth`](./packages/plugins/generic-auth) | Super flexible authentication, also supports `@auth` directive . | -| useAuth0 | [`@envelop/auth0`](./packages/plugins/auth0) | Validates Auth0 JWT tokens and injects the authenticated user to your context. | -| useGraphQLModules | [`@envelop/graphql-modules`](./packages/plugins/graphql-modules) | Integrates the execution lifecycle of GraphQL-Modules. | -| useGraphQLMiddleware | [`@envelop/graphql-middleware`](./packages/plugins/graphql-middleware) | Integrates middlewares written for `graphql-middleware` | -| useRateLimiter | [`@envelop/rate-limiter`](./packages/plugins/rate-limiter) | Limit request rate via `@rateLimit` directive | -| useDisableIntrospection | [`@envelop/disable-introspection`](./packages/plugins/disable-introspection) | Disables introspection by adding a validation rule | +| Name | Package | Description | +| -------------------------- | ---------------------------------------------------------------------------- | ------------------------------------------------------------------------------ | +| useSchema | [`@envelop/core`](./packages/core#useschema) | Simplest plugin to provide your GraphQL schema. | +| useErrorHandler | [`@envelop/core`](./packages/core#useerrorhandler) | Get notified when any execution error occurs. | +| useExtendContext | [`@envelop/core`](./packages/core#useextendcontext) | Extend execution context based on your needs. | +| useLogger | [`@envelop/core`](./packages/core#uselogger) | Simple, yet powerful logging for GraphQL execution. | +| usePayloadFormatter | [`@envelop/core`](./packages/core#usepayloadformatter) | Format, clean and customize execution result. | +| useTiming | [`@envelop/core`](./packages/core#usetiming) | Simple timing/tracing mechanism for your execution. | +| useGraphQLJit | [`@envelop/graphql-jit`](./packages/plugins/graphql-jit) | Custom executor based on GraphQL-JIT. | +| useParserCache | [`@envelop/parser-cache`](./packages/plugins/parser-cache) | Simple LRU for caching `parse` results. | +| useValidationCache | [`@envelop/validation-cache`](./packages/plugins/validation-cache) | Simple LRU for caching `validate` results. | +| useDepthLimit | [`@envelop/depth-limit`](./packages/plugins/depth-limit) | Limits the depth of your GraphQL selection sets. | +| useDataLoader | [`@envelop/dataloader`](./packages/plugins/dataloader) | Simply injects a DataLoader instance into your context. | +| useApolloTracing | [`@envelop/apollo-tracing`](./packages/plugins/apollo-tracing) | Integrates timing with Apollo-Tracing format (for GraphQL Playground) | +| useSentry | [`@envelop/sentry`](./packages/plugins/sentry) | Tracks performance, timing and errors and reports it to Sentry. | +| useOpenTelemetry | [`@envelop/opentelemetry`](./packages/plugins/opentelemetry) | Tracks performance, timing and errors and reports in OpenTelemetry structure. | +| useGenericAuth | [`@envelop/generic-auth`](./packages/plugins/generic-auth) | Super flexible authentication, also supports `@auth` directive . | +| useAuth0 | [`@envelop/auth0`](./packages/plugins/auth0) | Validates Auth0 JWT tokens and injects the authenticated user to your context. | +| useGraphQLModules | [`@envelop/graphql-modules`](./packages/plugins/graphql-modules) | Integrates the execution lifecycle of GraphQL-Modules. | +| useGraphQLMiddleware | [`@envelop/graphql-middleware`](./packages/plugins/graphql-middleware) | Integrates middlewares written for `graphql-middleware` | +| useRateLimiter | [`@envelop/rate-limiter`](./packages/plugins/rate-limiter) | Limit request rate via `@rateLimit` directive | +| useDisableIntrospection | [`@envelop/disable-introspection`](./packages/plugins/disable-introspection) | Disables introspection by adding a validation rule | +| useFilterAllowedOperations | [`@envelop/filter-operation-type`](./packages/plugins/filter-operation-type) | Only allow execution of specific operation types | ## Sharing `envelop`s diff --git a/packages/plugins/filter-operation-type/README.md b/packages/plugins/filter-operation-type/README.md new file mode 100644 index 0000000000..03156838bb --- /dev/null +++ b/packages/plugins/filter-operation-type/README.md @@ -0,0 +1,20 @@ +## `@envelop/filter-operation-type` + +This plugins injects a validation rule into the validation phase that only allows the specified operation types (e.g. `subscription`, `query` or `mutation`). + +## Getting Started + +``` +yarn add @envelop/filter-operation-type +``` + +## Usage Example + +```ts +import { envelop } from '@envelop/core'; +import { useFilterAllowedOperations } from '@envelop/filter-operation-type'; +const getEnveloped = envelop({ + // only allow execution of subscription operations + plugins: [useFilterAllowedOperations(['subscription'])], +}); +``` diff --git a/packages/plugins/filter-operation-type/package.json b/packages/plugins/filter-operation-type/package.json new file mode 100644 index 0000000000..ae133aae82 --- /dev/null +++ b/packages/plugins/filter-operation-type/package.json @@ -0,0 +1,38 @@ +{ + "name": "@envelop/filter-operation-type", + "version": "0.0.0", + "author": "Dotan Simha ", + "license": "MIT", + "sideEffects": false, + "repository": { + "type": "git", + "url": "https://github.com/dotansimha/envelop.git", + "directory": "packages/plugins/filter-operation-type" + }, + "main": "dist/index.cjs.js", + "module": "dist/index.esm.js", + "typings": "dist/index.d.ts", + "typescript": { + "definition": "dist/index.d.ts" + }, + "scripts": { + "test": "jest", + "prepack": "bob prepack" + }, + "dependencies": {}, + "devDependencies": { + "bob-the-bundler": "1.2.0", + "graphql": "15.5.0", + "typescript": "4.2.4" + }, + "peerDependencies": { + "graphql": "^14.0.0 || ^15.0.0" + }, + "buildOptions": { + "input": "./src/index.ts" + }, + "publishConfig": { + "directory": "dist", + "access": "public" + } +} diff --git a/packages/plugins/filter-operation-type/src/filter-operation-type-rule.ts b/packages/plugins/filter-operation-type/src/filter-operation-type-rule.ts new file mode 100644 index 0000000000..79ad34a801 --- /dev/null +++ b/packages/plugins/filter-operation-type/src/filter-operation-type-rule.ts @@ -0,0 +1,14 @@ +import { ValidationRule, OperationTypeNode, GraphQLError } from 'graphql'; + +export type AllowedOperations = Iterable; + +export const createFilterOperationTypeRule = (allowedOperations: AllowedOperations): ValidationRule => context => { + const ops = new Set(allowedOperations); + return { + OperationDefinition(node) { + if (!ops.has(node.operation)) { + context.reportError(new GraphQLError(`GraphQL operation type "${node.operation}" is not allowed.`, [node])); + } + }, + }; +}; diff --git a/packages/plugins/filter-operation-type/src/index.ts b/packages/plugins/filter-operation-type/src/index.ts new file mode 100644 index 0000000000..5714f2258f --- /dev/null +++ b/packages/plugins/filter-operation-type/src/index.ts @@ -0,0 +1,12 @@ +import { Plugin } from '@envelop/types'; +import { createFilterOperationTypeRule, AllowedOperations } from './filter-operation-type-rule'; + +export const useFilterAllowedOperations = (allowedOperations: AllowedOperations): Plugin => { + return { + onValidate: ({ addValidationRule }) => { + addValidationRule(createFilterOperationTypeRule(allowedOperations)); + }, + }; +}; + +export { createFilterOperationTypeRule };