[
  {
    "path": ".github/FUNDING.yml",
    "content": "# These are supported funding model platforms\n\ngithub: maticzav\npatreon: # Replace with a single Patreon username\nopen_collective: # Replace with a single Open Collective username\nko_fi: # Replace with a single Ko-fi username\ntidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel\ncommunity_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry\nliberapay: # Replace with a single Liberapay username\nissuehunt: # Replace with a single IssueHunt username\notechie: # Replace with a single Otechie username\ncustom: # Replace with up to 4 custom sponsorship URLs e.g., ['link1', 'link2']\n"
  },
  {
    "path": ".github/stale.yml",
    "content": "# Number of days of inactivity before an issue becomes stale\ndaysUntilStale: 45\n# Number of days of inactivity before a stale issue is closed\ndaysUntilClose: 10\n# Issues with these labels will never be considered stale\nexemptLabels:\n  - kind/feature\n  - reproduction-available\n  - help-wanted\n# Label to use when marking an issue as stale\nstaleLabel: stale\n# Comment to post when marking an issue as stale. Set to `false` to disable\nmarkComment: >\n  This issue has been automatically marked as stale because it has not had\n  recent activity. It will be closed if no further activity occurs. Thank you\n  for your contributions.\n# Comment to post when closing a stale issue. Set to `false` to disable\ncloseComment: false\n# Limit to only `issues`\nonly: issues\n"
  },
  {
    "path": ".github/workflows/publish.yml",
    "content": "name: Publish\n\non:\n  push:\n    branches:\n      - master\n\njobs:\n  build:\n    name: release\n    runs-on: ubuntu-latest\n    steps:\n      # Setup\n      - uses: actions/checkout@master\n      - uses: actions/setup-node@v1\n        with:\n          node-version: '14.x'\n      - run: npm i -g pnpm@7\n      - run: pnpm i\n      # Publish\n      - run: pnpm compile\n      - run: pnpm test\n        env:\n          GH_TOKEN: ${{ secrets.GH_SPONSORS_TOKEN }}\n      - run: pnpm coverage\n      # This alias makes semantic-release to use pnpm when publishing\n      # Which adds support for \"publishConfig.directory\"\n      - run: alias npm=pnpm\n      - run: npx semantic-release\n        env:\n          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}\n          NPM_TOKEN: ${{ secrets.NPM_TOKEN }}\n"
  },
  {
    "path": ".github/workflows/test.yml",
    "content": "name: Test\n\non: [push, pull_request]\n\njobs:\n  build:\n    name: release\n    runs-on: ubuntu-latest\n    steps:\n      # Setup\n      - uses: actions/checkout@master\n      - uses: actions/setup-node@v1\n        with:\n          node-version: '14.x'\n      - run: npm i -g pnpm@7\n      - run: pnpm install\n      # Test\n      - run: pnpm compile\n      - run: pnpm test\n        env:\n          GH_TOKEN: ${{ secrets.GH_SPONSORS_TOKEN }}\n      - run: pnpm coverage\n"
  },
  {
    "path": ".gitignore",
    "content": "node_modules\ndist\n.idea\n.DS_Store\n*.log*\npackage-lock.json\ncoverage"
  },
  {
    "path": ".huskyrc.json",
    "content": "{\n  \"hooks\": {\n    \"pre-commit\": \"pretty-quick --staged\"\n  }\n}\n"
  },
  {
    "path": ".vscode/launch.json",
    "content": "{\n  \"version\": \"0.2.0\",\n  \"configurations\": [\n    {\n      \"type\": \"node\",\n      \"request\": \"launch\",\n      \"name\": \"JS examples debug\",\n      \"program\": \"${workspaceFolder}/examples/authorization/index.js\",\n      \"skipFiles\": [\"<node_internals>/**/*.js\"]\n    },\n    {\n      \"type\": \"node\",\n      \"request\": \"launch\",\n      \"name\": \"AVA\",\n      \"program\": \"${workspaceRoot}/node_modules/ava/profile.js\",\n      \"args\": [\"--serial\", \"${file}\"],\n      \"skipFiles\": [\"<node_internals>/**/*.js\"]\n    },\n    {\n      \"type\": \"node\",\n      \"request\": \"launch\",\n      \"name\": \"Current TS File\",\n      \"args\": [\"${relativeFile}\"],\n      \"runtimeArgs\": [\"-r\", \"ts-node/register\"],\n      \"cwd\": \"${workspaceRoot}\",\n      \"protocol\": \"inspector\",\n      \"internalConsoleOptions\": \"openOnSessionStart\"\n    }\n  ]\n}\n"
  },
  {
    "path": ".vscode/settings.json",
    "content": "{\n  \"eslint.enable\": false,\n  \"files.watcherExclude\": {\n    \"**/.git/objects/**\": true,\n    \"**/.git/subtree-cache/**\": true,\n    \"**/node_modules/**\": true\n  },\n  \"typescript.tsdk\": \"./node_modules/typescript/lib\",\n  \"spellright.language\": [\"en\"],\n  \"spellright.documentTypes\": [\"plaintext\"],\n  \"editor.formatOnSave\": true\n}\n"
  },
  {
    "path": "LICENSE",
    "content": "MIT License\n\nCopyright (c) 2020 Matic Zavadlal\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n"
  },
  {
    "path": "README.md",
    "content": "<p align=\"center\"><img src=\"media/logo.png\" width=\"150\" /></p>\n\n# graphql-middleware\n\n[![Actions Status](https://github.com/maticzav/graphql-middleware/workflows/Test/badge.svg)](https://github.com/maticzav/graphql-middleware/actions)\n[![codecov](https://codecov.io/gh/maticzav/graphql-middleware/branch/master/graph/badge.svg?token=TuIfoaKhc5)](https://codecov.io/gh/maticzav/graphql-middleware)\n[![npm version](https://badge.fury.io/js/graphql-middleware.svg)](https://badge.fury.io/js/graphql-middleware)\n\nSplit up your GraphQL resolvers in middleware functions.\n\n## Overview\n\nGraphQL Middleware is a schema wrapper which allows you to manage additional functionality across multiple resolvers efficiently.\n\n- 💡 **Easy to use:** An intuitive, yet familiar API that you will pick up in a second.\n- 💪 **Powerful:** Allows complete control over your resolvers (Before, After).\n- 🌈 **Compatible:** Works with any GraphQL Schema.\n\n> **NOTE:** As of 3.0.0 `graphql-middleware` no longer wraps introspection queries.\n\n> **NOTE:** As of 5.0.0 `graphql-middleware` no longer supports GraphQL Yoga out of the box. We might bring back the support if the library becomes maintained again. We are keeping the docs as the reference for older versions.\n\n## Install\n\n```sh\nyarn add graphql-middleware\n```\n\n## How does it work\n\nGraphQL Middleware lets you run arbitrary code before or after a resolver is invoked. It improves your code structure by enabling code reuse and a clear separation of concerns.\n\n```ts\nconst { ApolloServer } = require('apollo-server')\nconst { makeExecutableSchema } = require('@graphql-tools/schema')\n\nconst typeDefs = `\ntype Query {\n  hello(name: String): String\n  bye(name: String): String\n}\n`\nconst resolvers = {\n  Query: {\n    hello: (root, args, context, info) => {\n      console.log(`3. resolver: hello`)\n      return `Hello ${args.name ? args.name : 'world'}!`\n    },\n    bye: (root, args, context, info) => {\n      console.log(`3. resolver: bye`)\n      return `Bye ${args.name ? args.name : 'world'}!`\n    },\n  },\n}\n\nconst logInput = async (resolve, root, args, context, info) => {\n  console.log(`1. logInput: ${JSON.stringify(args)}`)\n  const result = await resolve(root, args, context, info)\n  console.log(`5. logInput`)\n  return result\n}\n\nconst logResult = async (resolve, root, args, context, info) => {\n  console.log(`2. logResult`)\n  const result = await resolve(root, args, context, info)\n  console.log(`4. logResult: ${JSON.stringify(result)}`)\n  return result\n}\n\nconst schema = makeExecutableSchema({ typeDefs, resolvers })\n\nconst schemaWithMiddleware = applyMiddleware(schema, logInput, logResult)\n\nconst server = new ApolloServer({\n  schema: schemaWithMiddleware,\n})\n\nawait server.listen({ port: 8008 })\n```\n\nExecution of the middleware and resolver functions follow the \"onion\"-principle, meaning each middleware function adds a layer before and after the actual resolver invocation.\n\n<p align=\"center\"><img src=\"media/idea.png\" /></p>\n\n> The order of the middleware functions in the middlewares array is important. The first resolver is the \"most-outer\" layer, so it gets executed first and last. The second resolver is the \"second-outer\" layer, so it gets executed second and second to last... And so forth.\n\n> You can read more about GraphQL Middleware in this fantastic [article](https://www.prisma.io/blog/graphql-middleware-zie3iphithxy/).\n\n## Standalone usage\n\n```ts\nconst { ApolloServer } = require('apollo-server')\nconst { makeExecutableSchema } = require('@graphql-tools/schema')\n\n// Minimal example middleware (before & after)\nconst beepMiddleware = {\n  Query: {\n    hello: async (resolve, parent, args, context, info) => {\n      // You can use middleware to override arguments\n      const argsWithDefault = { name: 'Bob', ...args }\n      const result = await resolve(parent, argsWithDefault, context, info)\n      // Or change the returned values of resolvers\n      return result.replace(/Trump/g, 'beep')\n    },\n  },\n}\n\nconst typeDefs = `\n  type Query {\n    hello(name: String): String\n  }\n`\nconst resolvers = {\n  Query: {\n    hello: (parent, { name }, context) => `Hello ${name ? name : 'world'}!`,\n  },\n}\n\nconst schema = makeExecutableSchema({ typeDefs, resolvers })\n\nconst schemaWithMiddleware = applyMiddleware(\n  schema,\n  metricsMiddleware,\n  authMiddleware,\n  beepMiddleware,\n)\n\nconst server = new ApolloServer({\n  schema: schemaWithMiddleware,\n})\n\nawait server.listen({ port: 8008 })\n```\n\n### Usage with `graphql-yoga`\n\n> `graphql-yoga` has built-in support for `graphql-middleware`!\n\n```ts\nimport { GraphQLServer } from 'graphql-yoga'\nimport { authMiddleware, metricsMiddleware } from './middleware'\n\nconst typeDefs = `\n  type Query {\n    hello(name: String): String\n  }\n`\nconst resolvers = {\n  Query: {\n    hello: (parent, { name }, context) => `Hello ${name ? name : 'world'}!`,\n  },\n}\n\nconst server = new GraphQLServer({\n  typeDefs,\n  resolvers,\n  middlewares: [authMiddleware, metricsMiddleware],\n  documentMiddleware: [],\n})\nserver.start(() => console.log('Server is running on localhost:4000'))\n```\n\n## Awesome Middlewares [![Awesome](https://awesome.re/badge.svg)](https://awesome.re)\n\n- [graphql-shield](https://github.com/maticzav/graphql-shield) - Permissions as another layer of abstraction.\n- [graphql-middleware-apollo-upload-server](http://github.com/homeroom-live/graphql-middleware-apollo-upload-server) - Uploading files is hard, that's why this package manages it for you!\n- [graphql-middleware-sentry](https://github.com/maticzav/graphql-middleware-sentry) - Report your server errors to Sentry.\n- [graphql-middleware-forward-binding](https://github.com/maticzav/graphql-middleware-forward-binding) - GraphQL Binding forwardTo plugin for GraphQL Middleware.\n- [graphql-yup-middleware](https://github.com/JCMais/graphql-yup-middleware) - Use yup to validate mutation arguments\n- [graphql-pino-middleware](https://github.com/addityasingh/graphql-pino-middleware) - GraphQL middleware to augment resolvers with pino logger\n- [graphql-lightstep-middleware](https://github.com/addityasingh/graphql-lightstep-middleware) - GraphQL middleware to instrument resolvers with `lightstep` traces\n- [graphql-filter](https://github.com/hata6502/graphql-filter) - A GraphQL middleware to filter output data.\n\n## API\n\nA middleware is a resolver function that wraps another resolver function.\n\n```ts\nexport declare type IMiddlewareResolver<\n  TSource = any,\n  TContext = any,\n  TArgs = any\n> = (\n  resolve: Function,\n  parent: TSource,\n  args: TArgs,\n  context: TContext,\n  info: GraphQLResolveInfo,\n) => Promise<any>\n\nexport interface IMiddlewareWithOptions<\n  TSource = any,\n  TContext = any,\n  TArgs = any\n> {\n  fragment?: IMiddlewareFragment\n  fragments?: IMiddlewareFragment[]\n  resolve?: IMiddlewareResolver<TSource, TContext, TArgs>\n}\n\nexport type IMiddlewareFunction<TSource = any, TContext = any, TArgs = any> =\n  | IMiddlewareWithOptions<TSource, TContext, TArgs>\n  | IMiddlewareResolver<TSource, TContext, TArgs>\n\ninterface IMiddlewareTypeMap {\n  [key: string]: IMiddlewareFunction | IMiddlewareFieldMap\n}\n\ninterface IMiddlewareFieldMap {\n  [key: string]: IMiddlewareFunction\n}\n\ntype IMiddleware = IMiddlewareFunction | IMiddlewareTypeMap\n\nfunction middleware(\n  generator: (schema: GraphQLSchema) => IMiddleware,\n): MiddlewareGenerator\n\nfunction applyMiddleware(\n  schema: GraphQLSchema,\n  ...middleware: (IMiddleware | MiddlewareGenerator)[]\n): GraphQLSchema & {\n  schema?: GraphQLSchema\n  fragmentReplacements?: FragmentReplacement[]\n}\n\n/**\n * Applies middleware to a schema like `applyMiddleware` but only applies the\n * middleware to fields that have non-default resolvers. This method can be\n * useful if you want to report performance of only non-trivial methods.\n */\nfunction applyMiddlewareToDeclaredResolvers(\n  schema: GraphQLSchema,\n  ...middleware: (IMiddleware | MiddlewareGenerator)[]\n): GraphQLSchema & {\n  schema?: GraphQLSchema\n  fragmentReplacements?: FragmentReplacement[]\n}\n```\n\n### Middleware Generator\n\nIn some cases, your middleware could depend on how your schema looks. In such situations, you can turn your middleware into a middleware generator. Middleware generators are denoted with function `middleware` and receive `schema` as the first argument.\n\n```ts\nconst schemaDependentMiddleware = middleware((schema) => {\n  return generateMiddlewareFromSchema(schema)\n})\n\nconst schemaWithMiddleware = applyMiddleware(\n  schema,\n  schemaDependentMiddleware,\n  someOtherOptionalMiddleware,\n  etc,\n)\n```\n\n### Middleware Fragments\n\nFragments are a way of expressing what information your resolver requires to make sure it can execute correctly. They are primarily used in schema forwarding when the client might not always request all the fields your resolver demands. Because of that, we need to provide a way of telling what other information we need from a remote schema and that's why we use fragments.\n\nYou can read more about fragments in the [`graphql-binding`](https://github.com/graphql-binding/graphql-binding) repository and on [`graphql-tools`](https://www.apollographql.com/docs/graphql-tools/schema-transforms.html#Other) documentation website.\n\nGraphQL Middleware provides a convenient way to quickly and easily add fragments to your middleware. This might turn out particularly useful when your middleware depends on resolver data.\n\nWe've made fragments extremely flexible by using the general API which, if you have ever run over fragments, you probably already know.\n\n```ts\n// Schema wide - gets applied to every field.\nconst middlewareWithFragments = {\n  fragment: `fragment NodeID on Node { id }`,\n  resolve: (resolve, { id }, args, ctx, info) => {\n    const foo = doSomethingWithID(id)\n    return resolve(foo)\n  },\n}\n\n// Type wide - gets applied to every field of certain type.\nconst middlewareWithFragments = {\n  Query: {\n    fragment: `fragment NodeID on Node { id }`,\n    resolve: (resolve, { id }, args, ctx, info) => {\n      const foo = doSomethingWithID(id)\n      return resolve(foo)\n    },\n  },\n  Mutation: {\n    fragments: [\n      `fragment NodeID on Node { id }`,\n      `fragment NodeSecret on Node { secret }`,\n    ],\n    resolve: (resolve, parent, args, ctx, info) => {\n      return resolve(parent, customArgs)\n    },\n  },\n}\n\n// Field scoped - gets applied to particular field.\nconst middlewareWithFragments = {\n  Query: {\n    node: {\n      fragment: `fragment NodeID on Node { id }`,\n      resolve: (resolve, { id }, args, ctx, info) => {\n        const foo = doSomethingWithID(id)\n        return resolve(foo)\n      },\n    },\n    books: (resolve, parent, args, ctx, info) => {\n      return resolve(parent, customArgs)\n    },\n  },\n}\n\nconst { schema, fragmentReplacements } = applyMiddleware(\n  schema,\n  middlewareWithFragments,\n  someOtherMiddleware,\n)\n```\n\n> `graphql-middleware` automatically merges fragments from multiple middlewares if possible. Otherwise, validation function throws an error.\n\n## GraphQL Middleware Use Cases\n\n- Logging\n- Metrics\n- Input sanitisation\n- Performance measurement\n- Authorization\n- Caching\n- Tracing\n\n## FAQ\n\n### Can I use GraphQL Middleware without GraphQL Yoga?\n\nYes. Nevertheless, we encourage you to use it in combination with Yoga. Combining the power of `middlewares` that GraphQL Middleware offers, with `documentMiddleware` which Yoga exposes, gives you unparalleled control over the execution of your queries.\n\n### How does GraphQL Middleware compare to `directives`?\n\nGraphQL Middleware and `directives` tackle the same problem in a completely different way. GraphQL Middleware allows you to implement all your middleware logic in your code, whereas directives encourage you to mix schema with your functionality.\n\n### Should I modify the context using GraphQL Middleware?\n\nGraphQL Middleware allows you to modify the context of your resolvers, but we encourage you to use GraphQL Yoga's `documentMiddleware` for this functionality instead.\n\n## Thank you\n\nThanks to everyone who supported the development of this project. It's an honor to lead a project that helps so many people.\n\n- [Prisma](http://github.com/prisma) - for sponsoring the project,\n- Johannes Schickling - for guiding the project development, and\n- everyone else who personally contributed to the project in one way or another.\n\nThank you! :heart:\n"
  },
  {
    "path": "bob-esbuild.config.ts",
    "content": "export const config: import('bob-esbuild').BobConfig = {\r\n  tsc: {\r\n    dirs: ['.'],\r\n  },\r\n  distDir: 'dist',\r\n  verbose: true,\r\n  singleBuild: true,\r\n}\r\n"
  },
  {
    "path": "examples/logging/README.md",
    "content": "# GraphQL Middleware - Logging example\n\nThis example illustrates basic usage of GraphQL Middleware. The idea is to log every field that has been requested by user.\n\n## Code\n\n> Mind the following parts\n\n### Import\n\nThis is where we import `graphql-middleware`.\n\n```js\nconst { applyMiddleware } = require('graphql-middleware')\n```\n\n### Middleware\n\nBecause we want every field of our schema to make a log once it's requested, we use `schema` wide middleware definition.\n\n```js\nconst logMiddleware = async (resolve, parent, args, ctx, info) => {\n  console.log(args, info)\n  return resolve()\n}\n```\n\n### Applying middleware\n\nThis is the part where we modify the schema to reflect the changed middleware introduce.\n\n```js\nconst analysedSchema = applyMiddleware(schema, logMiddleware)\n```\n\n## License\n\nMIT\n"
  },
  {
    "path": "examples/logging/index.js",
    "content": "const { GraphQLServer } = require('graphql-yoga')\n\n// Schema\n\nconst typeDefs = `\n  type Query {\n    hello(name: String): String!\n    bye(name: String): String!\n  }\n`\n\nconst resolvers = {\n  Query: {\n    hello: (_, { name }) => {\n      throw new Error('No hello!')\n    },\n    bye: (_, { name }) => `Bye ${name || 'World'}`,\n  },\n}\n\n// Middleware\n\nconst logMiddleware = async (resolve, parent, args, ctx, info) => {\n  try {\n    const res = await resolve()\n    return res\n  } catch (e) {\n    console.log(e)\n  }\n}\n\nconst server = new GraphQLServer({\n  typeDefs: typeDefs,\n  resolvers: resolvers,\n  middlewares: [logMiddleware],\n  context: req => ({ ...req }),\n})\n\nserver.start(() => console.log('Server is running on http://localhost:4000'))\n"
  },
  {
    "path": "examples/logging/package.json",
    "content": "{\n  \"name\": \"logging\",\n  \"version\": \"1.0.0\",\n  \"main\": \"index.js\",\n  \"license\": \"MIT\",\n  \"dependencies\": {\n    \"graphql-yoga\": \"latest\"\n  }\n}\n"
  },
  {
    "path": "examples/permissions/README.md",
    "content": "# GraphQL Middleware - Permissions example\n\nThis example illustrates how to use GraphQL Middleware to handle user permissions. Do take into consideration that this is a low level implementation with no optimizations. We recommend using `graphql-shield` for production usage.\n\n## Code\n\n> Mind the following parts\n\n### Import\n\nThis is where we import `graphql-middleware`.\n\n```js\nconst { applyMiddleware } = require('graphql-middleware')\n```\n\n### Permission function\n\nThis is where we decide whether the user should or shouldn't access the information. The following implementation preassumes that the secret is passed as the query header using `Authorization: <token>` format.\n\n```js\nconst isLoggedIn = async (resolve, parent, args, ctx, info) => {\n  // Include your agent code as Authorization: <token> header.\n  const permit = ctx.request.get('Authorization') === code\n\n  if (!permit) {\n    throw new Error(`Not authorised!`)\n  }\n\n  return resolve()\n}\n```\n\n### Middleware\n\nThe following middleware implements one field-scoped and one type-scoped middleware. We use `field` scoped middleware with `secured` field to ensure only `secured` field of `Query` requires authorisation. Furthermore, we also use `type` middleware to make sure every field of `Me` type requires authorisation.\n\nThere is no need to apply permissions to `me` field of `Query` as requesting any of type `Me` fields already requires authentication.\n\n```js\nconst permissions = {\n  Query: {\n    secured: isLoggedIn,\n  },\n  Me: isLoggedIn,\n}\n```\n\n### Applying middleware\n\nThis is the part where we modify the schema to reflect the changed middleware introduce.\n\n```js\nconst protectedSchema = applyMiddleware(schema, permissions)\n```\n\n## License\n\nMIT\n"
  },
  {
    "path": "examples/permissions/index.js",
    "content": "const { GraphQLServer } = require('graphql-yoga')\n\n// Schema\n\nconst code = 'supersecret'\n\nconst typeDefs = `\n  type Query {\n    open: String!\n    secured: String!\n    me: Me!\n  }\n\n  type Me {\n    name: String!\n    surname: String!\n    age: Int!\n  }\n`\n\nconst resolvers = {\n  Query: {\n    open: () => `Open data, everyone's welcome!`,\n    secured: () => `Personal diary - this is for my eyes only!`,\n    me: () => ({}),\n  },\n  Me: {\n    name: () => 'Ben',\n    surname: () => 'Cool',\n    age: () => 18,\n  },\n}\n\n// Middleware - Permissions\n\nconst isLoggedIn = async (resolve, parent, args, ctx, info) => {\n  // Include your agent code as Authorization: <token> header.\n  const permit = ctx.request.get('Authorization') === code\n\n  if (!permit) {\n    throw new Error(`Not authorised!`)\n  }\n\n  return resolve()\n}\n\nconst permissions = {\n  Query: {\n    secured: isLoggedIn,\n  },\n  Me: isLoggedIn,\n}\n\n// Server\n\nconst server = new GraphQLServer({\n  typeDefs: typeDefs,\n  resolvers: resolvers,\n  middlewares: [permissions],\n  context: req => ({ ...req }),\n})\n\nserver.start(() => console.log('Server is running on http://localhost:4000'))\n"
  },
  {
    "path": "examples/permissions/package.json",
    "content": "{\n  \"name\": \"permissions\",\n  \"version\": \"1.0.0\",\n  \"main\": \"index.js\",\n  \"license\": \"MIT\",\n  \"dependencies\": {\n    \"graphql-yoga\": \"latest\"\n  }\n}\n"
  },
  {
    "path": "jest.config.js",
    "content": "module.exports = {\n  roots: ['<rootDir>/tests', '<rootDir>/src'],\n  testEnvironment: 'node',\n  transform: {\n    '^.+\\\\.tsx?$': 'ts-jest',\n  },\n  testRegex: '(/__tests__/.*|(\\\\.|/)(test|spec))\\\\.tsx?$',\n  testPathIgnorePatterns: ['/node_modules/', '/__fixtures__/'],\n  moduleFileExtensions: ['ts', 'tsx', 'js', 'jsx', 'json', 'node'],\n  collectCoverage: true,\n  collectCoverageFrom: [\n    '**/*.{ts,tsx}',\n    '!**/node_modules/**',\n    '!**/vendor/**',\n    '!**/generated/**',\n  ],\n  verbose: true,\n  coverageDirectory: './coverage',\n  coverageReporters: ['json', 'lcov', 'text', 'clover', 'html'],\n  globals: {\n    'ts-jest': {\n      tsconfig: 'tsconfig.test.json',\n    },\n  },\n}\n"
  },
  {
    "path": "package.json",
    "content": "{\n  \"name\": \"graphql-middleware\",\n  \"description\": \"GraphQL Middleware done right!\",\n  \"version\": \"0.0.0-semantic-release\",\n  \"main\": \"dist/index.js\",\n  \"module\": \"dist/index.mjs\",\n  \"typings\": \"dist/index.d.ts\",\n  \"typescript\": {\n    \"definition\": \"dist/index.d.ts\"\n  },\n  \"exports\": {\n    \".\": {\n      \"require\": \"./dist/index.js\",\n      \"import\": \"./dist/index.mjs\",\n      \"types\": \"./dist/index.d.ts\"\n    },\n    \"./*\": {\n      \"require\": \"./dist/*.js\",\n      \"import\": \"./dist/*.mjs\",\n      \"types\": \"./dist/*.d.ts\"\n    }\n  },\n  \"publishConfig\": {\n    \"directory\": \"dist\"\n  },\n  \"author\": \"Matic Zavadlal <matic.zavadlal@gmail.com>\",\n  \"dependencies\": {\n    \"@graphql-tools/delegate\": \"^8.8.1\",\n    \"@graphql-tools/schema\": \"^8.5.1\"\n  },\n  \"devDependencies\": {\n    \"@types/jest\": \"^26.0.24\",\n    \"@types/lodash\": \"^4.14.182\",\n    \"@types/node\":\"^18.8.3\",\n    \"apollo-server\": \"^3.10.2\",\n    \"axios\": \"^0.27.2\",\n    \"bob-esbuild\": \"^1.3.0\",\n    \"bob-esbuild-cli\": \"^1.0.1\",\n    \"codecov\": \"^3.8.3\",\n    \"graphql\": \"^16.6.0\",\n    \"husky\": \"^6.0.0\",\n    \"iterall\": \"^1.3.0\",\n    \"jest\": \"^26.6.3\",\n    \"prettier\": \"^2.7.1\",\n    \"pretty-quick\": \"^3.1.3\",\n    \"rimraf\": \"^3.0.2\",\n    \"semantic-release\": \"^17.4.7\",\n    \"ts-jest\": \"^26.5.6\",\n    \"ts-node\": \"^9.1.1\",\n    \"typescript\": \"^4.7.4\"\n  },\n  \"peerDependencies\": {\n    \"graphql\": \"^0.12.0 || ^0.13.0 || ^14.0.0 || ^15.0.0 || ^16.0.0\"\n  },\n  \"scripts\": {\n    \"clean\": \"rimraf dist\",\n    \"compile\": \"bob-esbuild build\",\n    \"coverage\": \"codecov\",\n    \"test\": \"jest\",\n    \"prepublishOnly\": \"npm run compile\"\n  },\n  \"files\": [\n    \"dist\"\n  ],\n  \"release\": {\n    \"branch\": \"master\"\n  },\n  \"homepage\": \"https://github.com/maticzav/graphql-middleware\",\n  \"repository\": {\n    \"type\": \"git\",\n    \"url\": \"https://github.com/maticzav/graphql-middleware.git\"\n  },\n  \"bugs\": {\n    \"url\": \"https://github.com/maticzav/graphql-middleware/issues\"\n  },\n  \"keywords\": [\n    \"graphql\",\n    \"middleware\",\n    \"schema\",\n    \"resolvers\",\n    \"server\",\n    \"yoga\"\n  ],\n  \"license\": \"MIT\"\n}\n"
  },
  {
    "path": "prettier.config.js",
    "content": "module.exports = {\n  semi: false,\n  trailingComma: 'all',\n  singleQuote: true,\n}\n"
  },
  {
    "path": "renovate.json",
    "content": "{\n  \"extends\": [\"config:base\", \"docker:disable\", \":automergeMinor\"],\n  \"rangeStrategy\": \"bump\",\n  \"pathRules\": [\n    {\n      \"paths\": [\"examples/**\"],\n      \"extends\": [\":semanticCommitTypeAll(chore)\", \":automergeMinor\"],\n      \"branchName\": \"{{branchPrefix}}examples-{{depNameSanitized}}-{{newVersionMajor}}.x\"\n    }\n  ]\n}\n"
  },
  {
    "path": "src/applicator.ts",
    "content": "import {\n  GraphQLObjectType,\n  GraphQLFieldResolver,\n  GraphQLField,\n  GraphQLSchema,\n  defaultFieldResolver,\n  isIntrospectionType,\n  GraphQLArgument,\n} from 'graphql'\nimport {\n  IMiddlewareFunction,\n  IMiddlewareResolver,\n  IMiddlewareFieldMap,\n  IApplyOptions,\n  IMiddleware,\n  IResolvers,\n  IResolverOptions,\n} from './types'\nimport {\n  isMiddlewareFunction,\n  isGraphQLObjectType,\n  isMiddlewareResolver,\n  isMiddlewareWithFragment,\n} from './utils'\n\n// Applicator\n\nfunction wrapResolverInMiddleware<TSource, TContext, TArgs>(\n  resolver: GraphQLFieldResolver<any, any, any>,\n  middleware: IMiddlewareResolver<TSource, TContext, TArgs>,\n): GraphQLFieldResolver<any, any, any> {\n  return (parent, args, ctx, info) =>\n    middleware(\n      (_parent = parent, _args = args, _ctx = ctx, _info = info) =>\n        resolver(_parent, _args, _ctx, _info),\n      parent,\n      args,\n      ctx,\n      info,\n    )\n}\n\nfunction parseField(\n  field: GraphQLField<any, any, any> & { isDeprecated?: boolean },\n) {\n  const { isDeprecated, ...restData } = field\n  const argsMap = field.args.reduce(\n    (acc, cur) => {\n      acc[cur.name] = cur;\n      return acc;\n    }, {} as Record<string, GraphQLArgument>,\n  )\n  return {\n    ...restData,\n    args: argsMap,\n  }\n}\n\nfunction applyMiddlewareToField<TSource, TContext, TArgs>(\n  field: GraphQLField<any, any, any>,\n  options: IApplyOptions,\n  middleware: IMiddlewareFunction<TSource, TContext, TArgs>,\n): IResolverOptions {\n  const parsedField = parseField(field)\n  if (\n    isMiddlewareWithFragment(middleware) &&\n    parsedField.resolve &&\n    parsedField.resolve !== defaultFieldResolver\n  ) {\n    return {\n      ...parsedField,\n      fragment: middleware.fragment,\n      fragments: middleware.fragments,\n      resolve: wrapResolverInMiddleware(\n        parsedField.resolve,\n        middleware.resolve,\n      ),\n    }\n  } else if (isMiddlewareWithFragment(middleware) && parsedField.subscribe) {\n    return {\n      ...parsedField,\n      fragment: middleware.fragment,\n      fragments: middleware.fragments,\n      subscribe: wrapResolverInMiddleware(\n        parsedField.subscribe,\n        middleware.resolve,\n      ),\n    }\n  } else if (\n    isMiddlewareResolver(middleware) &&\n    parsedField.resolve &&\n    parsedField.resolve !== defaultFieldResolver\n  ) {\n    return {\n      ...parsedField,\n      resolve: wrapResolverInMiddleware(parsedField.resolve, middleware),\n    }\n  } else if (isMiddlewareResolver(middleware) && parsedField.subscribe) {\n    return {\n      ...parsedField,\n      subscribe: wrapResolverInMiddleware(parsedField.subscribe, middleware),\n    }\n  } else if (\n    isMiddlewareWithFragment(middleware) &&\n    !options.onlyDeclaredResolvers\n  ) {\n    return {\n      ...parsedField,\n      fragment: middleware.fragment,\n      fragments: middleware.fragments,\n      resolve: wrapResolverInMiddleware(\n        defaultFieldResolver,\n        middleware.resolve,\n      ),\n    }\n  } else if (\n    isMiddlewareResolver(middleware) &&\n    !options.onlyDeclaredResolvers\n  ) {\n    return {\n      ...parsedField,\n      resolve: wrapResolverInMiddleware(defaultFieldResolver, middleware),\n    }\n  } else {\n    return { ...parsedField, resolve: defaultFieldResolver }\n  }\n}\n\nfunction applyMiddlewareToType<TSource, TContext, TArgs>(\n  type: GraphQLObjectType,\n  options: IApplyOptions,\n  middleware:\n    | IMiddlewareFunction<TSource, TContext, TArgs>\n    | IMiddlewareFieldMap<TSource, TContext, TArgs>,\n): IResolvers {\n  const fieldMap = type.getFields()\n\n  if (isMiddlewareFunction(middleware)) {\n    const resolvers = Object.keys(fieldMap).reduce(\n      (resolvers, fieldName) => {\n        resolvers[fieldName] = applyMiddlewareToField(\n          fieldMap[fieldName],\n          options,\n          middleware as IMiddlewareFunction<TSource, TContext, TArgs>,\n        );\n        return resolvers;\n      },\n      {},\n    )\n\n    return resolvers\n  } else {\n    const resolvers = Object.keys(middleware).reduce(\n      (resolvers, fieldName) => {\n        resolvers[fieldName] = applyMiddlewareToField(\n          fieldMap[fieldName],\n          options,\n          middleware[fieldName],\n        );\n        return resolvers;\n      },\n      {},\n    )\n\n    return resolvers\n  }\n}\n\nfunction applyMiddlewareToSchema<TSource, TContext, TArgs>(\n  schema: GraphQLSchema,\n  options: IApplyOptions,\n  middleware: IMiddlewareFunction<TSource, TContext, TArgs>,\n): IResolvers {\n  const typeMap = schema.getTypeMap()\n\n  const resolvers = Object.keys(typeMap)\n    .filter(\n      (type) =>\n        isGraphQLObjectType(typeMap[type]) &&\n        !isIntrospectionType(typeMap[type]),\n    )\n    .reduce(\n      (resolvers, type) => {\n        resolvers[type] = applyMiddlewareToType(\n          typeMap[type] as GraphQLObjectType,\n          options,\n          middleware,\n        );\n        return resolvers;\n      },\n      {},\n    )\n\n  return resolvers\n}\n\n// Generator\n\nexport function generateResolverFromSchemaAndMiddleware<\n  TSource,\n  TContext,\n  TArgs,\n>(\n  schema: GraphQLSchema,\n  options: IApplyOptions,\n  middleware: IMiddleware<TSource, TContext, TArgs>,\n): IResolvers {\n  if (isMiddlewareFunction(middleware)) {\n    return applyMiddlewareToSchema(\n      schema,\n      options,\n      middleware as IMiddlewareFunction<TSource, TContext, TArgs>,\n    )\n  } else {\n    const typeMap = schema.getTypeMap()\n\n    const resolvers = Object.keys(middleware).reduce(\n      (resolvers, type) => {\n        resolvers[type] = applyMiddlewareToType(\n          typeMap[type] as GraphQLObjectType,\n          options,\n          middleware[type],\n        );\n        return resolvers;\n      },\n      {},\n    )\n\n    return resolvers\n  }\n}\n"
  },
  {
    "path": "src/constructors.ts",
    "content": "import { MiddlewareGenerator } from './generator'\nimport { IMiddlewareGenerator, IMiddlewareGeneratorConstructor } from './types'\n\nexport function middleware<TSource = any, TContext = any, TArgs = any>(\n  generator: IMiddlewareGeneratorConstructor<TSource, TContext, TArgs>,\n): IMiddlewareGenerator<TSource, TContext, TArgs> {\n  return new MiddlewareGenerator(generator)\n}\n"
  },
  {
    "path": "src/fragments.ts",
    "content": "import {\n  Kind,\n  parse,\n  InlineFragmentNode,\n  OperationDefinitionNode,\n  print,\n} from 'graphql'\nimport { FragmentReplacement, IResolvers } from './types'\n\nexport function extractFragmentReplacements(\n  resolvers: IResolvers,\n): FragmentReplacement[] {\n  const allFragmentReplacements: FragmentReplacement[] = []\n\n  /* Collect fragments. */\n\n  for (const typeName in resolvers) {\n    const fieldResolvers = resolvers[typeName]\n    for (const fieldName in fieldResolvers) {\n      const fieldResolver = fieldResolvers[fieldName]\n      if (typeof fieldResolver === 'object' && fieldResolver.fragment) {\n        allFragmentReplacements.push({\n          field: fieldName,\n          fragment: fieldResolver.fragment,\n        })\n      }\n      if (typeof fieldResolver === 'object' && fieldResolver.fragments) {\n        for (const fragment of fieldResolver.fragments) {\n          allFragmentReplacements.push({\n            field: fieldName,\n            fragment: fragment,\n          })\n        }\n      }\n    }\n  }\n\n  /* Filter and map circular dependencies. */\n\n  const fragmentReplacements = allFragmentReplacements\n    .filter(fragment => Boolean(fragment))\n    .map(fragmentReplacement => {\n      const fragment = parseFragmentToInlineFragment(\n        fragmentReplacement.fragment,\n      )\n\n      const newSelections = fragment.selectionSet.selections.filter(node => {\n        switch (node.kind) {\n          case Kind.FIELD: {\n            return node.name.value !== fragmentReplacement.field\n          }\n          default: {\n            return true\n          }\n        }\n      })\n\n      if (newSelections.length === 0) {\n        return null\n      }\n\n      const newFragment: InlineFragmentNode = {\n        ...fragment,\n        selectionSet: {\n          kind: fragment.selectionSet.kind,\n          loc: fragment.selectionSet.loc,\n          selections: newSelections,\n        },\n      }\n\n      const parsedFragment = print(newFragment)\n\n      return {\n        field: fragmentReplacement.field,\n        fragment: parsedFragment,\n      }\n    })\n    .filter(fr => fr !== null)\n\n  return fragmentReplacements\n\n  /* Helper functions */\n\n  function parseFragmentToInlineFragment(\n    definitions: string,\n  ): InlineFragmentNode {\n    if (definitions.trim().startsWith('fragment')) {\n      const document = parse(definitions)\n      for (const definition of document.definitions) {\n        if (definition.kind === Kind.FRAGMENT_DEFINITION) {\n          return {\n            kind: Kind.INLINE_FRAGMENT,\n            typeCondition: definition.typeCondition,\n            selectionSet: definition.selectionSet,\n          }\n        }\n      }\n    }\n\n    const query = parse(`{${definitions}}`)\n      .definitions[0] as OperationDefinitionNode\n    for (const selection of query.selectionSet.selections) {\n      if (selection.kind === Kind.INLINE_FRAGMENT) {\n        return selection\n      }\n    }\n\n    throw new Error('Could not parse fragment')\n  }\n}\n"
  },
  {
    "path": "src/generator.ts",
    "content": "import {\n  IMiddlewareGeneratorConstructor,\n  IMiddleware,\n  IMiddlewareGenerator,\n} from './types'\nimport { GraphQLSchema } from 'graphql'\n\nexport class MiddlewareGenerator<TSource, TContext, TArgs>\n  implements IMiddlewareGenerator<TSource, TContext, TArgs> {\n  private generator: IMiddlewareGeneratorConstructor<TSource, TContext, TArgs>\n\n  constructor(\n    generator: IMiddlewareGeneratorConstructor<TSource, TContext, TArgs>,\n  ) {\n    this.generator = generator\n  }\n\n  generate(schema: GraphQLSchema): IMiddleware<TSource, TContext, TArgs> {\n    return this.generator(schema)\n  }\n}\n"
  },
  {
    "path": "src/index.ts",
    "content": "export type {\n  FragmentReplacement,\n  IMiddleware,\n  IMiddlewareTypeMap,\n  IMiddlewareFieldMap,\n  IMiddlewareFunction,\n  IMiddlewareGenerator,\n  IMiddlewareGeneratorConstructor,\n} from './types'\nexport {\n  applyMiddleware,\n  applyMiddlewareToDeclaredResolvers,\n} from './middleware'\nexport { middleware } from './constructors'\nexport { MiddlewareError } from './validation'\n"
  },
  {
    "path": "src/middleware.ts",
    "content": "import { GraphQLSchema } from 'graphql'\nimport { addResolversToSchema } from '@graphql-tools/schema'\nimport {\n  IApplyOptions,\n  IMiddleware,\n  FragmentReplacement,\n  IMiddlewareGenerator,\n  GraphQLSchemaWithFragmentReplacements,\n} from './types'\nimport { generateResolverFromSchemaAndMiddleware } from './applicator'\nimport { validateMiddleware } from './validation'\nimport { extractFragmentReplacements } from './fragments'\nimport { isMiddlewareGenerator } from './utils'\n\n/**\n *\n * @param schema\n * @param options\n * @param middleware\n *\n * Validates middleware and generates resolvers map for provided middleware.\n * Applies middleware to the current schema and returns the modified one.\n *\n */\nexport function addMiddlewareToSchema<TSource, TContext, TArgs>(\n  schema: GraphQLSchema,\n  options: IApplyOptions,\n  middleware: IMiddleware<TSource, TContext, TArgs>,\n): {\n  schema: GraphQLSchema\n  fragmentReplacements: FragmentReplacement[]\n} {\n  const validMiddleware = validateMiddleware(schema, middleware)\n  const resolvers = generateResolverFromSchemaAndMiddleware(\n    schema,\n    options,\n    validMiddleware,\n  )\n\n  const fragmentReplacements = extractFragmentReplacements(resolvers)\n\n  const newSchema = addResolversToSchema({\n    schema,\n    resolvers,\n    updateResolversInPlace: false,\n    resolverValidationOptions: {\n      requireResolversForResolveType: 'ignore',\n    },\n  })\n\n  return { schema: newSchema, fragmentReplacements }\n}\n\n/**\n *\n * @param schema\n * @param options\n * @param middlewares\n *\n * Generates middleware from middleware generators and applies middleware to\n * resolvers. Returns generated schema with all provided middleware.\n *\n */\nfunction applyMiddlewareWithOptions<TSource = any, TContext = any, TArgs = any>(\n  schema: GraphQLSchema,\n  options: IApplyOptions,\n  ...middlewares: (\n    | IMiddleware<TSource, TContext, TArgs>\n    | IMiddlewareGenerator<TSource, TContext, TArgs>\n  )[]\n): GraphQLSchemaWithFragmentReplacements {\n  const normalisedMiddlewares = middlewares.map((middleware) => {\n    if (isMiddlewareGenerator(middleware)) {\n      return middleware.generate(schema)\n    } else {\n      return middleware\n    }\n  })\n\n  const schemaWithMiddlewareAndFragmentReplacements = normalisedMiddlewares.reduceRight(\n    (\n      {\n        schema: currentSchema,\n        fragmentReplacements: currentFragmentReplacements,\n      },\n      middleware,\n    ) => {\n      const {\n        schema: newSchema,\n        fragmentReplacements: newFragmentReplacements,\n      } = addMiddlewareToSchema(currentSchema, options, middleware)\n\n      return {\n        schema: newSchema,\n        fragmentReplacements: [\n          ...currentFragmentReplacements,\n          ...newFragmentReplacements,\n        ],\n      }\n    },\n    { schema, fragmentReplacements: [] },\n  )\n\n  const schemaWithMiddleware: GraphQLSchemaWithFragmentReplacements =\n    schemaWithMiddlewareAndFragmentReplacements.schema\n\n  schemaWithMiddleware.schema =\n    schemaWithMiddlewareAndFragmentReplacements.schema\n  schemaWithMiddleware.fragmentReplacements =\n    schemaWithMiddlewareAndFragmentReplacements.fragmentReplacements\n\n  return schemaWithMiddleware\n}\n\n// Exposed functions\n\n/**\n *\n * @param schema\n * @param middlewares\n *\n * Apply middleware to resolvers and return generated schema.\n *\n */\nexport function applyMiddleware<TSource = any, TContext = any, TArgs = any>(\n  schema: GraphQLSchema,\n  ...middlewares: (\n    | IMiddleware<TSource, TContext, TArgs>\n    | IMiddlewareGenerator<TSource, TContext, TArgs>\n  )[]\n): GraphQLSchemaWithFragmentReplacements {\n  return applyMiddlewareWithOptions(\n    schema,\n    { onlyDeclaredResolvers: false },\n    ...middlewares,\n  )\n}\n\n/**\n *\n * @param schema\n * @param middlewares\n *\n * Apply middleware to declared resolvers and return new schema.\n *\n */\nexport function applyMiddlewareToDeclaredResolvers<\n  TSource = any,\n  TContext = any,\n  TArgs = any\n>(\n  schema: GraphQLSchema,\n  ...middlewares: (\n    | IMiddleware<TSource, TContext, TArgs>\n    | IMiddlewareGenerator<TSource, TContext, TArgs>\n  )[]\n): GraphQLSchemaWithFragmentReplacements {\n  return applyMiddlewareWithOptions(\n    schema,\n    { onlyDeclaredResolvers: true },\n    ...middlewares,\n  )\n}\n"
  },
  {
    "path": "src/types.ts",
    "content": "import {\n  GraphQLResolveInfo,\n  GraphQLSchema,\n  GraphQLTypeResolver,\n  GraphQLIsTypeOfFn,\n} from 'graphql'\nimport { StitchingInfo } from '@graphql-tools/delegate'\n\n// Middleware Tree\n\nexport declare type IMiddlewareFragment = string\n\nexport declare type IMiddlewareResolver<\n  TSource = any,\n  TContext = any,\n  TArgs = any\n> = (\n  resolve: (\n    source?: TSource,\n    args?: TArgs,\n    context?: TContext,\n    info?: GraphQLResolveInfo & { stitchingInfo?: StitchingInfo },\n  ) => any,\n  parent: TSource,\n  args: TArgs,\n  context: TContext,\n  info: GraphQLResolveInfo,\n) => Promise<any>\n\nexport interface IMiddlewareWithOptions<\n  TSource = any,\n  TContext = any,\n  TArgs = any\n> {\n  fragment?: IMiddlewareFragment\n  fragments?: IMiddlewareFragment[]\n  resolve?: IMiddlewareResolver<TSource, TContext, TArgs>\n}\n\nexport type IMiddlewareFunction<TSource = any, TContext = any, TArgs = any> =\n  | IMiddlewareWithOptions<TSource, TContext, TArgs>\n  | IMiddlewareResolver<TSource, TContext, TArgs>\n\nexport interface IMiddlewareTypeMap<\n  TSource = any,\n  TContext = any,\n  TArgs = any\n> {\n  [key: string]:\n    | IMiddlewareFunction<TSource, TContext, TArgs>\n    | IMiddlewareFieldMap<TSource, TContext, TArgs>\n}\n\nexport interface IMiddlewareFieldMap<\n  TSource = any,\n  TContext = any,\n  TArgs = any\n> {\n  [key: string]: IMiddlewareFunction<TSource, TContext, TArgs>\n}\n\n// Middleware Generator\n\nexport declare class IMiddlewareGenerator<TSource, TContext, TArgs> {\n  constructor(\n    generator: IMiddlewareGeneratorConstructor<TSource, TContext, TArgs>,\n  )\n  generate(schema: GraphQLSchema): IMiddleware<TSource, TContext, TArgs>\n}\n\nexport declare type IMiddlewareGeneratorConstructor<\n  TSource = any,\n  TContext = any,\n  TArgs = any\n> = (schema: GraphQLSchema) => IMiddleware<TSource, TContext, TArgs>\n\nexport declare type IMiddleware<TSource = any, TContext = any, TArgs = any> =\n  | IMiddlewareFunction<TSource, TContext, TArgs>\n  | IMiddlewareTypeMap<TSource, TContext, TArgs>\n\n// Middleware\n\nexport declare type IApplyOptions = {\n  onlyDeclaredResolvers: boolean\n}\n\nexport declare type GraphQLSchemaWithFragmentReplacements = GraphQLSchema & {\n  schema?: GraphQLSchema\n  fragmentReplacements?: FragmentReplacement[]\n}\n\n// Fragments (inspired by graphql-tools)\n\nexport interface FragmentReplacement {\n  field: string\n  fragment: string\n}\n\nexport interface IResolvers<TSource = any, TContext = any> {\n  [key: string]: IResolverObject<TSource, TContext>\n}\n\nexport interface IResolverObject<TSource = any, TContext = any> {\n  [key: string]:\n    | IFieldResolver<TSource, TContext>\n    | IResolverOptions<TSource, TContext>\n}\n\nexport interface IResolverOptions<TSource = any, TContext = any> {\n  fragment?: string\n  fragments?: string[]\n  resolve?: IFieldResolver<TSource, TContext>\n  subscribe?: IFieldResolver<TSource, TContext>\n  __resolveType?: GraphQLTypeResolver<TSource, TContext>\n  __isTypeOf?: GraphQLIsTypeOfFn<TSource, TContext>\n}\n\nexport type IFieldResolver<TSource, TContext> = (\n  source: TSource,\n  args: { [argument: string]: any },\n  context: TContext,\n  info: GraphQLResolveInfo & { stitchingInfo?: StitchingInfo },\n) => any\n"
  },
  {
    "path": "src/utils.ts",
    "content": "import { GraphQLObjectType, GraphQLInterfaceType } from 'graphql'\nimport {\n  IMiddlewareResolver,\n  IMiddlewareWithOptions,\n  IMiddlewareFunction,\n  IMiddlewareGenerator,\n} from './types'\nimport { MiddlewareGenerator } from './generator'\n\n// Type checkers\n\nexport function isMiddlewareResolver<TSource, TContext, TArgs>(\n  obj: any,\n): obj is IMiddlewareResolver<TSource, TContext, TArgs> {\n  return (\n    typeof obj === 'function' ||\n    (typeof obj === 'object' && obj.then !== undefined)\n  )\n}\n\nexport function isMiddlewareWithFragment<TSource, TContext, TArgs>(\n  obj: any,\n): obj is IMiddlewareWithOptions<TSource, TContext, TArgs> {\n  return (\n    (typeof obj.fragment === 'string' || typeof obj.fragments === 'object') &&\n    isMiddlewareResolver(obj.resolve)\n  )\n}\n\nexport function isMiddlewareFunction<TSource, TContext, TArgs>(\n  obj: any,\n): obj is IMiddlewareFunction<TSource, TContext, TArgs> {\n  return isMiddlewareWithFragment(obj) || isMiddlewareResolver(obj)\n}\n\nexport function isMiddlewareGenerator<TSource, TContext, TArgs>(\n  x: any,\n): x is IMiddlewareGenerator<TSource, TContext, TArgs> {\n  return x instanceof MiddlewareGenerator\n}\n\nexport function isGraphQLObjectType(\n  obj: any,\n): obj is GraphQLObjectType | GraphQLInterfaceType {\n  return obj instanceof GraphQLObjectType || obj instanceof GraphQLInterfaceType\n}\n"
  },
  {
    "path": "src/validation.ts",
    "content": "import { GraphQLSchema, GraphQLObjectType, GraphQLInterfaceType } from 'graphql'\nimport { IMiddleware } from './types'\nimport { isMiddlewareFunction } from './utils'\n\nexport function validateMiddleware<TSource, TContext, TArgs>(\n  schema: GraphQLSchema,\n  middleware: IMiddleware<TSource, TContext, TArgs>,\n): IMiddleware<TSource, TContext, TArgs> {\n  if (isMiddlewareFunction(middleware)) {\n    return middleware\n  }\n\n  const types = schema.getTypeMap()\n\n  Object.keys(middleware).forEach(type => {\n    if (!Object.keys(types).includes(type)) {\n      throw new MiddlewareError(\n        `Type ${type} exists in middleware but is missing in Schema.`,\n      )\n    }\n\n    if (!isMiddlewareFunction(middleware[type])) {\n      const fields = (types[type] as\n        | GraphQLObjectType\n        | GraphQLInterfaceType).getFields()\n\n      Object.keys(middleware[type]).forEach(field => {\n        if (!Object.keys(fields).includes(field)) {\n          throw new MiddlewareError(\n            `Field ${type}.${field} exists in middleware but is missing in Schema.`,\n          )\n        }\n\n        if (!isMiddlewareFunction(middleware[type][field])) {\n          throw new MiddlewareError(\n            `Expected ${type}.${field} to be a function but found ` +\n              typeof middleware[type][field],\n          )\n        }\n      })\n    }\n  })\n\n  return middleware\n}\n\nexport class MiddlewareError extends Error {}\n"
  },
  {
    "path": "tests/core.test.ts",
    "content": "import { makeExecutableSchema } from '@graphql-tools/schema'\nimport { ExecutionResult, graphql, subscribe, parse } from 'graphql'\nimport { $$asyncIterator } from 'iterall'\n\nimport { applyMiddleware } from '../src'\nimport {\n  IResolvers,\n  IMiddlewareTypeMap,\n  IMiddlewareFunction,\n} from '../src/types'\n\ndescribe('core:', () => {\n  /* Schema. */\n\n  const typeDefs = `\n    type Query {\n      before(arg: String!): String!\n      beforeNothing(arg: String!): String!\n      after: String!\n      afterNothing: String!\n      null: String\n      nested: Nothing!\n      resolverless: Resolverless!\n    }\n\n    type Subscription {\n      sub: String\n    }\n\n    type Nothing {\n      nothing: String!\n    }\n\n    type Resolverless {\n      someData: String!\n    }\n\n    schema {\n      query: Query,\n      subscription: Subscription\n    }\n  `\n\n  const resolvers: IResolvers = {\n    Query: {\n      before: (parent, { arg }, ctx, info) => arg,\n      beforeNothing: (parent, { arg }, ctx, info) => arg,\n      after: () => 'after',\n      afterNothing: () => 'after',\n      null: () => null,\n      nested: () => ({}),\n      resolverless: () => ({ someData: 'data' }),\n    },\n    Subscription: {\n      sub: {\n        subscribe: async (parent, { arg }, ctx, info) => {\n          const iterator = {\n            next: () => Promise.resolve({ done: false, value: { sub: arg } }),\n            return: () => {\n              return\n            },\n            throw: () => {\n              return\n            },\n            [$$asyncIterator]: () => iterator,\n          }\n          return iterator\n        },\n      },\n    },\n    Nothing: {\n      nothing: () => 'nothing',\n    },\n  }\n\n  const getSchema = () => makeExecutableSchema({ typeDefs, resolvers })\n\n  // Field Middleware\n\n  // Type Middleware\n\n  const typeMiddlewareBefore: IMiddlewareTypeMap = {\n    Query: async (resolve, parent, args, context, info) => {\n      const _args = { arg: 'changed' }\n      return resolve(parent, _args)\n    },\n    Subscription: async (resolve, parent, args, context, info) => {\n      const _args = { arg: 'changed' }\n      return resolve(parent, _args)\n    },\n  }\n\n  const typeMiddlewareAfter: IMiddlewareTypeMap = {\n    Query: async (resolve, parent, args, context, info) => {\n      const res = resolve()\n      return 'changed'\n    },\n  }\n\n  // Schema Middleware\n\n  const schemaMiddlewareBefore: IMiddlewareFunction = async (\n    resolve,\n    parent,\n    args,\n    context,\n    info,\n  ) => {\n    const _args = { arg: 'changed' }\n    return resolve(parent, _args, context, info)\n  }\n\n  const schemaMiddlewareAfter: IMiddlewareFunction = async (\n    resolve,\n    parent,\n    args,\n    context,\n    info,\n  ) => {\n    const res = resolve()\n    return 'changed'\n  }\n\n  const emptyStringMiddleware: IMiddlewareFunction = async (\n    resolve,\n    parent,\n    args,\n    context,\n    info,\n  ) => {\n    if (/^String!?$/.test(String(info.returnType))) {\n      return ''\n    } else {\n      return resolve()\n    }\n  }\n\n  test('field middleware', async () => {\n    const schema = getSchema()\n    const fieldMiddleware: IMiddlewareTypeMap = {\n      Query: {\n        before: async (resolve, parent) => {\n          const _args = { arg: 'changed' }\n          return resolve(parent, _args)\n        },\n        after: async (resolve) => {\n          return 'changed'\n        },\n      },\n    }\n    const schemaWithMiddleware = applyMiddleware(schema, fieldMiddleware)\n\n    const query = `\n      query {\n        before(arg: \"before\")\n        beforeNothing(arg: \"before\")\n        after\n        afterNothing\n        null\n        nested { nothing }\n      }\n    `\n    const res = await graphql({ schema: schemaWithMiddleware, source: query })\n\n    /* Tests. */\n\n    expect(res).toEqual({\n      data: {\n        before: 'changed',\n        beforeNothing: 'before',\n        after: 'changed',\n        afterNothing: 'after',\n        null: null,\n        nested: { nothing: 'nothing' },\n      },\n    })\n  })\n\n  test('field middleware subscriptions', async () => {\n    const schema = getSchema()\n\n    const fieldMiddleware: IMiddlewareTypeMap = {\n      Subscription: {\n        sub: async (resolve, parent, args, context, info) => {\n          const _args = { arg: 'changed' }\n          return resolve(parent, _args)\n        },\n      },\n    }\n    const schemaWithMiddleware = applyMiddleware(schema, fieldMiddleware)\n\n    const query = `\n      subscription {\n        sub\n      }\n    `\n    const iterator = await subscribe({\n      schema: schemaWithMiddleware,\n      document: parse(query),\n    })\n    const res = await (iterator as AsyncIterator<ExecutionResult>).next()\n\n    /* Tests. */\n\n    expect(res).toEqual({\n      done: false,\n      value: {\n        data: {\n          sub: 'changed',\n        },\n      },\n    })\n  })\n\n  test('type middleware before', async () => {\n    const schema = getSchema()\n    const schemaWithMiddleware = applyMiddleware(schema, typeMiddlewareBefore)\n\n    const query = `\n      query {\n        before(arg: \"before\")\n        beforeNothing(arg: \"before\")\n        after\n        afterNothing\n        null\n        nested { nothing }\n      }\n    `\n    const res = await graphql({ schema: schemaWithMiddleware, source: query })\n\n    /* Tests. */\n\n    expect(res).toEqual({\n      data: {\n        before: 'changed',\n        beforeNothing: 'changed',\n        after: 'after',\n        afterNothing: 'after',\n        null: null,\n        nested: { nothing: 'nothing' },\n      },\n    })\n  })\n\n  test('type middleware after', async () => {\n    const schema = getSchema()\n    const schemaWithMiddleware = applyMiddleware(schema, typeMiddlewareAfter)\n\n    const query = `\n      query {\n        before(arg: \"before\")\n        beforeNothing(arg: \"before\")\n        after\n        afterNothing\n        null\n        nested { nothing }\n      }\n    `\n    const res = await graphql({ schema: schemaWithMiddleware, source: query })\n\n    /* Tests. */\n\n    expect(res).toEqual({\n      data: {\n        before: 'changed',\n        beforeNothing: 'changed',\n        after: 'changed',\n        afterNothing: 'changed',\n        null: 'changed',\n        nested: { nothing: 'nothing' },\n      },\n    })\n  })\n\n  test('type middleware subscriptions', async () => {\n    const schema = getSchema()\n    const schemaWithMiddleware = applyMiddleware(schema, typeMiddlewareBefore)\n\n    const query = `\n      subscription {\n        sub\n      }\n    `\n    const iterator = await subscribe({\n      schema: schemaWithMiddleware,\n      document: parse(query),\n    })\n    const res = await (iterator as AsyncIterator<ExecutionResult>).next()\n\n    expect(res).toEqual({\n      done: false,\n      value: {\n        data: {\n          sub: 'changed',\n        },\n      },\n    })\n  })\n\n  test('schema middleware before', async () => {\n    const schema = getSchema()\n    const schemaWithMiddleware = applyMiddleware(schema, schemaMiddlewareBefore)\n\n    const query = `\n      query {\n        before(arg: \"before\")\n        beforeNothing(arg: \"before\")\n        after\n        afterNothing\n        null\n        nested { nothing }\n      }\n    `\n    const res = await graphql({ schema: schemaWithMiddleware, source: query })\n\n    /* Tests. */\n\n    expect(res).toEqual({\n      data: {\n        before: 'changed',\n        beforeNothing: 'changed',\n        after: 'after',\n        afterNothing: 'after',\n        null: null,\n        nested: { nothing: 'nothing' },\n      },\n    })\n  })\n\n  test('schema middleware after', async () => {\n    const schema = getSchema()\n    const schemaWithMiddleware = applyMiddleware(schema, schemaMiddlewareAfter)\n\n    const query = `\n      query {\n        before(arg: \"before\")\n        beforeNothing(arg: \"before\")\n        after\n        afterNothing\n        null\n        nested { nothing }\n      }\n    `\n    const res = await graphql({ schema: schemaWithMiddleware, source: query })\n\n    /* Tests. */\n\n    expect(res).toEqual({\n      data: {\n        before: 'changed',\n        beforeNothing: 'changed',\n        after: 'changed',\n        afterNothing: 'changed',\n        null: 'changed',\n        nested: { nothing: 'changed' },\n      },\n    })\n  })\n\n  test('schema middleware before', async () => {\n    const schema = getSchema()\n    const schemaWithMiddleware = applyMiddleware(schema, schemaMiddlewareBefore)\n\n    const query = `\n      query {\n        before(arg: \"before\")\n        beforeNothing(arg: \"before\")\n        after\n        afterNothing\n        null\n        nested { nothing }\n      }\n    `\n    const res = await graphql({ schema: schemaWithMiddleware, source: query })\n\n    /* Tests. */\n\n    expect(res).toEqual({\n      data: {\n        before: 'changed',\n        beforeNothing: 'changed',\n        after: 'after',\n        afterNothing: 'after',\n        null: null,\n        nested: { nothing: 'nothing' },\n      },\n    })\n  })\n\n  test('schema middleware subscription', async () => {\n    const schema = getSchema()\n    const schemaWithMiddleware = applyMiddleware(schema, schemaMiddlewareBefore)\n\n    const query = `\n      subscription {\n        sub\n      }\n    `\n    const iterator = await subscribe({\n      schema: schemaWithMiddleware,\n      document: parse(query),\n    })\n    const res = await (iterator as AsyncIterator<ExecutionResult>).next()\n\n    expect(res).toEqual({\n      done: false,\n      value: {\n        data: {\n          sub: 'changed',\n        },\n      },\n    })\n  })\n\n  test('schema middleware uses default field resolver', async () => {\n    const schema = getSchema()\n    const schemaWithMiddleware = applyMiddleware(schema, schemaMiddlewareBefore)\n\n    const query = `\n      query {\n        resolverless {\n          someData\n        }\n      }\n    `\n    const res = await graphql({ schema: schemaWithMiddleware, source: query })\n\n    expect(res).toEqual({\n      data: {\n        resolverless: {\n          someData: 'data',\n        },\n      },\n    })\n  })\n})\n"
  },
  {
    "path": "tests/execution.test.ts",
    "content": "import { makeExecutableSchema } from '@graphql-tools/schema'\nimport { graphql } from 'graphql'\nimport {\n  applyMiddleware,\n  applyMiddlewareToDeclaredResolvers,\n  IMiddlewareFunction,\n} from '../src'\nimport { IResolvers } from '../src/types'\n\ndescribe('execution:', () => {\n  test('follows correct order', async () => {\n    // Schema\n\n    const typeDefs = `\n      type Query {\n        test: String!\n      }\n    `\n\n    const resolvers = {\n      Query: {\n        test: () => 'pass',\n      },\n    }\n\n    const schema = makeExecutableSchema({ typeDefs, resolvers })\n\n    /* Middleware tests. */\n\n    let sequence: string[] = []\n\n    const firstMiddleware: IMiddlewareFunction = async (resolve) => {\n      sequence.push('first')\n      return resolve()\n    }\n\n    const secondMiddleware: IMiddlewareFunction = async (resolve) => {\n      sequence.push('second')\n      return resolve()\n    }\n\n    const schemaWithMiddleware = applyMiddleware(\n      schema,\n      firstMiddleware,\n      secondMiddleware,\n    )\n\n    const query = `\n      query {\n        test\n      }\n    `\n    await graphql({\n      schema: schemaWithMiddleware,\n      source: query,\n      rootValue: null,\n      contextValue: {},\n    })\n\n    /* Tests */\n\n    expect(JSON.stringify(sequence)).toBe(JSON.stringify(['first', 'second']))\n  })\n\n  test('forwards arguments correctly', async () => {\n    /* Schema. */\n\n    const typeDefs = `\n      type Query {\n        test(arg: String): String!\n      }\n    `\n\n    const resolvers: IResolvers = {\n      Query: {\n        test: (parent, { arg }) => arg,\n      },\n    }\n\n    const schema = makeExecutableSchema({ resolvers, typeDefs })\n\n    /* Middleware. */\n\n    const randomTestString = Math.random().toString()\n\n    const middleware: IMiddlewareFunction = (resolve, parent) => {\n      return resolve(parent, { arg: randomTestString })\n    }\n\n    const schemaWithMiddleware = applyMiddleware(schema, middleware)\n\n    const query = `\n      query {\n        test(arg: \"none\")\n      }\n    `\n\n    const res = await graphql({ schema: schemaWithMiddleware, source: query })\n\n    /* Tests. */\n\n    expect(res).toEqual({\n      data: {\n        test: randomTestString,\n      },\n    })\n  })\n\n  test('applies multiple middlwares only to declared resolvers', async () => {\n    /* Schema. */\n\n    const typeDefs = `\n      type Object {\n        id: String,\n        name: String\n      }\n      type Query {\n        test(arg: String): Object!\n      }\n    `\n\n    const resolvers: IResolvers = {\n      Query: {\n        test: (parent, { arg }) => ({ id: arg, name: 'name' }),\n      },\n    }\n\n    const schema = makeExecutableSchema({ resolvers, typeDefs })\n\n    /* Middleware. */\n\n    const randomTestString = Math.random().toString()\n\n    const firstMiddleware: IMiddlewareFunction = jest.fn((resolve, parent) => {\n      return resolve(parent, { arg: randomTestString })\n    })\n    const secondMiddleware: IMiddlewareFunction = jest.fn((resolve, parent) => {\n      return resolve(parent, { arg: randomTestString })\n    })\n\n    const schemaWithMiddleware = applyMiddlewareToDeclaredResolvers(\n      schema,\n      firstMiddleware,\n      secondMiddleware,\n    )\n\n    const query = `\n      query {\n        test(arg: \"id\") {\n          id\n          name\n        }\n      }\n    `\n\n    await graphql({ schema: schemaWithMiddleware, source: query })\n\n    /* Tests. */\n    expect(firstMiddleware).toHaveBeenCalledTimes(1)\n    expect(secondMiddleware).toHaveBeenCalledTimes(1)\n  })\n})\n"
  },
  {
    "path": "tests/fragments.test.ts",
    "content": "import { makeExecutableSchema } from '@graphql-tools/schema'\nimport { $$asyncIterator } from 'iterall'\nimport {\n  applyMiddleware,\n  applyMiddlewareToDeclaredResolvers,\n  IMiddlewareFunction,\n  IMiddlewareTypeMap,\n} from '../src'\nimport { IResolvers } from '../src/types'\n\n/**\n * Tests whether graphql-middleware-tool correctly applies middleware to fields it\n * ought to impact based on the width of the middleware specification.\n */\ndescribe('fragments:', () => {\n  test('schema-wide middleware', async () => {\n    /* Schema. */\n    const typeDefs = `\n      type Query {\n        book: Book!\n      }\n\n      type Book {\n        id: ID!\n        name: String!\n        content: String!\n        author: String!\n      }\n    `\n\n    const resolvers = {\n      Query: {\n        book() {\n          return {\n            id: 'id',\n            name: 'name',\n            content: 'content',\n            author: 'author',\n          }\n        },\n      },\n    }\n\n    const schema = makeExecutableSchema({ typeDefs, resolvers })\n\n    /* Middleware. */\n\n    const schemaMiddlewareWithFragment: IMiddlewareFunction = {\n      fragment: `fragment NodeID on Node { id }`,\n      resolve: (resolve) => resolve(),\n    }\n\n    const { fragmentReplacements } = applyMiddleware(\n      schema,\n      schemaMiddlewareWithFragment,\n    )\n\n    /* Tests. */\n\n    expect(fragmentReplacements).toEqual([\n      { field: 'book', fragment: '... on Node {\\n  id\\n}' },\n      { field: 'name', fragment: '... on Node {\\n  id\\n}' },\n      { field: 'content', fragment: '... on Node {\\n  id\\n}' },\n      { field: 'author', fragment: '... on Node {\\n  id\\n}' },\n    ])\n  })\n\n  test('type-wide middleware', async () => {\n    /* Schema. */\n    const typeDefs = `\n      type Query {\n        book: Book!\n        author: Author!\n      }\n\n      type Book {\n        id: ID!\n        content: String!\n        author: String!\n      }\n\n      type Author {\n        id: ID!\n        name: String!\n      }\n    `\n\n    const resolvers = {\n      Query: {\n        book() {\n          return {\n            id: 'id',\n            content: 'content',\n            author: 'author',\n          }\n        },\n        author() {\n          return {\n            name: 'name',\n          }\n        },\n      },\n    }\n\n    const schema = makeExecutableSchema({ typeDefs, resolvers })\n\n    // Middleware\n\n    const typeMiddlewareWithFragment: IMiddlewareTypeMap = {\n      Book: {\n        fragment: `fragment BookId on Book { id }`,\n        resolve: (resolve) => resolve(),\n      },\n      Author: {\n        fragments: [`... on Author { id }`, `... on Author { name }`],\n        resolve: (resolve) => resolve(),\n      },\n    }\n\n    const { fragmentReplacements } = applyMiddleware(\n      schema,\n      typeMiddlewareWithFragment,\n    )\n\n    /* Tests. */\n\n    expect(fragmentReplacements).toEqual([\n      {\n        field: 'content',\n        fragment: '... on Book {\\n  id\\n}',\n      },\n      {\n        field: 'author',\n        fragment: '... on Book {\\n  id\\n}',\n      },\n      {\n        field: 'id',\n        fragment: '... on Author {\\n  name\\n}',\n      },\n      {\n        field: 'name',\n        fragment: '... on Author {\\n  id\\n}',\n      },\n    ])\n  })\n\n  test('field-specific middleware', async () => {\n    const typeDefs = `\n      type Query {\n        book: Book!\n      }\n\n      type Book {\n        id: ID!\n        name: String!\n        content: String!\n        author: String!\n      }\n    `\n\n    const resolvers = {\n      Query: {\n        book() {\n          return {\n            id: 'id',\n            name: 'name',\n            content: 'content',\n            author: 'author',\n          }\n        },\n      },\n    }\n\n    const schema = makeExecutableSchema({ typeDefs, resolvers })\n\n    // Middleware\n\n    const fieldMiddlewareWithFragment: IMiddlewareTypeMap = {\n      Book: {\n        content: {\n          fragment: `fragment BookId on Book { id ... on Book { name } }`,\n          resolve: (resolve) => resolve(),\n        },\n        author: {\n          fragments: [\n            `fragment BookId on Book { id }`,\n            `fragment BookContent on Book { content }`,\n          ],\n          resolve: (resolve) => resolve(),\n        },\n      },\n    }\n\n    const { fragmentReplacements } = applyMiddleware(\n      schema,\n      fieldMiddlewareWithFragment,\n    )\n\n    /* Tests. */\n\n    expect(fragmentReplacements).toEqual([\n      {\n        field: 'content',\n        fragment: '... on Book {\\n  id\\n  ... on Book {\\n    name\\n  }\\n}',\n      },\n      {\n        field: 'author',\n        fragment: '... on Book {\\n  id\\n}',\n      },\n      {\n        field: 'author',\n        fragment: '... on Book {\\n  content\\n}',\n      },\n    ])\n  })\n\n  test('subscription fragment', async () => {\n    /* Schema. */\n    const typeDefs = `\n      type Query {\n        book(id: ID!): Book!\n      }\n\n      type Subscription {\n        book(id: ID!): Book!\n      }\n\n      type Book {\n        id: ID!\n        name: String!\n      }\n\n      schema {\n        query: Query,\n        subscription: Subscription\n      }\n    `\n\n    const resolvers: IResolvers = {\n      Query: {\n        book() {\n          return {\n            id: 'id',\n            name: 'name',\n          }\n        },\n      },\n      Subscription: {\n        book: {\n          subscribe: async (parent, { id }) => {\n            const iterator = {\n              next: () => Promise.resolve({ done: false, value: { sub: id } }),\n              return: () => {\n                return\n              },\n              throw: () => {\n                return\n              },\n              [$$asyncIterator]: () => iterator,\n            }\n            return iterator\n          },\n        },\n      },\n    }\n\n    const schema = makeExecutableSchema({ typeDefs, resolvers })\n\n    /* Middleware. */\n\n    const fieldMiddlewareWithFragment: IMiddlewareTypeMap = {\n      Subscription: {\n        book: {\n          fragment: `fragment Ignored on Book { ignore }`,\n          resolve: (resolve) => resolve(),\n        },\n      },\n    }\n\n    const { fragmentReplacements } = applyMiddlewareToDeclaredResolvers(\n      schema,\n      fieldMiddlewareWithFragment,\n    )\n\n    /* Tests. */\n\n    expect(fragmentReplacements).toEqual([\n      {\n        field: 'book',\n        fragment: '... on Book {\\n  ignore\\n}',\n      },\n    ])\n  })\n})\n\ndescribe('fragments on declared resolvers:', () => {\n  test('schema-wide middleware', async () => {\n    /* Schema. */\n    const typeDefs = `\n      type Query {\n        book: Book!\n      }\n\n      type Book {\n        id: ID!\n        name: String!\n        content: String!\n        author: String!\n      }\n    `\n\n    const resolvers = {\n      Query: {\n        book() {\n          return {\n            id: 'id',\n            name: 'name',\n            content: 'content',\n            author: 'author',\n          }\n        },\n      },\n    }\n\n    const schema = makeExecutableSchema({ typeDefs, resolvers })\n\n    /* Middleware. */\n\n    const schemaMiddlewareWithFragment: IMiddlewareFunction = {\n      fragment: `fragment NodeId on Node { id }`,\n      resolve: (resolve) => resolve(),\n    }\n\n    const { fragmentReplacements } = applyMiddlewareToDeclaredResolvers(\n      schema,\n      schemaMiddlewareWithFragment,\n    )\n\n    /* Tests. */\n\n    expect(fragmentReplacements).toEqual([\n      { field: 'book', fragment: '... on Node {\\n  id\\n}' },\n    ])\n  })\n\n  test('type-wide middleware', async () => {\n    /* Schema. */\n    const typeDefs = `\n      type Query {\n        book: Book!\n      }\n\n      type Book {\n        id: ID!\n        name: String!\n        content: String!\n        author: String!\n      }\n    `\n\n    const resolvers = {\n      Query: {\n        book() {\n          return {\n            id: 'id',\n            name: 'name',\n            content: 'content',\n            author: 'author',\n          }\n        },\n      },\n    }\n\n    const schema = makeExecutableSchema({ typeDefs, resolvers })\n\n    /* Middleware. */\n\n    const typeMiddlewareWithFragment: IMiddlewareTypeMap = {\n      Query: {\n        fragments: [`fragment QueryViewer on Query { viewer }`],\n        resolve: (resolve) => resolve(),\n      },\n      Book: {\n        fragment: `... on Book { id }`,\n        resolve: (resolve) => resolve(),\n      },\n    }\n\n    const { fragmentReplacements } = applyMiddlewareToDeclaredResolvers(\n      schema,\n      typeMiddlewareWithFragment,\n    )\n\n    /* Tests. */\n\n    expect(fragmentReplacements).toEqual([\n      {\n        field: 'book',\n        fragment: '... on Query {\\n  viewer\\n}',\n      },\n    ])\n  })\n\n  test('field-specific middleware', async () => {\n    /* Schema. */\n    const typeDefs = `\n      type Query {\n        book: Book!\n      }\n\n      type Book {\n        id: ID!\n        name: String!\n        content: String!\n        author: String!\n      }\n    `\n\n    const resolvers = {\n      Query: {\n        book() {\n          return {}\n        },\n      },\n      Book: {\n        id: () => 'id',\n        name: () => 'name',\n        content: () => 'content',\n        author: () => 'author',\n      },\n    }\n\n    const schema = makeExecutableSchema({ typeDefs, resolvers })\n\n    /* Middleware. */\n\n    const fieldMiddlewareWithFragment: IMiddlewareTypeMap = {\n      Book: {\n        id: {\n          fragment: `fragment Ignored on Book { ignore }`,\n          resolve: (resolve) => resolve(),\n        },\n        content: {\n          fragment: `fragment BookId on Book { id }`,\n          resolve: (resolve) => resolve(),\n        },\n        author: {\n          fragments: [\n            `fragment AuthorId on Author { id }`,\n            `fragment AuthorName on Author { name }`,\n          ],\n          resolve: (resolve) => resolve(),\n        },\n      },\n    }\n\n    const { fragmentReplacements } = applyMiddlewareToDeclaredResolvers(\n      schema,\n      fieldMiddlewareWithFragment,\n    )\n\n    /* Tests. */\n\n    expect(fragmentReplacements).toEqual([\n      {\n        field: 'id',\n        fragment: '... on Book {\\n  ignore\\n}',\n      },\n      {\n        field: 'content',\n        fragment: '... on Book {\\n  id\\n}',\n      },\n      {\n        field: 'author',\n        fragment: '... on Author {\\n  id\\n}',\n      },\n      {\n        field: 'author',\n        fragment: '... on Author {\\n  name\\n}',\n      },\n    ])\n  })\n})\n\ntest('imparsable fragment', async () => {\n  /* Schema. */\n  const typeDefs = `\n      type Query {\n        book: String!\n      }\n    `\n\n  const resolvers = {\n    Query: {\n      book() {\n        return 'book'\n      },\n    },\n  }\n\n  const schema = makeExecutableSchema({ typeDefs, resolvers })\n\n  /* Middleware. */\n\n  const fieldMiddlewareWithFragment: IMiddlewareFunction = {\n    fragment: 'foo',\n    resolve: (resolve) => resolve(),\n  }\n\n  /* Tests. */\n\n  expect(() => {\n    applyMiddlewareToDeclaredResolvers(schema, fieldMiddlewareWithFragment)\n  }).toThrow('Could not parse fragment')\n})\n"
  },
  {
    "path": "tests/generator.test.ts",
    "content": "import { makeExecutableSchema } from '@graphql-tools/schema'\nimport { GraphQLSchema } from 'graphql'\nimport { applyMiddleware, middleware, IMiddlewareGenerator } from '../src'\n\ntest('middleware generator integration', async () => {\n  /* Schema. */\n  const typeDefs = `\n    type Query {\n      test: String!\n    }\n  `\n\n  const resolvers = {\n    Query: {\n      test: () => 'fail',\n    },\n  }\n\n  const schema = makeExecutableSchema({ typeDefs, resolvers })\n\n  let generatorSchema: GraphQLSchema\n\n  /* Middleware. */\n\n  const testMiddleware: IMiddlewareGenerator<any, any, any> = middleware(\n    (_schema) => {\n      generatorSchema = _schema\n      return async () => 'pass'\n    },\n  )\n\n  applyMiddleware(schema, testMiddleware)\n\n  /* Tests. */\n\n  expect(generatorSchema).toEqual(schema)\n})\n"
  },
  {
    "path": "tests/immutability.test.ts",
    "content": "import { makeExecutableSchema } from '@graphql-tools/schema'\nimport { graphql } from 'graphql'\nimport { applyMiddleware, IMiddleware } from '../src'\n\ntype Context = {\n  middlewareCalled: boolean\n}\n\ntest('immutable', async () => {\n  const typeDefs = `\n    type Query {\n      test: Boolean!\n    }\n  `\n  const resolvers = {\n    Query: {\n      test: (_: unknown, __: unknown, ctx: Context) => ctx.middlewareCalled,\n    },\n  }\n\n  const middleware: IMiddleware = (\n    resolve,\n    parent,\n    args,\n    ctx: Context,\n    info,\n  ) => {\n    ctx.middlewareCalled = true\n    return resolve(parent, args, { ...ctx, middlewareCalled: true }, info)\n  }\n  const middlewares = {\n    Query: {\n      test: middleware,\n    },\n  }\n\n  const schema = makeExecutableSchema({ typeDefs, resolvers })\n  const schemaWithMiddlewares = applyMiddleware(schema, middlewares)\n\n  const query = `\n    query TestQuery {\n      test\n    }\n  `\n\n  const responseWithMiddleware = await graphql({\n    schema: schemaWithMiddlewares,\n    source: query,\n    contextValue: { middlewareCalled: false },\n  })\n  expect(responseWithMiddleware.errors).toBeUndefined()\n  expect(responseWithMiddleware.data!.test).toEqual(true)\n\n  const responseWihoutMiddleware = await graphql({\n    schema,\n    source: query,\n    rootValue: {},\n    contextValue: { middlewareCalled: false },\n    variableValues: {},\n  })\n  expect(responseWihoutMiddleware.errors).toBeUndefined()\n  expect(responseWihoutMiddleware.data!.test).toEqual(false)\n})\n"
  },
  {
    "path": "tests/integration.test.ts",
    "content": "import { makeExecutableSchema } from '@graphql-tools/schema'\n// import { GraphQLServer as YogaServer } from 'graphql-yoga'\nimport { ApolloServer } from 'apollo-server'\nimport Axios from 'axios'\n// import { AddressInfo } from 'ws'\nimport { applyMiddleware } from '../src'\n\ndescribe('integrations', () => {\n  /* GraphQL Yoga */\n\n  // https://github.com/prisma-labs/graphql-yoga/issues/449\n  // We might bring back support for GraphQL Yoga if they start\n  // supporting new GraphQL versions.\n  //\n  // test('GraphQL Yoga', async () => {\n  //   const typeDefs = `\n  //     type Query {\n  //       test: String!\n  //     }\n  //   `\n\n  //   const resolvers = {\n  //     Query: {\n  //       test: () => 'test',\n  //     },\n  //   }\n\n  //   const schema = makeExecutableSchema({ typeDefs, resolvers })\n\n  //   const schemaWithMiddleware = applyMiddleware(schema, async (resolve) => {\n  //     const res = await resolve()\n  //     return `pass-${res}`\n  //   })\n\n  //   const server = new YogaServer({\n  //     schema: schemaWithMiddleware,\n  //   })\n  //   const http = await server.start({ port: 0 })\n  //   try {\n  //     const { port } = http.address() as AddressInfo\n  //     const uri = `http://localhost:${port}/`\n\n  //     /* Tests */\n\n  //     const query = `\n  //       query {\n  //         test\n  //       }\n  //     `\n\n  //     const body = await Axios.post(uri, {\n  //       query,\n  //     })\n\n  //     /* Tests. */\n\n  //     expect(body.data).toEqual({\n  //       data: {\n  //         test: 'pass-test',\n  //       },\n  //     })\n  //   } finally {\n  //     http.close()\n  //   }\n  // })\n\n  /* Apollo Server */\n\n  test('ApolloServer', async () => {\n    /* Schema. */\n    const typeDefs = `\n      type Query {\n        test: String!\n      }\n    `\n\n    const resolvers = {\n      Query: {\n        test: () => 'test',\n      },\n    }\n\n    const schema = makeExecutableSchema({ typeDefs, resolvers })\n\n    const schemaWithMiddleware = applyMiddleware(schema, async (resolve) => {\n      const res = await resolve()\n      return `pass-${res}`\n    })\n\n    const server = new ApolloServer({\n      schema: schemaWithMiddleware,\n    })\n\n    await server.listen({ port: 8008 })\n\n    const uri = `http://localhost:8008/`\n\n    /* Tests */\n\n    const query = `\n      query {\n        test\n      }\n    `\n    try {\n      const body = await Axios.post(uri, { query })\n      /* Tests. */\n\n      expect(body.data).toEqual({\n        data: {\n          test: 'pass-test',\n        },\n      })\n    } finally {\n      await server.stop()\n    }\n  })\n})\n"
  },
  {
    "path": "tests/validation.test.ts",
    "content": "import { makeExecutableSchema } from '@graphql-tools/schema'\nimport { validateMiddleware, MiddlewareError } from '../src/validation'\nimport { IMiddlewareFieldMap, IMiddlewareTypeMap } from '../src'\n\ndescribe('validation:', () => {\n  test('warns about the unknown type', async () => {\n    /* Schema. */\n    const typeDefs = `\n      type Query {\n        pass: String!\n      }\n    `\n\n    const resolvers = {\n      Query: {\n        pass: () => 'pass',\n      },\n    }\n\n    const schema = makeExecutableSchema({ resolvers, typeDefs })\n\n    /* Middleware. */\n\n    const middlewareWithUndefinedType: IMiddlewareFieldMap = {\n      Test: async () => ({}),\n    }\n\n    /* Tests. */\n\n    expect(() => {\n      validateMiddleware(schema, middlewareWithUndefinedType)\n    }).toThrow(\n      new MiddlewareError(\n        `Type Test exists in middleware but is missing in Schema.`,\n      ),\n    )\n  })\n\n  test('warns about the unknown field', async () => {\n    /* Schema. */\n    const typeDefs = `\n      type Query {\n        pass: String!\n      }\n    `\n\n    const resolvers = {\n      Query: {\n        pass: () => 'pass',\n      },\n    }\n\n    const schema = makeExecutableSchema({ resolvers, typeDefs })\n\n    /* Middleware. */\n\n    const middlewareWithUndefinedField: IMiddlewareTypeMap = {\n      Query: {\n        test: async () => ({}),\n      },\n    }\n\n    /* Tests. */\n\n    expect(() => {\n      validateMiddleware(schema, middlewareWithUndefinedField)\n    }).toThrow(\n      new MiddlewareError(\n        `Field Query.test exists in middleware but is missing in Schema.`,\n      ),\n    )\n  })\n\n  test('warns that middleware leafs are not functions', async () => {\n    /* Schema. */\n    const typeDefs = `\n    type Query {\n      test: String!\n    }\n  `\n\n    const resolvers = {\n      Query: {\n        test: () => 'pass',\n      },\n    }\n\n    const schema = makeExecutableSchema({ resolvers, typeDefs })\n\n    /* Middleware. */\n\n    const middlewareWithObjectField: any = {\n      Query: {\n        test: false,\n      },\n    }\n\n    /* Tests. */\n\n    expect(() => {\n      validateMiddleware(schema, middlewareWithObjectField as any)\n    }).toThrow(\n      new MiddlewareError(\n        `Expected Query.test to be a function but found boolean`,\n      ),\n    )\n  })\n})\n"
  },
  {
    "path": "tsconfig.json",
    "content": "{\n  \"compilerOptions\": {\n    \"target\": \"es2017\",\n    \"moduleResolution\": \"node\",\n    \"module\": \"commonjs\",\n    \"sourceMap\": true,\n    \"rootDir\": \"src\",\n    \"outDir\": \"dist\",\n    \"lib\": [\"esnext\"],\n    \"skipLibCheck\": true,\n    \"declaration\": true,\n    \"emitDeclarationOnly\": true\n  },\n  \"include\": [\"src/**/*\"],\n  \"exclude\": [\"node_modules\", \"dist\"]\n}\n"
  },
  {
    "path": "tsconfig.test.json",
    "content": "{\n  \"compilerOptions\": {\n    \"target\": \"es5\",\n    \"moduleResolution\": \"node\",\n    \"module\": \"commonjs\",\n    \"sourceMap\": true,\n    \"rootDir\": \"src\",\n    \"outDir\": \"dist\",\n    \"lib\": [\"esnext\"],\n    \"skipLibCheck\": true\n  },\n  \"include\": [\"tests/**/*\"],\n  \"exclude\": [\"node_modules\", \"dist\"]\n}\n"
  }
]