[
  {
    "path": ".gitignore",
    "content": "# Logs\nlogs\n*.log\nnpm-debug.log*\nyarn-debug.log*\nyarn-error.log*\nlerna-debug.log*\n\n# Diagnostic reports (https://nodejs.org/api/report.html)\nreport.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json\n\n# Runtime data\npids\n*.pid\n*.seed\n*.pid.lock\n\n# Directory for instrumented libs generated by jscoverage/JSCover\nlib-cov\n\n# Coverage directory used by tools like istanbul\ncoverage\n*.lcov\n\n# nyc test coverage\n.nyc_output\n\n# Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files)\n.grunt\n\n# Bower dependency directory (https://bower.io/)\nbower_components\n\n# node-waf configuration\n.lock-wscript\n\n# Compiled binary addons (https://nodejs.org/api/addons.html)\nbuild/Release\n\n# Dependency directories\nnode_modules/\njspm_packages/\n\n# TypeScript v1 declaration files\ntypings/\n\n# TypeScript cache\n*.tsbuildinfo\n\n# Optional npm cache directory\n.npm\n\n# Optional eslint cache\n.eslintcache\n\n# Microbundle cache\n.rpt2_cache/\n.rts2_cache_cjs/\n.rts2_cache_es/\n.rts2_cache_umd/\n\n# Optional REPL history\n.node_repl_history\n\n# Output of 'npm pack'\n*.tgz\n\n# Yarn Integrity file\n.yarn-integrity\n\n# dotenv environment variables file\n.env\n.env.test\n\n# parcel-bundler cache (https://parceljs.org/)\n.cache\n\n# Next.js build output\n.next\n\n# Nuxt.js build / generate output\n.nuxt\ndist\n\n# Gatsby files\n.cache/\n# Comment in the public line in if your project uses Gatsby and *not* Next.js\n# https://nextjs.org/blog/next-9-1#public-directory-support\n# public\n\n# vuepress build output\n.vuepress/dist\n\n# Serverless directories\n.serverless/\n\n# FuseBox cache\n.fusebox/\n\n# DynamoDB Local files\n.dynamodb/\n\n# TernJS port file\n.tern-port\n"
  },
  {
    "path": ".prettierignore",
    "content": "node_modules/\ndist/\npackage*.json\n\nexample/.next\nexample/src/queries/__generated__\nexample/data\n\nwebsite/node_modules\nwebsite/build\nwebsite/.docusaurus\nwebsite/.cache-loader\n"
  },
  {
    "path": ".prettierrc",
    "content": "{\n  \"singleQuote\": true,\n  \"bracketSpacing\": true,\n  \"arrowParens\": \"always\",\n  \"proseWrap\": \"always\"\n}\n"
  },
  {
    "path": "LICENSE",
    "content": "MIT License\n\nCopyright (c) 2021 Revere CRE\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\">\n  <b>Revere CRE is hiring! Interested in working on the cutting edge of frontend?</b>\n  <br>\n  <b>Reach out to <a href=\"mailto:eng-jobs@reverecre.com\">eng-jobs@reverecre.com</a> for more information.</b>\n</p>\n\n<h1 align=\"center\">\n  Relay + Next.js\n</h1>\n\n[![npm version](https://badge.fury.io/js/relay-nextjs.svg)](https://badge.fury.io/js/relay-nextjs)\n![npm downloads](https://img.shields.io/npm/dm/relay-nextjs)\n![npm bundle size](https://img.shields.io/bundlephobia/minzip/relay-nextjs)\n\n<p align=\"center\">\n  <a href=\"https://reverecre.github.io/relay-nextjs\"><b>Documentation</b></a> |\n  <a href=\"https://github.com/RevereCRE/relay-nextjs/discussions\"><b>Discussion</b></a> |\n  <a href=\"https://github.com/RevereCRE/relay-nextjs/releases\"><b>Latest Releases</b></a>\n</p>\n \n<p align=\"center\">\n  <code>relay-nextjs</code> is the best way to use Relay and Next.js in the same project! It supports\n  <b>incremental migration</b>, is <b>suspense ready</b>, and is <b>run in production</b> by major\n  companies.\n</p>\n\n## Overview\n\n`relay-nextjs` wraps page components, a GraphQL query, and some helper methods\nto automatically hook up data fetching using Relay. On initial load a Relay\nenvironment is created, the data is fetched server-side, the page is rendered,\nand resulting state is serialized as a script tag. On boot in the client a new\nRelay environment and preloaded query are created using that serialized state.\nData is fetched using the client-side Relay environment on subsequent\nnavigations.\n\nNote: `relay-nextjs` does not support [Nextjs 13 App Router](https://nextjs.org/docs/app) at the moment.\n\n- See [GitHub issue #89](https://github.com/RevereCRE/relay-nextjs/issues/89) for more info.\n\n## Getting Started\n\nInstall using npm or your other favorite package manager:\n\n```sh\n$ npm install relay-nextjs\n```\n\n`relay-nextjs` must be configured in `_app` to properly intercept and handle\nrouting.\n\n### Setting up the Relay Environment\n\nFor basic information about the Relay environment please see the\n[Relay docs](https://relay.dev/docs/getting-started/step-by-step-guide/#42-configure-relay-runtime).\n\n`relay-nextjs` was designed with both client-side and server-side rendering in\nmind. As such it needs to be able to use either a client-side or server-side\nRelay environment. The library knows how to handle which environment to use, but\nwe have to tell it how to create these environments. For this we will define two\nfunctions: `getClientEnvironment` and `createServerEnvironment`. Note the\ndistinction — on the client only one environment is ever created because there\nis only one app, but on the server we must create an environment per-render to\nensure the cache is not shared between requests.\n\nFirst we'll define `getClientEnvironment`:\n\n```tsx\n// lib/client_environment.ts\nimport { Environment, Network, Store, RecordSource } from 'relay-runtime';\n\nexport function createClientNetwork() {\n  return Network.create(async (params, variables) => {\n    const response = await fetch('/api/graphql', {\n      method: 'POST',\n      credentials: 'include',\n      headers: {\n        'Content-Type': 'application/json',\n      },\n      body: JSON.stringify({\n        query: params.text,\n        variables,\n      }),\n    });\n\n    const json = await response.text();\n    return JSON.parse(json);\n  });\n}\n\nlet clientEnv: Environment | undefined;\nexport function getClientEnvironment() {\n  if (typeof window === 'undefined') return null;\n\n  if (clientEnv == null) {\n    clientEnv = new Environment({\n      network: createClientNetwork(),\n      store: new Store(new RecordSource()),\n      isServer: false,\n    });\n  }\n\n  return clientEnv;\n}\n```\n\nand then `createServerEnvironment`:\n\n```tsx\nimport { graphql } from 'graphql';\nimport { GraphQLResponse, Network } from 'relay-runtime';\nimport { schema } from 'lib/schema';\n\nexport function createServerNetwork() {\n  return Network.create(async (text, variables) => {\n    const context = {\n      token,\n      // More context variables here\n    };\n\n    const results = await graphql({\n      schema,\n      source: text.text!,\n      variableValues: variables,\n      contextValue: context,\n    });\n\n    return JSON.parse(JSON.stringify(results)) as GraphQLResponse;\n  });\n}\n\nexport function createServerEnvironment() {\n  return new Environment({\n    network: createServerNetwork(),\n    store: new Store(new RecordSource()),\n    isServer: true,\n  });\n}\n```\n\nNote in the example server environment we’re executing against a local schema\nbut you may fetch from a remote API as well.\n\n### Configuring `_app`\n\n```tsx\n// pages/_app.tsx\nimport { RelayEnvironmentProvider } from 'react-relay/hooks';\nimport { useRelayNextjs } from 'relay-nextjs/app';\nimport { getClientEnvironment } from '../lib/client_environment';\n\nfunction MyApp({ Component, pageProps }: AppProps) {\n  const { env, ...relayProps } = useRelayNextjs(pageProps, {\n    createClientEnvironment: () => getClientSideEnvironment()!,\n  });\n\n  return (\n    <>\n      <RelayEnvironmentProvider environment={env}>\n        <Component {...pageProps} {...relayProps} />\n      </RelayEnvironmentProvider>\n    </>\n  );\n}\n\nexport default MyApp;\n```\n\n## Usage in a Page\n\n```tsx\n// src/pages/user/[uuid].tsx\nimport { withRelay, RelayProps } from 'relay-nextjs';\nimport { graphql, usePreloadedQuery } from 'react-relay/hooks';\n\n// The $uuid variable is injected automatically from the route.\nconst ProfileQuery = graphql`\n  query profile_ProfileQuery($uuid: ID!) {\n    user(id: $uuid) {\n      id\n      firstName\n      lastName\n    }\n  }\n`;\n\nfunction UserProfile({ preloadedQuery }: RelayProps<{}, profile_ProfileQuery>) {\n  const query = usePreloadedQuery(ProfileQuery, preloadedQuery);\n\n  return (\n    <div>\n      Hello {query.user.firstName} {query.user.lastName}\n    </div>\n  );\n}\n\nfunction Loading() {\n  return <div>Loading...</div>;\n}\n\nexport default withRelay(UserProfile, UserProfileQuery, {\n  // Fallback to render while the page is loading.\n  // This property is optional.\n  fallback: <Loading />,\n  // Create a Relay environment on the client-side.\n  // Note: This function must always return the same value.\n  createClientEnvironment: () => getClientEnvironment()!,\n  // variablesFromContext allows you to declare and customize variables for the graphql query.\n  // by default variablesFromContext is ctx.query\n  variablesFromContext: (ctx: NextRouter | NextPageContext) => ({ ...ctx.query, otherVariable: true }),\n  // Gets server side props for the page.\n  serverSideProps: async (ctx) => {\n    // This is an example of getting an auth token from the request context.\n    // If you don't need to authenticate users this can be removed and return an\n    // empty object instead.\n    const { getTokenFromCtx } = await import('lib/server/auth');\n    const token = await getTokenFromCtx(ctx);\n    if (token == null) {\n      return {\n        redirect: { destination: '/login', permanent: false },\n      };\n    }\n\n    return { token };\n  },\n  // Server-side props can be accessed as the second argument\n  // to this function.\n  createServerEnvironment: async (\n    ctx,\n    // The object returned from serverSideProps. If you don't need a token\n    // you can remove this argument.\n    { token }: { token: string }\n  ) => {\n    const { createServerEnvironment } = await import('lib/server_environment');\n    return createServerEnvironment(token);\n  },\n});\n```\n"
  },
  {
    "path": "example/.gitignore",
    "content": "# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.\n\n# dependencies\n/node_modules\n/.pnp\n.pnp.js\n\n# testing\n/coverage\n\n# next.js\n/.next/\n/out/\n\n# production\n/build\n\n# misc\n.DS_Store\n*.pem\n\n# debug\nnpm-debug.log*\nyarn-debug.log*\nyarn-error.log*\n\n# local env files\n.env.local\n.env.development.local\n.env.test.local\n.env.production.local\n\n# vercel\n.vercel\n"
  },
  {
    "path": "example/.prettierignore",
    "content": ".next\ndata\nnode_modules\n**/__generated__\npublic/"
  },
  {
    "path": "example/.prettierrc",
    "content": "{\n  \"singleQuote\": true,\n  \"bracketSpacing\": true,\n  \"arrowParens\": \"always\"\n}\n"
  },
  {
    "path": "example/README.md",
    "content": "This is a [Next.js](https://nextjs.org/) project bootstrapped with [`create-next-app`](https://github.com/vercel/next.js/tree/canary/packages/create-next-app).\n\n## Getting Started\n\nFirst, run the development server:\n\n```bash\nnpm run dev\n# or\nyarn dev\n```\n\nOpen [http://localhost:3000](http://localhost:3000) with your browser to see the result.\n\nYou can start editing the page by modifying `pages/index.js`. The page auto-updates as you edit the file.\n\n[API routes](https://nextjs.org/docs/api-routes/introduction) can be accessed on [http://localhost:3000/api/hello](http://localhost:3000/api/hello). This endpoint can be edited in `pages/api/hello.js`.\n\nThe `pages/api` directory is mapped to `/api/*`. Files in this directory are treated as [API routes](https://nextjs.org/docs/api-routes/introduction) instead of React pages.\n\n## Learn More\n\nTo learn more about Next.js, take a look at the following resources:\n\n- [Next.js Documentation](https://nextjs.org/docs) - learn about Next.js features and API.\n- [Learn Next.js](https://nextjs.org/learn) - an interactive Next.js tutorial.\n\nYou can check out [the Next.js GitHub repository](https://github.com/vercel/next.js/) - your feedback and contributions are welcome!\n\n## Deploy on Vercel\n\nThe easiest way to deploy your Next.js app is to use the [Vercel Platform](https://vercel.com/new?utm_medium=default-template&filter=next.js&utm_source=create-next-app&utm_campaign=create-next-app-readme) from the creators of Next.js.\n\nCheck out our [Next.js deployment documentation](https://nextjs.org/docs/deployment) for more details.\n"
  },
  {
    "path": "example/data/schema.graphql",
    "content": "schema {\n  query: Root\n}\n\n\"\"\"A single film.\"\"\"\ntype Film implements Node {\n  \"\"\"The title of this film.\"\"\"\n  title: String\n\n  \"\"\"The episode number of this film.\"\"\"\n  episodeID: Int\n\n  \"\"\"The opening paragraphs at the beginning of this film.\"\"\"\n  openingCrawl: String\n\n  \"\"\"The name of the director of this film.\"\"\"\n  director: String\n\n  \"\"\"The name(s) of the producer(s) of this film.\"\"\"\n  producers: [String]\n\n  \"\"\"The ISO 8601 date format of film release at original creator country.\"\"\"\n  releaseDate: String\n  speciesConnection(after: String, first: Int, before: String, last: Int): FilmSpeciesConnection\n  starshipConnection(after: String, first: Int, before: String, last: Int): FilmStarshipsConnection\n  vehicleConnection(after: String, first: Int, before: String, last: Int): FilmVehiclesConnection\n  characterConnection(after: String, first: Int, before: String, last: Int): FilmCharactersConnection\n  planetConnection(after: String, first: Int, before: String, last: Int): FilmPlanetsConnection\n\n  \"\"\"The ISO 8601 date format of the time that this resource was created.\"\"\"\n  created: String\n\n  \"\"\"The ISO 8601 date format of the time that this resource was edited.\"\"\"\n  edited: String\n\n  \"\"\"The ID of an object\"\"\"\n  id: ID!\n}\n\n\"\"\"A connection to a list of items.\"\"\"\ntype FilmCharactersConnection {\n  \"\"\"Information to aid in pagination.\"\"\"\n  pageInfo: PageInfo!\n\n  \"\"\"A list of edges.\"\"\"\n  edges: [FilmCharactersEdge]\n\n  \"\"\"\n  A count of the total number of objects in this connection, ignoring pagination.\n  This allows a client to fetch the first five objects by passing \"5\" as the\n  argument to \"first\", then fetch the total count so it could display \"5 of 83\",\n  for example.\n  \"\"\"\n  totalCount: Int\n\n  \"\"\"\n  A list of all of the objects returned in the connection. This is a convenience\n  field provided for quickly exploring the API; rather than querying for\n  \"{ edges { node } }\" when no edge data is needed, this field can be be used\n  instead. Note that when clients like Relay need to fetch the \"cursor\" field on\n  the edge to enable efficient pagination, this shortcut cannot be used, and the\n  full \"{ edges { node } }\" version should be used instead.\n  \"\"\"\n  characters: [Person]\n}\n\n\"\"\"An edge in a connection.\"\"\"\ntype FilmCharactersEdge {\n  \"\"\"The item at the end of the edge\"\"\"\n  node: Person\n\n  \"\"\"A cursor for use in pagination\"\"\"\n  cursor: String!\n}\n\n\"\"\"A connection to a list of items.\"\"\"\ntype FilmPlanetsConnection {\n  \"\"\"Information to aid in pagination.\"\"\"\n  pageInfo: PageInfo!\n\n  \"\"\"A list of edges.\"\"\"\n  edges: [FilmPlanetsEdge]\n\n  \"\"\"\n  A count of the total number of objects in this connection, ignoring pagination.\n  This allows a client to fetch the first five objects by passing \"5\" as the\n  argument to \"first\", then fetch the total count so it could display \"5 of 83\",\n  for example.\n  \"\"\"\n  totalCount: Int\n\n  \"\"\"\n  A list of all of the objects returned in the connection. This is a convenience\n  field provided for quickly exploring the API; rather than querying for\n  \"{ edges { node } }\" when no edge data is needed, this field can be be used\n  instead. Note that when clients like Relay need to fetch the \"cursor\" field on\n  the edge to enable efficient pagination, this shortcut cannot be used, and the\n  full \"{ edges { node } }\" version should be used instead.\n  \"\"\"\n  planets: [Planet]\n}\n\n\"\"\"An edge in a connection.\"\"\"\ntype FilmPlanetsEdge {\n  \"\"\"The item at the end of the edge\"\"\"\n  node: Planet\n\n  \"\"\"A cursor for use in pagination\"\"\"\n  cursor: String!\n}\n\n\"\"\"A connection to a list of items.\"\"\"\ntype FilmsConnection {\n  \"\"\"Information to aid in pagination.\"\"\"\n  pageInfo: PageInfo!\n\n  \"\"\"A list of edges.\"\"\"\n  edges: [FilmsEdge]\n\n  \"\"\"\n  A count of the total number of objects in this connection, ignoring pagination.\n  This allows a client to fetch the first five objects by passing \"5\" as the\n  argument to \"first\", then fetch the total count so it could display \"5 of 83\",\n  for example.\n  \"\"\"\n  totalCount: Int\n\n  \"\"\"\n  A list of all of the objects returned in the connection. This is a convenience\n  field provided for quickly exploring the API; rather than querying for\n  \"{ edges { node } }\" when no edge data is needed, this field can be be used\n  instead. Note that when clients like Relay need to fetch the \"cursor\" field on\n  the edge to enable efficient pagination, this shortcut cannot be used, and the\n  full \"{ edges { node } }\" version should be used instead.\n  \"\"\"\n  films: [Film]\n}\n\n\"\"\"An edge in a connection.\"\"\"\ntype FilmsEdge {\n  \"\"\"The item at the end of the edge\"\"\"\n  node: Film\n\n  \"\"\"A cursor for use in pagination\"\"\"\n  cursor: String!\n}\n\n\"\"\"A connection to a list of items.\"\"\"\ntype FilmSpeciesConnection {\n  \"\"\"Information to aid in pagination.\"\"\"\n  pageInfo: PageInfo!\n\n  \"\"\"A list of edges.\"\"\"\n  edges: [FilmSpeciesEdge]\n\n  \"\"\"\n  A count of the total number of objects in this connection, ignoring pagination.\n  This allows a client to fetch the first five objects by passing \"5\" as the\n  argument to \"first\", then fetch the total count so it could display \"5 of 83\",\n  for example.\n  \"\"\"\n  totalCount: Int\n\n  \"\"\"\n  A list of all of the objects returned in the connection. This is a convenience\n  field provided for quickly exploring the API; rather than querying for\n  \"{ edges { node } }\" when no edge data is needed, this field can be be used\n  instead. Note that when clients like Relay need to fetch the \"cursor\" field on\n  the edge to enable efficient pagination, this shortcut cannot be used, and the\n  full \"{ edges { node } }\" version should be used instead.\n  \"\"\"\n  species: [Species]\n}\n\n\"\"\"An edge in a connection.\"\"\"\ntype FilmSpeciesEdge {\n  \"\"\"The item at the end of the edge\"\"\"\n  node: Species\n\n  \"\"\"A cursor for use in pagination\"\"\"\n  cursor: String!\n}\n\n\"\"\"A connection to a list of items.\"\"\"\ntype FilmStarshipsConnection {\n  \"\"\"Information to aid in pagination.\"\"\"\n  pageInfo: PageInfo!\n\n  \"\"\"A list of edges.\"\"\"\n  edges: [FilmStarshipsEdge]\n\n  \"\"\"\n  A count of the total number of objects in this connection, ignoring pagination.\n  This allows a client to fetch the first five objects by passing \"5\" as the\n  argument to \"first\", then fetch the total count so it could display \"5 of 83\",\n  for example.\n  \"\"\"\n  totalCount: Int\n\n  \"\"\"\n  A list of all of the objects returned in the connection. This is a convenience\n  field provided for quickly exploring the API; rather than querying for\n  \"{ edges { node } }\" when no edge data is needed, this field can be be used\n  instead. Note that when clients like Relay need to fetch the \"cursor\" field on\n  the edge to enable efficient pagination, this shortcut cannot be used, and the\n  full \"{ edges { node } }\" version should be used instead.\n  \"\"\"\n  starships: [Starship]\n}\n\n\"\"\"An edge in a connection.\"\"\"\ntype FilmStarshipsEdge {\n  \"\"\"The item at the end of the edge\"\"\"\n  node: Starship\n\n  \"\"\"A cursor for use in pagination\"\"\"\n  cursor: String!\n}\n\n\"\"\"A connection to a list of items.\"\"\"\ntype FilmVehiclesConnection {\n  \"\"\"Information to aid in pagination.\"\"\"\n  pageInfo: PageInfo!\n\n  \"\"\"A list of edges.\"\"\"\n  edges: [FilmVehiclesEdge]\n\n  \"\"\"\n  A count of the total number of objects in this connection, ignoring pagination.\n  This allows a client to fetch the first five objects by passing \"5\" as the\n  argument to \"first\", then fetch the total count so it could display \"5 of 83\",\n  for example.\n  \"\"\"\n  totalCount: Int\n\n  \"\"\"\n  A list of all of the objects returned in the connection. This is a convenience\n  field provided for quickly exploring the API; rather than querying for\n  \"{ edges { node } }\" when no edge data is needed, this field can be be used\n  instead. Note that when clients like Relay need to fetch the \"cursor\" field on\n  the edge to enable efficient pagination, this shortcut cannot be used, and the\n  full \"{ edges { node } }\" version should be used instead.\n  \"\"\"\n  vehicles: [Vehicle]\n}\n\n\"\"\"An edge in a connection.\"\"\"\ntype FilmVehiclesEdge {\n  \"\"\"The item at the end of the edge\"\"\"\n  node: Vehicle\n\n  \"\"\"A cursor for use in pagination\"\"\"\n  cursor: String!\n}\n\n\"\"\"An object with an ID\"\"\"\ninterface Node {\n  \"\"\"The id of the object.\"\"\"\n  id: ID!\n}\n\n\"\"\"Information about pagination in a connection.\"\"\"\ntype PageInfo {\n  \"\"\"When paginating forwards, are there more items?\"\"\"\n  hasNextPage: Boolean!\n\n  \"\"\"When paginating backwards, are there more items?\"\"\"\n  hasPreviousPage: Boolean!\n\n  \"\"\"When paginating backwards, the cursor to continue.\"\"\"\n  startCursor: String\n\n  \"\"\"When paginating forwards, the cursor to continue.\"\"\"\n  endCursor: String\n}\n\n\"\"\"A connection to a list of items.\"\"\"\ntype PeopleConnection {\n  \"\"\"Information to aid in pagination.\"\"\"\n  pageInfo: PageInfo!\n\n  \"\"\"A list of edges.\"\"\"\n  edges: [PeopleEdge]\n\n  \"\"\"\n  A count of the total number of objects in this connection, ignoring pagination.\n  This allows a client to fetch the first five objects by passing \"5\" as the\n  argument to \"first\", then fetch the total count so it could display \"5 of 83\",\n  for example.\n  \"\"\"\n  totalCount: Int\n\n  \"\"\"\n  A list of all of the objects returned in the connection. This is a convenience\n  field provided for quickly exploring the API; rather than querying for\n  \"{ edges { node } }\" when no edge data is needed, this field can be be used\n  instead. Note that when clients like Relay need to fetch the \"cursor\" field on\n  the edge to enable efficient pagination, this shortcut cannot be used, and the\n  full \"{ edges { node } }\" version should be used instead.\n  \"\"\"\n  people: [Person]\n}\n\n\"\"\"An edge in a connection.\"\"\"\ntype PeopleEdge {\n  \"\"\"The item at the end of the edge\"\"\"\n  node: Person\n\n  \"\"\"A cursor for use in pagination\"\"\"\n  cursor: String!\n}\n\n\"\"\"An individual person or character within the Star Wars universe.\"\"\"\ntype Person implements Node {\n  \"\"\"The name of this person.\"\"\"\n  name: String\n\n  \"\"\"\n  The birth year of the person, using the in-universe standard of BBY or ABY -\n  Before the Battle of Yavin or After the Battle of Yavin. The Battle of Yavin is\n  a battle that occurs at the end of Star Wars episode IV: A New Hope.\n  \"\"\"\n  birthYear: String\n\n  \"\"\"\n  The eye color of this person. Will be \"unknown\" if not known or \"n/a\" if the\n  person does not have an eye.\n  \"\"\"\n  eyeColor: String\n\n  \"\"\"\n  The gender of this person. Either \"Male\", \"Female\" or \"unknown\",\n  \"n/a\" if the person does not have a gender.\n  \"\"\"\n  gender: String\n\n  \"\"\"\n  The hair color of this person. Will be \"unknown\" if not known or \"n/a\" if the\n  person does not have hair.\n  \"\"\"\n  hairColor: String\n\n  \"\"\"The height of the person in centimeters.\"\"\"\n  height: Int\n\n  \"\"\"The mass of the person in kilograms.\"\"\"\n  mass: Float\n\n  \"\"\"The skin color of this person.\"\"\"\n  skinColor: String\n\n  \"\"\"A planet that this person was born on or inhabits.\"\"\"\n  homeworld: Planet\n  filmConnection(after: String, first: Int, before: String, last: Int): PersonFilmsConnection\n\n  \"\"\"The species that this person belongs to, or null if unknown.\"\"\"\n  species: Species\n  starshipConnection(after: String, first: Int, before: String, last: Int): PersonStarshipsConnection\n  vehicleConnection(after: String, first: Int, before: String, last: Int): PersonVehiclesConnection\n\n  \"\"\"The ISO 8601 date format of the time that this resource was created.\"\"\"\n  created: String\n\n  \"\"\"The ISO 8601 date format of the time that this resource was edited.\"\"\"\n  edited: String\n\n  \"\"\"The ID of an object\"\"\"\n  id: ID!\n}\n\n\"\"\"A connection to a list of items.\"\"\"\ntype PersonFilmsConnection {\n  \"\"\"Information to aid in pagination.\"\"\"\n  pageInfo: PageInfo!\n\n  \"\"\"A list of edges.\"\"\"\n  edges: [PersonFilmsEdge]\n\n  \"\"\"\n  A count of the total number of objects in this connection, ignoring pagination.\n  This allows a client to fetch the first five objects by passing \"5\" as the\n  argument to \"first\", then fetch the total count so it could display \"5 of 83\",\n  for example.\n  \"\"\"\n  totalCount: Int\n\n  \"\"\"\n  A list of all of the objects returned in the connection. This is a convenience\n  field provided for quickly exploring the API; rather than querying for\n  \"{ edges { node } }\" when no edge data is needed, this field can be be used\n  instead. Note that when clients like Relay need to fetch the \"cursor\" field on\n  the edge to enable efficient pagination, this shortcut cannot be used, and the\n  full \"{ edges { node } }\" version should be used instead.\n  \"\"\"\n  films: [Film]\n}\n\n\"\"\"An edge in a connection.\"\"\"\ntype PersonFilmsEdge {\n  \"\"\"The item at the end of the edge\"\"\"\n  node: Film\n\n  \"\"\"A cursor for use in pagination\"\"\"\n  cursor: String!\n}\n\n\"\"\"A connection to a list of items.\"\"\"\ntype PersonStarshipsConnection {\n  \"\"\"Information to aid in pagination.\"\"\"\n  pageInfo: PageInfo!\n\n  \"\"\"A list of edges.\"\"\"\n  edges: [PersonStarshipsEdge]\n\n  \"\"\"\n  A count of the total number of objects in this connection, ignoring pagination.\n  This allows a client to fetch the first five objects by passing \"5\" as the\n  argument to \"first\", then fetch the total count so it could display \"5 of 83\",\n  for example.\n  \"\"\"\n  totalCount: Int\n\n  \"\"\"\n  A list of all of the objects returned in the connection. This is a convenience\n  field provided for quickly exploring the API; rather than querying for\n  \"{ edges { node } }\" when no edge data is needed, this field can be be used\n  instead. Note that when clients like Relay need to fetch the \"cursor\" field on\n  the edge to enable efficient pagination, this shortcut cannot be used, and the\n  full \"{ edges { node } }\" version should be used instead.\n  \"\"\"\n  starships: [Starship]\n}\n\n\"\"\"An edge in a connection.\"\"\"\ntype PersonStarshipsEdge {\n  \"\"\"The item at the end of the edge\"\"\"\n  node: Starship\n\n  \"\"\"A cursor for use in pagination\"\"\"\n  cursor: String!\n}\n\n\"\"\"A connection to a list of items.\"\"\"\ntype PersonVehiclesConnection {\n  \"\"\"Information to aid in pagination.\"\"\"\n  pageInfo: PageInfo!\n\n  \"\"\"A list of edges.\"\"\"\n  edges: [PersonVehiclesEdge]\n\n  \"\"\"\n  A count of the total number of objects in this connection, ignoring pagination.\n  This allows a client to fetch the first five objects by passing \"5\" as the\n  argument to \"first\", then fetch the total count so it could display \"5 of 83\",\n  for example.\n  \"\"\"\n  totalCount: Int\n\n  \"\"\"\n  A list of all of the objects returned in the connection. This is a convenience\n  field provided for quickly exploring the API; rather than querying for\n  \"{ edges { node } }\" when no edge data is needed, this field can be be used\n  instead. Note that when clients like Relay need to fetch the \"cursor\" field on\n  the edge to enable efficient pagination, this shortcut cannot be used, and the\n  full \"{ edges { node } }\" version should be used instead.\n  \"\"\"\n  vehicles: [Vehicle]\n}\n\n\"\"\"An edge in a connection.\"\"\"\ntype PersonVehiclesEdge {\n  \"\"\"The item at the end of the edge\"\"\"\n  node: Vehicle\n\n  \"\"\"A cursor for use in pagination\"\"\"\n  cursor: String!\n}\n\n\"\"\"\nA large mass, planet or planetoid in the Star Wars Universe, at the time of\n0 ABY.\n\"\"\"\ntype Planet implements Node {\n  \"\"\"The name of this planet.\"\"\"\n  name: String\n\n  \"\"\"The diameter of this planet in kilometers.\"\"\"\n  diameter: Int\n\n  \"\"\"\n  The number of standard hours it takes for this planet to complete a single\n  rotation on its axis.\n  \"\"\"\n  rotationPeriod: Int\n\n  \"\"\"\n  The number of standard days it takes for this planet to complete a single orbit\n  of its local star.\n  \"\"\"\n  orbitalPeriod: Int\n\n  \"\"\"\n  A number denoting the gravity of this planet, where \"1\" is normal or 1 standard\n  G. \"2\" is twice or 2 standard Gs. \"0.5\" is half or 0.5 standard Gs.\n  \"\"\"\n  gravity: String\n\n  \"\"\"The average population of sentient beings inhabiting this planet.\"\"\"\n  population: Float\n\n  \"\"\"The climates of this planet.\"\"\"\n  climates: [String]\n\n  \"\"\"The terrains of this planet.\"\"\"\n  terrains: [String]\n\n  \"\"\"\n  The percentage of the planet surface that is naturally occuring water or bodies\n  of water.\n  \"\"\"\n  surfaceWater: Float\n  residentConnection(after: String, first: Int, before: String, last: Int): PlanetResidentsConnection\n  filmConnection(after: String, first: Int, before: String, last: Int): PlanetFilmsConnection\n\n  \"\"\"The ISO 8601 date format of the time that this resource was created.\"\"\"\n  created: String\n\n  \"\"\"The ISO 8601 date format of the time that this resource was edited.\"\"\"\n  edited: String\n\n  \"\"\"The ID of an object\"\"\"\n  id: ID!\n}\n\n\"\"\"A connection to a list of items.\"\"\"\ntype PlanetFilmsConnection {\n  \"\"\"Information to aid in pagination.\"\"\"\n  pageInfo: PageInfo!\n\n  \"\"\"A list of edges.\"\"\"\n  edges: [PlanetFilmsEdge]\n\n  \"\"\"\n  A count of the total number of objects in this connection, ignoring pagination.\n  This allows a client to fetch the first five objects by passing \"5\" as the\n  argument to \"first\", then fetch the total count so it could display \"5 of 83\",\n  for example.\n  \"\"\"\n  totalCount: Int\n\n  \"\"\"\n  A list of all of the objects returned in the connection. This is a convenience\n  field provided for quickly exploring the API; rather than querying for\n  \"{ edges { node } }\" when no edge data is needed, this field can be be used\n  instead. Note that when clients like Relay need to fetch the \"cursor\" field on\n  the edge to enable efficient pagination, this shortcut cannot be used, and the\n  full \"{ edges { node } }\" version should be used instead.\n  \"\"\"\n  films: [Film]\n}\n\n\"\"\"An edge in a connection.\"\"\"\ntype PlanetFilmsEdge {\n  \"\"\"The item at the end of the edge\"\"\"\n  node: Film\n\n  \"\"\"A cursor for use in pagination\"\"\"\n  cursor: String!\n}\n\n\"\"\"A connection to a list of items.\"\"\"\ntype PlanetResidentsConnection {\n  \"\"\"Information to aid in pagination.\"\"\"\n  pageInfo: PageInfo!\n\n  \"\"\"A list of edges.\"\"\"\n  edges: [PlanetResidentsEdge]\n\n  \"\"\"\n  A count of the total number of objects in this connection, ignoring pagination.\n  This allows a client to fetch the first five objects by passing \"5\" as the\n  argument to \"first\", then fetch the total count so it could display \"5 of 83\",\n  for example.\n  \"\"\"\n  totalCount: Int\n\n  \"\"\"\n  A list of all of the objects returned in the connection. This is a convenience\n  field provided for quickly exploring the API; rather than querying for\n  \"{ edges { node } }\" when no edge data is needed, this field can be be used\n  instead. Note that when clients like Relay need to fetch the \"cursor\" field on\n  the edge to enable efficient pagination, this shortcut cannot be used, and the\n  full \"{ edges { node } }\" version should be used instead.\n  \"\"\"\n  residents: [Person]\n}\n\n\"\"\"An edge in a connection.\"\"\"\ntype PlanetResidentsEdge {\n  \"\"\"The item at the end of the edge\"\"\"\n  node: Person\n\n  \"\"\"A cursor for use in pagination\"\"\"\n  cursor: String!\n}\n\n\"\"\"A connection to a list of items.\"\"\"\ntype PlanetsConnection {\n  \"\"\"Information to aid in pagination.\"\"\"\n  pageInfo: PageInfo!\n\n  \"\"\"A list of edges.\"\"\"\n  edges: [PlanetsEdge]\n\n  \"\"\"\n  A count of the total number of objects in this connection, ignoring pagination.\n  This allows a client to fetch the first five objects by passing \"5\" as the\n  argument to \"first\", then fetch the total count so it could display \"5 of 83\",\n  for example.\n  \"\"\"\n  totalCount: Int\n\n  \"\"\"\n  A list of all of the objects returned in the connection. This is a convenience\n  field provided for quickly exploring the API; rather than querying for\n  \"{ edges { node } }\" when no edge data is needed, this field can be be used\n  instead. Note that when clients like Relay need to fetch the \"cursor\" field on\n  the edge to enable efficient pagination, this shortcut cannot be used, and the\n  full \"{ edges { node } }\" version should be used instead.\n  \"\"\"\n  planets: [Planet]\n}\n\n\"\"\"An edge in a connection.\"\"\"\ntype PlanetsEdge {\n  \"\"\"The item at the end of the edge\"\"\"\n  node: Planet\n\n  \"\"\"A cursor for use in pagination\"\"\"\n  cursor: String!\n}\n\ntype Root {\n  allFilms(after: String, first: Int, before: String, last: Int): FilmsConnection\n  film(id: ID, filmID: ID): Film\n  allPeople(after: String, first: Int, before: String, last: Int): PeopleConnection\n  person(id: ID, personID: ID): Person\n  allPlanets(after: String, first: Int, before: String, last: Int): PlanetsConnection\n  planet(id: ID, planetID: ID): Planet\n  allSpecies(after: String, first: Int, before: String, last: Int): SpeciesConnection\n  species(id: ID, speciesID: ID): Species\n  allStarships(after: String, first: Int, before: String, last: Int): StarshipsConnection\n  starship(id: ID, starshipID: ID): Starship\n  allVehicles(after: String, first: Int, before: String, last: Int): VehiclesConnection\n  vehicle(id: ID, vehicleID: ID): Vehicle\n\n  \"\"\"Fetches an object given its ID\"\"\"\n  node(\n    \"\"\"The ID of an object\"\"\"\n    id: ID!\n  ): Node\n}\n\n\"\"\"A type of person or character within the Star Wars Universe.\"\"\"\ntype Species implements Node {\n  \"\"\"The name of this species.\"\"\"\n  name: String\n\n  \"\"\"The classification of this species, such as \"mammal\" or \"reptile\".\"\"\"\n  classification: String\n\n  \"\"\"The designation of this species, such as \"sentient\".\"\"\"\n  designation: String\n\n  \"\"\"The average height of this species in centimeters.\"\"\"\n  averageHeight: Float\n\n  \"\"\"The average lifespan of this species in years, null if unknown.\"\"\"\n  averageLifespan: Int\n\n  \"\"\"\n  Common eye colors for this species, null if this species does not typically\n  have eyes.\n  \"\"\"\n  eyeColors: [String]\n\n  \"\"\"\n  Common hair colors for this species, null if this species does not typically\n  have hair.\n  \"\"\"\n  hairColors: [String]\n\n  \"\"\"\n  Common skin colors for this species, null if this species does not typically\n  have skin.\n  \"\"\"\n  skinColors: [String]\n\n  \"\"\"The language commonly spoken by this species.\"\"\"\n  language: String\n\n  \"\"\"A planet that this species originates from.\"\"\"\n  homeworld: Planet\n  personConnection(after: String, first: Int, before: String, last: Int): SpeciesPeopleConnection\n  filmConnection(after: String, first: Int, before: String, last: Int): SpeciesFilmsConnection\n\n  \"\"\"The ISO 8601 date format of the time that this resource was created.\"\"\"\n  created: String\n\n  \"\"\"The ISO 8601 date format of the time that this resource was edited.\"\"\"\n  edited: String\n\n  \"\"\"The ID of an object\"\"\"\n  id: ID!\n}\n\n\"\"\"A connection to a list of items.\"\"\"\ntype SpeciesConnection {\n  \"\"\"Information to aid in pagination.\"\"\"\n  pageInfo: PageInfo!\n\n  \"\"\"A list of edges.\"\"\"\n  edges: [SpeciesEdge]\n\n  \"\"\"\n  A count of the total number of objects in this connection, ignoring pagination.\n  This allows a client to fetch the first five objects by passing \"5\" as the\n  argument to \"first\", then fetch the total count so it could display \"5 of 83\",\n  for example.\n  \"\"\"\n  totalCount: Int\n\n  \"\"\"\n  A list of all of the objects returned in the connection. This is a convenience\n  field provided for quickly exploring the API; rather than querying for\n  \"{ edges { node } }\" when no edge data is needed, this field can be be used\n  instead. Note that when clients like Relay need to fetch the \"cursor\" field on\n  the edge to enable efficient pagination, this shortcut cannot be used, and the\n  full \"{ edges { node } }\" version should be used instead.\n  \"\"\"\n  species: [Species]\n}\n\n\"\"\"An edge in a connection.\"\"\"\ntype SpeciesEdge {\n  \"\"\"The item at the end of the edge\"\"\"\n  node: Species\n\n  \"\"\"A cursor for use in pagination\"\"\"\n  cursor: String!\n}\n\n\"\"\"A connection to a list of items.\"\"\"\ntype SpeciesFilmsConnection {\n  \"\"\"Information to aid in pagination.\"\"\"\n  pageInfo: PageInfo!\n\n  \"\"\"A list of edges.\"\"\"\n  edges: [SpeciesFilmsEdge]\n\n  \"\"\"\n  A count of the total number of objects in this connection, ignoring pagination.\n  This allows a client to fetch the first five objects by passing \"5\" as the\n  argument to \"first\", then fetch the total count so it could display \"5 of 83\",\n  for example.\n  \"\"\"\n  totalCount: Int\n\n  \"\"\"\n  A list of all of the objects returned in the connection. This is a convenience\n  field provided for quickly exploring the API; rather than querying for\n  \"{ edges { node } }\" when no edge data is needed, this field can be be used\n  instead. Note that when clients like Relay need to fetch the \"cursor\" field on\n  the edge to enable efficient pagination, this shortcut cannot be used, and the\n  full \"{ edges { node } }\" version should be used instead.\n  \"\"\"\n  films: [Film]\n}\n\n\"\"\"An edge in a connection.\"\"\"\ntype SpeciesFilmsEdge {\n  \"\"\"The item at the end of the edge\"\"\"\n  node: Film\n\n  \"\"\"A cursor for use in pagination\"\"\"\n  cursor: String!\n}\n\n\"\"\"A connection to a list of items.\"\"\"\ntype SpeciesPeopleConnection {\n  \"\"\"Information to aid in pagination.\"\"\"\n  pageInfo: PageInfo!\n\n  \"\"\"A list of edges.\"\"\"\n  edges: [SpeciesPeopleEdge]\n\n  \"\"\"\n  A count of the total number of objects in this connection, ignoring pagination.\n  This allows a client to fetch the first five objects by passing \"5\" as the\n  argument to \"first\", then fetch the total count so it could display \"5 of 83\",\n  for example.\n  \"\"\"\n  totalCount: Int\n\n  \"\"\"\n  A list of all of the objects returned in the connection. This is a convenience\n  field provided for quickly exploring the API; rather than querying for\n  \"{ edges { node } }\" when no edge data is needed, this field can be be used\n  instead. Note that when clients like Relay need to fetch the \"cursor\" field on\n  the edge to enable efficient pagination, this shortcut cannot be used, and the\n  full \"{ edges { node } }\" version should be used instead.\n  \"\"\"\n  people: [Person]\n}\n\n\"\"\"An edge in a connection.\"\"\"\ntype SpeciesPeopleEdge {\n  \"\"\"The item at the end of the edge\"\"\"\n  node: Person\n\n  \"\"\"A cursor for use in pagination\"\"\"\n  cursor: String!\n}\n\n\"\"\"A single transport craft that has hyperdrive capability.\"\"\"\ntype Starship implements Node {\n  \"\"\"The name of this starship. The common name, such as \"Death Star\".\"\"\"\n  name: String\n\n  \"\"\"\n  The model or official name of this starship. Such as \"T-65 X-wing\" or \"DS-1\n  Orbital Battle Station\".\n  \"\"\"\n  model: String\n\n  \"\"\"\n  The class of this starship, such as \"Starfighter\" or \"Deep Space Mobile\n  Battlestation\"\n  \"\"\"\n  starshipClass: String\n\n  \"\"\"The manufacturers of this starship.\"\"\"\n  manufacturers: [String]\n\n  \"\"\"The cost of this starship new, in galactic credits.\"\"\"\n  costInCredits: Float\n\n  \"\"\"The length of this starship in meters.\"\"\"\n  length: Float\n\n  \"\"\"The number of personnel needed to run or pilot this starship.\"\"\"\n  crew: String\n\n  \"\"\"The number of non-essential people this starship can transport.\"\"\"\n  passengers: String\n\n  \"\"\"\n  The maximum speed of this starship in atmosphere. null if this starship is\n  incapable of atmosphering flight.\n  \"\"\"\n  maxAtmospheringSpeed: Int\n\n  \"\"\"The class of this starships hyperdrive.\"\"\"\n  hyperdriveRating: Float\n\n  \"\"\"\n  The Maximum number of Megalights this starship can travel in a standard hour.\n  A \"Megalight\" is a standard unit of distance and has never been defined before\n  within the Star Wars universe. This figure is only really useful for measuring\n  the difference in speed of starships. We can assume it is similar to AU, the\n  distance between our Sun (Sol) and Earth.\n  \"\"\"\n  MGLT: Int\n\n  \"\"\"The maximum number of kilograms that this starship can transport.\"\"\"\n  cargoCapacity: Float\n\n  \"\"\"\n  The maximum length of time that this starship can provide consumables for its\n  entire crew without having to resupply.\n  \"\"\"\n  consumables: String\n  pilotConnection(after: String, first: Int, before: String, last: Int): StarshipPilotsConnection\n  filmConnection(after: String, first: Int, before: String, last: Int): StarshipFilmsConnection\n\n  \"\"\"The ISO 8601 date format of the time that this resource was created.\"\"\"\n  created: String\n\n  \"\"\"The ISO 8601 date format of the time that this resource was edited.\"\"\"\n  edited: String\n\n  \"\"\"The ID of an object\"\"\"\n  id: ID!\n}\n\n\"\"\"A connection to a list of items.\"\"\"\ntype StarshipFilmsConnection {\n  \"\"\"Information to aid in pagination.\"\"\"\n  pageInfo: PageInfo!\n\n  \"\"\"A list of edges.\"\"\"\n  edges: [StarshipFilmsEdge]\n\n  \"\"\"\n  A count of the total number of objects in this connection, ignoring pagination.\n  This allows a client to fetch the first five objects by passing \"5\" as the\n  argument to \"first\", then fetch the total count so it could display \"5 of 83\",\n  for example.\n  \"\"\"\n  totalCount: Int\n\n  \"\"\"\n  A list of all of the objects returned in the connection. This is a convenience\n  field provided for quickly exploring the API; rather than querying for\n  \"{ edges { node } }\" when no edge data is needed, this field can be be used\n  instead. Note that when clients like Relay need to fetch the \"cursor\" field on\n  the edge to enable efficient pagination, this shortcut cannot be used, and the\n  full \"{ edges { node } }\" version should be used instead.\n  \"\"\"\n  films: [Film]\n}\n\n\"\"\"An edge in a connection.\"\"\"\ntype StarshipFilmsEdge {\n  \"\"\"The item at the end of the edge\"\"\"\n  node: Film\n\n  \"\"\"A cursor for use in pagination\"\"\"\n  cursor: String!\n}\n\n\"\"\"A connection to a list of items.\"\"\"\ntype StarshipPilotsConnection {\n  \"\"\"Information to aid in pagination.\"\"\"\n  pageInfo: PageInfo!\n\n  \"\"\"A list of edges.\"\"\"\n  edges: [StarshipPilotsEdge]\n\n  \"\"\"\n  A count of the total number of objects in this connection, ignoring pagination.\n  This allows a client to fetch the first five objects by passing \"5\" as the\n  argument to \"first\", then fetch the total count so it could display \"5 of 83\",\n  for example.\n  \"\"\"\n  totalCount: Int\n\n  \"\"\"\n  A list of all of the objects returned in the connection. This is a convenience\n  field provided for quickly exploring the API; rather than querying for\n  \"{ edges { node } }\" when no edge data is needed, this field can be be used\n  instead. Note that when clients like Relay need to fetch the \"cursor\" field on\n  the edge to enable efficient pagination, this shortcut cannot be used, and the\n  full \"{ edges { node } }\" version should be used instead.\n  \"\"\"\n  pilots: [Person]\n}\n\n\"\"\"An edge in a connection.\"\"\"\ntype StarshipPilotsEdge {\n  \"\"\"The item at the end of the edge\"\"\"\n  node: Person\n\n  \"\"\"A cursor for use in pagination\"\"\"\n  cursor: String!\n}\n\n\"\"\"A connection to a list of items.\"\"\"\ntype StarshipsConnection {\n  \"\"\"Information to aid in pagination.\"\"\"\n  pageInfo: PageInfo!\n\n  \"\"\"A list of edges.\"\"\"\n  edges: [StarshipsEdge]\n\n  \"\"\"\n  A count of the total number of objects in this connection, ignoring pagination.\n  This allows a client to fetch the first five objects by passing \"5\" as the\n  argument to \"first\", then fetch the total count so it could display \"5 of 83\",\n  for example.\n  \"\"\"\n  totalCount: Int\n\n  \"\"\"\n  A list of all of the objects returned in the connection. This is a convenience\n  field provided for quickly exploring the API; rather than querying for\n  \"{ edges { node } }\" when no edge data is needed, this field can be be used\n  instead. Note that when clients like Relay need to fetch the \"cursor\" field on\n  the edge to enable efficient pagination, this shortcut cannot be used, and the\n  full \"{ edges { node } }\" version should be used instead.\n  \"\"\"\n  starships: [Starship]\n}\n\n\"\"\"An edge in a connection.\"\"\"\ntype StarshipsEdge {\n  \"\"\"The item at the end of the edge\"\"\"\n  node: Starship\n\n  \"\"\"A cursor for use in pagination\"\"\"\n  cursor: String!\n}\n\n\"\"\"A single transport craft that does not have hyperdrive capability\"\"\"\ntype Vehicle implements Node {\n  \"\"\"\n  The name of this vehicle. The common name, such as \"Sand Crawler\" or \"Speeder\n  bike\".\n  \"\"\"\n  name: String\n\n  \"\"\"\n  The model or official name of this vehicle. Such as \"All-Terrain Attack\n  Transport\".\n  \"\"\"\n  model: String\n\n  \"\"\"The class of this vehicle, such as \"Wheeled\" or \"Repulsorcraft\".\"\"\"\n  vehicleClass: String\n\n  \"\"\"The manufacturers of this vehicle.\"\"\"\n  manufacturers: [String]\n\n  \"\"\"The cost of this vehicle new, in Galactic Credits.\"\"\"\n  costInCredits: Float\n\n  \"\"\"The length of this vehicle in meters.\"\"\"\n  length: Float\n\n  \"\"\"The number of personnel needed to run or pilot this vehicle.\"\"\"\n  crew: String\n\n  \"\"\"The number of non-essential people this vehicle can transport.\"\"\"\n  passengers: String\n\n  \"\"\"The maximum speed of this vehicle in atmosphere.\"\"\"\n  maxAtmospheringSpeed: Int\n\n  \"\"\"The maximum number of kilograms that this vehicle can transport.\"\"\"\n  cargoCapacity: Float\n\n  \"\"\"\n  The maximum length of time that this vehicle can provide consumables for its\n  entire crew without having to resupply.\n  \"\"\"\n  consumables: String\n  pilotConnection(after: String, first: Int, before: String, last: Int): VehiclePilotsConnection\n  filmConnection(after: String, first: Int, before: String, last: Int): VehicleFilmsConnection\n\n  \"\"\"The ISO 8601 date format of the time that this resource was created.\"\"\"\n  created: String\n\n  \"\"\"The ISO 8601 date format of the time that this resource was edited.\"\"\"\n  edited: String\n\n  \"\"\"The ID of an object\"\"\"\n  id: ID!\n}\n\n\"\"\"A connection to a list of items.\"\"\"\ntype VehicleFilmsConnection {\n  \"\"\"Information to aid in pagination.\"\"\"\n  pageInfo: PageInfo!\n\n  \"\"\"A list of edges.\"\"\"\n  edges: [VehicleFilmsEdge]\n\n  \"\"\"\n  A count of the total number of objects in this connection, ignoring pagination.\n  This allows a client to fetch the first five objects by passing \"5\" as the\n  argument to \"first\", then fetch the total count so it could display \"5 of 83\",\n  for example.\n  \"\"\"\n  totalCount: Int\n\n  \"\"\"\n  A list of all of the objects returned in the connection. This is a convenience\n  field provided for quickly exploring the API; rather than querying for\n  \"{ edges { node } }\" when no edge data is needed, this field can be be used\n  instead. Note that when clients like Relay need to fetch the \"cursor\" field on\n  the edge to enable efficient pagination, this shortcut cannot be used, and the\n  full \"{ edges { node } }\" version should be used instead.\n  \"\"\"\n  films: [Film]\n}\n\n\"\"\"An edge in a connection.\"\"\"\ntype VehicleFilmsEdge {\n  \"\"\"The item at the end of the edge\"\"\"\n  node: Film\n\n  \"\"\"A cursor for use in pagination\"\"\"\n  cursor: String!\n}\n\n\"\"\"A connection to a list of items.\"\"\"\ntype VehiclePilotsConnection {\n  \"\"\"Information to aid in pagination.\"\"\"\n  pageInfo: PageInfo!\n\n  \"\"\"A list of edges.\"\"\"\n  edges: [VehiclePilotsEdge]\n\n  \"\"\"\n  A count of the total number of objects in this connection, ignoring pagination.\n  This allows a client to fetch the first five objects by passing \"5\" as the\n  argument to \"first\", then fetch the total count so it could display \"5 of 83\",\n  for example.\n  \"\"\"\n  totalCount: Int\n\n  \"\"\"\n  A list of all of the objects returned in the connection. This is a convenience\n  field provided for quickly exploring the API; rather than querying for\n  \"{ edges { node } }\" when no edge data is needed, this field can be be used\n  instead. Note that when clients like Relay need to fetch the \"cursor\" field on\n  the edge to enable efficient pagination, this shortcut cannot be used, and the\n  full \"{ edges { node } }\" version should be used instead.\n  \"\"\"\n  pilots: [Person]\n}\n\n\"\"\"An edge in a connection.\"\"\"\ntype VehiclePilotsEdge {\n  \"\"\"The item at the end of the edge\"\"\"\n  node: Person\n\n  \"\"\"A cursor for use in pagination\"\"\"\n  cursor: String!\n}\n\n\"\"\"A connection to a list of items.\"\"\"\ntype VehiclesConnection {\n  \"\"\"Information to aid in pagination.\"\"\"\n  pageInfo: PageInfo!\n\n  \"\"\"A list of edges.\"\"\"\n  edges: [VehiclesEdge]\n\n  \"\"\"\n  A count of the total number of objects in this connection, ignoring pagination.\n  This allows a client to fetch the first five objects by passing \"5\" as the\n  argument to \"first\", then fetch the total count so it could display \"5 of 83\",\n  for example.\n  \"\"\"\n  totalCount: Int\n\n  \"\"\"\n  A list of all of the objects returned in the connection. This is a convenience\n  field provided for quickly exploring the API; rather than querying for\n  \"{ edges { node } }\" when no edge data is needed, this field can be be used\n  instead. Note that when clients like Relay need to fetch the \"cursor\" field on\n  the edge to enable efficient pagination, this shortcut cannot be used, and the\n  full \"{ edges { node } }\" version should be used instead.\n  \"\"\"\n  vehicles: [Vehicle]\n}\n\n\"\"\"An edge in a connection.\"\"\"\ntype VehiclesEdge {\n  \"\"\"The item at the end of the edge\"\"\"\n  node: Vehicle\n\n  \"\"\"A cursor for use in pagination\"\"\"\n  cursor: String!\n}"
  },
  {
    "path": "example/next-env.d.ts",
    "content": "/// <reference types=\"next\" />\n/// <reference types=\"next/image-types/global\" />\n\n// NOTE: This file should not be edited\n// see https://nextjs.org/docs/basic-features/typescript for more information.\n"
  },
  {
    "path": "example/next.config.js",
    "content": "const relay = require('./relay.config');\n\nmodule.exports = {\n  compiler: {\n    relay,\n  },\n  webpack: (config, { isServer, webpack }) => {\n    if (!isServer) {\n      // Ensures no server modules are included on the client.\n      config.plugins.push(new webpack.IgnorePlugin({\n        resourceRegExp: /lib\\/server/\n      }));\n    }\n\n    return config;\n  },\n};\n"
  },
  {
    "path": "example/package.json",
    "content": "{\n  \"name\": \"example\",\n  \"version\": \"0.1.0\",\n  \"private\": true,\n  \"scripts\": {\n    \"dev\": \"next dev\",\n    \"build\": \"next build\",\n    \"start\": \"next start\",\n    \"generate:relay\": \"relay-compiler\"\n  },\n  \"dependencies\": {\n    \"next\": \"^13.0.4\",\n    \"react\": \"^18.2.0\",\n    \"react-dom\": \"^18.2.0\",\n    \"react-relay\": \"^14.1.0\",\n    \"relay-nextjs\": \"^2.0.0-rc.0\",\n    \"relay-runtime\": \"^14.1.0\"\n  },\n  \"devDependencies\": {\n    \"@types/node\": \"^17.0.21\",\n    \"@types/react\": \"^18.0.25\",\n    \"@types/react-dom\": \"^18.0.9\",\n    \"@types/react-relay\": \"^14.1.2\",\n    \"@types/relay-runtime\": \"^14.1.4\",\n    \"autoprefixer\": \"^10.2.5\",\n    \"graphql\": \"^15.5.0\",\n    \"postcss\": \"^8.2.9\",\n    \"relay-compiler\": \"^14.1.0\",\n    \"tailwindcss\": \"^2.1.1\",\n    \"typescript\": \"^4.9.3\"\n  }\n}\n"
  },
  {
    "path": "example/postcss.config.js",
    "content": "module.exports = {\n  plugins: {\n    tailwindcss: {},\n    autoprefixer: {},\n  },\n};\n"
  },
  {
    "path": "example/relay.config.js",
    "content": "module.exports = {\n  src: './src',\n  schema: './data/schema.graphql',\n  exclude: ['**/node_modules/**', '**/__generated__/**'],\n  language: 'typescript',\n  artifactDirectory: 'src/queries/__generated__',\n};\n"
  },
  {
    "path": "example/src/lib/relay_client_environment.ts",
    "content": "import { Environment, Network, Store, RecordSource } from 'relay-runtime';\n\nexport function createClientNetwork() {\n  return Network.create(async (params, variables) => {\n    const response = await fetch(\n      'https://swapi-graphql.netlify.app/.netlify/functions/index',\n      {\n        method: 'POST',\n        headers: {\n          'Content-Type': 'application/json',\n        },\n        body: JSON.stringify({\n          query: params.text,\n          variables,\n        }),\n      }\n    );\n\n    return await response.json();\n  });\n}\n\nlet clientEnv: Environment | undefined;\nexport function getClientEnvironment() {\n  if (typeof window === 'undefined') return null;\n\n  if (clientEnv == null) {\n    clientEnv = new Environment({\n      network: createClientNetwork(),\n      store: new Store(new RecordSource()),\n      isServer: false,\n    });\n  }\n\n  return clientEnv;\n}\n"
  },
  {
    "path": "example/src/lib/server/relay_server_environment.ts",
    "content": "import { Environment, Network, Store, RecordSource } from 'relay-runtime';\n\nexport function createServerNetwork() {\n  return Network.create(async (params, variables) => {\n    const response = await fetch(\n      'https://swapi-graphql.netlify.app/.netlify/functions/index',\n      {\n        method: 'POST',\n        headers: {\n          'Content-Type': 'application/json',\n        },\n        body: JSON.stringify({\n          query: params.text,\n          variables,\n        }),\n      }\n    );\n\n    return await response.json();\n  });\n}\n\nexport function createServerEnvironment() {\n  return new Environment({\n    network: createServerNetwork(),\n    store: new Store(new RecordSource()),\n    isServer: true,\n  });\n}\n"
  },
  {
    "path": "example/src/pages/_app.tsx",
    "content": "import { getClientEnvironment } from 'lib/relay_client_environment';\nimport type { AppProps } from 'next/app';\nimport { RelayEnvironmentProvider } from 'react-relay/hooks';\nimport { useRelayNextjs } from 'relay-nextjs/app';\nimport 'tailwindcss/tailwind.css';\n\nfunction ExampleApp({ Component, pageProps }: AppProps) {\n  const { env, ...relayProps } = useRelayNextjs(pageProps, {\n    createClientEnvironment: () => getClientEnvironment()!,\n  });\n\n  return (\n    <RelayEnvironmentProvider environment={env}>\n      <Component {...pageProps} {...relayProps} />\n    </RelayEnvironmentProvider>\n  );\n}\n\nexport default ExampleApp;\n"
  },
  {
    "path": "example/src/pages/film/[id].tsx",
    "content": "import { getClientEnvironment } from 'lib/relay_client_environment';\nimport Link from 'next/link';\nimport type { Id_filmDescription$key } from 'queries/__generated__/Id_filmDescription.graphql';\nimport type { Id_filmQuery } from 'queries/__generated__/Id_filmQuery.graphql';\nimport { graphql, useFragment, usePreloadedQuery } from 'react-relay';\nimport type { RelayProps } from 'relay-nextjs';\nimport { withRelay } from 'relay-nextjs';\n\nfunction FilmDescription(props: { film: Id_filmDescription$key }) {\n  const film = useFragment(\n    graphql`\n      fragment Id_filmDescription on Film {\n        director\n        openingCrawl\n      }\n    `,\n    props.film\n  );\n\n  return (\n    <div className=\"flex flex-col items-center text-center\">\n      <p>Directed by {film.director}</p>\n      <p>{film.openingCrawl}</p>\n    </div>\n  );\n}\n\nconst FilmQuery = graphql`\n  query Id_filmQuery($id: ID!) {\n    film(id: $id) {\n      title\n\n      ...Id_filmDescription\n    }\n  }\n`;\n\nfunction Film({ preloadedQuery }: RelayProps<{}, Id_filmQuery>) {\n  const query = usePreloadedQuery(FilmQuery, preloadedQuery);\n  if (query.film == null) return null;\n\n  return (\n    <div className=\"max-w-xl mx-auto p-8\">\n      <div className=\"flex items-center justify-center w-full pb-3\">\n        <Link href=\"/\" className=\"text-blue-500 hover:underline mr-3\">\n          « Home\n        </Link>\n        <h1 className=\"text-center text-3xl font-semibold\">\n          {query.film.title}\n        </h1>\n      </div>\n\n      <FilmDescription film={query.film} />\n    </div>\n  );\n}\n\nexport default withRelay(Film, FilmQuery, {\n  createClientEnvironment: () => getClientEnvironment()!,\n  createServerEnvironment: async () => {\n    const { createServerEnvironment } = await import(\n      'lib/server/relay_server_environment'\n    );\n\n    return createServerEnvironment();\n  },\n  // This code is executed on the client between page transitions.\n  // All props returned are passed directly to the component.\n  clientSideProps: async () => {\n    await new Promise((resolve) => setTimeout(resolve, 200));\n    return {};\n  },\n});\n"
  },
  {
    "path": "example/src/pages/index.tsx",
    "content": "import { getClientEnvironment } from 'lib/relay_client_environment';\nimport type { pages_listFilmsQuery } from 'queries/__generated__/pages_listFilmsQuery.graphql';\nimport React from 'react';\nimport { graphql, usePreloadedQuery } from 'react-relay';\nimport type { RelayProps } from 'relay-nextjs';\nimport { withRelay } from 'relay-nextjs';\nimport Link from 'next/link';\n\nconst FilmListQuery = graphql`\n  query pages_listFilmsQuery {\n    allFilms {\n      films {\n        id\n        title\n        openingCrawl\n      }\n    }\n  }\n`;\n\nfunction FilmList({ preloadedQuery }: RelayProps<{}, pages_listFilmsQuery>) {\n  const query = usePreloadedQuery(FilmListQuery, preloadedQuery);\n  if (query.allFilms == null || query.allFilms.films == null) return null;\n\n  return (\n    <div className=\"max-w-xl mx-auto p-8\">\n      <h1 className=\"text-center text-3xl font-semibold mb-5\">All Films</h1>\n\n      <div className=\"grid grid-cols-3 gap-3\">\n        {query.allFilms.films.map((film) => {\n          if (film == null) return null;\n          return (\n            <div\n              key={film.id}\n              className=\"rounded-md h-32 bg-gray-700 text-white\"\n            >\n              <Link href={`/film/${film.id}`}>\n                <h2 className=\"text-center mt-3 hover:underline\">\n                  {film.title}\n                </h2>\n              </Link>\n              <p className=\"text-sm p-2 truncate text-gray-200\">\n                {film.openingCrawl}\n              </p>\n            </div>\n          );\n        })}\n      </div>\n    </div>\n  );\n}\n\nexport default withRelay(FilmList, FilmListQuery, {\n  createClientEnvironment: () => getClientEnvironment()!,\n  createServerEnvironment: async () => {\n    const { createServerEnvironment } = await import(\n      'lib/server/relay_server_environment'\n    );\n\n    return createServerEnvironment();\n  },\n});\n"
  },
  {
    "path": "example/src/queries/__generated__/Id_filmDescription.graphql.ts",
    "content": "/**\n * @generated SignedSource<<ed9ee293b0eda0b05416355b644db88d>>\n * @lightSyntaxTransform\n * @nogrep\n */\n\n/* tslint:disable */\n/* eslint-disable */\n// @ts-nocheck\n\nimport { Fragment, ReaderFragment } from 'relay-runtime';\nimport { FragmentRefs } from \"relay-runtime\";\nexport type Id_filmDescription$data = {\n  readonly director: string | null;\n  readonly openingCrawl: string | null;\n  readonly \" $fragmentType\": \"Id_filmDescription\";\n};\nexport type Id_filmDescription$key = {\n  readonly \" $data\"?: Id_filmDescription$data;\n  readonly \" $fragmentSpreads\": FragmentRefs<\"Id_filmDescription\">;\n};\n\nconst node: ReaderFragment = {\n  \"argumentDefinitions\": [],\n  \"kind\": \"Fragment\",\n  \"metadata\": null,\n  \"name\": \"Id_filmDescription\",\n  \"selections\": [\n    {\n      \"alias\": null,\n      \"args\": null,\n      \"kind\": \"ScalarField\",\n      \"name\": \"director\",\n      \"storageKey\": null\n    },\n    {\n      \"alias\": null,\n      \"args\": null,\n      \"kind\": \"ScalarField\",\n      \"name\": \"openingCrawl\",\n      \"storageKey\": null\n    }\n  ],\n  \"type\": \"Film\",\n  \"abstractKey\": null\n};\n\n(node as any).hash = \"0cff8413ec741c40ba2da65ea4176a9b\";\n\nexport default node;\n"
  },
  {
    "path": "example/src/queries/__generated__/Id_filmQuery.graphql.ts",
    "content": "/**\n * @generated SignedSource<<09ea506460f6041b1df834301726692e>>\n * @lightSyntaxTransform\n * @nogrep\n */\n\n/* tslint:disable */\n/* eslint-disable */\n// @ts-nocheck\n\nimport { ConcreteRequest, Query } from 'relay-runtime';\nimport { FragmentRefs } from \"relay-runtime\";\nexport type Id_filmQuery$variables = {\n  id: string;\n};\nexport type Id_filmQuery$data = {\n  readonly film: {\n    readonly title: string | null;\n    readonly \" $fragmentSpreads\": FragmentRefs<\"Id_filmDescription\">;\n  } | null;\n};\nexport type Id_filmQuery = {\n  variables: Id_filmQuery$variables;\n  response: Id_filmQuery$data;\n};\n\nconst node: ConcreteRequest = (function(){\nvar v0 = [\n  {\n    \"defaultValue\": null,\n    \"kind\": \"LocalArgument\",\n    \"name\": \"id\"\n  }\n],\nv1 = [\n  {\n    \"kind\": \"Variable\",\n    \"name\": \"id\",\n    \"variableName\": \"id\"\n  }\n],\nv2 = {\n  \"alias\": null,\n  \"args\": null,\n  \"kind\": \"ScalarField\",\n  \"name\": \"title\",\n  \"storageKey\": null\n};\nreturn {\n  \"fragment\": {\n    \"argumentDefinitions\": (v0/*: any*/),\n    \"kind\": \"Fragment\",\n    \"metadata\": null,\n    \"name\": \"Id_filmQuery\",\n    \"selections\": [\n      {\n        \"alias\": null,\n        \"args\": (v1/*: any*/),\n        \"concreteType\": \"Film\",\n        \"kind\": \"LinkedField\",\n        \"name\": \"film\",\n        \"plural\": false,\n        \"selections\": [\n          (v2/*: any*/),\n          {\n            \"args\": null,\n            \"kind\": \"FragmentSpread\",\n            \"name\": \"Id_filmDescription\"\n          }\n        ],\n        \"storageKey\": null\n      }\n    ],\n    \"type\": \"Root\",\n    \"abstractKey\": null\n  },\n  \"kind\": \"Request\",\n  \"operation\": {\n    \"argumentDefinitions\": (v0/*: any*/),\n    \"kind\": \"Operation\",\n    \"name\": \"Id_filmQuery\",\n    \"selections\": [\n      {\n        \"alias\": null,\n        \"args\": (v1/*: any*/),\n        \"concreteType\": \"Film\",\n        \"kind\": \"LinkedField\",\n        \"name\": \"film\",\n        \"plural\": false,\n        \"selections\": [\n          (v2/*: any*/),\n          {\n            \"alias\": null,\n            \"args\": null,\n            \"kind\": \"ScalarField\",\n            \"name\": \"director\",\n            \"storageKey\": null\n          },\n          {\n            \"alias\": null,\n            \"args\": null,\n            \"kind\": \"ScalarField\",\n            \"name\": \"openingCrawl\",\n            \"storageKey\": null\n          },\n          {\n            \"alias\": null,\n            \"args\": null,\n            \"kind\": \"ScalarField\",\n            \"name\": \"id\",\n            \"storageKey\": null\n          }\n        ],\n        \"storageKey\": null\n      }\n    ]\n  },\n  \"params\": {\n    \"cacheID\": \"db6af483ec2e52c7c7359182fe7688db\",\n    \"id\": null,\n    \"metadata\": {},\n    \"name\": \"Id_filmQuery\",\n    \"operationKind\": \"query\",\n    \"text\": \"query Id_filmQuery(\\n  $id: ID!\\n) {\\n  film(id: $id) {\\n    title\\n    ...Id_filmDescription\\n    id\\n  }\\n}\\n\\nfragment Id_filmDescription on Film {\\n  director\\n  openingCrawl\\n}\\n\"\n  }\n};\n})();\n\n(node as any).hash = \"3573cf75b79f7fd10e324897f10a7d3a\";\n\nexport default node;\n"
  },
  {
    "path": "example/src/queries/__generated__/pages_listFilmsQuery.graphql.ts",
    "content": "/**\n * @generated SignedSource<<4b786e7bb83bbdb4f636d8f71dac9a5f>>\n * @lightSyntaxTransform\n * @nogrep\n */\n\n/* tslint:disable */\n/* eslint-disable */\n// @ts-nocheck\n\nimport { ConcreteRequest, Query } from 'relay-runtime';\nexport type pages_listFilmsQuery$variables = {};\nexport type pages_listFilmsQuery$data = {\n  readonly allFilms: {\n    readonly films: ReadonlyArray<{\n      readonly id: string;\n      readonly title: string | null;\n      readonly openingCrawl: string | null;\n    } | null> | null;\n  } | null;\n};\nexport type pages_listFilmsQuery = {\n  variables: pages_listFilmsQuery$variables;\n  response: pages_listFilmsQuery$data;\n};\n\nconst node: ConcreteRequest = (function(){\nvar v0 = [\n  {\n    \"alias\": null,\n    \"args\": null,\n    \"concreteType\": \"FilmsConnection\",\n    \"kind\": \"LinkedField\",\n    \"name\": \"allFilms\",\n    \"plural\": false,\n    \"selections\": [\n      {\n        \"alias\": null,\n        \"args\": null,\n        \"concreteType\": \"Film\",\n        \"kind\": \"LinkedField\",\n        \"name\": \"films\",\n        \"plural\": true,\n        \"selections\": [\n          {\n            \"alias\": null,\n            \"args\": null,\n            \"kind\": \"ScalarField\",\n            \"name\": \"id\",\n            \"storageKey\": null\n          },\n          {\n            \"alias\": null,\n            \"args\": null,\n            \"kind\": \"ScalarField\",\n            \"name\": \"title\",\n            \"storageKey\": null\n          },\n          {\n            \"alias\": null,\n            \"args\": null,\n            \"kind\": \"ScalarField\",\n            \"name\": \"openingCrawl\",\n            \"storageKey\": null\n          }\n        ],\n        \"storageKey\": null\n      }\n    ],\n    \"storageKey\": null\n  }\n];\nreturn {\n  \"fragment\": {\n    \"argumentDefinitions\": [],\n    \"kind\": \"Fragment\",\n    \"metadata\": null,\n    \"name\": \"pages_listFilmsQuery\",\n    \"selections\": (v0/*: any*/),\n    \"type\": \"Root\",\n    \"abstractKey\": null\n  },\n  \"kind\": \"Request\",\n  \"operation\": {\n    \"argumentDefinitions\": [],\n    \"kind\": \"Operation\",\n    \"name\": \"pages_listFilmsQuery\",\n    \"selections\": (v0/*: any*/)\n  },\n  \"params\": {\n    \"cacheID\": \"de4a2a5dbbdb78fb7ded1409cb88a921\",\n    \"id\": null,\n    \"metadata\": {},\n    \"name\": \"pages_listFilmsQuery\",\n    \"operationKind\": \"query\",\n    \"text\": \"query pages_listFilmsQuery {\\n  allFilms {\\n    films {\\n      id\\n      title\\n      openingCrawl\\n    }\\n  }\\n}\\n\"\n  }\n};\n})();\n\n(node as any).hash = \"26d1e122fd6b9b275c2ded9ee0a59a18\";\n\nexport default node;\n"
  },
  {
    "path": "example/tailwind.config.js",
    "content": "module.exports = {\n  purge: [\n    './src/pages/**/*.{js,ts,jsx,tsx}',\n    './src/components/**/*.{js,ts,jsx,tsx}',\n  ],\n  darkMode: false, // or 'media' or 'class'\n  theme: {\n    extend: {},\n  },\n  variants: {\n    extend: {},\n  },\n  plugins: [],\n};\n"
  },
  {
    "path": "example/tsconfig.json",
    "content": "{\n  \"compilerOptions\": {\n    \"allowJs\": false,\n    \"allowUnusedLabels\": false,\n    \"baseUrl\": \"./src\",\n    \"esModuleInterop\": true,\n    \"forceConsistentCasingInFileNames\": true,\n    \"isolatedModules\": true,\n    \"jsx\": \"preserve\",\n    \"lib\": [\"dom\", \"dom.iterable\", \"esnext\"],\n    \"module\": \"esnext\",\n    \"moduleResolution\": \"node\",\n    \"noEmit\": true,\n    \"noFallthroughCasesInSwitch\": true,\n    \"noImplicitReturns\": true,\n    \"resolveJsonModule\": true,\n    \"skipLibCheck\": true,\n    \"strict\": true,\n    \"target\": \"es5\",\n    \"incremental\": true\n  },\n  \"include\": [\"next-env.d.ts\", \"**/*.ts\", \"**/*.tsx\"],\n  \"exclude\": [\"node_modules\"]\n}\n"
  },
  {
    "path": "package.json",
    "content": "{\n  \"name\": \"relay-nextjs\",\n  \"version\": \"3.0.1\",\n  \"description\": \"Use Relay in your Next.js apps!\",\n  \"main\": \"index.js\",\n  \"scripts\": {\n    \"build\": \"tsc && cp -r dist/* . && rm -rf dist\",\n    \"clean\": \"rm *.js *.d.ts\",\n    \"format\": \"prettier --write .\",\n    \"check\": \"npm run check:prettier\",\n    \"check:prettier\": \"prettier --check .\"\n  },\n  \"repository\": {\n    \"type\": \"git\",\n    \"url\": \"git+https://github.com/RevereCRE/relay-nextjs.git\"\n  },\n  \"keywords\": [\n    \"relay\",\n    \"next\",\n    \"nextjs\",\n    \"graphql\"\n  ],\n  \"author\": \"Ryan Delaney <rrdelaney@outlook.com>\",\n  \"license\": \"MIT\",\n  \"bugs\": {\n    \"url\": \"https://github.com/RevereCRE/relay-nextjs/issues\"\n  },\n  \"homepage\": \"https://github.com/RevereCRE/relay-nextjs#readme\",\n  \"devDependencies\": {\n    \"@types/lodash.isequal\": \"^4.5.6\",\n    \"@types/node\": \"^14.14.41\",\n    \"@types/react\": \"^17.0.3\",\n    \"@types/react-dom\": \"^17.0.3\",\n    \"@types/react-relay\": \"^11.0.0\",\n    \"@types/relay-runtime\": \"^10.1.10\",\n    \"@types/serialize-javascript\": \"^5.0.0\",\n    \"graphql\": \"^15.5.0\",\n    \"next\": \"^10.0.9\",\n    \"prettier\": \"^2.2.1\",\n    \"typescript\": \"^5.0.4\"\n  },\n  \"dependencies\": {\n    \"lodash.isequal\": \"^4.5.0\",\n    \"serialize-javascript\": \"^5.0.1\"\n  },\n  \"files\": [\n    \"*.js\",\n    \"*.d.ts\"\n  ]\n}\n"
  },
  {
    "path": "src/app.ts",
    "content": "/* eslint-disable @typescript-eslint/no-unnecessary-condition */\nimport { useMemo, useState } from 'react';\nimport type { Environment } from 'react-relay';\nimport { loadQuery } from 'react-relay';\nimport type { GraphQLSingularResponse } from 'relay-runtime';\nimport type { AnyPreloadedQuery, UseRelayNextJsProps } from './component';\nimport { hydrateObject } from './json_meta';\n\nexport function useRelayNextjs(\n  props: UseRelayNextJsProps,\n  opts: { createClientEnvironment: () => Environment }\n): { env: Environment; preloadedQuery?: AnyPreloadedQuery; CSN: boolean } {\n  const [relayEnvironment] = useState(() => {\n    if (props.preloadedQuery?.environment) {\n      return props.preloadedQuery.environment;\n    }\n\n    const env = opts.createClientEnvironment();\n    if (props.payload && props.payloadMeta && props.operationDescriptor) {\n      hydrateObject(props.payloadMeta, props.payload);\n\n      // After SSR, during initial render (hydration), the store is empty.\n      // `getInitialProps` from the server gives us data to \"replay\" the data\n      // fetching allowing us to \"hydrate\" the store, ensuring the initial\n      // render matches the server's.\n      env.commitPayload(\n        props.operationDescriptor,\n        (props.payload as GraphQLSingularResponse).data!\n      );\n    }\n\n    return env;\n  });\n\n  const preloadedQuery = useMemo(() => {\n    if (props.preloadedQuery) {\n      // During SSR and client-side navigations this will be defined.\n      return props.preloadedQuery;\n    } else if (props.operationDescriptor) {\n      // During initial hydration we don't have a reference to the preloadedQuery\n      // from the server because it cannot be serialized. In that case we recreate\n      // it from store data.\n      return loadQuery(\n        relayEnvironment,\n        props.operationDescriptor.request.node,\n        props.operationDescriptor.request.variables,\n        { fetchPolicy: 'store-or-network' }\n      );\n    } else {\n      // If the page we landed on doesn't have these props defined it is not a\n      // page using relay-nextjs, so we should just return undefined.\n      return undefined;\n    }\n  }, [props, relayEnvironment]);\n\n  return { env: relayEnvironment, preloadedQuery, CSN: props.CSN };\n}\n"
  },
  {
    "path": "src/component.tsx",
    "content": "import isEqual from 'lodash.isequal';\nimport type { NextPageContext, Redirect } from 'next';\nimport Router, { NextRouter, useRouter } from 'next/router';\nimport {\n  ComponentType,\n  ReactNode,\n  Suspense,\n  useEffect,\n  useMemo,\n  useRef,\n  useState,\n} from 'react';\nimport {\n  LoadQueryOptions,\n  PreloadedQuery,\n  loadQuery,\n  useRelayEnvironment,\n} from 'react-relay';\nimport {\n  ConcreteRequest,\n  Environment,\n  GraphQLResponse,\n  GraphQLTaggedNode,\n  OperationDescriptor,\n  OperationType,\n  RelayFeatureFlags,\n  Variables,\n  createOperationDescriptor,\n} from 'relay-runtime';\nimport { HydrationMeta, collectMeta } from './json_meta';\n\nexport type AnyPreloadedQuery = PreloadedQuery<OperationType>;\n\n// Enabling this feature flag to determine if a page should 404 on the server.\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\n(RelayFeatureFlags as any).ENABLE_REQUIRED_DIRECTIVES = true;\n\nexport type RelayProps<\n  P extends {} = {},\n  Q extends OperationType = OperationType\n> = P & Required<Pick<UseRelayNextJsProps<P, Q>, 'CSN' | 'preloadedQuery'>>;\n\nexport type UseRelayNextJsProps<\n  P extends {} = {},\n  Q extends OperationType = OperationType\n> = P & {\n  /** If this page rendering resulted from a client-side navigation. */\n  CSN: boolean;\n  /** Undefined during initial hydration, but defined for SSR and subsequent renders */\n  preloadedQuery?: PreloadedQuery<Q>;\n  operationDescriptor?: OperationDescriptor;\n  payload?: GraphQLResponse;\n  payloadMeta?: HydrationMeta;\n};\n\nexport type OrRedirect<T> = T | { redirect: Redirect };\n\nexport interface RelayOptions<\n  Props extends RelayProps,\n  ServerSideProps extends {} = {}\n> {\n  /** Fallback rendered when the page suspends. */\n  fallback?: ReactNode;\n  variablesFromContext?: (\n    ctx: NextPageContext | NextRouter\n  ) => Props['preloadedQuery']['variables'];\n  queryOptionsFromContext?: (\n    ctx: NextPageContext | NextRouter\n  ) => LoadQueryOptions;\n  /** Called when creating a Relay environment on the client. Should be idempotent. */\n  createClientEnvironment: () => Environment;\n  /** Props passed to the component when rendering on the client. */\n  clientSideProps?: (\n    ctx: NextPageContext\n  ) => OrRedirect<Partial<ServerSideProps>>;\n  /** Called when creating a Relay environment on the server. */\n  createServerEnvironment: (\n    ctx: NextPageContext,\n    props: ServerSideProps\n  ) => Promise<Environment>;\n  /** Props passed to the component when rendering on the server. */\n  serverSideProps?: (\n    ctx: NextPageContext\n  ) => Promise<OrRedirect<ServerSideProps>>;\n  /** Runs after a query has been executed on the server. */\n  serverSidePostQuery?: (\n    queryResult: GraphQLResponse | undefined,\n    ctx: NextPageContext\n  ) => Promise<unknown> | unknown;\n}\n\nfunction defaultVariablesFromContext(\n  ctx: NextPageContext | NextRouter\n): Variables {\n  return ctx.query;\n}\n\nfunction defaultQueryOptionsFromContext(\n  _ctx: NextPageContext | NextRouter\n): LoadQueryOptions {\n  return { fetchPolicy: 'store-or-network' };\n}\n\nfunction useStableIdentity<T>(nextValue: T): T {\n  const lastValue = useRef<T>(nextValue);\n  return useMemo((): T => {\n    if (!isEqual(lastValue.current, nextValue)) {\n      lastValue.current = nextValue;\n    }\n\n    return lastValue.current;\n  }, [nextValue]);\n}\n\nexport function withRelay<Props extends RelayProps, ServerSideProps extends {}>(\n  Component: ComponentType<Props>,\n  query: GraphQLTaggedNode,\n  opts: RelayOptions<Props, ServerSideProps>\n) {\n  const {\n    queryOptionsFromContext = defaultQueryOptionsFromContext,\n    variablesFromContext = defaultVariablesFromContext,\n  } = opts;\n\n  function useLoadedQuery(initialPreloadedQuery: Props['preloadedQuery']) {\n    const router = useRouter();\n\n    const queryOptions = useStableIdentity(\n      useMemo(() => queryOptionsFromContext(router), [router])\n    );\n\n    const queryVariables = useStableIdentity(\n      useMemo(() => variablesFromContext(router), [router])\n    );\n\n    const [preloadedQuery, setPreloadedQuery] = useState(initialPreloadedQuery);\n\n    const isMountedRef = useRef(false);\n    const env = useRelayEnvironment();\n    useEffect(() => {\n      // Avoid re-setting the initial preloaded query on the first render.\n      if (!isMountedRef.current) {\n        isMountedRef.current = true;\n        return;\n      }\n\n      const nextPreloadedQuery = loadQuery(\n        env,\n        query,\n        queryVariables,\n        queryOptions\n      );\n\n      setPreloadedQuery(nextPreloadedQuery);\n      return () => nextPreloadedQuery.dispose();\n    }, [env, queryVariables, queryOptions]);\n\n    return preloadedQuery;\n  }\n\n  function RelayComponent(props: Props) {\n    const preloadedQuery = useLoadedQuery(props.preloadedQuery);\n    return (\n      <Suspense fallback={opts.fallback ?? 'Loading...'}>\n        <Component {...props} preloadedQuery={preloadedQuery} />\n      </Suspense>\n    );\n  }\n\n  RelayComponent.getInitialProps = relayInitialProps(query, opts);\n\n  return RelayComponent;\n}\n\nfunction relayInitialProps<\n  Props extends RelayProps,\n  ServerSideProps extends {}\n>(query: GraphQLTaggedNode, opts: RelayOptions<Props, ServerSideProps>) {\n  return async (ctx: NextPageContext): Promise<UseRelayNextJsProps> => {\n    if (typeof window === 'undefined') {\n      return getServerInitialProps(ctx, query, opts);\n    } else {\n      return getClientInitialProps(ctx, query, opts);\n    }\n  };\n}\n\nasync function getServerInitialProps<\n  Props extends RelayProps,\n  ServerSideProps extends {}\n>(\n  ctx: NextPageContext,\n  query: GraphQLTaggedNode,\n  opts: RelayOptions<Props, ServerSideProps>\n): Promise<UseRelayNextJsProps> {\n  const {\n    variablesFromContext = defaultVariablesFromContext,\n    queryOptionsFromContext = defaultQueryOptionsFromContext,\n  } = opts;\n\n  const serverSideProps = opts.serverSideProps\n    ? await opts.serverSideProps(ctx)\n    : ({} as ServerSideProps);\n\n  if ('redirect' in serverSideProps) {\n    const { redirect } = serverSideProps;\n\n    let statusCode = 302;\n    if ('statusCode' in redirect) {\n      statusCode = redirect.statusCode;\n    } else if ('permanent' in redirect) {\n      statusCode = redirect.permanent ? 308 : 307;\n    }\n\n    ctx\n      .res!.writeHead(statusCode, {\n        Location: redirect.destination,\n      })\n      .end();\n\n    return { CSN: false };\n  }\n\n  const env = await opts.createServerEnvironment(ctx, serverSideProps);\n  const variables = variablesFromContext(ctx);\n  const queryOptions = queryOptionsFromContext(ctx);\n  const preloadedQuery = loadQuery(env, query, variables, queryOptions);\n\n  const payload = await ensureQueryFlushed(preloadedQuery);\n  await opts.serverSidePostQuery?.(payload, ctx);\n\n  const payloadSerializationMetadata = collectMeta(payload);\n\n  const request = query as { default: ConcreteRequest } | ConcreteRequest;\n  const operationDescriptor = createOperationDescriptor(\n    'default' in request ? request.default : request,\n    variables\n  );\n\n  const props: UseRelayNextJsProps = {\n    ...serverSideProps,\n    CSN: false,\n    operationDescriptor,\n    payload,\n    payloadMeta: payloadSerializationMetadata,\n  };\n\n  // This will only be available during SSR, not during client side render or hydration.\n  Object.defineProperty(props, 'preloadedQuery', {\n    enumerable: false,\n    value: preloadedQuery,\n  });\n\n  return props;\n}\n\nasync function getClientInitialProps<\n  Props extends RelayProps,\n  ClientSideProps extends {}\n>(\n  ctx: NextPageContext,\n  query: GraphQLTaggedNode,\n  opts: RelayOptions<Props, ClientSideProps>\n): Promise<UseRelayNextJsProps> {\n  const {\n    variablesFromContext = defaultVariablesFromContext,\n    queryOptionsFromContext = defaultQueryOptionsFromContext,\n  } = opts;\n\n  const clientSideProps = opts.clientSideProps\n    ? opts.clientSideProps(ctx)\n    : ({} as ClientSideProps);\n\n  if ('redirect' in clientSideProps) {\n    void Router.push(clientSideProps.redirect.destination);\n    return { CSN: true };\n  }\n\n  const env = opts.createClientEnvironment();\n  const variables = variablesFromContext(ctx);\n  const queryOptions = queryOptionsFromContext(ctx);\n  const preloadedQuery = loadQuery(env, query, variables, queryOptions);\n\n  return {\n    ...clientSideProps,\n    CSN: true,\n    preloadedQuery,\n  };\n}\n\nasync function ensureQueryFlushed(\n  query: AnyPreloadedQuery\n): Promise<GraphQLResponse> {\n  return new Promise((resolve, reject) => {\n    if (query.source == null) {\n      resolve({ data: {} });\n    } else {\n      query.source.subscribe({\n        next: resolve,\n        error: reject,\n      });\n    }\n  });\n}\n"
  },
  {
    "path": "src/index.tsx",
    "content": "export { withRelay } from './component';\nexport type { OrRedirect, RelayOptions, RelayProps } from './component';\n"
  },
  {
    "path": "src/json_meta.ts",
    "content": "/**\n * @fileoverview Functions for extracting and applying serialization metadata\n * to JSON. When a JS object is serialized to JSON it will call the `toJSON`\n * and `toString` methods on objects. When deserializing the original types of\n * those values are lost. This library exports `collectMeta` which returns a\n * JSON-serializable representation of how the original object will be\n * serialized. This can be passed to `hydrateObject` to restore the\n * original object. Currently supports `Date` and `URL` values.\n */\n\n/** Type of value that can be restored. */\nexport enum EncodedType {\n  DATE = 'date',\n  URL = 'url',\n}\n\nexport type HydrationMeta = Record<string, EncodedType>;\n\n/**\n * Restores the type of values after deserializing a JSON object. Meta must be\n * the object returned from `collectMeta`. Mutates the object in place.\n */\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nexport function hydrateObject(meta: HydrationMeta, value: any) {\n  for (const [path, encoding] of Object.entries(meta)) {\n    let updatingValue = value;\n    const parts = path.split('.');\n\n    for (let i = 0; i < parts.length - 1; ++i) {\n      let accessor: string | number = Number(parts[i]);\n      if (Number.isNaN(accessor)) {\n        accessor = parts[i]!;\n      }\n\n      updatingValue = updatingValue[accessor];\n    }\n\n    let lastAccessor: string | number = Number(parts[parts.length - 1]);\n    if (Number.isNaN(lastAccessor)) {\n      lastAccessor = parts[parts.length - 1]!;\n    }\n\n    switch (encoding) {\n      case EncodedType.DATE:\n        updatingValue[lastAccessor] = new Date(updatingValue[lastAccessor]);\n        break;\n      case EncodedType.URL:\n        updatingValue[lastAccessor] = new URL(updatingValue[lastAccessor]);\n        break;\n      default:\n        checkExhaustive(encoding);\n    }\n  }\n}\n\nfunction* walk(): Generator<\n  string,\n  void,\n  { parent: {}; key: string; value: unknown }\n> {\n  const path: [string, unknown][] = [];\n\n  do {\n    const { parent, key, value } = yield path.map(([key]) => key).join('.');\n    while (path.length > 0 && path[path.length - 1]![1] !== parent) {\n      path.pop();\n    }\n\n    path.push([key, value]);\n  } while (path.length > 0);\n}\n\nfunction createReplacer() {\n  const meta: HydrationMeta = {};\n  const walker = walk();\n\n  function replacer(\n    this: Record<string, unknown>,\n    key: string,\n    value: unknown\n  ) {\n    const path = walker.next({ parent: this, key, value }).value;\n    if (path && this[key] instanceof Date) {\n      meta[path] = EncodedType.DATE;\n    } else if (path && this[key] instanceof URL) {\n      meta[path] = EncodedType.URL;\n    }\n\n    return value;\n  }\n\n  return [replacer, () => meta] as const;\n}\n\n/**\n * Walks an object and extracts information for hydrating it after\n * deserialization.\n */\nexport function collectMeta(obj: unknown) {\n  const [replacer, dumpMeta] = createReplacer();\n  JSON.stringify(obj, replacer);\n  return dumpMeta();\n}\n\nfunction checkExhaustive(cased: never): asserts cased is never {\n  if (process.env.NODE_ENV !== 'production') {\n    throw new Error(`Unexpected condition: ${cased}`);\n  }\n\n  return undefined;\n}\n"
  },
  {
    "path": "tsconfig.json",
    "content": "{\n  \"compilerOptions\": {\n    \"module\": \"CommonJS\",\n    \"target\": \"ES2015\",\n    \"jsx\": \"react-jsx\",\n    \"outDir\": \"dist\",\n    \"declaration\": true,\n    \"allowJs\": false,\n    \"allowUnusedLabels\": false,\n    \"esModuleInterop\": true,\n    \"forceConsistentCasingInFileNames\": true,\n    \"isolatedModules\": true,\n    \"lib\": [\"dom\", \"dom.iterable\", \"esnext\"],\n    \"moduleResolution\": \"node\",\n    \"noFallthroughCasesInSwitch\": true,\n    \"noImplicitReturns\": true,\n    \"resolveJsonModule\": true,\n    \"skipLibCheck\": true,\n    \"strict\": true\n  },\n  \"include\": [\"src\"]\n}\n"
  },
  {
    "path": "website/.gitignore",
    "content": "# Dependencies\n/node_modules\n\n# Production\n/build\n\n# Generated files\n.docusaurus\n.cache-loader\n\n# Misc\n.DS_Store\n.env.local\n.env.development.local\n.env.test.local\n.env.production.local\n\nnpm-debug.log*\nyarn-debug.log*\nyarn-error.log*\n"
  },
  {
    "path": "website/README.md",
    "content": "# Website\n\nThis website is built using [Docusaurus 2](https://v2.docusaurus.io/), a modern static website generator.\n\n## Installation\n\n```console\nyarn install\n```\n\n## Local Development\n\n```console\nyarn start\n```\n\nThis command starts a local development server and open up a browser window. Most changes are reflected live without having to restart the server.\n\n## Build\n\n```console\nyarn build\n```\n\nThis command generates static content into the `build` directory and can be served using any static contents hosting service.\n\n## Deployment\n\n```console\nGIT_USER=<Your GitHub username> USE_SSH=true yarn deploy\n```\n\nIf you are using GitHub pages for hosting, this command is a convenient way to build the website and push to the `gh-pages` branch.\n"
  },
  {
    "path": "website/babel.config.js",
    "content": "module.exports = {\n  presets: [require.resolve('@docusaurus/core/lib/babel/preset')],\n};\n"
  },
  {
    "path": "website/docs/app-api.md",
    "content": "---\ntitle: Relay App API\n---\n\n`relay-nextjs/app` exposes a single hook to configure your app to use Relay.\n\n## `useRelayNextjs`\n\nReturns an object containing an `Environment` and props needed to render a page\nusing `relay-nextjs`. Example usage:\n\n```tsx\n// src/pages/_app.tsx\nimport { RelayEnvironmentProvider } from 'react-relay/hooks';\nimport { useRelayNextjs } from 'relay-nextjs/app';\n\n// This function should return a RelayEnvironment pointed at your GraphQL API.\n// Note that this should always return the same object, **not** create a new\n// RelayEnvironment on every call.\nimport { getClientEnvironment } from '../lib/client_environment';\n\nfunction MyApp({ Component, pageProps }: AppProps) {\n  const { env, ...relayProps } = useRelayNextjs(pageProps, {\n    createClientEnvironment: () => getClientSideEnvironment()!,\n  });\n\n  return (\n    <>\n      <RelayEnvironmentProvider environment={env}>\n        <Component {...pageProps} {...relayProps} />\n      </RelayEnvironmentProvider>\n    </>\n  );\n}\n\nexport default MyApp;\n```\n"
  },
  {
    "path": "website/docs/configuration.md",
    "content": "---\ntitle: Configuring relay-nextjs\n---\n\n## Installing `relay-nextjs`\n\nInstall using npm or your other favorite package manager:\n\n```\nnpm install relay-nextjs\n```\n\n## Routing Integration\n\n`relay-nextjs` must be configured in a custom `_app` to properly intercept and\nhandle routing.\n\n### Setting up the Relay Environment\n\nFor basic information about the Relay environment please see the\n[Relay docs](https://relay.dev/docs/getting-started/step-by-step-guide/#42-configure-relay-runtime).\n\n`relay-nextjs` was designed with both client-side and server-side rendering in\nmind. As such it needs to be able to use either a client-side or server-side\nRelay environment. The library knows how to handle which environment to use, but\nwe have to tell it how to create these environments. For this we will define two\nfunctions: `getClientEnvironment` and `createServerEnvironment`. Note the\ndistinction — on the client only one environment is ever created because there\nis only one app, but on the server we must create an environment per-render to\nensure the cache is not shared between requests.\n\nFirst let’s define `getClientEnvironment`:\n\n```tsx\n// lib/client_environment.ts\nimport { Environment, Network, Store, RecordSource } from 'relay-runtime';\n\nexport function createClientNetwork() {\n  return Network.create(async (params, variables) => {\n    const response = await fetch('/api/graphql', {\n      method: 'POST',\n      credentials: 'include',\n      headers: {\n        'Content-Type': 'application/json',\n      },\n      body: JSON.stringify({\n        query: params.text,\n        variables,\n      }),\n    });\n\n    const json = await response.text();\n    return JSON.parse(json);\n  });\n}\n\nlet clientEnv: Environment | undefined;\nexport function getClientEnvironment() {\n  if (typeof window === 'undefined') return null;\n\n  if (clientEnv == null) {\n    clientEnv = new Environment({\n      network: createClientNetwork(),\n      store: new Store(new RecordSource()),\n      isServer: false,\n    });\n  }\n\n  return clientEnv;\n}\n```\n\nand then `createServerEnvironment`:\n\n```tsx\nimport { graphql } from 'graphql';\nimport { GraphQLResponse, Network } from 'relay-runtime';\n\n// Relay is not prescriptive about how GraphQL requests are made.\n// This is an example showing how to request GraphQL data.\n// You should fill this in with how to make requests to your GraphQL\n// API of choice.\nimport { makeGraphQLRequest } from './my_graphql_api';\n\nexport function createServerNetwork() {\n  return Network.create(async (text, variables) => {\n    const results = await makeGraphQLRequest(text, variables);\n\n    return JSON.parse(JSON.stringify(results)) as GraphQLResponse;\n  });\n}\n\n// Optional: this function can take a token used for authentication and pass it into `createServerNetwork`.\nexport function createServerEnvironment() {\n  return new Environment({\n    network: createServerNetwork(),\n    store: new Store(new RecordSource()),\n    isServer: true,\n  });\n}\n```\n\n### Configuring `_app`\n\n```tsx\n// pages/_app.tsx\nimport { RelayEnvironmentProvider } from 'react-relay/hooks';\nimport { useRelayNextjs } from 'relay-nextjs/app';\nimport { getClientEnvironment } from '../lib/client_environment';\n\nfunction MyApp({ Component, pageProps }: AppProps) {\n  const { env, ...relayProps } = useRelayNextjs(pageProps, {\n    createClientEnvironment: () => getClientSideEnvironment()!,\n  });\n\n  return (\n    <>\n      <RelayEnvironmentProvider environment={env}>\n        <Component {...pageProps} {...relayProps} />\n      </RelayEnvironmentProvider>\n    </>\n  );\n}\n\nexport default MyApp;\n```\n\n## Usage in a Page\n\n```tsx\n// src/pages/user/[uuid].tsx\nimport { withRelay, RelayProps } from 'relay-nextjs';\nimport { graphql, usePreloadedQuery } from 'react-relay/hooks';\n\n// The $uuid variable is injected automatically from the route.\nconst ProfileQuery = graphql`\n  query profile_ProfileQuery($uuid: ID!) {\n    user(id: $uuid) {\n      id\n      firstName\n      lastName\n    }\n  }\n`;\n\nfunction UserProfile({ preloadedQuery }: RelayProps<{}, profile_ProfileQuery>) {\n  const query = usePreloadedQuery(ProfileQuery, preloadedQuery);\n\n  return (\n    <div>\n      Hello {query.user.firstName} {query.user.lastName}\n    </div>\n  );\n}\n\nfunction Loading() {\n  return <div>Loading...</div>;\n}\n\nexport default withRelay(UserProfile, UserProfileQuery, {\n  // Fallback to render while the page is loading.\n  // This property is optional.\n  fallback: <Loading />,\n  // Create a Relay environment on the client-side.\n  // Note: This function must always return the same value.\n  createClientEnvironment: () => getClientEnvironment()!,\n  // Gets server side props for the page.\n  serverSideProps: async (ctx) => {\n    // This is an example of getting an auth token from the request context.\n    // If you don't need to authenticate users this can be removed and return an\n    // empty object instead.\n    const { getTokenFromCtx } = await import('lib/server/auth');\n    const token = await getTokenFromCtx(ctx);\n    if (token == null) {\n      return {\n        redirect: { destination: '/login', permanent: false },\n      };\n    }\n\n    return { token };\n  },\n  // Server-side props can be accessed as the second argument\n  // to this function.\n  createServerEnvironment: async (\n    ctx,\n    // The object returned from serverSideProps. If you don't need a token\n    // you can remove this argument.\n    { token }: { token: string }\n  ) => {\n    const { createServerEnvironment } = await import('lib/server_environment');\n    return createServerEnvironment(token);\n  },\n});\n```\n"
  },
  {
    "path": "website/docs/installation-and-setup.md",
    "content": "---\ntitle: Installation and Setup\n---\n\n## Installing Relay\n\nRelay comes with quite a number of dependencies that don't involve Next.js.\nWe'll set those up first before moving on to `relay-nextjs`.\n\nFirst install Relay's runtime dependencies:\n\n```\nnpm install react-relay relay-runtime\n```\n\nTypeScript users should install appropriate `@types` packages:\n\n```\nnpm install --save-dev @types/react-relay @types/relay-runtime\n```\n\n## Configuring Relay\n\nInstall `relay-config` to provide a single configuration file to the rest of\nRelay:\n\n```\nnpm install --save-dev relay-config\n```\n\nCreate `relay.config.js`. For Next.js projects using TypeScript this should look\nsomething like this:\n\n```js\nmodule.exports = {\n  src: './src',\n  schema: './src/schema/__generated__/schema.graphql',\n  exclude: ['**/node_modules/**', '**/__mocks__/**', '**/__generated__/**'],\n  extensions: ['ts', 'tsx'],\n  language: 'typescript',\n  artifactDirectory: 'src/queries/__generated__',\n};\n```\n\n### Configuring `artifactDirectory`\n\nNext.js's `/pages` directory cannot include non-React components as default\nexport.\n\nBy default, the relay-compiler generates `*.graphql.ts` files that are\nco-located with the corresponding files containing graphql tags. To fix this\nconfigure `artifactDirectory` to emit to `src/queries/__generated__`:\n\n```js:relay.config.js\nmodule.exports = {\n  // ...\n  artifactDirectory: 'src/queries/__generated__',\n}\n```\n\nFor more information please see the Relay\n[type emission documentation](https://relay.dev/docs/guides/type-emission/#single-artifact-directory).\nAlternatively you can keep `*.graphql.ts` files in `/pages` directory with\n[`pageExtensions`](https://nextjs.org/docs/api-reference/next.config.js/custom-page-extensions).\n\n## Installing Relay Compiler\n\nThe Relay Compiler statically analyzes and optimizes GraphQL queries in your\napplication. To install the dependencies run:\n\n```\nnpm install --save-dev relay-compiler relay-compiler-language-typescript babel-plugin-relay graphql\n```\n\nFor convenience create a `package.json` to run the compiler:\n\n```json\n{\n  \"scripts\": {\n    \"generate:relay\": \"relay-compiler\"\n  }\n}\n```\n\nThen configure Babel to compile away `graphql` strings:\n\n`.babelrc`:\n\n```json\n{\n  \"presets\": [\"next/babel\"],\n  \"plugins\": [\"relay\"]\n}\n```\n\n`relay-nextjs` is designed to run on both the server and client. To avoid\npulling in server dependencies to the client bundle configure Webpack to ignore\nany files in `src/lib/server`. In `next.config.js`:\n\n```js\nconst webpack = require(\"webpack\");\n\n//...\n\nmodule.exports = {\n  webpack: (config, { isServer, webpack }) => {\n    if (!isServer) {\n      // Ensures no server modules are included on the client.\n      config.plugins.push(\n        new webpack.IgnorePlugin({ resourceRegExp: /lib\\/server/ })\n      );\n    }\n\n    return config;\n  },\n};\n```\n\nIf your path to server-only files is different please adjust the above RegExp\nproperly.\n"
  },
  {
    "path": "website/docs/lazy-loaded-query.md",
    "content": "---\ntitle: Lazy-loaded Queries\n---\n\nRelay's\n[`useLazyLoadQuery` API](https://relay.dev/docs/api-reference/use-lazy-load-query/)\nlet us defer loading queries until a component is mounted. To render a loading\nstate while the query is pending the docs recommended adding a `<Suspense>`\nboundary. Next.js and `relay-nextjs` both expect to be able to render on the\nserver and as of the time of writing React Suspense does not support server\nrendering. When using `withRelay` and `usePreloadedQuery` we take care of adding\nthe `<Suspense>` boundary for you but we cannot here.\n\nTo use `useLazyLoadQuery` and render a `<Suspense>` boundary you must create a\ndynamically rendered component that skips SSR. For example:\n\n```tsx\n// src/components/user_stats.tsx\nimport type { userStats_Birthday } from 'queries/__generated__/userStats_Birthday.graphql';\nimport React, { Suspense, useCallback } from 'react';\nimport { graphql, useLazyLoadQuery } from 'react-relay';\n\nfunction UserBirthday({ uuid }: { uuid: string }) {\n  const query = useLazyLoadQuery<userStats_Birthday>(\n    graphql`\n      query userStats_Birthday($uuid: ID!) {\n        user(id: $uuid) {\n          birthday\n        }\n      }\n    `,\n    { uuid }\n  );\n\n  return <div>Birthday is {query.user.birthday}!</div>;\n}\n\nfunction UserStats({ uuid }: { uuid: string }) {\n  return (\n    <Suspense fallback=\"Loading...\">\n      <UserBirthday uuid={uuid} />\n    </Suspense>\n  );\n}\n\nexport default UserStats;\n```\n\nNote that we have two components here: one that has a `<Suspense>` boundary and\none that actually calls `useLazyLoadQuery`. If these two were merged into the\nsame component there would be no boundary to catch `useLazyLoadQuery`\nsuspending!\n\nTo render this component use the\n[Next.js `dynamic` API](https://nextjs.org/docs/advanced-features/dynamic-import):\n\n```tsx\n// src/pages/user_profile.tsx\nimport dynamic from 'next/dynamic';\n\nconst UserStats = dynamic(() => import('components/components/user_stats'), {\n  ssr: false,\n});\n\nfunction UserProfile({ uuid }: { uuid: string }) {\n  return (\n    <div>\n      {/* ... */}\n      <UserStats uuid={uuid} />\n    </div>\n  );\n}\n```\n"
  },
  {
    "path": "website/docs/page-api.md",
    "content": "---\ntitle: Relay Page API\n---\n\n## `withRelay`\n\nWraps a component, GraphQL query, and a set of options to manage loading the\npage and its data, as specified by the query. Example usage:\n\n```tsx\n// src/pages/user/[uuid].tsx\nimport { withRelay, RelayProps } from 'relay-nextjs';\nimport { graphql, usePreloadedQuery } from 'react-relay/hooks';\n\n// The $uuid variable is injected automatically from the route.\nconst ProfileQuery = graphql`\n  query profile_ProfileQuery($uuid: ID!) {\n    user(id: $uuid) {\n      id\n      firstName\n      lastName\n    }\n  }\n`;\n\nfunction UserProfile({ preloadedQuery }: RelayProps<{}, profile_ProfileQuery>) {\n  const query = usePreloadedQuery(ProfileQuery, preloadedQuery);\n\n  return (\n    <div>\n      Hello {query.user.firstName} {query.user.lastName}\n    </div>\n  );\n}\n\nexport default withRelay(UserProfile, UserProfileQuery, options);\n```\n\n### Arguments\n\n- `component`: A\n  [Next.js page component](https://nextjs.org/docs/basic-features/pages) to\n  recieve the preloaded query from `relay-nextjs`.\n- `query`: A GraphQL query using the `graphql` tag from Relay.\n- `options`: A [`RelayOptions`](#relayoptions) object.\n\n## `RelayOptions`\n\nInterface for configuring `withRelay`. Example usage:\n\n```tsx\nconst options: RelayOptions<{ token: string }> = {\n  fallback: <Loading />,\n  queryOptionsFromContext: () => ({ fetchPolicy: 'store-and-network' }),\n  createClientEnvironment: () => getClientEnvironment()!,\n  serverSideProps: async (ctx) => {\n    const { getTokenFromCtx } = await import('lib/server/auth');\n    const token = await getTokenFromCtx(ctx);\n    if (token == null) {\n      return {\n        redirect: { destination: '/login', permanent: false },\n      };\n    }\n\n    return { token };\n  },\n  createServerEnvironment: async (ctx, { token }) => {\n    const { createServerEnvironment } = await import('lib/server_environment');\n    return createServerEnvironment(token);\n  },\n};\n```\n\n### Properties\n\n- `fallback?`: React component to use as a loading indicator. See\n  [React Suspense docs](https://reactjs.org/docs/concurrent-mode-suspense.html).\n- `queryOptionsFromContext?`: Load query configuration. Defaults to\n  `{ fetchPolicy: 'store-or-network' }`. See\n  [Relay docs](https://relay.dev/docs/api-reference/use-lazy-load-query/#arguments)\n  for more information.\n- `clientSideProps?`: Provides props to the page on client-side navigations. Not\n  required.\n- `createClientEnvironment`: A function that returns a `RelayEnvironment`.\n  Should return the same environment each time it is called.\n- `serverSideProps?`: Fetch any server-side only props such as authentication\n  tokens. Note that you should import server-only deps with\n  `await import('...')`.\n- `createServerEnvironment`: A function that returns a `RelayEnvironment`. First\n  argument is `NextPageContext` and the second is the object returned by\n  `serverSideProps`.\n- `variablesFromContext?`: Function that extracts GraphQL query variables from\n  `NextPageContext`. Run on both the client and server. If omitted query\n  variables are set to `ctx.query`.\n- `serverSidePostQuery?`: Function that is called during server side rendering\n  after fetching the query is finished. First parameter gives you access to the\n  data returned by your query and the second parameter gives access to\n  `NextPageContext`. This function can be used for example to set your response\n  status to 404 if your query didn't return data.\n"
  },
  {
    "path": "website/docs/prerequisites.md",
    "content": "---\ntitle: Prerequisites\n---\n\nFirst check out the [Relay docs](https://relay.dev) and the\n[Relay prerequisites](https://relay.dev/docs/getting-started/prerequisites/).\nThen make sure you are ready with each of the following.\n\n## A Next.js project using [Page Router](https://nextjs.org/docs/pages)\n\n:::info\n\n`relay-nextjs` does not support [Nextjs 13 App Router](https://nextjs.org/docs/app) at the moment.\n\nSee [GitHub issue #89](https://github.com/RevereCRE/relay-nextjs/issues/89) for more info.\n\n:::\n\n`relay-nextjs` is meant to integrate the Relay framework with Next.js. If you're\nnot using Next.js you don't need this project. The rest of this guide will\nassume your project is using **TypeScript** and the page to your pages is\n`src/pages`.\n\nRelay generates artifacts in a single directory. To avoid traversing directories\nas much it will be helpful to configure TypeScript with the following `baseUrl`:\n\n```json\n// tsconfig.json\n{\n  \"compilerOptions\": {\n    \"baseUrl\": \"./src\"\n  }\n}\n```\n\n## A GraphQL API and Schema\n\nRelay uses a GraphQL API to fetch data and compiles queries against a GraphQL\nschema. This guide assumes a local schema (a `.graphql` file). To set up Relay\nwith a remote schema please see the\n[Relay Compiler docs](https://relay.dev/docs/guides/compiler/).\n"
  },
  {
    "path": "website/docs/what-why.md",
    "content": "---\ntitle: What is relay-nextjs\nslug: /\n---\n\n`relay-nextjs` is a bridge between [Next.js](https://nextjs.org/) and\n[Relay](https://relay.dev). Because these are two highly opinionated frameworks\nit can be difficult to get them to work together. This library solves that\nproblem by glueing the two together using techniques that require low-level\nknowledge of both frameworks.\n\nBasically we wrote the glue code for you!\n\nThis library has several goals:\n\n- Use Relay with no modifications, be able to copy code exactly as is from the\n  docs\n- Use only documented public APIs of React, Relay, and Next.js to prevent\n  lock-in\n- Does not require modifications to pages not using Relay\n- Incremental adoption across your app\n"
  },
  {
    "path": "website/docusaurus.config.js",
    "content": "/** @type {import('@docusaurus/types').DocusaurusConfig} */\nmodule.exports = {\n  title: 'relay-nextjs',\n  tagline: 'Relay Hooks integration for Next.js apps',\n  url: 'https://reverecre.github.io',\n  baseUrl: '/relay-nextjs/',\n  organizationName: 'RevereCRE',\n  projectName: 'relay-nextjs',\n  trailingSlash: false,\n  onBrokenLinks: 'throw',\n  onBrokenMarkdownLinks: 'warn',\n  favicon: 'img/favicon.ico',\n  organizationName: 'RevereCRE', // Usually your GitHub org/user name.\n  projectName: 'relay-nextjs', // Usually your repo name.\n  themeConfig: {\n    navbar: {\n      title: 'relay-nextjs',\n      items: [\n        {\n          to: 'docs/',\n          activeBasePath: 'docs',\n          label: 'Docs',\n          position: 'left',\n        },\n        {\n          href: 'https://github.com/RevereCRE/relay-nextjs',\n          label: 'GitHub',\n          position: 'right',\n        },\n      ],\n    },\n    footer: {\n      copyright: `Copyright © ${new Date().getFullYear()} Revere CRE, Inc. Built with Docusaurus.`,\n    },\n  },\n  presets: [\n    [\n      '@docusaurus/preset-classic',\n      {\n        docs: {\n          sidebarPath: require.resolve('./sidebars.js'),\n          editUrl:\n            'https://github.com/RevereCRE/relay-nextjs/edit/main/website/',\n        },\n        theme: {\n          customCss: require.resolve('./src/css/custom.css'),\n        },\n      },\n    ],\n  ],\n};\n"
  },
  {
    "path": "website/package.json",
    "content": "{\n  \"name\": \"website\",\n  \"version\": \"0.0.0\",\n  \"private\": true,\n  \"scripts\": {\n    \"docusaurus\": \"docusaurus\",\n    \"start\": \"docusaurus start\",\n    \"build\": \"docusaurus build\",\n    \"swizzle\": \"docusaurus swizzle\",\n    \"deploy\": \"docusaurus deploy\",\n    \"clear\": \"docusaurus clear\",\n    \"serve\": \"docusaurus serve\",\n    \"write-translations\": \"docusaurus write-translations\",\n    \"write-heading-ids\": \"docusaurus write-heading-ids\"\n  },\n  \"browserslist\": {\n    \"production\": [\n      \">0.5%\",\n      \"not dead\",\n      \"not op_mini all\"\n    ],\n    \"development\": [\n      \"last 1 chrome version\",\n      \"last 1 firefox version\",\n      \"last 1 safari version\"\n    ]\n  },\n  \"dependencies\": {\n    \"@docusaurus/core\": \"^2.4.1\",\n    \"@docusaurus/preset-classic\": \"^2.4.1\",\n    \"@mdx-js/react\": \"^1.6.22\",\n    \"clsx\": \"^1.2.1\",\n    \"react\": \"^17.0.2\",\n    \"react-dom\": \"^17.0.2\"\n  }\n}\n"
  },
  {
    "path": "website/sidebars.js",
    "content": "module.exports = {\n  docs: [\n    {\n      type: 'category',\n      label: 'Getting Started',\n      items: [\n        'what-why',\n        'prerequisites',\n        'installation-and-setup',\n        'configuration',\n      ],\n    },\n    {\n      type: 'category',\n      label: 'Guides',\n      items: ['lazy-loaded-query'],\n    },\n    {\n      type: 'category',\n      label: 'API Reference',\n      items: ['page-api', 'app-api'],\n    },\n  ],\n};\n"
  },
  {
    "path": "website/src/css/custom.css",
    "content": "/* stylelint-disable docusaurus/copyright-header */\n/**\n * Any CSS included here will be global. The classic template\n * bundles Infima by default. Infima is a CSS framework designed to\n * work well for content-centric websites.\n */\n\n/* You can override the default Infima variables here. */\n:root {\n  --ifm-color-primary: #0074b8;\n  --ifm-color-primary-dark: #0091e6;\n  --ifm-color-primary-darker: rgb(31, 165, 136);\n  --ifm-color-primary-darkest: rgb(26, 136, 112);\n  --ifm-color-primary-light: rgb(70, 203, 174);\n  --ifm-color-primary-lighter: rgb(102, 212, 189);\n  --ifm-color-primary-lightest: rgb(146, 224, 208);\n  --ifm-code-font-size: 95%;\n}\n\n.docusaurus-highlight-code-line {\n  background-color: rgb(72, 77, 91);\n  display: block;\n  margin: 0 calc(-1 * var(--ifm-pre-padding));\n  padding: 0 var(--ifm-pre-padding);\n}\n"
  },
  {
    "path": "website/src/pages/index.js",
    "content": "import React from 'react';\nimport clsx from 'clsx';\nimport Layout from '@theme/Layout';\nimport Link from '@docusaurus/Link';\nimport useDocusaurusContext from '@docusaurus/useDocusaurusContext';\nimport useBaseUrl from '@docusaurus/useBaseUrl';\nimport styles from './styles.module.css';\n\nconst features = [\n  {\n    title: 'Integrated with Next.js',\n    imageUrl: 'img/undraw_next_js_8g5m.svg',\n    description: (\n      <>\n        <code>relay-nextjs</code> was designed with Next.js in mind from the\n        start. Perfectly integrated with Relay Hooks and no need to change pages\n        not using it. 100% backwards compatible.\n      </>\n    ),\n  },\n  {\n    title: 'Designed for Server Rendering',\n    imageUrl: 'img/undraw_Server_re_twwj.svg',\n    description: (\n      <>\n        Next.js speeds your page loads up using server-side rendering but\n        subsequent navigations require a server-round trip.{' '}\n        <code>relay-nextjs</code> keeps client-side navigation snappy with all\n        the performance of SSR.\n      </>\n    ),\n  },\n  {\n    title: 'Unlock React Suspense',\n    imageUrl: 'img/undraw_react_y7wq.svg',\n    description: (\n      <>\n        <code>relay-nextjs</code> uses React Suspense under the hood to\n        orchestrate loading states across the page. Don't worry — we only use\n        publicly documented APIs so you won't be stranded in two years.\n      </>\n    ),\n  },\n];\n\nfunction Feature({ imageUrl, title, description }) {\n  const imgUrl = useBaseUrl(imageUrl);\n  return (\n    <div className={clsx('col col--4', styles.feature)}>\n      {imgUrl && (\n        <div className=\"text--center\">\n          <img className={styles.featureImage} src={imgUrl} alt={title} />\n        </div>\n      )}\n      <h3>{title}</h3>\n      <p>{description}</p>\n    </div>\n  );\n}\n\nexport default function Home() {\n  const context = useDocusaurusContext();\n  const { siteConfig = {} } = context;\n  return (\n    <Layout title={`Relay for Next.js`}>\n      <header className={clsx('hero hero--primary', styles.heroBanner)}>\n        <div className=\"container\">\n          <h1 className=\"hero__title\">{siteConfig.title}</h1>\n          <p className=\"hero__subtitle\">{siteConfig.tagline}</p>\n          <div className={styles.buttons}>\n            <Link\n              className={clsx(\n                'button button--outline button--secondary button--lg',\n                styles.getStarted\n              )}\n              to={useBaseUrl('docs/')}\n            >\n              Get Started\n            </Link>\n          </div>\n        </div>\n      </header>\n      <main>\n        {features && features.length > 0 && (\n          <section className={styles.features}>\n            <div className=\"container\">\n              <div className=\"row\">\n                {features.map((props, idx) => (\n                  <Feature key={idx} {...props} />\n                ))}\n              </div>\n            </div>\n          </section>\n        )}\n      </main>\n    </Layout>\n  );\n}\n"
  },
  {
    "path": "website/src/pages/styles.module.css",
    "content": "/* stylelint-disable docusaurus/copyright-header */\n\n/**\n * CSS files with the .module.css suffix will be treated as CSS modules\n * and scoped locally.\n */\n\n.heroBanner {\n  padding: 4rem 0;\n  text-align: center;\n  position: relative;\n  overflow: hidden;\n}\n\n@media screen and (max-width: 966px) {\n  .heroBanner {\n    padding: 2rem;\n  }\n}\n\n.buttons {\n  display: flex;\n  align-items: center;\n  justify-content: center;\n}\n\n.features {\n  display: flex;\n  align-items: center;\n  padding: 2rem 0;\n  width: 100%;\n}\n\n.featureImage {\n  height: 200px;\n  width: 200px;\n}\n"
  },
  {
    "path": "website/static/.nojekyll",
    "content": ""
  }
]