[
  {
    "path": ".changeset/README.md",
    "content": "# Changesets\n\nHello and welcome! This folder has been automatically generated by `@changesets/cli`, a build tool that works\nwith multi-package repos, or single-package repos to help you version and publish your code. You can\nfind the full documentation for it [in our repository](https://github.com/changesets/changesets)\n\nWe have a quick list of common questions to get you started engaging with this project in\n[our documentation](https://github.com/changesets/changesets/blob/master/docs/common-questions.md)\n"
  },
  {
    "path": ".changeset/config.json",
    "content": "{\n  \"$schema\": \"https://unpkg.com/@changesets/config@0.3.0/schema.json\",\n  \"changelog\": \"../scripts/changesets/changelog.js\",\n  \"commit\": false,\n  \"access\": \"public\",\n  \"baseBranch\": \"main\",\n  \"updateInternalDependencies\": \"minor\",\n  \"snapshot\": {\n    \"prereleaseTemplate\": \"{tag}-{commit}\",\n    \"useCalculatedVersion\": true\n  },\n  \"___experimentalUnsafeOptions_WILL_CHANGE_IN_PATCH\": {\n    \"onlyUpdatePeerDependentsWhenOutOfRange\": true,\n    \"updateInternalDependents\": \"out-of-range\"\n  }\n}\n"
  },
  {
    "path": ".changeset/late-boats-listen.md",
    "content": "---\n'@urql/solid-start': minor\n---\n\nFix SSR runtime failures caused by importing SolidStart's `action` API at module load time by reading `action` from `Provider` context instead.\n"
  },
  {
    "path": ".changeset/shiny-pets-give.md",
    "content": "---\n'@urql/solid-start': patch\n---\n\nFix `createSubscription` to use `@urql/solid-start` context instead of re-exporting the Solid-only implementation from `@urql/solid`.\n"
  },
  {
    "path": ".editorconfig",
    "content": "# http://editorconfig.org\nroot = true\n\n[*]\ncharset = utf-8\nindent_size = 2\nend_of_line = lf\nindent_style = space\ninsert_final_newline = true\ntrim_trailing_whitespace = true\n\n[*.md]\nmax_line_length = 100\ntrim_trailing_whitespace = false\n\n[COMMIT_EDITMSG]\nmax_line_length = 0\n"
  },
  {
    "path": ".gitattributes",
    "content": "* text=auto\n"
  },
  {
    "path": ".github/CODEOWNERS",
    "content": "/.github/ @urql-graphql/core\n/.changeset/config.json @urql-graphql/core\n/scripts/actions/* @urql-graphql/core\n/scripts/prepare/* @urql-graphql/core\n/scripts/rollup/* @urql-graphql/core\n/scripts/changesets/* @urql-graphql/core\n"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/RFC.md",
    "content": "---\nname: 'RFC'\nabout: Propose an enhancement / feature and start a discussion\ntitle: 'RFC: Your Proposal'\nlabels: \"future \\U0001F52E\"\n---\n\n<!--\n  🚨 RFCs are for proposed changes (not bugs or questions)\n  Specifically they are whenever you'd like to see new features\n  being added to urql, or enable new use-cases.\n\n  Please open a Bug Report for issues/bugs, and use GitHub Discussions\n  or the Discord channel for questions instead.\n-->\n\n## Summary\n\n<!--\n  Describe in a couple of words *what* you're proposing.\n  If relevant, include *why* this should be addressed now.\n  The problem should be clearly stated and the solution\n  should be summarised.\n-->\n\n## Proposed Solution\n\n<!--\n  Explain the solution you're proposing in detail.\n  *How* will this change be implemented, and how does it work?\n-->\n\n## Requirements\n\n<!--\n  This section is *optional*.\n  But if your proposed solution has multiple ways\n  of being implemented, you don't want to state how\n  it may be implemented, or you don't know yet how\n  it will be implemented, then:\n  *List* what the implementation needs to achieve to fulfil this RFC;\n-->\n"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/bug_report.yaml",
    "content": "name: \"\\U0001F41E Bug report\"\ndescription: Report an issue with urql\nlabels: []\nbody:\n  - type: markdown\n    attributes:\n      value: |\n        Thanks for taking the time to fill out this bug report!\n  - type: markdown\n    attributes:\n      value: |\n        Thanks for taking the time to fill out this bug report!\n  - type: textarea\n    id: bug-description\n    attributes:\n      label: Describe the bug\n      description: Please describe your bug clearly and concisely.\n      placeholder: Bug description\n    validations:\n      required: true\n  - type: input\n    id: reproduction\n    attributes:\n      label: Reproduction\n      description: Please provide a link to a reproduction. Templates can be found in the [examples folder](https://github.com/urql-graphql/urql/tree/main/examples). A [minimal reproduction](https://stackoverflow.com/help/minimal-reproducible-example) is required. If a report is vague (e.g. just a generic error message) and if no reproduction is provided the issue will be auto-closed.\n      placeholder: Reproduction\n    validations:\n      required: true\n  - type: textarea\n    id: urql-version\n    attributes:\n      label: Urql version\n      description: The versions of the relevant urql packages you are using\n      placeholder: urql v2.0.0\n    validations:\n      required: true\n  - type: checkboxes\n    id: checkboxes\n    attributes:\n      label: Validations\n      description: Before submitting the issue, please make sure you do the following\n      options:\n        - label: I can confirm that this is a bug report, and not a feature request, RFC, question, or discussion, for which [GitHub Discussions](https://github.com/urql-graphql/urql/discussions) should be used\n          required: true\n        - label: Read the [docs](https://formidable.com/open-source/urql/docs/).\n          required: true\n        - label: Follow our [Code of Conduct](https://github.com/urql-graphql/urql/blob/main/CODE_OF_CONDUCT.md)\n          required: true\n"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/config.yml",
    "content": "blank_issues_enabled: true\ncontact_links:\n  - name: Ask a question\n    url: https://github.com/urql-graphql/urql/discussions\n    about: Ask questions and discuss with other community members\n  - name: Join the Discord\n    url: https://urql.dev/discord\n    about: Chat with maintainers and other community members\n"
  },
  {
    "path": ".github/PULL_REQUEST_TEMPLATE.md",
    "content": "<!--\n  Thanks for opening a pull request! We appreciate your dedication and help!\n  Before submitting your pull request, please make sure to read our CONTRIBUTING guide.\n\n  The best contribution is always a PR, but please make sure to open an issue or discuss\n  your changes first, if you’re looking to submit a larger PR.\n\n  If this PR is already related to an issue, please reference it like so:\n  Resolves #123\n-->\n\n## Summary\n\n<!-- What's the motivation of this change? What does it solve? -->\n\n## Set of changes\n\n<!--\n  Roughly list the changes you've made and which packages are affected.\n  Leave some notes on what may be noteworthy files you've changed.\n  And lastly, please let us know if you think this is a breaking change.\n-->\n"
  },
  {
    "path": ".github/actions/discord-message/action.mjs",
    "content": "import * as core from '@actions/core';\nimport * as github from '@actions/github';\n\nconst GITHUB_TOKEN = process.env.GITHUB_TOKEN;\nconst WEBHOOK_URL = process.env.DISCORD_WEBHOOK_URL;\n\nconst octokit = github.getOctokit(GITHUB_TOKEN);\n\nconst formatBody = input => {\n  const titleRe = /(?:^|\\n)#+[^\\n]+/g;\n  const updatedDepsRe = /\\n-\\s*Updated dependencies[\\s\\S]+\\n(\\n\\s+-[\\s\\S]+)*/gi;\n  const markdownLinkRe = /\\[([^\\]]+)\\]\\(([^\\)]+)\\)/g;\n  const creditRe = new RegExp(\n    `Submitted by (?:undefined|${markdownLinkRe.source})`,\n    'ig'\n  );\n  const repeatedNewlineRe = /(?:\\n[ ]*)*(\\n[ ]*)/g;\n  return input\n    .replace(titleRe, '')\n    .replace(updatedDepsRe, '')\n    .replace(creditRe, (_match, text, url) => {\n      if (!text || /@kitten|@JoviDeCroock/i.test(text)) return '';\n      return `Submitted by [${text}](${url})`;\n    })\n    .replace(markdownLinkRe, (_match, text, url) => `[${text}](<${url}>)`)\n    .replace(repeatedNewlineRe, (_match, text) => (text ? ` ${text}` : '\\n'))\n    .trim();\n};\n\nasync function getReleaseBody(name, version) {\n  const tag = `${name}@${version}`;\n  const [owner, repo] = process.env.GITHUB_REPOSITORY.split('/');\n  const result = await octokit.rest.repos.getReleaseByTag({ owner, repo, tag });\n\n  const release = result.status === 200 ? result.data : undefined;\n  if (!release || !release.body) return;\n\n  const title = `:package: [${tag}](<${release.html_url}>)`;\n  const body = formatBody(release.body);\n  if (!body) return;\n\n  return `${title}\\n${body}`;\n}\n\nasync function main() {\n  const inputPackages = core.getInput('publishedPackages');\n  let packages;\n\n  try {\n    packages = JSON.parse(inputPackages);\n  } catch (e) {\n    console.error('invalid JSON in publishedPackages input.');\n    return;\n  }\n\n  // Get releases\n  const releasePromises = packages.map(entry => {\n    return getReleaseBody(entry.name, entry.version);\n  });\n\n  const content = (await Promise.allSettled(releasePromises))\n    .map(x => x.status === 'fulfilled' && x.value)\n    .filter(Boolean)\n    .join('\\n\\n');\n\n  // Send message through a discord webhook or bot\n  const response = await fetch(WEBHOOK_URL, {\n    method: 'POST',\n    headers: {\n      'Content-Type': 'application/json',\n    },\n    body: JSON.stringify({ content }),\n  });\n\n  if (!response.ok) {\n    console.error(\n      'Something went wrong while sending the discord webhook.',\n      response.status\n    );\n    console.error(await response.text());\n  }\n}\n\nmain().then().catch(console.error);\n"
  },
  {
    "path": ".github/actions/discord-message/action.yml",
    "content": "name: 'Send a discord message'\ndescription: 'Send a discord message as a result of an urql publish.'\ninputs:\n  publishedPackages:\n    description: >\n      A JSON array to present the published packages. The format is `[{\"name\": \"@xx/xx\", \"version\": \"1.2.0\"}, {\"name\": \"@xx/xy\", \"version\": \"0.8.9\"}]`\nruns:\n  using: 'node20'\n  main: 'action.mjs'\n"
  },
  {
    "path": ".github/actions/pnpm-run/action.mjs",
    "content": "import { execa } from 'execa';\n\nconst run = execa('pnpm', ['run', process.env.INPUT_COMMAND], {\n  cwd: process.cwd(),\n});\n\nrun.stdout.pipe(process.stdout);\nrun.stderr.pipe(process.stderr);\n\nrun\n  .then(result => process.exit(result.exitCode))\n  .catch(error => process.exit(error.exitCode || -1));\n"
  },
  {
    "path": ".github/actions/pnpm-run/action.yml",
    "content": "name: 'Run a pnpm command'\ndescription: 'Locally run a forked pnpm command as an action.'\ninputs:\n  command:\n    description: 'Command'\n    default: 'help'\nruns:\n  using: 'node20'\n  main: 'action.mjs'\n"
  },
  {
    "path": ".github/workflows/ci.yml",
    "content": "name: CI\n\non:\n  pull_request:\n  pull_request_review:\n    types: [submitted, edited]\n    branches: changeset-release/main\n\njobs:\n  check:\n    name: Checks\n    runs-on: ubuntu-latest\n    timeout-minutes: 10\n    steps:\n      - name: Checkout Repo\n        uses: actions/checkout@v4\n        with:\n          fetch-depth: 0\n\n      - name: Setup Node\n        uses: actions/setup-node@v4\n        with:\n          node-version: 18\n\n      - name: Setup pnpm\n        uses: pnpm/action-setup@v3\n        with:\n          version: 9\n          run_install: false\n\n      - name: Get pnpm store directory\n        id: pnpm-store\n        run: echo \"pnpm_cache_dir=$(pnpm store path)\" >> $GITHUB_OUTPUT\n\n      - name: Use pnpm store\n        uses: actions/cache@v4\n        id: pnpm-cache\n        with:\n          path: |\n            ~/.cache/Cypress\n            ${{ steps.pnpm-store.outputs.pnpm_cache_dir }}\n          key: ${{ runner.os }}-pnpm-${{ hashFiles('**/pnpm-lock.yaml') }}\n          restore-keys: |\n            ${{ runner.os }}-pnpm-\n\n      - name: Install Dependencies\n        run: pnpm install --frozen-lockfile --prefer-offline\n\n      - name: TypeScript\n        run: pnpm run check\n\n      - name: Linting\n        run: pnpm run lint\n\n      - name: Unit Tests\n        run: pnpm run test\n\n      - name: Check for slow types\n        run: pnpm jsr:dryrun\n\n  react-e2e:\n    name: React E2E\n    runs-on: ubuntu-latest\n    timeout-minutes: 10\n    steps:\n      - name: Checkout Repo\n        uses: actions/checkout@v4\n        with:\n          fetch-depth: 0\n\n      - name: Setup Node\n        uses: actions/setup-node@v4\n        with:\n          node-version: 18\n\n      - name: Setup pnpm\n        uses: pnpm/action-setup@v3\n        with:\n          version: 9\n          run_install: false\n\n      - name: Get pnpm store directory\n        id: pnpm-store\n        run: echo \"pnpm_cache_dir=$(pnpm store path)\" >> $GITHUB_OUTPUT\n\n      - name: Use pnpm store\n        uses: actions/cache@v4\n        id: pnpm-cache\n        with:\n          path: |\n            ~/.cache/Cypress\n            ${{ steps.pnpm-store.outputs.pnpm_cache_dir }}\n          key: ${{ runner.os }}-pnpm-${{ hashFiles('**/pnpm-lock.yaml') }}\n          restore-keys: |\n            ${{ runner.os }}-pnpm-\n\n      - name: Install Dependencies\n        run: pnpm install --frozen-lockfile --prefer-offline\n\n      - name: Build\n        run: pnpm -F @urql/core build && pnpm -F urql build\n\n      - name: e2e tests 🧪\n        uses: cypress-io/github-action@v6\n        with:\n          install: false\n          command: pnpm cypress run --component\n          working-directory: packages/react-urql\n\n  graphcache-e2e:\n    name: Graphcache E2E\n    runs-on: ubuntu-latest\n    timeout-minutes: 10\n    steps:\n      - name: Checkout Repo\n        uses: actions/checkout@v4\n        with:\n          fetch-depth: 0\n\n      - name: Setup Node\n        uses: actions/setup-node@v4\n        with:\n          node-version: 18\n\n      - name: Setup pnpm\n        uses: pnpm/action-setup@v3\n        with:\n          version: 9\n          run_install: false\n\n      - name: Get pnpm store directory\n        id: pnpm-store\n        run: echo \"pnpm_cache_dir=$(pnpm store path)\" >> $GITHUB_OUTPUT\n\n      - name: Use pnpm store\n        uses: actions/cache@v4\n        id: pnpm-cache\n        with:\n          path: |\n            ~/.cache/Cypress\n            ${{ steps.pnpm-store.outputs.pnpm_cache_dir }}\n          key: ${{ runner.os }}-pnpm-${{ hashFiles('**/pnpm-lock.yaml') }}\n          restore-keys: |\n            ${{ runner.os }}-pnpm-\n\n      - name: Install Dependencies\n        run: pnpm install --frozen-lockfile --prefer-offline\n\n      - name: Build\n        run: pnpm -F \"@urql/core\" -F urql -F \"@urql/exchange-execute\" build\n\n      - name: e2e tests 🧪\n        uses: cypress-io/github-action@v6\n        with:\n          install: false\n          command: pnpm cypress run --component\n          working-directory: exchanges/graphcache\n\n  build:\n    name: Build\n    runs-on: ubuntu-latest\n    timeout-minutes: 10\n    strategy:\n      matrix:\n        node: [0, 1, 2]\n    env:\n      NODE_TOTAL: 3\n      NODE_INDEX: ${{matrix.node}}\n    steps:\n      - name: Checkout Repo\n        uses: actions/checkout@v4\n        with:\n          fetch-depth: 0\n\n      - name: Setup Node\n        uses: actions/setup-node@v4\n        with:\n          node-version: 18\n\n      - name: Setup pnpm\n        uses: pnpm/action-setup@v3\n        with:\n          version: 9\n          run_install: false\n\n      - name: Get pnpm store directory\n        id: pnpm-store\n        run: echo \"pnpm_cache_dir=$(pnpm store path)\" >> $GITHUB_OUTPUT\n\n      - name: Use pnpm store\n        uses: actions/cache@v4\n        id: pnpm-cache\n        with:\n          path: |\n            ~/.cache/Cypress\n            ${{ steps.pnpm-store.outputs.pnpm_cache_dir }}\n          key: ${{ runner.os }}-pnpm-${{ hashFiles('**/pnpm-lock.yaml') }}\n          restore-keys: |\n            ${{ runner.os }}-pnpm-\n\n      - name: Install Dependencies\n        run: pnpm install --frozen-lockfile --prefer-offline\n\n      - name: Build\n        run: pnpm build\n\n      - name: Pack\n        uses: ./.github/actions/pnpm-run\n        with:\n          command: pack\n"
  },
  {
    "path": ".github/workflows/mirror.yml",
    "content": "# Mirrors to https://tangled.sh/@kitten.sh (knot.kitten.sh)\nname: Mirror (Git Backup)\non:\n  push:\n    branches:\n      - main\njobs:\n  mirror:\n    runs-on: ubuntu-latest\n    steps:\n      - name: Checkout repository\n        uses: actions/checkout@v4\n        with:\n          fetch-depth: 0\n          fetch-tags: true\n      - name: Mirror\n        env:\n          MIRROR_SSH_KEY: ${{ secrets.MIRROR_SSH_KEY }}\n          GIT_SSH_COMMAND: 'ssh -o StrictHostKeyChecking=yes'\n        run: |\n          mkdir -p ~/.ssh\n          echo \"$MIRROR_SSH_KEY\" > ~/.ssh/id_rsa\n          chmod 600 ~/.ssh/id_rsa\n          ssh-keyscan -H knot.kitten.sh >> ~/.ssh/known_hosts\n          git remote add mirror \"git@knot.kitten.sh:kitten.sh/${GITHUB_REPOSITORY#*/}\"\n          git push --mirror mirror\n"
  },
  {
    "path": ".github/workflows/release.yml",
    "content": "name: Release\non:\n  push:\n    branches:\n      - main\n\njobs:\n  release:\n    name: Release\n    runs-on: ubuntu-24.04\n    timeout-minutes: 20\n    permissions:\n      contents: write\n      id-token: write\n      issues: write\n      repository-projects: write\n      deployments: write\n      packages: write\n      pull-requests: write\n    steps:\n      - name: Checkout Repo\n        uses: actions/checkout@v4\n        with:\n          fetch-depth: 0\n\n      - name: Setup Node\n        uses: actions/setup-node@v4\n        with:\n          node-version: 20\n          registry-url: \"https://registry.npmjs.org\"\n\n      - name: Update npm\n        run: npm install -g npm@latest\n\n      - name: Setup pnpm\n        uses: pnpm/action-setup@v3\n        with:\n          version: 9\n          run_install: false\n\n      - name: Get pnpm store directory\n        id: pnpm-store\n        run: echo \"pnpm_cache_dir=$(pnpm store path)\" >> $GITHUB_OUTPUT\n\n      - name: Use pnpm store\n        uses: actions/cache@v4\n        id: pnpm-cache\n        with:\n          path: |\n            ~/.cache/Cypress\n            ${{ steps.pnpm-store.outputs.pnpm_cache_dir }}\n          key: ${{ runner.os }}-pnpm-${{ hashFiles('**/pnpm-lock.yaml') }}\n          restore-keys: |\n            ${{ runner.os }}-pnpm-\n\n      - name: Install Dependencies\n        run: pnpm install\n\n      - name: PR or Publish\n        id: changesets\n        uses: changesets/action@v1.5.3\n        with:\n          version: pnpm changeset:version\n          publish: pnpm changeset:publish\n        env:\n          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}\n\n      - name: Notify discord\n        id: discord-msg\n        if: steps.changesets.outputs.published == 'true'\n        uses: ./.github/actions/discord-message\n        with:\n          publishedPackages: ${{ steps.changesets.outputs.publishedPackages }}\n        env:\n          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}\n          DISCORD_WEBHOOK_URL: ${{ secrets.DISCORD_WEBHOOK_URL }}\n\n      - name: Publish Prerelease\n        if: steps.changesets.outputs.published != 'true'\n        env:\n          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}\n        run: |\n          git reset --hard origin/main\n          pnpm changeset version --no-git-tag --snapshot canary\n          pnpm changeset publish --no-git-tag --snapshot canary --tag canary\n"
  },
  {
    "path": ".gitignore",
    "content": "/.idea\n/.vscode\n**/node_modules\n*.log\n.rts2_cache*\n.husky\ndist/\nbuild/\ncoverage/\npackage-lock.json\n.DS_Store\n.next\n\npackages/*/LICENSE\nexchanges/*/LICENSE\n\n# TODO: Figure out how to remove these:\ntmp/\ndist/\nexamples/yarn.lock\nexamples/pnpm-lock.yaml\nexamples/package-lock.json\nexamples/*/public\nexamples/*/yarn.lock\nexamples/*/pnpm-lock.yaml\nexamples/*/package-lock.json\nexamples/*/ios/\nexamples/*/android/\nexamples/*/.watchmanconfig\nexamples/*/metro.config.js\nexamples/*/babel.config.js\n"
  },
  {
    "path": "CODE_OF_CONDUCT.md",
    "content": "# Contributor Covenant Code of Conduct\n\n## Our Pledge\n\nIn the interest of fostering an open and welcoming environment, we as\ncontributors and maintainers pledge to making participation in our project and\nour community a harassment-free experience for everyone, regardless of age, body\nsize, disability, ethnicity, sex characteristics, gender identity and expression,\nlevel of experience, education, socio-economic status, nationality, personal\nappearance, race, religion, or sexual identity and orientation.\n\n## Our Standards\n\nExamples of behavior that contributes to creating a positive environment\ninclude:\n\n- Using welcoming and inclusive language\n- Being respectful of differing viewpoints and experiences\n- Gracefully accepting constructive criticism\n- Focusing on what is best for the community\n- Showing empathy towards other community members\n\nExamples of unacceptable behavior by participants include:\n\n- The use of sexualized language or imagery and unwelcome sexual attention or\n  advances\n- Trolling, insulting/derogatory comments, and personal or political attacks\n- Public or private harassment\n- Publishing others' private information, such as a physical or electronic\n  address, without explicit permission\n- Other conduct which could reasonably be considered inappropriate in a\n  professional setting\n\n## Our Responsibilities\n\nProject maintainers are responsible for clarifying the standards of acceptable\nbehavior and are expected to take appropriate and fair corrective action in\nresponse to any instances of unacceptable behavior.\n\nProject maintainers have the right and responsibility to remove, edit, or\nreject comments, commits, code, wiki edits, issues, and other contributions\nthat are not aligned to this Code of Conduct, or to ban temporarily or\npermanently any contributor for other behaviors that they deem inappropriate,\nthreatening, offensive, or harmful.\n\n## Scope\n\nThis Code of Conduct applies both within project spaces and in public spaces\nwhen an individual is representing the project or its community. Examples of\nrepresenting a project or community include using an official project e-mail\naddress, posting via an official social media account, or acting as an appointed\nrepresentative at an online or offline event. Representation of a project may be\nfurther defined and clarified by project maintainers.\n\n## Enforcement\n\nInstances of abusive, harassing, or otherwise unacceptable behavior may be\nreported by contacting the project team:\n\n- phil@0no.co\n- grant.sander@formidable.com\n- jovi@preact.dev\n\nAll complaints will be reviewed and investigated and will result in a response that\nis deemed necessary and appropriate to the circumstances. The project team is\nobligated to maintain confidentiality with regard to the reporter of an incident.\nFurther details of specific enforcement policies may be posted separately.\n\nProject maintainers who do not follow or enforce the Code of Conduct in good\nfaith may face temporary or permanent repercussions as determined by other\nmembers of the project's leadership.\n\n## Attribution\n\nThis Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4,\navailable at https://www.contributor-covenant.org/version/1/4/code-of-conduct.html\n\n[homepage]: https://www.contributor-covenant.org\n\nFor answers to common questions about this code of conduct, see\nhttps://www.contributor-covenant.org/faq\n"
  },
  {
    "path": "CONTRIBUTING.md",
    "content": "# Development\n\nThanks for contributing! We want to ensure that `urql` evolves and fulfills\nits idea of extensibility and flexibility by seeing continuous improvements\nand enhancements, no matter how small or big they might be.\n\nIf you're about to add a new exchange, please consider publishing it as\na separate package.\n\n## How to contribute?\n\nWe follow fairly standard but lenient rules around pull requests and issues.\nPlease pick a title that describes your change briefly, optionally in the imperative\nmood if possible.\n\nIf you have an idea for a feature or want to fix a bug, consider opening an issue\nfirst. We're also happy to discuss and help you open a PR and get your changes\nin!\n\n- If you have a question, try [creating a GitHub Discussions thread.](https://github.com/urql-graphql/urql/discussions/new)\n- If you think you've found a bug, [open a new issue.](https://github.com/urql-graphql/urql/issues/new/choose)\n- or, if you found a bug you'd like to fix, [open a PR.](https://github.com/urql-graphql/urql/compare)\n- If you'd like to propose a change [open an RFC issue.](https://github.com/urql-graphql/urql/issues/new?labels=future+%F0%9F%94%AE&template=RFC.md&title=RFC%3A+Your+Proposal) You can read more about the RFC process [below](#how-do-i-propose-changes).\n\n### What are the issue conventions?\n\nThere are **no strict conventions**, but we do have two templates in place that will fit most\nissues, since questions and other discussion start on GitHub Discussions. The bug template is fairly\nstandard and the rule of thumb is to try to explain **what you expected** and **what you got\ninstead.** Following this makes it very clear whether it's a known behavior, an unexpected issue,\nor an undocumented quirk.\n\nWe do ask that issues _aren’t_ created for questions, or where a bug is likely to be either caused\nby misusage or misconfiguration. In short, if you can’t provide a reproduction of the issue, then\nit may be the case that you’ve got a question instead.\n\nIf you need a template for creating a reproduction, all of our examples can be opened in isolated\nsandboxes or modified as you see fit: https://github.com/urql-graphql/urql/tree/main/examples\n\n### How do I propose changes?\n\nWe follow an **RFC proposal process**. This allows anyone to propose a new feature or a change, and\nallows us to communicate our current planned features or changes, so any technical discussion,\nprogress, or upcoming changes are always **documented transparently.** You can [find the RFC\ntemplate](https://github.com/urql-graphql/urql/issues/new/choose) in our issue creator.\n\nAll RFCs are added to the [RFC Lifecycle board.](https://github.com/urql-graphql/urql/projects/3)\nThis board tracks where an RFC stands and who's working on it until it's completed. Bugs and PRs may\nend up on there too if no corresponding RFC exists or was necessary. RFCs are typically first added\nto \"In Discussion\" until we believe they're ready to be worked on. This step may either be short,\nskipped, or rather long, if no plan is in place for a change yet. So if you see a way to help,\nplease leave some suggestions.\n\n### What are the PR conventions?\n\nThis also comes with **no strict conventions**. We only ask you to follow the PR template we have\nin place more strictly here than the templates for issues, since it asks you to list a summary\n(maybe even with a short explanation) and a list of technical changes.\n\nIf you're **resolving** an issue please don't forget to add `Resolve #123` to the description so that\nit's automatically linked, so that there's no ambiguity and which issue is being addressed (if any)\n\nYou'll find that a comment by the \"Changeset\" bot may pop up. If you don't know what a **changeset**\nis and why it's asking you to document your changes, read on at [\"How do I document a change for the\nchangelog\"](#how-do-i-document-a-change-for-the-changelog)\n\nWe also typically **name** our PRs with a slightly descriptive title, e.g. `(shortcode) - Title`,\nwhere shortcode is either the name of a package, e.g. `(core)` and the title is an imperative mood\ndescription, e.g. \"Update X\" or \"Refactor Y.\"\n\n## How do I set up the project?\n\nLuckily it's not hard to get started. You can install dependencies\n[using `pnpm`](https://pnpm.io/installation#using-corepack).\nPlease don't use `npm` or `yarn` to respect the lockfile.\n\n```sh\npnpm install\n```\n\nThere are multiple commands you can run in the root folder to test your changes:\n\n```sh\n# TypeScript checks:\npnpm run check\n\n# Linting (prettier & eslint):\npnpm run lint\n\n# Unit Tests (for all packages):\npnpm run test\n\n# Builds (for all packages):\npnpm run build\n```\n\nYou can find the main packages in `packages/*` and the addon exchanges in `exchanges/*`.\nEach package also has its own scripts that are common and shared between all packages.\n\n```sh\n# Unit Tests for the current package:\npnpm run test\n\n# Linting (prettier & eslint):\npnpm run lint\n\n# Build the current package:\npnpm run build\n\n# TypeScript checks for the current package:\npnpm run check\n```\n\nWhile you can run `build` globally in the interest of time it's advisable to only run it\non the packages you're working on. Note that TypeScript checks don't require any packages\nto be built.\n\n## How do I test my changes?\n\nIt's always good practice to run the tests when making changes. If you're unsure which packages\nmay be affected by your new tests or changes you may run `pnpm test` in the root of\nthe repository.\n\nIf your editor is not set up with type checks you may also want to run `pnpm run check` on your\nchanges.\n\nAdditionally you can head to any example in the `examples/` folder\nand run them. There you'll also need to install their dependencies as they're isolated projects,\nwithout a lockfile and without linking to packages in the monorepos.\nAll examples are started using the `package.json`'s `start` script.\n\n## How do I lint my code?\n\nWe ensure consistency in `urql`'s codebase using `eslint` and `prettier`.\nThey are run on a `precommit` hook, so if something's off they'll try\nto automatically fix up your code, or display an error.\n\nIf you have them set up in your editor, even better!\n\n## How do I document a change for the changelog?\n\nThis project uses [changesets](https://github.com/atlassian/changesets). This means that for\nevery PR there must be documentation for what has been changed and which package is affected.\n\nYou can document a change by running `changeset`, which will ask you which packages\nhave changed and whether the change is major/minor/patch. It will then ask you to write\na change entry as markdown.\n\n```sh\n# In the root of the urql repository call:\npnpm changeset\n```\n\nThis will create a new \"changeset file\" in the `.changeset` folder, which you should commit and\npush, so that it's added to your PR.\nThis will eventually end up in the package's `CHANGELOG.md` file when we do a release.\n\nYou won't need to add a changeset if you're simply making \"non-visible\" changes to the docs or other\nfiles that aren't published to the npm registry.\n\n[Read more about adding a `changeset` here.](https://github.com/atlassian/changesets/blob/master/docs/adding-a-changeset.md#i-am-in-a-multi-package-repository-a-mono-repo)\n\n## How do I release new versions of our packages?\n\nHold up, that's **automated**! Since we use `changeset` to document our changes, which determines what\ngoes into the changelog and what kind of version bump a change should make, you can also use the\ntool to check what's currently posed to change after a release batch using: `pnpm changeset status`.\n\nWe have a [GitHub Actions workflow](./.github/workflow/release.yml) which is triggered whenever new\nchanges are merged. It will always open a **\"Version Packages\" PR** which is kept up-to-date. This PR\ndocuments all changes that are made and will show in its description what all new changelogs are\ngoing to contain for their new entries.\n\nOnce a \"Version Packages\" PR is approved by a contributor and merged, the action will automatically\ntake care of creating the release, publishing all updated packages to the npm registry, and creating\nappropriate tags on GitHub too.\n\nThis process is automated, but the changelog should be checked for errors.\n\nAs to **when** to merge the automated PR and publish? Maybe not after every change. Typically there\nare two release batches: hotfixes and release batches. We expect that a hotfix for a single package\nshould go out as quickly as possible if it negatively affects users. For **release batches**\nhowever, it's common to assume that if one change is made to a package that more will follow in the\nsame week. So waiting for **a day or two** when other changes are expected will make sense to keep the\nfatigue as low as possible for downstream maintainers.\n\n## How do I upgrade all dependencies?\n\nIt may be a good idea to keep all dependencies on the `urql` repository **up-to-date** every now and\nthen. Typically we do this by running `pnpm update --interactive --latest` and checking one-by-one\nwhich dependencies will need to be bumped. In case of any security issues it may make sense to\njust run `pnpm update [package]`.\n\nWhile this is rare with `pnpm`, upgrading some transitive dependencies may accidentally duplicate\nthem if two packages depend on different compatible version ranges. This can be fixed by running:\n\n```sh\nnpx pnpm-deduplicate\npnpm install\n```\n\nIt's common to then **create a PR** (with a changeset documenting the packages that need to reflect\nnew changes if any `dependencies` have changed) with the name of\n\"(chore) - Upgrade direct and transitive dependencies\" or something similar.\n\n## How do I add a new package?\n\nFirst of all we need to know **where** to put the package.\n\n- Exchanges should be added to `exchanges/` and the folder should be the plain\n  name of the exchange. Since the `package.json:name` is following the convention\n  of `@urql/exchange-*` the folder should just be without this conventional prefix.\n- All other packages should be added to `packages/`. Typically all packages should\n  be named `@urql/*` and their folders should be named exactly this without the\n  prefix or `*-urql`. Optionally if the package will be named `*-urql` then the folder\n  can take on the same name.\n\nWhen adding a new package, start by **copying** a `package.json` file from another project.\nYou may want to alter the following fields first:\n\n- `name`\n- `version` (either start at `0.1.0` or `1.0.0`)\n- `description`\n- `repository.directory`\n- `keywords`\n\nMake sure to also alter the `devDependencies`, `peerDependencies`, and `dependencies` to match\nthe new package's needs.\n\n**The `main` and `module` fields follow a convention:**\nAll output bundles will always be output in the `./dist` folder by `rollup`, which is set up in\nthe `build` script. Their filenames are a \"kebab case\" (dash-cased) version of the `name` field with\nan appropriate extension (`.esm.js` for `module` and `.cjs.js` for `main`).\n\nIf your entrypoint won't be at `src/index.ts` you may alter it. But the `types` field has to match\nthe same file relative to the `dist/types` folder, where `rollup` will output the TypeScript\ndeclaration files.\n\nWhen setting up your package make sure to create a `src/index.ts` file\n(or any other file which you've pointed `package.json:source` to). Also don't forget to\ncopy over the `tsconfig.json` from another package (You won't need to change it).\n\nThe `scripts.prepare` task is set up to check your new `package.json` file for correctness. So in\ncase you get anything wrong, you'll get a short error when running `pnpm` after setting your new\nproject up. Just in case! 😄\n\nAfterwards you can check whether everything is working correctly by running:\n\n```sh\npnpm install\npnpm run check\n```\n\nAt this point, **don't publish** the package or a prerelease yourself if you can avoid it. If you can't\nor have already, we'll need to get the **rights** fixed by adding the package to the `@urql` scope.\nTypically what we do is:\n\n```sh\nnpm access grant read-write urql:developers [package]\n```\n"
  },
  {
    "path": "LICENSE",
    "content": "MIT License\n\nCopyright (c) 2018–2020 Formidable,\nCopyright (c) urql GraphQL Team and other contributors\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": "<div align=\"center\">\n  <img alt=\"urql\" width=\"250\" src=\"packages/site/src/assets/sidebar-badge.svg\" />\n\n  <br />\n  <br />\n\n  <strong>\n    A highly customisable and versatile GraphQL client\n  </strong>\n\n  <br />\n  <br />\n  <a href=\"https://github.com/urql-graphql/urql/actions/workflows/ci.yml\">\n    <img alt=\"CI Status\" src=\"https://github.com/urql-graphql/urql/actions/workflows/ci.yml/badge.svg?branch=main\" />\n  </a>\n  <a href=\"https://www.npmjs.com/package/@urql/core\">\n    <img alt=\"Weekly downloads\" src=\"https://badgen.net/npm/dw/@urql/core?color=blue\" />\n  </a>\n  <a href=\"https://urql.dev/discord\">\n    <img alt=\"Discord\" src=\"https://img.shields.io/discord/1082378892523864074?color=7389D8&label&logo=discord&logoColor=ffffff\" />\n  </a>\n  <br />\n  <br />\n</div>\n\n## ✨ Features\n\n- 📦 **One package** to get a working GraphQL client in React, Preact, Vue, Solid and Svelte\n- ⚙️ Fully **customisable** behaviour [via \"exchanges\"](https://formidable.com/open-source/urql/docs/advanced/authoring-exchanges/)\n- 🗂 Logical but simple default behaviour and document caching\n- 🌱 Normalized caching via [`@urql/exchange-graphcache`](https://formidable.com/open-source/urql/docs/graphcache)\n- 🔬 Easy debugging with the [`urql` devtools browser extensions](https://formidable.com/open-source/urql/docs/advanced/debugging/)\n\n`urql` is a GraphQL client that exposes a set of helpers for several frameworks. It's built to be highly customisable and versatile so\nyou can take it from getting started with your first GraphQL project all the way to building complex apps and experimenting with GraphQL clients.\n\n**📃 For more information, [check out the docs](https://formidable.com/open-source/urql/docs/).**\n\n## 💙 [Sponsors](https://github.com/sponsors/urql-graphql)\n\n<table>\n  <tr>\n   <td align=\"center\"><a href=\"https://bigcommerce.com/\"><img src=\"https://avatars.githubusercontent.com/u/186342?s=200&v=4\" width=\"150\" alt=\"BigCommerce\"/><br />BigCommerce</a></td>\n   <td align=\"center\"><a href=\"https://wundergraph.com/\"><img src=\"https://avatars.githubusercontent.com/u/64281914?s=200&v=4\" width=\"150\" alt=\"WunderGraph\"/><br />WunderGraph</a></td>\n   <td align=\"center\"><a href=\"https://the-guild.dev/\"><img src=\"https://avatars.githubusercontent.com/u/42573040?s=200&v=4\" width=\"150\" alt=\"The Guild \"/><br />The Guild</a></td>\n  </tr>\n</table>\n<table>\n  <tr>\n   <td align=\"center\"><a href=\"https://beatgig.com/\"><img src=\"https://avatars.githubusercontent.com/u/51333382?s=200&v=4\" width=\"100\" alt=\"BeatGig\"/><br />BeatGig</a></td>\n  </tr>\n</table>\n\n## 🙌 Contributing\n\n**The urql project was founded by [Formidable](https://formidable.com/) and is actively developed\nby the urql GraphQL team.**\n\nIf you'd like to get involved, [check out our Contributor's guide.](https://github.com/urql-graphql/urql/blob/main/CONTRIBUTING.md)\n\n## 📦 [Releases](https://github.com/urql-graphql/urql/releases)\n\nAll new releases and updates are listed on GitHub with full changelogs. Each package in this\nrepository further contains an independent `CHANGELOG.md` file with the historical changelog, for\ninstance, [here’s `@urql/core`’s\nchangelog](https://github.com/urql-graphql/urql/blob/main/packages/core/CHANGELOG.md).\n\nIf you’re upgrading to v4, [check out our migration guide, posted as an\nissue.](https://github.com/urql-graphql/urql/issues/3114)\n\nNew releases are prepared using\n[changesets](https://github.com/urql-graphql/urql/blob/main/CONTRIBUTING.md#how-do-i-document-a-change-for-the-changelog),\nwhich are changelog entries added to each PR, and we have “Version Packages” PRs that once merged\nwill release new versions of `urql` packages. You can use `@canary` releases from `npm` if you’d\nlike to get a preview of the merged changes.\n\n## 📃 [Documentation](https://urql.dev/goto/docs)\n\nThe documentation contains everything you need to know about `urql`, and contains several sections in order of importance\nwhen you first get started:\n\n- **[Basics](https://formidable.com/open-source/urql/docs/basics/)** — contains the [\"Getting Started\" guide](https://formidable.com/open-source/urql/docs/#where-to-start) and all you need to know when first using `urql`.\n- **[Architecture](https://formidable.com/open-source/urql/docs/architecture/)** — explains how `urql` functions and is built.\n- **[Advanced](https://formidable.com/open-source/urql/docs/advanced/)** — covers more uncommon use-cases and things you don't immediately need when getting started.\n- **[Graphcache](https://formidable.com/open-source/urql/docs/graphcache/)** — documents [\"Normalized Caching\" support](https://formidable.com/open-source/urql/docs/graphcache/normalized-caching/) which enables more complex apps and use-cases.\n- **[API](https://formidable.com/open-source/urql/docs/api/)** — the API documentation for each individual package.\n\nFurthermore, all APIs and packages are self-documented using TSDocs. If you’re using a language\nserver for TypeScript, the documentation for each API should pop up in your editor when hovering\n`urql`’s code and APIs.\n\n_You can find the raw markdown files inside this repository's `docs` folder._\n\n<img width=\"100%\" src=\"docs/assets/urql-spoiler.png\" />\n"
  },
  {
    "path": "docs/README.md",
    "content": "---\ntitle: Overview\norder: 1\n---\n\n# Overview\n\n`urql` is a highly customizable and versatile GraphQL client with which you add on features like\nnormalized caching as you grow. It's built to be both easy to use for newcomers to\nGraphQL, and extensible, to grow to support dynamic single-app applications and highly\ncustomized GraphQL infrastructure. In short, `urql` prioritizes usability and adaptability.\n\nAs you're adopting GraphQL, `urql` becomes your primary data layer and can handle content-heavy\npages through [\"Document Caching\"](./basics/document-caching.md) as well as dynamic and data-heavy\napps through [\"Normalized Caching\"](./graphcache/normalized-caching.md).\n\n`urql` can be understood as a collection of connected parts and packages.\nWhen we only need to install a single package for our framework of choice. We're then able to\ndeclaratively send GraphQL requests to our API. All framework packages — like `urql` (for React),\n`@urql/preact`, `@urql/svelte`, `@urql/solid`/`@urql/solid-start` and `@urql/vue` — wrap the [core package,\n`@urql/core`](./basics/core.md), which we can imagine as the brain\nof `urql` with most of its logic. As we progress with implementing `urql` into our application,\nwe're later able to extend it by adding [\"addon packages\", which we call\n_Exchanges_](./advanced/authoring-exchanges.md)\n\nIf at this point you're still unsure of whether to use `urql`, [have a look at the **Comparison**\npage](./comparison.md) and check whether `urql` supports all features you're looking for.\n\n## Where to start\n\nWe have **Getting Started** guides for:\n\n- [**React/Preact**](./basics/react-preact.md) covers how to work with the bindings for React/Preact.\n- [**Vue**](./basics/vue.md) covers how to work with the bindings for Vue 3.\n- [**Svelte**](./basics/svelte.md) covers how to work with the bindings for Svelte.\n- [**Solid**](./basics/solid.md) covers how to work with the bindings for Solid.\n- [**SolidStart**](./basics/solid-start.md) covers how to work with the bindings for SolidStart.\n- [**Core Package**](./basics/core.md) covers the shared \"core APIs\" and how we can use them directly\n  in Node.js or imperatively.\n\nEach of these sections will walk you through the specific instructions for the framework bindings,\nincluding how to install and set them up, how to write queries, and how to send mutations.\n\n## Following the Documentation\n\nThis documentation is split into groups or sections that cover different levels of usage or areas of\ninterest.\n\n- **Basics** is the section where we'll want to start learning about `urql` as it contains \"Getting\n  Started\" guides for our framework of choice.\n- **Architecture** then explains more about how `urql` functions, what it's made up of, and covers\n  the main aspects of the `Client` and exchanges.\n- **Advanced** covers all more uncommon use-cases and contains guides that we won't need immediately\n  when we get started with `urql`.\n- **Graphcache** documents one of the most important addons to `urql`, which adds [\"Normalized\n  Caching\" support](./graphcache/normalized-caching.md) to the `Client` and enables more complex\n  use-cases, smarter caching, and more dynamic apps to function.\n- **Showcase** aims to list users of `urql`, third-party packages, and other helpful resources,\n  like tutorials and guides.\n- **API** contains a detailed documentation on each package's APIs. The documentation links to each\n  of these as appropriate, but if we're unsure of how to use a utility or package, we can go here\n  directly to look up how to use a specific API.\n\nWe hope you grow to love `urql`!\n"
  },
  {
    "path": "docs/advanced/README.md",
    "content": "---\ntitle: Advanced\norder: 4\n---\n\n# Advanced\n\nIn this chapter we'll dive into various topics of \"advanced\" `urql` usage. This is admittedly a\ncatch-all chapter of various use-cases that can only be covered after [the \"Architecture\"\nchapter.](../architecture.md)\n\n- [**Subscriptions**](./subscriptions.md) covers how to use `useSubscription` and how to set up GraphQL subscriptions with\n  `urql`.\n- [**Persistence & Uploads**](./persistence-and-uploads.md) teaches us how to set up Automatic\n  Persisted Queries and File Uploads using the two respective packages.\n- [**Server-side Rendering**](./server-side-rendering.md) guides us through how to set up server-side rendering and rehydration.\n- [**Debugging**](./debugging.md) shows us the [`urql`\n  devtools](https://github.com/urql-graphql/urql-devtools/) and how to add our own debug events\n  for its event view.\n- [**Retrying operations**](./retry-operations.md) shows the `retryExchange` which allows you to retry operations when they've failed.\n- [**Authentication**](./authentication.md) describes how to implement authentication using the `authExchange`\n- [**Testing**](./testing.md) covers how to test components that use `urql` particularly in React.\n- [**Authoring Exchanges**](./authoring-exchanges.md) describes how to implement exchanges from\n  scratch and how they work internally. This is a good basis to understanding how some\n  features in this section function.\n- [**Auto-populate Mutations**](./auto-populate-mutations.md) presents the `populateExchange` addon, which can make it easier to\n  update normalized data after mutations.\n"
  },
  {
    "path": "docs/advanced/authentication.md",
    "content": "---\ntitle: Authentication\norder: 6\n---\n\n# Authentication\n\nMost APIs include some type of authentication, usually in the form of an auth token that is sent with each request header.\n\nThe purpose of the [`authExchange`](../api/auth-exchange.md) is to provide a flexible API that facilitates the typical\nJWT-based authentication flow.\n\n> **Note:** [You can find a code example for `@urql/exchange-auth` in an example in the `urql` repository.](https://github.com/urql-graphql/urql/tree/main/examples/with-refresh-auth)\n\n## Typical Authentication Flow\n\n**Initial login** — the user opens the application and authenticates for the first time. They enter their credentials and receive an auth token.\nThe token is saved to storage that is persisted though sessions, e.g. `localStorage` on the web or `AsyncStorage` in React Native. The token is\nadded to each subsequent request in an auth header.\n\n**Resume** — the user opens the application after having authenticated in the past. In this case, we should already have the token in persisted\nstorage. We fetch the token from storage and add to each request, usually as an auth header.\n\n**Forced log out due to invalid token** — the user's session could become invalid for a variety reasons: their token expired, they requested to be\nsigned out of all devices, or their session was invalidated remotely. In this case, we would want to\nalso log them out in the application, so they\ncould have the opportunity to log in again. To do this, we want to clear any persisted storage, and redirect them to the application home or login page.\n\n**User initiated log out** — when the user chooses to log out of the application, we usually send a logout request to the API, then clear any tokens\nfrom persisted storage, and redirect them to the application home or login page.\n\n**Refresh (optional)** — this is not always implemented; if your API supports it, the\nuser will receive both an auth token, and a refresh token.\nThe auth token is usually valid for a shorter duration of time (e.g. 1 week) than the refresh token\n(e.g. 6 months), and the latter can be used to request a new\nauth token if the auth token has expired. The refresh logic is triggered either when the JWT is known to be invalid (e.g. by decoding it and inspecting the expiry date),\nor when an API request returns with an unauthorized response. For graphQL APIs, it is usually an error code, instead of a 401 HTTP response, but both can be supported.\nWhen the token has been successfully refreshed (this can be done as a mutation to the graphQL API or a request to a different API endpoint, depending on implementation),\nwe will save the new token in persisted storage, and retry the failed request with the new auth header. The user should be logged out and persisted storage cleared if\nthe refresh fails or if the re-executing the query with the new token fails with an auth error for the second time.\n\n## Installation & Setup\n\nFirst, install the `@urql/exchange-auth` alongside `urql`:\n\n```sh\nyarn add @urql/exchange-auth\n# or\nnpm install --save @urql/exchange-auth\n```\n\nYou'll then need to add the `authExchange`, that this package exposes to your `Client`. The `authExchange` is an asynchronous exchange, so it must be placed\nin front of all `fetchExchange`s but after all other synchronous exchanges, like the `cacheExchange`.\n\n```js\nimport { Client, cacheExchange, fetchExchange } from 'urql';\nimport { authExchange } from '@urql/exchange-auth';\n\nconst client = new Client({\n  url: 'http://localhost:3000/graphql',\n  exchanges: [\n    cacheExchange,\n    authExchange(async utils => {\n      return {\n        /* config... */\n      };\n    }),\n    fetchExchange,\n  ],\n});\n```\n\nYou pass an initialization function to the `authExchange`. This function is called by the exchange\nwhen it first initializes. It'll let you receive an object of utilities and you must return\na (promisified) object of configuration options.\n\nLet's discuss each of the [configuration options](../api/auth-exchange.md#options) and how to use them in turn.\n\n### Configuring the initializer function (initial load)\n\nThe initializer function must return a promise of a configuration object and hence also gives you an\nopportunity to fetch your authentication state from storage.\n\n```js\nasync function initializeAuthState() {\n  const token = localStorage.getItem('token');\n  const refreshToken = localStorage.getItem('refreshToken');\n  return { token, refreshToken };\n}\n\nauthExchange(async utils => {\n  let { token, refreshToken } = initializeAuthState();\n  return {\n    /* config... */\n  };\n});\n```\n\nThe first step here is to retrieve our tokens from a kind of storage, which may be asynchronous as\nwell, as illustrated by `initializeAuthState`.\n\nIn React Native, this is very similar, but because persisted storage in React Native is always\nasynchronous and promisified, we would await our tokens. This works because the\nfunction that `authExchange` is async, i.e. must return a `Promise`.\n\n```js\nasync function initializeAuthState() {\n  const token = await AsyncStorage.getItem(TOKEN_KEY);\n  const refreshToken = await AsyncStorage.getItem(REFRESH_KEY);\n  return { token, refreshToken };\n}\n\nauthExchange(async utils => {\n  let { token, refreshToken } = initializeAuthState();\n  return {\n    /* config... */\n  };\n});\n```\n\n### Configuring `addAuthToOperation`\n\nThe purpose of `addAuthToOperation` is to apply an auth state to each request. Here, we'll use the\ntokens we retrieved from storage and add them to our operations.\n\nIn this example, we're using a utility we're passed, `appendHeaders`. This utility is a simply\nshortcut to quickly add HTTP headers via `fetchOptions` to an `Operation`, however, we may as well\nbe editing the `Operation` context here using `makeOperation`.\n\n```js\nauthExchange(async utils => {\n  let token = await AsyncStorage.getItem(TOKEN_KEY);\n  let refreshToken = await AsyncStorage.getItem(REFRESH_KEY);\n\n  return {\n    addAuthToOperation(operation) {\n      if (!token) return operation;\n      return utils.appendHeaders(operation, {\n        Authorization: `Bearer ${token}`,\n      });\n    },\n    // ...\n  };\n});\n```\n\nFirst, we check that we have a non-null `token`. Then we apply it to the request using the\n`appendHeaders` utility as an `Authorization` header.\n\nWe could also be using `makeOperation` here to update the context in any other way, such as:\n\n```js\nimport { makeOperation } from '@urql/core';\n\nmakeOperation(operation.kind, operation, {\n  ...operation.context,\n  someAuthThing: token,\n});\n```\n\n### Configuring `didAuthError`\n\nThis function lets the `authExchange` know what is defined to be an API error for your API.\n`didAuthError` is called by `authExchange` when it receives an `error` on an `OperationResult`, which\nis of type [`CombinedError`](../api/core.md#combinederror).\n\nWe can for example check the error's `graphQLErrors` array in `CombinedError` to determine if an auth\nerror has occurred. While your API may implement this differently, an authentication error on an\nexecution result may look a little like this if your API uses `extensions.code` on errors:\n\n```js\n{\n  data: null,\n  errors: [\n    {\n      message: 'Unauthorized: Token has expired',\n      extensions: {\n        code: 'FORBIDDEN'\n      },\n    }\n  ]\n}\n```\n\nIf you're building a new API, using `extensions` on errors is the recommended approach to add\nmetadata to your errors. We'll be able to determine whether any of the GraphQL errors were due\nto an unauthorized error code, which would indicate an auth failure:\n\n```js\nauthExchange(async utils => {\n  // ...\n  return {\n    // ...\n    didAuthError(error, _operation) {\n      return error.graphQLErrors.some(e => e.extensions?.code === 'FORBIDDEN');\n    },\n  };\n});\n```\n\nFor some GraphQL APIs, the authentication error is only communicated via a 401 HTTP status as is\ncommon in RESTful APIs, which is suboptimal, but which we can still write a check for.\n\n```js\nauthExchange(async utils => {\n  // ...\n  return {\n    // ...\n    didAuthError(error, _operation) {\n      return error.response?.status === 401;\n    },\n  };\n});\n```\n\nIf `didAuthError` returns `true`, it will trigger the `authExchange` to trigger the logic for asking\nfor re-authentication via `refreshAuth`.\n\n### Configuring `refreshAuth` (triggered after an auth error has occurred)\n\nIf the API doesn't support any sort of token refresh, this is where we could simply log the user out.\n\n```js\nauthExchange(async utils => {\n  // ...\n  return {\n    // ...\n    async refreshAuth() {\n      logout();\n    },\n  };\n});\n```\n\nHere, `logout()` is a placeholder that is called when we got an error, so that we can redirect to a\nlogin page again and clear our tokens from local storage or otherwise.\n\nIf we had a way to refresh our token using a refresh token, we can attempt to get a new token for the\nuser first:\n\n```js\nauthExchange(async utils => {\n  let token = localStorage.getItem('token');\n  let refreshToken = localStorage.getItem('refreshToken');\n\n  return {\n    // ...\n    async refreshAuth() {\n      const result = await utils.mutate(REFRESH, { refreshToken });\n\n      if (result.data?.refreshLogin) {\n        // Update our local variables and write to our storage\n        token = result.data.refreshLogin.token;\n        refreshToken = result.data.refreshLogin.refreshToken;\n        localStorage.setItem('token', token);\n        localStorage.setItem('refreshToken', refreshToken);\n      } else {\n        // This is where auth has gone wrong and we need to clean up and redirect to a login page\n        localStorage.clear();\n        logout();\n      }\n    },\n  };\n});\n```\n\nHere we use the special `mutate` utility method provided by the `authExchange` to do the token\nrefresh. This is a useful method to use if your GraphQL API expects you to make a GraphQL mutation\nto update your authentication state. It will send the mutation and bypass all authentication and\nprior exchanges.\n\nIf your authentication is not handled via GraphQL but a REST endpoint, you can use the `fetch` API\nhere however instead of a mutation.\n\nAll other requests will be paused while `refreshAuth` runs, so we won't have to deal with multiple\nauthentication errors or refreshes at once.\n\n### Configuring `willAuthError`\n\n`willAuthError` is an optional parameter and is run _before_ a request is made.\n\nWe can use it to trigger an authentication error and let the `authExchange` run our `refreshAuth`\nfunction without the need to first let a request fail with an authentication error. For example, we\ncan use this to predict an authentication error, for instance, because of expired JWT tokens.\n\n```js\nauthExchange(async utils => {\n  // ...\n  return {\n    // ...\n    willAuthError(_operation) {\n      // Check whether `token` JWT is expired\n      return false;\n    },\n  };\n});\n```\n\nThis can be really useful when we know when our authentication state is invalid and want to prevent\neven sending any operation that we know will fail with an authentication error.\n\nHowever, we have to be careful on how we define this function, if some queries or login mutations\nare sent to our API without being logged in. In these cases, it's better to either detect the\nmutations we'd like to allow or return `false` when a token isn't set in storage yet.\n\nIf we'd like to detect a mutation that will never fail with an authentication error, we could for\ninstance write the following logic:\n\n```js\nauthExchange(async utils => {\n  // ...\n  return {\n    // ...\n    willAuthError(operation) {\n      if (\n        operation.kind === 'mutation' &&\n        // Here we find any mutation definition with the \"login\" field\n        operation.query.definitions.some(definition => {\n          return (\n            definition.kind === 'OperationDefinition' &&\n            definition.selectionSet.selections.some(node => {\n              // The field name is just an example, since signup may also be an exception\n              return node.kind === 'Field' && node.name.value === 'login';\n            })\n          );\n        })\n      ) {\n        return false;\n      } else if (false /* is JWT expired? */) {\n        return true;\n      } else {\n        return false;\n      }\n    },\n  };\n});\n```\n\nAlternatively, you may decide to let all operations through if your token isn't set in storage, i.e.\nif you have no prior authentication state.\n\n## Handling Logout by reacting to Errors\n\nWe can also handle authentication errors in a `mapExchange` instead of the `authExchange`.\nTo do this, we'll need to add the `mapExchange` to the exchanges array, _before_ the `authExchange`.\nThe order is very important here:\n\n```js\nimport { createClient, cacheExchange, fetchExchange, mapExchange } from 'urql';\nimport { authExchange } from '@urql/exchange-auth';\n\nconst client = createClient({\n  url: 'http://localhost:3000/graphql',\n  exchanges: [\n    cacheExchange,\n    mapExchange({\n      onError(error, _operation) {\n        const isAuthError = error.graphQLErrors.some(e => e.extensions?.code === 'FORBIDDEN');\n        if (isAuthError) {\n          logout();\n        }\n      },\n    }),\n    authExchange(async utils => {\n      return {\n        /* config */\n      };\n    }),\n    fetchExchange,\n  ],\n});\n```\n\nThe `mapExchange` will only receive an auth error when the auth exchange has already tried and failed\nto handle it. This means we have either failed to refresh the token, or there is no token refresh\nfunctionality. If we receive an auth error in the `mapExchange`'s `onError` function\n(as defined in the `didAuthError` configuration section above), then we can be confident that it is\nan authentication error that the `authExchange` isn't able to recover from, and the user should be\nlogged out.\n\n## Cache Invalidation on Logout\n\nIf we're dealing with multiple authentication states at the same time, e.g. logouts, we need to\nensure that the `Client` is reinitialized whenever the authentication state changes.\nHere's an example of how we may do this in React if necessary:\n\n```jsx\nimport { createClient, Provider } from 'urql';\n\nconst App = ({ isLoggedIn }: { isLoggedIn: boolean | null }) => {\n  const client = useMemo(() => {\n    if (isLoggedIn === null) {\n      return null;\n    }\n\n    return createClient({ /* config */ });\n  }, [isLoggedIn]);\n\n  if (!client) {\n    return null;\n  }\n\n  return {\n    <Provider value={client}>\n      {/* app content  */}\n    <Provider>\n  }\n}\n```\n\nWhen the application launches, the first thing we do is check whether the user has any authentication\ntokens in persisted storage. This will tell us whether to show the user the logged in or logged out view.\n\nThe `isLoggedIn` prop should always be updated based on authentication state change. For instance, we may set it to\n`true` after the user has authenticated and their tokens have been added to storage, and set it to\n`false` once the user has been logged out and their tokens have been cleared. It's important to clear\nor add tokens to a storage _before_ updating the prop in order for the auth exchange to work\ncorrectly.\n\nThis pattern of creating a new `Client` when changing authentication states is especially useful\nsince it will also recreate our client-side cache and invalidate all cached data.\n"
  },
  {
    "path": "docs/advanced/authoring-exchanges.md",
    "content": "---\ntitle: Authoring Exchanges\norder: 8\n---\n\n# Exchange Author Guide\n\nAs we've learned [on the \"Architecture\" page](../architecture.md) page, `urql`'s `Client` structures\nits data as an event hub. We have an input stream of operations, which are instructions for the\n`Client` to provide a result. These results then come from an output stream of operation results.\n\n_Exchanges_ are responsible for performing the important transform from the operations (input) stream\nto the results stream. Exchanges are handler functions that deal with these input and\noutput streams. They're one of `urql`'s key components, and are needed to implement vital pieces of\nlogic such as caching, fetching, deduplicating requests, and more. In other words, Exchanges are\nhandlers that fulfill our GraphQL requests and can change the stream of operations or results.\n\nIn this guide we'll learn more about how exchanges work and how we can write our own exchanges.\n\n## An Exchange Signature\n\nExchanges are akin to [middleware in\nRedux](https://redux.js.org/advanced/middleware) due to the way that they apply transforms.\n\n```ts\nimport { Client, Operation, OperationResult } from '@urql/core';\n\ntype ExchangeInput = { forward: ExchangeIO; client: Client };\ntype Exchange = (input: ExchangeInput) => ExchangeIO;\ntype ExchangeIO = (ops$: Source<Operation>) => Source<OperationResult>;\n```\n\nThe first parameter to an exchange is a `forward` function that refers to the next Exchange in the\nchain. The second second parameter is the `Client` being used. Exchanges always return an `ExchangeIO`\nfunction (this applies to the `forward` function as well), which accepts the source of\n[_Operations_](../api/core.md#operation) and returns a source of [_Operation\nResults_](../api/core.md#operationresult).\n\n- [Read more about streams on the \"Architecture\" page.](../architecture.md#stream-patterns-in-urql)\n- [Read more about the _Exchange_ type signature on the API docs.](../api/core.md#exchange)\n\n## Using Exchanges\n\nThe `Client` accepts an `exchanges` option that. Initially, we may choose to just\nset this to two very standard exchanges — `cacheExchange` and `fetchExchange`.\n\nIn essence these exchanges build a pipeline that runs in the order they're passed; _Operations_ flow\nin from the start to the end, and _Results_ are returned through the chain in reverse.\n\nSuppose we pass the `cacheExchange` and then the `fetchExchange` to the `exchanges`.\n\n**First,** operations are checked against the cache. Depending on the `requestPolicy`,\ncached results can be resolved from here instead, which would mean that the cache sends back the\nresult, and the operation doesn't travel any further in the chain.\n\n**Second,** operations are sent to the API, and the result is turned into an `OperationResult`.\n\n**Lastly,** operation results then travel through the exchanges in _reverse order_, which is because\nexchanges are a pipeline where all operations travel forward deeper into the exchange chain, and\nthen backwards. When these results pass through the cache then the `cacheExchange` stores the\nresult.\n\n```js\nimport { Client, fetchExchange, cacheExchange } from 'urql';\n\nconst client = new Client({\n  url: 'http://localhost:3000/graphql',\n  exchanges: [cacheExchange, fetchExchange],\n});\n```\n\nWe can add more exchanges to this chain, for instance, we can add the `mapExchange`, which can call a\ncallback whenever it sees [a `CombinedError`](../basics/errors.md) occur on a result.\n\n```js\nimport { Client, fetchExchange, cacheExchange, mapExchange } from 'urql';\n\nconst client = new Client({\n  url: 'http://localhost:3000/graphql',\n  exchanges: [\n    cacheExchange,\n    mapExchange({\n      onError(error) {\n        console.error(error);\n      },\n    }),\n    fetchExchange,\n  ],\n});\n```\n\nThis is an example for adding a synchronous exchange to the chain that only reacts to results. It\ndoesn't add any special behavior for operations travelling through it. An example for an\nasynchronous exchange that looks at both operations and results [we may look at the `retryExchange`\nwhich retries failed operations.](../advanced/retry-operations.md)\n\n## The Rules of Exchanges\n\nBefore we can start writing some exchanges, there are a couple of consistent patterns and limitations that\nmust be adhered to when writing an exchange. We call these the \"rules of Exchanges\", which\nalso come in useful when trying to learn what Exchanges actually are.\n\nFor reference, this is a basic template for an exchange:\n\n```js\nconst noopExchange = ({ client, forward }) => {\n  return operations$ => {\n    // <-- The ExchangeIO function\n    const operationResult$ = forward(operations$);\n    return operationResult$;\n  };\n};\n```\n\nThis exchange does nothing else than forward all operations and return all results. Hence, it's\ncalled a `noopExchange` — an exchange that doesn't do anything.\n\n### Forward and Return Composition\n\nWhen you create a `Client` and pass it an array of exchanges, `urql` composes them left-to-right.\nIf we look at our previous `noopExchange` example in context, we can track what it does if it is located between the `cacheExchange` and the `fetchExchange`.\n\n```js\nimport { Client, cacheExchange, fetchExchange } from 'urql';\n\nconst noopExchange = ({ client, forward }) => {\n  return operations$ => {\n    // <-- The ExchangeIO function\n    // We receive a stream of Operations from `cacheExchange` which\n    // we can modify before...\n    const forwardOperations$ = operations$;\n\n    // ...calling `forward` with the modified stream. The `forward`\n    // function is the next exchange's `ExchangeIO` function, in this\n    // case `fetchExchange`.\n    const operationResult$ = forward(operations$);\n\n    // We get back `fetchExchange`'s stream of results, which we can\n    // also change before returning, which is what `cacheExchange`\n    // will receive when calling `forward`.\n    return operationResult$;\n  };\n};\n\nconst client = new Client({\n  exchanges: [cacheExchange, noopExchange, fetchExchange],\n});\n```\n\n### How to Avoid Accidentally Dropping Operations\n\nTypically the `operations$` stream will send you `query`, `mutation`,\n`subscription`, and `teardown`. There is no constraint for new operations\nto be added later on or a custom exchange adding new operations altogether.\n\nThis means that you have to take \"unknown\" operations into account and\nnot `filter` operations too aggressively.\n\n```js\nimport { pipe, filter, merge } from 'wonka';\n\n// DON'T: drop unknown operations\n({ forward }) =>\n  operations$ => {\n    // This doesn't handle operations that aren't queries\n    const queries = pipe(\n      operations$,\n      filter(op => op.kind === 'query')\n    );\n    return forward(queries);\n  };\n\n// DO: forward operations that you don't handle\n({ forward }) =>\n  operations$ => {\n    const queries = pipe(\n      operations$,\n      filter(op => op.kind === 'query')\n    );\n    const rest = pipe(\n      operations$,\n      filter(op => op.kind !== 'query')\n    );\n    return forward(merge([queries, rest]));\n  };\n```\n\nIf operations are grouped and/or filtered by what the exchange is handling, then it's also important to\nmake that any streams of operations not handled by the exchange should also be forwarded.\n\n### Synchronous first, Asynchronous last\n\nBy default exchanges and Wonka streams are as predictable as possible.\nEvery operator in Wonka runs synchronously until asynchronicity is introduced.\n\nThis may happen when using a timing utility from Wonka, like\n[`delay`](https://wonka.kitten.sh/api/operators#delay) or\n[`throttle`](https://wonka.kitten.sh/api/operators#throttle)\nThis can also happen because the exchange inherently does something asynchronous, like fetching some\ndata or using a promise.\n\nWhen writing exchanges, some will inevitably be asynchronous. For example if\nthey're fetching results, performing authentication, or other tasks\nthat you have to wait for.\n\nThis can cause problems, because the behavior in `urql` is built\nto be _synchronous_ first. This is very helpful for suspense mode and allowing components receive cached data on their initial\nmount without rerendering.\n\nThis why **all exchanges should be ordered synchronous first and\nasynchronous last**.\n\nWhat we for instance repeat as the default setup in our docs is this:\n\n```js\nimport { Client, cacheExchange, fetchExchange } from 'urql';\n\nnew Client({\n  // ...\n  exchanges: [cacheExchange, fetchExchange];\n});\n```\n\nThe `cacheExchange` is completely synchronous.\nThe `fetchExchange` is asynchronous since it makes a `fetch` request and waits for a server response.\nIf we put an asynchronous exchange in front of the `cacheExchange`, that would be unexpected, and\nsince all results would then be delayed, nothing would ever be \"cached\" and instead always take some\namount of time to be returned.\n\nWhen you're adding more exchanges, it's often crucial\nto put them in a specific order. For instance, an authentication exchange\nwill need to go before the `fetchExchange`, a secondary cache will probably have to\ngo in front of the default cache exchange.\n\nTo ensure the correct behavior of suspense mode and\nthe initialization of our hooks, it's vital to order exchanges\nso that synchronous ones come before asynchronous ones.\n"
  },
  {
    "path": "docs/advanced/auto-populate-mutations.md",
    "content": "---\ntitle: Auto-populate Mutations\norder: 9\n---\n\n# Automatically populating Mutations\n\nThe `populateExchange` allows you to auto-populate selection sets in your mutations using the\n`@populate` directive. In combination with [Graphcache](../graphcache/README.md) this is a useful\ntool to update the data in your application automatically following a mutation, when your app grows,\nand it becomes harder to track all fields that have been queried before.\n\n> **NOTE:** The `populateExchange` is _experimental_! Certain patterns and usage paths\n> like GraphQL field arguments aren't covered yet, and the exchange hasn't been extensively used\n> yet.\n\n## Installation and Setup\n\nThe `populateExchange` can be installed via the `@urql/exchange-populate` package.\n\n```sh\nyarn add @urql/exchange-populate\n# or\nnpm install --save @urql/exchange-populate\n```\n\nAfterwards we can set the `populateExchange` up by adding it to our list of `exchanges` in the\nclient options.\n\n```ts\nimport { Client, fetchExchange } from '@urql/core';\nimport { populateExchange } from '@urql/exchange-populate';\n\nconst client = new Client({\n  // ...\n  exchanges: [populateExchange({ schema }), cacheExchange, fetchExchange],\n});\n```\n\nThe `populateExchange` should be placed in front of the `cacheExchange`, especially if you're using\n[Graphcache](../graphcache/README.md), since it won't understand the `@populate` directive on its\nown. It should also be placed in front the `cacheExchange` to avoid unnecessary work.\n\nAdding the `populateExchange` now enables us to use the `@populate` directive in our mutations.\n\nThe `schema` option is the introspection result for your backend graphql schema, more information\nabout how to get your schema can be found [in the \"Schema Awareness\" Page of the Graphcache documentation.](../graphcache/schema-awareness.md#getting-your-schema).\n\n## Example usage\n\nConsider the following queries, which have been requested in other parts of your application:\n\n```graphql\n# Query 1\n{\n  todos {\n    id\n    name\n  }\n}\n\n# Query 2\n{\n  todos {\n    id\n    createdAt\n  }\n}\n```\n\nWithout the `populateExchange` you may write a mutation like the following which returns a newly created todo item:\n\n```graphql\n# Without populate\nmutation addTodo(id: ID!) {\n  addTodo(id: $id) {\n    id        # To update Query 1 & 2\n    name      # To update Query 1\n    createdAt # To update Query 2\n  }\n}\n```\n\nBy using `populateExchange`, you no longer need to manually specify the selection set required to update your other queries. Instead you can just add the `@populate` directive.\n\n```graphql\n# With populate\nmutation addTodo(id: ID!) {\n  addTodo(id: $id) @populate\n}\n```\n\n### Choosing when to populate\n\nYou may not want to populate your whole mutation response. To reduce your payload, pass populate lower in your query.\n\n```graphql\nmutation addTodo(id: ID!) {\n  addTodo(id: $id) {\n    id\n    user @populate\n  }\n}\n```\n\n### Using aliases\n\nIf you find yourself using multiple queries with variables, it may be necessary to\n[use aliases](https://graphql.org/learn/queries/#aliases) to allow merging of queries.\n\n> **Note:** This caveat may change in the future or this restriction may be lifted.\n\n**Invalid usage**\n\n```graphql\n# Query 1\n{\n  todos(first: 10) {\n    id\n    name\n  }\n}\n\n# Query 2\n{\n  todos(last: 20) {\n    id\n    createdAt\n  }\n}\n```\n\n**Usage with aliases**\n\n```graphql\n# Query 1\n{\n  firstTodos: todos(first: 10) {\n    id\n    name\n  }\n}\n\n# Query 2\n{\n  lastTodos: todos(last: 20) {\n    id\n    createdAt\n  }\n}\n```\n"
  },
  {
    "path": "docs/advanced/debugging.md",
    "content": "---\ntitle: Debugging\norder: 4\n---\n\n# Debugging\n\nWe've tried to make debugging in `urql` as seamless as possible by creating tools for users of `urql`\nand those creating their own exchanges.\n\n## Devtools\n\nIt's easiest to debug `urql` with the [`urql` devtools.](https://github.com/urql-graphql/urql-devtools/)\n\nIt offers tools to inspect internal [\"Debug Events\"](#debug-events) as they happen, to explore data\nas your app is seeing it, and to quickly trigger GraphQL queries.\n\n[For instructions on how to set up the devtools, check out `@urql/devtools`'s readme in its\nrepository.](https://github.com/urql-graphql/urql-devtools)\n\n![Urql Devtools Timeline](../assets/devtools-timeline.png)\n\n## Debug events\n\nThe \"Debug Events\" are internally what displays more information to the user on the devtools'\n\"Events\" tab than just [Operations](../api/core.md#operation) and [Operation\nResults](../api/core.md#operationresult).\n\nEvents may be fired inside exchanges to add additional development logging to an exchange.\nThe `fetchExchange` for instance will fire a `fetchRequest` event when a request is initiated and\neither a `fetchError` or `fetchSuccess` event when a result comes back from the GraphQL API.\n\nThe [Devtools](#browser-devtools) aren't the only way to observe these internal events.\nAnyone can start listening to these events for debugging events by calling the\n[`Client`'s](../api/core.md#client) `client.subscribeToDebugTarget()` method.\n\nUnlike `Operation`s these events are fire-and-forget events that are only used for debugging. Hence,\nthey shouldn't be used for anything but logging and not for messaging. **Debug events are also\nentirely disabled in production.**\n\n### Subscribing to Debug Events\n\nInternally the `devtoolsExchange` calls the `client.subscribeToDebugTarget`, but if we're looking to\nbuild custom debugging tools, it's also possible to call this function directly and to replace the\n`devtoolsExchange`.\n\n```\nconst { unsubscribe } = client.subscribeToDebugTarget(event => {\n  if (event.source === 'cacheExchange')\n    return;\n  console.log(event); // { type, message, operation, data, source, timestamp }\n});\n```\n\nAs demonstrated above, the `client.subscribeToDebugTarget` accepts a callback function and returns\na subscription with an `unsubscribe` method. We've seen this pattern in the prior [\"Stream Patterns\"\nsection on the \"Architecture\" page.](../architecture.md)\n\n## Adding your own Debug Events\n\nDebug events are a means of sharing implementation details to consumers of an exchange. If you're\ncreating an exchange and want to share relevant information with the `devtools`, then you may want\nto start adding your own events.\n\n#### Dispatching an event\n\n[On the \"Authoring Exchanges\" page](./authoring-exchanges.md) we've learned about the [`ExchangeInput`\nobject](../api/core.md#exchangeinput), which comes with a `client` and a `forward` property.\nIt also contains a `dispatchDebug` property.\n\nIt is called with an object containing the following properties:\n\n| Prop        | Type        | Description                                                                           |\n| ----------- | ----------- | ------------------------------------------------------------------------------------- |\n| `type`      | `string`    | A unique type identifier for the Debug Event.                                         |\n| `message`   | `string`    | A human readable description of the event.                                            |\n| `operation` | `Operation` | The [`Operation`](../api/core.md#operation) that the event targets.                   |\n| `data`      | `?object`   | This is an optional payload to include any data that may become useful for debugging. |\n\nFor instance, we may call `dispatchDebug` with our `fetchRequest` event. This is the event that the\n`fetchExchange` uses to notify us that a request has commenced:\n\n```ts\nexport const fetchExchange: Exchange = ({ forward, dispatchDebug }) => {\n  // ...\n\n  return ops$ => {\n    return pipe(\n      ops$,\n      // ...\n      mergeMap(operation => {\n        dispatchDebug({\n          type: 'fetchRequest',\n          message: 'A network request has been triggered',\n          operation,\n          data: {\n            /* ... */\n          },\n        });\n\n        // ...\n      })\n    );\n  };\n};\n```\n\nIf we're adding new events that aren't included in the main `urql` repository and are using\nTypeScript, we may also declare a fixed type for the `data` property, so we can guarantee a\nconsistent payload for our Debug Events. This also prevents accidental conflicts.\n\n```ts\n// urql.d.ts\nimport '@urql/core';\n\ndeclare module '@urql/core' {\n  interface DebugEventTypes {\n    customEventType: { somePayload: string };\n  }\n}\n```\n\nRead more about extending types, like `urql`'s `DebugEventTypes` on the [TypeScript docs on\ndeclaration merging](https://www.typescriptlang.org/docs/handbook/declaration-merging.html).\n\n### Tips\n\nLastly, in summary, here are a few tips, that are important when we're adding new Debug Events to\ncustom exchanges:\n\n- ✅ **Share internal details**: Frequent debug messages on key events inside your exchange are very\n  useful when later inspecting them, e.g. in the `devtools`.\n- ✅ **Create unique event types** : Key events should be easily identifiable and have a unique\n  names.\n- ❌ **Don't listen to debug events inside your exchange**: While it's possible to call\n  `client.subscribeToDebugTarget` in an exchange it's only valuable when creating a debugging\n  exchange, like the `devtoolsExchange`.\n- ❌ **Don't send warnings in debug events**: Informing your user about warnings isn't effective\n  when the event isn't seen. You should still rely on `console.warn` so all users see your important\n  warnings.\n"
  },
  {
    "path": "docs/advanced/persistence-and-uploads.md",
    "content": "---\ntitle: Persistence & Uploads\norder: 1\n---\n\n# Persisted Queries and Uploads\n\n`urql` supports (Automatic) Persisted Queries, and File Uploads via GraphQL\nMultipart requests. For persisted queries to work, some setup work is needed,\nwhile File Upload support is built into `@urql/core@4`.\n\n## Automatic Persisted Queries\n\nPersisted Queries allow us to send requests to the GraphQL API that can easily be cached on the fly,\nboth by the GraphQL API itself and potential CDN caching layers. This is based on the unofficial\n[GraphQL Persisted Queries\nSpec](https://github.com/apollographql/apollo-link-persisted-queries#apollo-engine).\n\nWith Automatic Persisted Queries the client hashes the GraphQL query and turns it into an SHA256\nhash and sends this hash instead of the full query. If the server has seen this GraphQL query before\nit will recognise it by its hash and process the GraphQL API request as usual, otherwise it may\nrespond using a `PersistedQueryNotFound` error. In that case the client is supposed to instead send\nthe full GraphQL query, and the hash together, which will cause the query to be \"registered\" with the\nserver.\n\nAdditionally, we could also decide to send these hashed queries as GET requests instead of POST\nrequests. If we only send the persisted queries with hashes as GET requests then they become a lot\neasier for a CDN to cache, as by default most caches would not cache POST requests automatically.\n\nIn `urql`, we may use the `@urql/exchange-persisted` package's `persistedExchange` to\nenable support for Automatic Persisted Queries. This exchange works alongside other fetch or\nsubscription exchanges by adding metadata for persisted queries to each GraphQL\nrequest by modifying the `extensions` object of operations.\n\n> **Note:** [You can find a code example for `@urql/exchange-persisted` in an example in the `urql` repository.](https://github.com/urql-graphql/urql/tree/main/examples/with-apq)\n\n### Installation & Setup\n\nFirst install `@urql/exchange-persisted` alongside `urql`:\n\n```sh\nyarn add @urql/exchange-persisted\n# or\nnpm install --save @urql/exchange-persisted\n```\n\nYou'll then need to add the `persistedExchange` function, that this package exposes,\nto your `exchanges`, in front of exchanges that communicate with the API:\n\n```js\nimport { Client, fetchExchange, cacheExchange } from 'urql';\nimport { persistedExchange } from '@urql/exchange-persisted';\n\nconst client = new Client({\n  url: 'http://localhost:1234/graphql',\n  exchanges: [\n    cacheExchange,\n    persistedExchange({\n      preferGetForPersistedQueries: true,\n    }),\n    fetchExchange,\n  ],\n});\n```\n\nAs we can see, typically it's recommended to set `preferGetForPersistedQueries` to `true`\nto encourage persisted queries to use GET requests instead of POST so that CDNs can do their job.\nWhen set to `true` or `'within-url-limit'`, persisted queries will use GET requests if the\nresulting URL doesn't exceed the 2048 character limit.\n\nThe `fetchExchange` can see the modifications that the `persistedExchange` is\nmaking to operations, and understands to leave out the `query` from any request\nas needed. The same should be happening to the `subscriptionExchange`, if you're\nusing it for queries.\n\n### Customizing Hashing\n\nThe `persistedExchange` also accepts a `generateHash` option. This may be used to swap out the\nexchange's default method of generating SHA256 hashes. By default, the exchange will use the\nbuilt-in [Web Crypto API](https://developer.mozilla.org/en-US/docs/Web/API/Web_Crypto_API) when it's\navailable, and in Node.js it'll use the [Node Crypto Module](https://nodejs.org/api/crypto.html)\ninstead.\n\nIf you're using [the `graphql-persisted-document-loader` for\nWebpack](https://github.com/leoasis/graphql-persisted-document-loader), for instance, then you will\nalready have a loader generating SHA256 hashes for you at compile time. In that case we could swap\nout the `generateHash` function with a much simpler one that uses the `generateHash` function's\nsecond argument, a GraphQL `DocumentNode` object.\n\n```js\npersistedExchange({\n  generateHash: (_, document) => document.documentId,\n});\n```\n\nIf you're using **React Native** then you may not have access to the Web Crypto API, which means\nthat you have to provide your own SHA256 function to the `persistedExchange`. Luckily, we can do\nso easily by using the first argument `generateHash` receives, a GraphQL query as a string.\n\n```js\nimport sha256 from 'hash.js/lib/hash/sha/256';\n\npersistedExchange({\n  async generateHash(query) {\n    return sha256().update(query).digest('hex');\n  },\n});\n```\n\nAdditionally, if the API only expects persisted queries and not arbitrary ones and all queries are\npre-registered against the API then the `persistedExchange` may be put into a **non-automatic**\npersisted queries mode by giving it the `enforcePersistedQueries: true` option. This disables any\nretry logic and assumes that persisted queries will be handled like regular GraphQL requests.\n\n## File Uploads\n\nGraphQL server APIs commonly support the [GraphQL Multipart Request\nspec](https://github.com/jaydenseric/graphql-multipart-request-spec) to allow for File Uploads\ndirectly with a GraphQL API.\n\nIf a GraphQL API supports this, we can pass a [`File`](https://developer.mozilla.org/en-US/docs/Web/API/File)\nor a [`Blob`](https://developer.mozilla.org/en-US/docs/Web/API/Blob) directly into our variables and\ndefine the corresponding scalar for our variable, which is often called `File` or `Upload`.\n\nIn a browser, the `File` object may often be retrieved via a\n[file input](https://developer.mozilla.org/en-US/docs/Web/API/File/Using_files_from_web_applications),\nfor example.\n\n> **Note:** If you are using your own version of `File` and `Blob` ensure you are properly extending the\n> so it can be properly identified as a file.\n\nThe `@urql/core@4` package supports File Uploads natively, so we won't have to do any installation\nor setup work. When `urql` sees a `File` or a `Blob` anywhere in your `variables`, it switches to\na `multipart/form-data` request, converts the request to a `FormData` object, according to the\nGraphQL Multipart Request specification, and sends it off to the API.\n\n> **Note:** Previously, this worked by installing the `@urql/multipart-fetch-exchange` package.\n> however, this package has been deprecated and file uploads are now built into `@urql/core@4`.\n\n[You can find a code example for file uploads in an example in the `urql` repository.](https://github.com/urql-graphql/urql/tree/main/examples/with-multipart)\n"
  },
  {
    "path": "docs/advanced/retry-operations.md",
    "content": "---\ntitle: Retrying Operations\norder: 5\n---\n\n# Retrying Operations\n\nThe `retryExchange` lets us retry specific operation, by default it will\nretry only network errors, but we can specify additional options to add\nfunctionality.\n\n> **Note:** [You can find a code example for `@urql/exchange-retry` in an example in the `urql` repository.](https://github.com/urql-graphql/urql/tree/main/examples/with-retry)\n\n## Installation and Setup\n\nFirst install `@urql/exchange-retry` alongside `urql`:\n\n```sh\nyarn add @urql/exchange-retry\n# or\nnpm install --save @urql/exchange-retry\n```\n\nYou'll then need to add the `retryExchange`, exposed by this package, to your `urql` Client:\n\n```js\nimport { Client, cacheExchange, fetchExchange } from 'urql';\nimport { retryExchange } from '@urql/exchange-retry';\n\n// None of these options have to be added, these are the default values.\nconst options = {\n  initialDelayMs: 1000,\n  maxDelayMs: 15000,\n  randomDelay: true,\n  maxNumberAttempts: 2,\n  retryIf: err => err && err.networkError,\n};\n\n// Note the position of the retryExchange - it should be placed prior to the\n// fetchExchange and after the cacheExchange for it to function correctly\nconst client = new Client({\n  url: 'http://localhost:1234/graphql',\n  exchanges: [\n    cacheExchange,\n    retryExchange(options), // Use the retryExchange factory to add a new exchange\n    fetchExchange,\n  ],\n});\n```\n\nWe want to place the `retryExchange` before the `fetchExchange` so that retries are only performed _after_ the operation has passed through the cache and has attempted to fetch.\n\n## The Options\n\nThere are a set of optional options that allow for fine-grained control over the `retry` mechanism.\n\nWe have the `initialDelayMs` to specify at what interval the `retrying` should start, this means that if we specify `1000` that when our `operation` fails we'll wait 1 second and then retry it.\n\nNext up is the `maxDelayMs`, our `retryExchange` will keep increasing the time between retries, so we don't spam our server with requests it can't complete, this option ensures we don't exceed a certain threshold. This time between requests will increase with a random `back-off` factor multiplied by the `initialDelayMs`, read more about the [thundering herd problem](https://en.wikipedia.org/wiki/Thundering_herd_problem).\n\nTalking about increasing the `delay` randomly, `randomDelay` allows us to disable this. When this option is set to `false` we'll only increase the time between attempts with the `initialDelayMs`. This means if we fail the first time we'll have 1 second wait, next fail we'll have 2 seconds and so on.\n\nWe can declare the maximum number of attempts (including the initial request) with `maxNumberAttempts`, otherwise, it defaults to 2 (which means one retry). If you want it to retry indefinitely, you can simply pass in `Number.POSITIVE_INFINITY`.\n\n[For more information on the available options check out the API Docs.](../api/retry-exchange.md)\n\n## Reacting to Different Errors\n\nWe can introduce specific triggers for the `retryExchange` to start retrying operations,\nlet's look at an example:\n\n```js\nimport { Client, cacheExchange, fetchExchange } from 'urql';\nimport { retryExchange } from '@urql/exchange-retry';\n\nconst client = new Client({\n  url: 'http://localhost:1234/graphql',\n  exchanges: [\n    cacheExchange,\n    retryExchange({\n      retryIf: error => {\n        return !!(error.graphQLErrors.length > 0 || error.networkError);\n      },\n    }),\n    fetchExchange,\n  ],\n});\n```\n\nIn the above example we'll retry when we have `graphQLErrors` or a `networkError`, we can go\nmore granular and check for certain errors in `graphQLErrors`.\n\n## Failover / Fallback\n\nIn case of a network error, e.g., when part the infrastructure is down, but a fallback GraphQL endpoint is available, e.g., from a different provider on a different domain, the `retryWith` option allows for client-side failover. This could also be used in case of a `graphQLError`, for example, when APIs are deployed via a windowing strategy, i.e., a newer version at URL X, while an older one remains at Y.\n\nNote that finer granularity depending on custom requirements may be applicable, and that this does not allow for balancing load.\n\n```js\nconst fallbackUrl = 'http://localhost:1337/anotherGraphql';\n\nconst options = {\n  initialDelayMs: 1000,\n  maxDelayMs: 15000,\n  randomDelay: true,\n  maxNumberAttempts: 2,\n  retryWith: (error, operation) => {\n    if (error.networkError) {\n      const context = { ...operation.context, url: fallbackUrl };\n      return { ...operation, context };\n    }\n    return null;\n  },\n};\n```\n"
  },
  {
    "path": "docs/advanced/server-side-rendering.md",
    "content": "---\ntitle: Server-side Rendering\norder: 3\n---\n\n# Server-side Rendering\n\nIn server-side rendered applications we often need to set our application up so that data will be\nfetched on the server-side and later sent down to the client for hydration. `urql` supports this\nthrough the `ssrExchange.`\n\n## The SSR Exchange\n\nThe `ssrExchange` has two functions. On the server-side it's able to gather all results as they're\nbeing fetched, which can then be serialized and sent to the client. On the client-side it's able to\nuse these serialized results to rehydrate and render the application without refetching this data.\n\nTo start out with the `ssrExchange` we have to add the exchange to our `Client`:\n\n```js\nimport { Client, cacheExchange, fetchExchange, ssrExchange } from '@urql/core';\n\nconst isServerSide = typeof window === 'undefined';\n\n// The `ssrExchange` must be initialized with `isClient` and `initialState`\nconst ssr = ssrExchange({\n  isClient: !isServerSide,\n  initialState: !isServerSide ? window.__URQL_DATA__ : undefined,\n});\n\nconst client = new Client({\n  exchanges: [\n    cacheExchange,\n    ssr, // Add `ssr` in front of the `fetchExchange`\n    fetchExchange,\n  ],\n});\n```\n\nThe `ssrExchange` must be initialized with the `isClient` and `initialState` options. The `isClient`\noption tells the exchange whether it's on the server- or client-side. In our example we use `typeof window` to determine this, but in Webpack environments you may also be able to use `process.browser`.\n\nOptionally, we may also choose to enable `staleWhileRevalidate`. When enabled this flag will ensure that although a result may have been rehydrated from our SSR result, another\nrefetch `network-only` operation will be issued, to update stale data. This is useful for statically generated sites (SSG) that may ship stale data to our application initially.\n\nThe `initialState` option should be set to the serialized data you retrieve on your server-side.\nThis data may be retrieved using methods on `ssrExchange()`. You can retrieve the serialized data\nafter server-side rendering using `ssr.extractData()`:\n\n```js\n// Extract and serialise the data like so from the `ssr` instance\n// we've previously created by calling `ssrExchange()`\nconst data = JSON.stringify(ssr.extractData());\n\nconst markup = ''; // The render code for our framework goes here\n\nconst html = `\n<html>\n  <body>\n    <div id=\"root\">${markup}</div>\n    <script>\n      window.__URQL_DATA__ = JSON.parse(${data});\n    </script>\n  </body>\n</html>\n`;\n```\n\nThis will provide `__URQL_DATA__` globally, which we've used in our first example to inject data into\nthe `ssrExchange` on the client-side.\n\nAlternatively you can also call `restoreData` as long as this call happens synchronously before the\n`client` starts receiving queries.\n\n```js\nconst isServerSide = typeof window === 'undefined';\nconst ssr = ssrExchange({ isClient: !isServerSide });\n\nif (!isServerSide) {\n  ssr.restoreData(window.__URQL_DATA__);\n}\n```\n\n## Using `react-ssr-prepass`\n\nIn the previous examples we've set up the `ssrExchange`, however with React this still requires us\nto manually execute our queries before rendering a server-side React app [using `renderToString`\nor `renderToNodeStream`](https://reactjs.org/docs/react-dom-server.html#rendertostring).\n\nFor React, `urql` has a \"Suspense mode\" that [allows data fetching to interrupt\nrendering](https://reactjs.org/docs/concurrent-mode-suspense.html). However, Suspense is\nnot supported by React during server-side rendering.\n\nUsing [the `react-ssr-prepass` package](https://github.com/FormidableLabs/react-ssr-prepass) however,\nwe can implement a prerendering step before we let React server-side render, which allows us to\nautomatically fetch all data that the app requires with Suspense. This technique is commonly\nreferred to as a \"two-pass approach\", since our React element is traversed twice.\n\nTo set this up, first we'll install `react-ssr-prepass`. It has a peer dependency on `react-is`\nand `react`.\n\n```sh\nyarn add react-ssr-prepass react-is react-dom\n# or\nnpm install --save react-ssr-prepass react-is react-dom\n```\n\nNext, we'll modify our server-side code and add `react-ssr-prepass` in front of `renderToString`.\n\n```jsx\nimport { renderToString } from 'react-dom/server';\nimport prepass from 'react-ssr-prepass';\n\nimport {\n  Client,\n  cacheExchange,\n  fetchExchange,\n  ssrExchange,\n  Provider,\n} from 'urql';\n\nconst handleRequest = async (req, res) => {\n  // ...\n  const ssr = ssrExchange({ isClient: false });\n\n  const client = new Client({\n    url: 'https://??',\n    suspense: true, // This activates urql's Suspense mode on the server-side\n    exchanges: [cacheExchange, ssr, fetchExchange]\n  });\n\n  const element = (\n    <Provider value={client}>\n      <App />\n    </Provider>\n  );\n\n  // Using `react-ssr-prepass` this prefetches all data\n  await prepass(element);\n  // This is the usual React SSR rendering code\n  const markup = renderToString(element);\n  // Extract the data after prepass and rendering\n  const data = JSON.stringify(ssr.extractData());\n\n  res.status(200).send(`\n    <html>\n      <body>\n        <div id=\"root\">${markup}</div>\n        <script>\n          window.__URQL_DATA__ = JSON.parse(${data});\n        </script>\n      </body>\n    </html>\n  `);\n};\n```\n\nIt's important to set enable the `suspense` option on the `Client`, which switches it to support\nReact suspense.\n\n### With Preact\n\nIf you're using Preact instead of React, there's a drop-in replacement package for\n`react-ssr-prepass`, which is called `preact-ssr-prepass`. It only has a peer dependency on Preact,\nand we can install it like so:\n\n```sh\nyarn add preact-ssr-prepass preact\n# or\nnpm install --save preact-ssr-prepass preact\n```\n\nAll above examples for `react-ssr-prepass` will still be the same, except that instead of\nusing the `urql` package we'll have to import from `@urql/preact`, and instead of `react-ssr-prepass`\nwe'll have to import from. `preact-ssr-prepass`.\n\n## Next.js\n\nIf you're using [Next.js](https://nextjs.org/) you can save yourself a lot of work by using\n`@urql/next`. The `@urql/next` package is set to work with Next 13.\n\nTo set up `@urql/next`, first we'll install `@urql/next` and `urql` as\npeer dependencies:\n\n```sh\nyarn add @urql/next urql graphql\n# or\nnpm install --save @urql/next urql graphql\n```\n\nWe now have two ways to leverage `@urql/next`, one being part of a Server component\nor being part of the general `app/` folder.\n\nIn a server component we will import from `@urql/next/rsc`\n\n```ts\n// app/page.tsx\nimport React from 'react';\nimport { cacheExchange, createClient, fetchExchange, gql } from '@urql/core';\nimport { registerUrql } from '@urql/next/rsc';\n\nconst makeClient = () => {\n  return createClient({\n    url: 'https://trygql.formidable.dev/graphql/basic-pokedex',\n    exchanges: [cacheExchange, fetchExchange],\n  });\n};\n\nconst { getClient } = registerUrql(makeClient);\n\nexport default async function Home() {\n  const result = await getClient().query(PokemonsQuery, {});\n  return (\n    <main>\n      <h1>This is rendered as part of an RSC</h1>\n      <ul>\n        {result.data.pokemons.map((x: any) => (\n          <li key={x.id}>{x.name}</li>\n        ))}\n      </ul>\n    </main>\n  );\n}\n```\n\nWhen we aren't leveraging server components we will import the things we will\nneed to do a bit more setup, we go to the `client` component's layout file and\nstructure it as the following.\n\n```tsx\n// app/client/layout.tsx\n'use client';\n\nimport { useMemo } from 'react';\nimport { UrqlProvider, ssrExchange, cacheExchange, fetchExchange, createClient } from '@urql/next';\n\nexport default function Layout({ children }: React.PropsWithChildren) {\n  const [client, ssr] = useMemo(() => {\n    const ssr = ssrExchange({\n      isClient: typeof window !== 'undefined',\n    });\n    const client = createClient({\n      url: 'https://trygql.formidable.dev/graphql/web-collections',\n      exchanges: [cacheExchange, ssr, fetchExchange],\n      suspense: true,\n    });\n\n    return [client, ssr];\n  }, []);\n\n  return (\n    <UrqlProvider client={client} ssr={ssr}>\n      {children}\n    </UrqlProvider>\n  );\n}\n```\n\nIt is important that we pass both a client as well as the `ssrExchange` to the `Provider`\nthis way we will be able to restore the data that Next streams to the client later on\nwhen we are hydrating.\n\nThe next step is to query data in your client components by means of the `useQuery`\nmethod defined in `@urql/next`.\n\n```tsx\n// app/client/page.tsx\n'use client';\n\nimport Link from 'next/link';\nimport { Suspense } from 'react';\nimport { useQuery, gql } from '@urql/next';\n\nexport default function Page() {\n  return (\n    <Suspense>\n      <Pokemons />\n    </Suspense>\n  );\n}\n\nconst PokemonsQuery = gql`\n  query {\n    pokemons(limit: 10) {\n      id\n      name\n    }\n  }\n`;\n\nfunction Pokemons() {\n  const [result] = useQuery({ query: PokemonsQuery });\n  return (\n    <main>\n      <h1>This is rendered as part of SSR</h1>\n      <ul>\n        {result.data.pokemons.map((x: any) => (\n          <li key={x.id}>{x.name}</li>\n        ))}\n      </ul>\n    </main>\n  );\n}\n```\n\nThe data queried in the above component will be rendered on the server\nand re-hydrated back on the client. When using multiple Suspense boundaries\nthese will also get flushed as they complete and re-hydrated.\n\n> When data is used throughout the application we advise against\n> rendering this as part of a server-component so you can benefit\n> from the client-side cache.\n\n### Invalidating data from a server-component\n\nWhen data is rendered by a server component but you dispatch a mutation\nfrom a client component the server won't automatically know that the\nserver-component on the client needs refreshing. You can forcefully\ntell the server to do so by using the Next router and calling `.refresh()`.\n\n```tsx\nimport { useRouter } from 'next/navigation';\n\nconst Todo = () => {\n  const router = useRouter();\n  const executeMutation = async () => {\n    await updateTodo();\n    router.refresh();\n  };\n};\n```\n\n### Disabling RSC fetch caching\n\nYou can pass `fetchOptions: { cache: \"no-store\" }` to the `createClient`\nconstructor to avoid running into cached fetches with server-components.\n\n## Legacy Next.js (pages)\n\nIf you're using [Next.js](https://nextjs.org/) with the classic `pages` you can instead use `next-urql`.\nTo set up `next-urql`, first we'll install `next-urql` with `react-is` and `urql` as peer dependencies:\n\n```sh\nyarn add next-urql react-is urql graphql\n# or\nnpm install --save next-urql react-is urql graphql\n```\n\nThe peer dependency on `react-is` is inherited from `react-ssr-prepass` requiring it.\n\nNote that if you are using Next before v9.4 you'll need to polyfill fetch, this can be\ndone through [`isomorphic-unfetch`](https://www.npmjs.com/package/isomorphic-unfetch).\n\nWe're now able to wrap any page or `_app.js` using the `withUrqlClient` higher-order component. If\nwe wrap `_app.js` we won't have to wrap any individual page.\n\n```js\n// pages/index.js\nimport React from 'react';\nimport { useQuery } from 'urql';\nimport { withUrqlClient } from 'next-urql';\n\nconst Index = () => {\n  const [result] = useQuery({\n    query: '{ test }',\n  });\n\n  // ...\n};\n\nexport default withUrqlClient((_ssrExchange, ctx) => ({\n  // ...add your Client options here\n  url: 'http://localhost:3000/graphql',\n}))(Index);\n```\n\nThe `withUrqlClient` higher-order component function accepts the usual `Client` options as\nan argument. This may either just be an object, or a function that receives the Next.js'\n`getInitialProps` context.\n\nOne added caveat is that these options may not include the `exchanges` option because `next-urql`\ninjects the `ssrExchange` automatically at the right location. If you're setting up custom exchanges\nyou'll need to instead provide them in the `exchanges` property of the returned client object.\n\n```js\nimport { cacheExchange, fetchExchange } from '@urql/core';\n\nimport { withUrqlClient } from 'next-urql';\n\nexport default withUrqlClient(ssrExchange => ({\n  url: 'http://localhost:3000/graphql',\n  exchanges: [cacheExchange, ssrExchange, fetchExchange],\n}))(Index);\n```\n\nUnless the component that is being wrapped already has a `getInitialProps` method, `next-urql` won't add its own SSR logic, which automatically fetches queries during\nserver-side rendering. This can be explicitly enabled by passing the `{ ssr: true }` option as a second argument to `withUrqlClient`.\n\nWhen you are using `getStaticProps`, `getServerSideProps`, or `getStaticPaths`, you should opt-out of `Suspense` by setting the `neverSuspend` option to `true` in your `withUrqlClient` configuration.\nDuring the prepass of your component tree `next-urql` can't know how these functions will alter the props passed to your page component. This injection\ncould change the `variables` used in your `useQuery`. This will lead to error being thrown during the subsequent `toString` pass, which isn't supported in React 16.\n\n### SSR with { ssr: true }\n\nThe `withUrqlClient` only wraps our component tree with the context provider by default.\nTo enable SSR, the easiest way is specifying the `{ ssr: true }` option as a second\nargument to `withUrqlClient`:\n\n```js\nimport { cacheExchange, fetchExchange } from '@urql/core';\n\nimport { withUrqlClient } from 'next-urql';\n\nexport default withUrqlClient(\n  ssrExchange => ({\n    url: 'http://localhost:3000/graphql',\n    exchanges: [cacheExchange, ssrExchange, fetchExchange],\n  }),\n  { ssr: true } // Enables server-side rendering using `getInitialProps`\n)(Index);\n```\n\nBe aware that wrapping the `_app` component using `withUrqlClient` with the `{ ssr: true }`\noption disables Next's [\"Automatic Static\nOptimization\"](https://nextjs.org/docs/advanced-features/automatic-static-optimization) for\n**all our pages**. It is thus preferred to enable server-side rendering on a per-page basis.\n\n### SSR with getStaticProps or getServerSideProps\n\nEnabling server-side rendering using `getStaticProps` and `getServerSideProps` is a little\nmore involved, but has two major benefits:\n\n1. allows **direct schema execution** for performance optimisation\n2. allows performing extra operations in those functions\n\nTo make the functions work with the `withUrqlClient` wrapper, return the `urqlState` prop\nwith the extracted data from the `ssrExchange`:\n\n```js\nimport { withUrqlClient, initUrqlClient } from 'next-urql';\nimport { ssrExchange, cacheExchange, fetchExchange, useQuery } from 'urql';\n\nconst TODOS_QUERY = `\n  query { todos { id text } }\n`;\n\nfunction Todos() {\n  const [res] = useQuery({ query: TODOS_QUERY });\n  return (\n    <div>\n      {res.data.todos.map(todo => (\n        <div key={todo.id}>\n          {todo.id} - {todo.text}\n        </div>\n      ))}\n    </div>\n  );\n}\n\nexport async function getStaticProps(ctx) {\n  const ssrCache = ssrExchange({ isClient: false });\n  const client = initUrqlClient(\n    {\n      url: 'your-url',\n      exchanges: [cacheExchange, ssrCache, fetchExchange],\n    },\n    false\n  );\n\n  // This query is used to populate the cache for the query\n  // used on this page.\n  await client.query(TODOS_QUERY).toPromise();\n\n  return {\n    props: {\n      // urqlState is a keyword here so withUrqlClient can pick it up.\n      urqlState: ssrCache.extractData(),\n    },\n    revalidate: 600,\n  };\n}\n\nexport default withUrqlClient(\n  ssr => ({\n    url: 'your-url',\n  })\n  // Cannot specify { ssr: true } here so we don't wrap our component in getInitialProps\n)(Todos);\n```\n\nThe above example will make sure the page is rendered as a static-page, It's important that\nyou fully pre-populate your cache so in our case we were only interested in getting our todos,\nif there are child components relying on data you'll have to make sure these are fetched as well.\n\nThe `getServerSideProps` and `getStaticProps` functions only run on the **server-side** — any\ncode used in them is automatically stripped away from the client-side bundle using the\n[next-code-elimination tool](https://next-code-elimination.vercel.app/). This allows **executing\nour schema directly** using `@urql/exchange-execute` if we have access to our GraphQL server:\n\n```js\nimport { withUrqlClient, initUrqlClient } from 'next-urql';\nimport { ssrExchange, cacheExchange, fetchExchange, useQuery } from 'urql';\nimport { executeExchange } from '@urql/exchange-execute';\n\nimport { schema } from '@/server/graphql'; // our GraphQL server's executable schema\n\nconst TODOS_QUERY = `\n  query { todos { id text } }\n`;\n\nfunction Todos() {\n  const [res] = useQuery({ query: TODOS_QUERY });\n  return (\n    <div>\n      {res.data.todos.map(todo => (\n        <div key={todo.id}>\n          {todo.id} - {todo.text}\n        </div>\n      ))}\n    </div>\n  );\n}\n\nexport async function getServerSideProps(ctx) {\n  const ssrCache = ssrExchange({ isClient: false });\n  const client = initUrqlClient(\n    {\n      url: '', // not needed without `fetchExchange`\n      exchanges: [\n        cacheExchange,\n        ssrCache,\n        executeExchange({ schema }), // replaces `fetchExchange`\n      ],\n    },\n    false\n  );\n\n  await client.query(TODOS_QUERY).toPromise();\n\n  return {\n    props: {\n      urqlState: ssrCache.extractData(),\n    },\n  };\n}\n\nexport default withUrqlClient(ssr => ({\n  url: 'your-url',\n}))(Todos);\n```\n\nDirect schema execution skips one network round trip by accessing your resolvers directly\ninstead of performing a `fetch` API call.\n\n### Stale While Revalidate\n\nIf we choose to use Next's static site generation (SSG or ISG) we may be embedding data in our initial payload that's stale on the client. In this case, we may want to update this data immediately after rehydration.\nWe can pass `staleWhileRevalidate: true` to `withUrqlClient`'s second option argument to Switch it to a mode where it'll refresh its rehydrated data immediately by issuing another network request.\n\n```js\nexport default withUrqlClient(\n  ssr => ({\n    url: 'your-url',\n  }),\n  { staleWhileRevalidate: true }\n)(...);\n```\n\nNow, although on rehydration we'll receive the stale data from our `ssrExchange` first, it'll also immediately issue another `network-only` operation to update the data.\nDuring this revalidation our stale results will be marked using `result.stale`. While this is similar to what we see with `cache-and-network` without server-side rendering, it isn't quite the same. Changing the request policy wouldn't actually refetch our data on rehydration as the `ssrExchange` is simply a replacement of a full network request. Hence, this flag allows us to treat this case separately.\n\n### Resetting the client instance\n\nIn rare scenario's you possibly will have to reset the client instance (reset all cache, ...), this\nis an uncommon scenario, and we consider it \"unsafe\" so evaluate this carefully for yourself.\n\nWhen this does seem like the appropriate solution any component wrapped with `withUrqlClient` will receive the `resetUrqlClient`\nproperty, when invoked this will create a new top-level client and reset all prior operations.\n\n## Vue Suspense\n\nIn Vue 3 a [new feature was introduced](https://vuedose.tips/go-async-in-vue-3-with-suspense/) that\nnatively allows components to suspend while data is loading, which works universally on the server\nand on the client, where a replacement loading template is rendered on a parent while data is\nloading.\n\nWe've previously seen how we can change our usage of `useQuery`'s `PromiseLike` result to [make use\nof Vue Suspense on the \"Queries\" page.](../basics/vue.md#vue-suspense)\n\nAny component's `setup()` function can be updated to instead be an `async setup()` function, in\nother words, to return a `Promise` instead of directly returning its data. This means that we can\nupdate any `setup()` function to make use of Suspense.\n\nOn the server-side we can then use `@vue/server-renderer`'s `renderToString`, which will return a\n`Promise` that resolves when all suspense-related loading is completed.\n\n```jsx\nimport { createSSRApp } = from 'vue'\nimport { renderToString } from '@vue/server-renderer';\n\nimport urql, {\n  createClient,\n  cacheExchange,\n  fetchExchange,\n  ssrExchange\n} from '@urql/vue';\n\nconst handleRequest = async (req, res) => {\n  // This is where we'll put our root component\n  const app = createSSRApp(Root)\n\n  // NOTE: All we care about here is that the SSR Exchange is included\n  const ssr = ssrExchange({ isClient: false });\n  app.use(urql, {\n    exchanges: [cacheExchange, ssr, fetchExchange]\n  });\n\n  const markup = await renderToString(app);\n\n  const data = JSON.stringify(ssr.extractData());\n\n  res.status(200).send(`\n    <html>\n      <body>\n        <div id=\"root\">${markup}</div>\n        <script>\n          window.__URQL_DATA__ = JSON.parse(${data});\n        </script>\n      </body>\n    </html>\n  `);\n};\n```\n\nThis effectively renders our Vue app on the server-side and provides the client-side data for\nrehydration that we've set up in the above [SSR Exchange section](#the-ssr-exchange) to use.\n"
  },
  {
    "path": "docs/advanced/subscriptions.md",
    "content": "---\ntitle: Subscriptions\norder: 0\n---\n\n# Subscriptions\n\nOne feature of `urql` that was not mentioned in the [\"Basics\" sections](../basics/README.md) is `urql`'s\nAPIs and ability to handle GraphQL subscriptions.\n\n## The Subscription Exchange\n\nTo add support for subscriptions we need to add the `subscriptionExchange` to our `Client`.\n\n```js\nimport { Client, cacheExchange, fetchExchange, subscriptionExchange } from 'urql';\n\nconst client = new Client({\n  url: 'http://localhost:3000/graphql',\n  exchanges: [\n    cacheExchange,\n    fetchExchange,\n    subscriptionExchange({\n      forwardSubscription,\n    }),\n  ],\n});\n```\n\nRead more about Exchanges and how they work [on the \"Authoring Exchanges\"\npage.](./authoring-exchanges.md) or what they are [on the \"Architecture\"\npage.](../architecture.md)\n\nIn the above example, we add the `subscriptionExchange` to the `Client` with the default exchanges\nadded before it. The `subscriptionExchange` is a factory that accepts additional options and returns\nthe actual `Exchange` function. It does not make any assumption over the transport protocol and\nscheme that is used. Instead, we need to pass a `forwardSubscription` function.\n\nThe `forwardSubscription` is called when the `subscriptionExchange` receives an `Operation`, so\ntypically, when you’re executing a GraphQL subscription. This will call the `forwardSubscription`\nfunction with a GraphQL request body, in the same shape that a GraphQL HTTP API may receive it as\nJSON input.\n\nIf you’re using TypeScript, you may notice that the input that `forwardSubscription` receives has\nan optional `query` property. This is because of persisted query support. For some transports, the\n`query` property may have to be defaulted to an empty string, which matches the GraphQL over HTTP\nspecification more closely.\n\nWhen we define this function it must return an \"Observable-like\" object, which needs to follow the\n[Observable spec](https://github.com/tc39/proposal-observable), which comes down to having an\nobject with a `.subscribe()` method accepting an observer.\n\n### Setting up `graphql-ws`\n\nFor backends supporting `graphql-ws`, we recommend using the [graphql-ws](https://github.com/enisdenjo/graphql-ws) client.\n\n```js\nimport { Client, cacheExchange, fetchExchange, subscriptionExchange } from 'urql';\nimport { createClient as createWSClient } from 'graphql-ws';\n\nconst wsClient = createWSClient({\n  url: 'ws://localhost/graphql',\n});\n\nconst client = new Client({\n  url: '/graphql',\n  exchanges: [\n    cacheExchange,\n    fetchExchange,\n    subscriptionExchange({\n      forwardSubscription(request) {\n        const input = { ...request, query: request.query || '' };\n        return {\n          subscribe(sink) {\n            const unsubscribe = wsClient.subscribe(input, sink);\n            return { unsubscribe };\n          },\n        };\n      },\n    }),\n  ],\n});\n```\n\nIn this example, we're creating a `SubscriptionClient`, are passing in a URL and some parameters,\nand are using the `SubscriptionClient`'s `request` method to create a Subscription Observable, which\nwe return to the `subscriptionExchange` inside `forwardSubscription`.\n\n[Read more on the `graphql-ws` README.](https://github.com/enisdenjo/graphql-ws/blob/master/README.md)\n\n### Setting up `subscriptions-transport-ws`\n\nFor backends supporting `subscriptions-transport-ws`, [Apollo's `subscriptions-transport-ws`\npackage](https://github.com/apollographql/subscriptions-transport-ws) can be used.\n\n> The `subscriptions-transport-ws` package isn't actively maintained. If your API supports the new protocol or you can swap the package out, consider using [`graphql-ws`](#setting-up-graphql-ws) instead.\n\n```js\nimport { Client, cacheExchange, fetchExchange, subscriptionExchange } from 'urql';\nimport { SubscriptionClient } from 'subscriptions-transport-ws';\n\nconst subscriptionClient = new SubscriptionClient('ws://localhost/graphql', { reconnect: true });\n\nconst client = new Client({\n  url: '/graphql',\n  exchanges: [\n    cacheExchange,\n    fetchExchange,\n    subscriptionExchange({\n      forwardSubscription: request => subscriptionClient.request(request),\n    }),\n  ],\n});\n```\n\nIn this example, we're creating a `SubscriptionClient`, are passing in a URL and some parameters,\nand are using the `SubscriptionClient`'s `request` method to create a Subscription Observable, which\nwe return to the `subscriptionExchange` inside `forwardSubscription`.\n\n[Read more about `subscription-transport-ws` on its README.](https://github.com/apollographql/subscriptions-transport-ws/blob/master/README.md)\n\n### Using `fetch` for subscriptions\n\nSome GraphQL backends (for example GraphQL Yoga) support built-in transport protocols that\ncan execute subscriptions via a simple HTTP fetch call.\nIn fact, this is how `@defer` and `@stream` directives are supported. These transports can\nalso be used for subscriptions.\n\n```js\nimport { Client, cacheExchange, fetchExchange, subscriptionExchange } from 'urql';\n\nconst client = new Client({\n  url: '/graphql',\n  fetchSubscriptions: true,\n  exchanges: [cacheExchange, fetchExchange],\n});\n```\n\nIn this example, we only need to enable `fetchSubscriptions: true` on the `Client`, and the\n`fetchExchange` will be used to send subscriptions to the API. If your API supports this transport,\nit will stream results back to the `fetchExchange`.\n\n[You can find a code example of subscriptions via `fetch` in an example in the `urql` repository.](https://github.com/urql-graphql/urql/tree/main/examples/with-subscriptions-via-fetch)\n\n## React & Preact\n\nThe `useSubscription` hooks comes with a similar API to `useQuery`, which [we've learned about in\nthe \"Queries\" page in the \"Basics\" section.](../basics/react-preact.md#queries)\n\nIts usage is extremely similar in that it accepts options, which may contain `query` and\n`variables`. However, it also accepts a second argument, which is a reducer function, similar to\nwhat you would pass to `Array.prototype.reduce`.\n\nIt receives the previous set of data that this function has returned or `undefined`.\nAs the second argument, it receives the event that has come in from the subscription.\nYou can use this to accumulate the data over time, which is useful for a\nlist for example.\n\nIn the following example, we create a subscription that informs us of\nnew messages. We will concatenate the incoming messages so that we\ncan display all messages that have come in over the subscription across\nevents.\n\n```js\nimport React from 'react';\nimport { useSubscription } from 'urql';\n\nconst newMessages = `\n  subscription MessageSub {\n    newMessages {\n      id\n      from\n      text\n    }\n  }\n`;\n\nconst handleSubscription = (messages = [], response) => {\n  return [response.newMessages, ...messages];\n};\n\nconst Messages = () => {\n  const [res] = useSubscription({ query: newMessages }, handleSubscription);\n\n  if (!res.data) {\n    return <p>No new messages</p>;\n  }\n\n  return (\n    <ul>\n      {res.data.map(message => (\n        <p key={message.id}>\n          {message.from}: \"{message.text}\"\n        </p>\n      ))}\n    </ul>\n  );\n};\n```\n\nAs we can see, the `res.data` is being updated and transformed by\nthe `handleSubscription` function. This works over time, so as\nnew messages come in, we will append them to the list of previous\nmessages.\n\n[Read more about the `useSubscription` API in the API docs for it.](../api/urql.md#usesubscription)\n\n## Svelte\n\nThe `subscriptionStore` function in `@urql/svelte` comes with a similar API to `query`, which [we've\nlearned about in the \"Queries\" page in the \"Basics\" section.](../basics/svelte.md#queries)\n\nIts usage is extremely similar in that it accepts an `operationStore`, which will typically contain\nour GraphQL subscription query.\n\nIn the following example, we create a subscription that informs us of new messages.\n\n```js\n<script>\n  import { gql, getContextClient, subscriptionStore } from '@urql/svelte';\n\n  const messages = subscriptionStore({\n    client: getContextClient(),\n    query: gql`\n      subscription MessageSub {\n        newMessages {\n          id\n          from\n          text\n        }\n      }\n    `,\n  });\n</script>\n\n{#if !$messages.data}\n  <p>No new messages</p>\n{:else}\n  <ul>\n    {#each $messages.data.newMessages as message}\n      <li>{message.from}: \"{message.text}\"</li>\n    {/each}\n  </ul>\n{/if}\n\n```\n\nAs we can see, `$messages.data` is being updated and transformed by the `$messages` subscriptionStore. This works over time, so as new messages come in, we will append them to\nthe list of previous messages.\n\n`subscriptionStore` optionally accepts a second argument, a handler function, allowing custom update behavior from the subscription.\n\n[Read more about the `subscription` API in the API docs for it.](../api/svelte.md#subscriptionstore)\n\n## Vue\n\nThe `useSubscription` API is very similar to `useQuery`, which [we've learned about in\nthe \"Queries\" page in the \"Basics\" section.](../basics/vue.md#queries)\n\nIts usage is extremely similar in that it accepts options, which may contain `query` and\n`variables`. However, it also accepts a second argument, which is a reducer function, similar to\nwhat you would pass to `Array.prototype.reduce`.\n\nIt receives the previous set of data that this function has returned or `undefined`.\nAs the second argument, it receives the event that has come in from the subscription.\nYou can use this to accumulate the data over time, which is useful for a\nlist for example.\n\nIn the following example, we create a subscription that informs us of\nnew messages. We will concatenate the incoming messages so that we\ncan display all messages that have come in over the subscription across\nevents.\n\n```jsx\n<template>\n  <div v-if=\"error\">\n    Oh no... {{error}}\n  </div>\n  <div v-else>\n    <ul v-if=\"data\">\n      <li v-for=\"msg in data\">{{ msg.from }}: \"{{ msg.text }}\"</li>\n    </ul>\n  </div>\n</template>\n\n<script>\nimport { useSubscription } from '@urql/vue';\n\nexport default {\n  setup() {\n    const handleSubscription = (messages = [], response) => {\n      return [response.newMessages, ...messages];\n    };\n\n    const result = useSubscription({\n      query: `\n        subscription MessageSub {\n          newMessages {\n            id\n            from\n            text\n          }\n        }\n      `,\n    }, handleSubscription)\n\n    return {\n      data: result.data,\n      error: result.error,\n    };\n  }\n};\n</script>\n```\n\nAs we can see, the `result.data` is being updated and transformed by\nthe `handleSubscription` function. This works over time, so as\nnew messages come in, we will append them to the list of previous\nmessages.\n\n[Read more about the `useSubscription` API in the API docs for it.](../api/vue.md#usesubscription)\n\n## One-off Subscriptions\n\nWhen you're using subscriptions directly without `urql`'s framework bindings, you can use the\n`Client`'s `subscription` method for one-off subscriptions. This method is similar to the ones for\nmutations and subscriptions [that we've seen before on the \"Core Package\" page.](../basics/core.md)\n\nThis method will always [returns a Wonka stream](../architecture.md#the-wonka-library) and doesn't\nhave a `.toPromise()` shortcut method, since promises won't return the multiple values that a\nsubscription may deliver. Let's convert the above example to one without framework code, as we may\nuse subscriptions in a Node.js environment.\n\n```js\nimport { gql } from '@urql/core';\n\nconst MessageSub = gql`\n  subscription MessageSub {\n    newMessages {\n      id\n      from\n      text\n    }\n  }\n`;\n\nconst { unsubscribe } = client.subscription(MessageSub).subscribe(result => {\n  console.log(result); // { data: ... }\n});\n```\n"
  },
  {
    "path": "docs/advanced/testing.md",
    "content": "---\ntitle: Testing\norder: 7\n---\n\n# Testing\n\nTesting with `urql` can be done in a multitude of ways. The most effective and straightforward\nmethod is to mock the `Client` to force your components into a fixed state during testing.\n\nThe following examples demonstrate this method of testing for React and the `urql` package only,\nhowever the pattern itself can be adapted for any framework-bindings of `urql`.\n\n## Mocking the client\n\nFor the most part, urql's hooks are just adapters for talking to the urql client.\n\nThe way in which they do this is by making calls to the client via context.\n\n- `useQuery` calls `executeQuery`\n- `useMutation` calls `executeMutation`\n- `useSubscription` calls `executeSubscription`\n\nIn the section [\"Stream Patterns\" on the \"Architecture\" page](../architecture.md) we've seen, that\nall methods on the client operate with and return streams. These streams are created using\n[the Wonka library](../architecture.md#the-wonka-library), and we're able to create streams\nourselves to mock the different states of our operations, e.g. fetching, errors, or success with data.\n\nYou'll probably use one of these utility functions to create streams:\n\n- `never`: This stream doesn’t emit any values and never completes, which puts our `urql` code in a permanent `fetching: true` state.\n- `fromValue`: This utility function accepts a value and emits it immediately, which we can use to mock a result from the server.\n- `makeSubject`: Allows us to create a source and imperatively push responses, which is useful to test subscription and simulate changes, i.e. multiple states.\n\nCreating a mock `Client` is pretty quick as we'll create an object that contains the `Client`'s methods that the React `urql` hooks use. We'll mock the appropriate `execute` functions that we need to mock a set of hooks. After we've created the mock `Client` we can wrap components with the `Provider` from `urql` and pass it.\n\nHere's an example client mock being used while testing a component.\n\n```tsx\nimport { mount } from 'enzyme';\nimport { Provider } from 'urql';\nimport { never } from 'wonka';\nimport { MyComponent } from './MyComponent';\n\nit('renders', () => {\n  const mockClient = {\n    executeQuery: jest.fn(() => never),\n    executeMutation: jest.fn(() => never),\n    executeSubscription: jest.fn(() => never),\n  };\n\n  const wrapper = mount(\n    <Provider value={mockClient}>\n      <MyComponent />\n    </Provider>\n  );\n});\n```\n\n## Testing calls to the client\n\nOnce you have your mock setup, calls to the client can be tested.\n\n```tsx\nimport { mount } from 'enzyme';\nimport { Provider } from 'urql';\nimport { MyComponent } from './MyComponent';\n\nit('skips the query', () => {\n  mount(\n    <Provider value={mockClient}>\n      <MyComponent skip={true} />\n    </Provider>\n  );\n  expect(mockClient.executeQuery).toBeCalledTimes(0);\n});\n```\n\nTesting mutations and subscriptions also work in a similar fashion.\n\n```tsx\nimport { mount } from 'enzyme';\nimport { Provider } from 'urql';\nimport { MyComponent } from './MyComponent';\n\nit('triggers a mutation', () => {\n  const wrapper = mount(\n    <Provider value={mockClient}>\n      <MyComponent />\n    </Provider>\n  );\n\n  const variables = { name: 'Carla' };\n\n  wrapper.find('input').simulate('change', { currentTarget: { value: variables.name } });\n  wrapper.find('button').simulate('click');\n\n  expect(mockClient.executeMutation).toBeCalledTimes(1);\n  expect(mockClient.executeMutation).toBeCalledWith(expect.objectContaining({ variables }), {});\n});\n```\n\n## Forcing states\n\nFor testing render output, or creating fixtures, you may want to force the state of your components.\n\n### Fetching\n\nFetching states can be simulated by returning a stream, which never returns. Wonka provides a utility for this, aptly called `never`.\n\nHere's a fixture, which stays in the _fetching_ state.\n\n```tsx\nimport { Provider } from 'urql';\nimport { never } from 'wonka';\nimport { MyComponent } from './MyComponent';\n\nconst fetchingState = {\n  executeQuery: () => never,\n};\n\nexport default (\n  <Provider value={fetchingState}>\n    <MyComponent />\n  </Provider>\n);\n```\n\n### Response (success)\n\nResponse states are simulated by providing a stream, which contains a network response. For single responses, Wonka's `fromValue` function can do this for us.\n\n**Example snapshot test of response state**\n\n```tsx\nimport { mount } from 'enzyme';\nimport { Provider } from 'urql';\nimport { fromValue } from 'wonka';\nimport { MyComponent } from './MyComponent';\n\nit('matches snapshot', () => {\n  const responseState = {\n    executeQuery: () =>\n      fromValue({\n        data: {\n          posts: [\n            { id: 1, title: 'Post title', content: 'This is a post' },\n            { id: 3, title: 'Final post', content: 'Final post here' },\n          ],\n        },\n      }),\n  };\n\n  const wrapper = mount(\n    <Provider value={responseState}>\n      <MyComponent />\n    </Provider>\n  );\n  expect(wrapper).toMatchSnapshot();\n});\n```\n\n### Response (error)\n\nError responses are similar to success responses, only the value in the stream is changed.\n\n```tsx\nimport { Provider, CombinedError } from 'urql';\nimport { fromValue } from 'wonka';\n\nconst errorState = {\n  executeQuery: () =>\n    fromValue({\n      error: new CombinedError({\n        networkError: Error('something went wrong!'),\n      }),\n    }),\n};\n```\n\n### Handling multiple hooks\n\nReturning different values for many `useQuery` calls can be done by introducing conditionals into the mocked client functions.\n\n```tsx\nimport { fromValue } from 'wonka';\n\nlet mockClient;\nbeforeEach(() => {\n  mockClient = () => {\n    executeQuery: ({ query }) => {\n      if (query === GET_USERS) {\n        return fromValue(usersResponse);\n      }\n\n      if (query === GET_POSTS) {\n        return fromValue(postsResponse);\n      }\n    };\n  };\n});\n```\n\nThe above client we've created mocks all three operations — queries, mutations and subscriptions — to always remain in the `fetching: true` state.\nGenerally when we're _hoisting_ our mocked client and reuse it across multiple tests we have to be\nmindful not to instantiate the mocks outside of Jest's lifecycle functions (like `it`, `beforeEach`,\n`beforeAll` and such) as it may otherwise reset our mocked functions' return values or\nimplementation.\n\n## Subscriptions\n\nTesting subscriptions can be done by simulating the arrival of new data over time. To do this we may use the `interval` utility from Wonka, which emits values on a timer, and for each value we can map over the response that we'd like to mock.\n\nIf you prefer to have more control on when the new data is arriving you can use the `makeSubject` utility from Wonka. You can see more details in the next section.\n\nHere's an example of testing a list component, which uses a subscription.\n\n```tsx\nimport { OperationContext, makeOperation } from '@urql/core';\nimport { mount } from 'enzyme';\nimport { Provider } from 'urql';\nimport { MyComponent } from './MyComponent';\n\nit('should update the list', done => {\n  const mockClient = {\n    executeSubscription: jest.fn(query =>\n      pipe(\n        interval(200),\n        map((i: number) => ({\n          // To mock a full result, we need to pass a mock operation back as well\n          operation: makeOperation('subscription', query, {} as OperationContext),\n          data: { posts: { id: i, title: 'Post title', content: 'This is a post' } },\n        }))\n      )\n    ),\n  };\n\n  let index = 0;\n\n  const wrapper = mount(\n    <Provider value={mockClient}>\n      <MyComponent />\n    </Provider>\n  );\n\n  setTimeout(() => {\n    expect(wrapper.find('.list').children()).toHaveLength(index + 1); // See how many items are in the list\n    index++;\n    if (index === 2) done();\n  }, 200);\n});\n```\n\n## Simulating changes\n\nSimulating multiple responses can be useful, particularly testing `useEffect` calls dependent on changing query responses.\n\nFor this, a _subject_ is the way to go. In short, it's a stream that you can push responses to. The `makeSubject` function from Wonka is what you'll want to use for this purpose.\n\nBelow is an example of simulating subsequent responses (such as a cache update/refetch) in a test.\n\n```tsx\nimport { mount } from 'enzyme';\nimport { act } from 'react-dom/test-utils';\nimport { Provider } from 'urql';\nimport { makeSubject } from 'wonka';\nimport { MyComponent } from './MyComponent';\n\nconst { source: stream, next: pushResponse } = makeSubject();\n\nit('shows notification on updated data', () => {\n  const mockedClient = {\n    executeQuery: jest.fn(() => stream),\n  };\n\n  const wrapper = mount(\n    <Provider value={mockedClient}>\n      <MyComponent />\n    </Provider>\n  );\n\n  // First response\n  act(() => {\n    pushResponse({\n      data: {\n        posts: [{ id: 1, title: 'Post title', content: 'This is a post' }],\n      },\n    });\n  });\n  expect(wrapper.find('dialog').exists()).toBe(false);\n\n  // Second response\n  act(() => {\n    pushResponse({\n      data: {\n        posts: [\n          { id: 1, title: 'Post title', content: 'This is a post' },\n          { id: 1, title: 'Post title', content: 'This is a post' },\n        ],\n      },\n    });\n  });\n  expect(wrapper.find('dialog').exists()).toBe(true);\n});\n```\n"
  },
  {
    "path": "docs/api/README.md",
    "content": "---\ntitle: API\norder: 9\n---\n\n# API\n\n`urql` is a collection of multiple packages. You'll likely be using one of the framework bindings\npackage or exchange packages, which are all listed in this section.\n\nMost of these packages will refer to or use utilities and types from the `@urql/core` package. [Read\nmore about the core package on the \"Core\" page.](../basics/core.md)\n\n> **Note:** These API docs are deprecated as we now keep TSDocs in all published packages.\n> You can view TSDocs while using these packages in your editor, as long as it supports the\n> TypeScript Language Server.\n> We're planning to replace these API docs with a separate web app soon.\n\n- [`@urql/core` API docs](./core.md)\n- [`urql` React API docs](./urql.md)\n- [`@urql/preact` Preact API docs](./preact.md)\n- [`@urql/svelte` Svelte API docs](./svelte.md)\n- [`@urql/exchange-graphcache` API docs](./graphcache.md)\n- [`@urql/exchange-retry` API docs](./retry-exchange.md)\n- [`@urql/exchange-execute` API docs](./execute-exchange.md)\n- [`@urql/exchange-request-policy` API docs](./request-policy-exchange.md)\n- [`@urql/exchange-auth` API docs](./auth-exchange.md)\n- [`@urql/exchange-refocus` API docs](./refocus-exchange.md)\n"
  },
  {
    "path": "docs/api/auth-exchange.md",
    "content": "---\ntitle: '@urql/exchange-auth'\norder: 10\n---\n\n# Authentication Exchange\n\n> **Note:** These API docs are deprecated as we now keep TSDocs in all published packages.\n> You can view TSDocs while using these packages in your editor, as long as it supports the\n> TypeScript Language Server.\n> We're planning to replace these API docs with a separate web app soon.\n\nThe `@urql/exchange-auth` package contains an addon `authExchange` for `urql` that aims to make it\neasy to implement complex authentication and reauthentication flows as are typically found with JWT\ntoken based API authentication.\n\n## Installation and Setup\n\nFirst install `@urql/exchange-auth` alongside `urql`:\n\n```sh\nyarn add @urql/exchange-auth\n# or\nnpm install --save @urql/exchange-auth\n```\n\nYou'll then need to add the `authExchange`, that this package exposes to your `Client`. The\n`authExchange` is an asynchronous exchange, so it must be placed in front of all `fetchExchange`s\nbut after all other synchronous exchanges, like the `cacheExchange`.\n\n```js\nimport { createClient, cacheExchange, fetchExchange } from 'urql';\nimport { authExchange } from '@urql/exchange-auth';\n\nconst client = createClient({\n  url: 'http://localhost:3000/graphql',\n  exchanges: [\n    cacheExchange,\n    authExchange(async utils => {\n      return {\n        /* config... */\n      };\n    }),\n    fetchExchange,\n  ],\n});\n```\n\nThe `authExchange` accepts an initialization function. This function is called when your exchange\nand `Client` first start up, and must return an object of options wrapped in a `Promise`, which is\nused to configure how your authentication method works.\n\nYou can use this function to first retrieve your authentication state from a kind\nof local storage, or to call your API to validate your authentication state first.\n\nThe relevant configuration options, returned to the `authExchange`, then determine\nhow the `authExchange` behaves:\n\n- `addAuthToOperation` must be provided to tell `authExchange` how to add authentication information\n  to an operation, e.g. how to add the authentication state to an operation's fetch headers.\n- `willAuthError` may be provided to detect expired tokens or tell whether an operation will likely\n  fail due to an authentication error.\n- `didAuthError` may be provided to let the `authExchange` detect authentication errors from the\n  API on results.\n- `refreshAuth` is called when an authentication error occurs and gives you an opportunity to update\n  your authentication state. Afterwards, the `authExchange` will retry your operation.\n\n[Read more examples in the documentation given here.](../advanced/authentication.md)\n"
  },
  {
    "path": "docs/api/core.md",
    "content": "---\ntitle: '@urql/core'\norder: 0\n---\n\n# @urql/core\n\n> **Note:** These API docs are deprecated as we now keep TSDocs in all published packages.\n> You can view TSDocs while using these packages in your editor, as long as it supports the\n> TypeScript Language Server.\n> We're planning to replace these API docs with a separate web app soon.\n\nThe `@urql/core` package is the basis of all framework bindings. Each bindings-package,\nlike [`urql` for React](./urql.md) or [`@urql/preact`](./preact.md), will reuse the core logic and\nreexport all exports from `@urql/core`.\nTherefore if you're not accessing utilities directly, aren't in a Node.js environment, and are using\nframework bindings, you'll likely want to import from your framework bindings package directly.\n\n[Read more about `urql`'s core on the \"Core Package\" page.](../basics/core.md)\n\n## Client\n\nThe `Client` manages all operations and ongoing requests to the exchange pipeline.\nIt accepts several options on creation.\n\n`@urql/core` also exposes `createClient()` that is just a convenient alternative to calling `new Client()`.\n\n| Input             | Type                                        | Description                                                                                                                                                                                                                                                                                                    |\n| ----------------- | ------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |\n| `exchanges`       | `Exchange[]`                                | An array of `Exchange`s that the client should use                                                                                                                                                                                                                                                             |\n| `url`             | `string`                                    | The GraphQL API URL as used by `fetchExchange`                                                                                                                                                                                                                                                                 |\n| `fetchOptions`    | `RequestInit \\| () => RequestInit`          | Additional `fetchOptions` that `fetch` in `fetchExchange` should use to make a request                                                                                                                                                                                                                         |\n| `fetch`           | `typeof fetch`                              | An alternative implementation of `fetch` that will be used by the `fetchExchange` instead of `window.fetch`                                                                                                                                                                                                    |\n| `suspense`        | `?boolean`                                  | Activates the experimental React suspense mode, which can be used during server-side rendering to prefetch data                                                                                                                                                                                                |\n| `requestPolicy`   | `?RequestPolicy`                            | Changes the default request policy that will be used. By default, this will be `cache-first`.                                                                                                                                                                                                                  |\n| `preferGetMethod` | `?boolean \\| 'force' \\| 'within-url-limit'` | This is picked up by the `fetchExchange` and will force all queries (not mutations) to be sent using the HTTP GET method instead of POST if the length of the resulting URL doesn't exceed 2048 characters. When `'force'` is passed a GET request is always sent regardless of how long the resulting URL is. |\n\n### client.executeQuery\n\nAccepts a [`GraphQLRequest`](#graphqlrequest) and optionally `Partial<OperationContext>`, and returns a\n[`Source<OperationResult>`](#operationresult) — a stream of query results that can be subscribed to.\n\nInternally, subscribing to the returned source will create an [`Operation`](#operation), with\n`kind` set to `'query'`, and dispatch it on the\nexchanges pipeline. If no subscribers are listening to this operation anymore and unsubscribe from\nthe query sources, the `Client` will dispatch a \"teardown\" operation.\n\n- [Instead of using this method directly, you may want to use the `client.query` shortcut\n  instead.](#clientquery)\n- [See `createRequest` for a utility that creates `GraphQLRequest` objects.](#createrequest)\n\n### client.executeSubscription\n\nThis is functionally the same as `client.executeQuery`, but creates operations for subscriptions\ninstead, with `kind` set to `'subscription'`.\n\n### client.executeMutation\n\nThis is functionally the same as `client.executeQuery`, but creates operations for mutations\ninstead, with `kind` set to `'mutation'`.\n\nA mutation source is always guaranteed to only respond with a single [`OperationResult`](#operationresult) and then complete.\n\n### client.query\n\nThis is a shorthand method for [`client.executeQuery`](#clientexecutequery), which accepts a query\n(`DocumentNode | string`) and variables separately and creates a [`GraphQLRequest`](#graphqlrequest) [`createRequest`](#createrequest) automatically.\n\nThe returned `Source<OperationResult>` will also have an added `toPromise` method, so the stream can\nbe conveniently converted to a promise.\n\n```js\nimport { pipe, subscribe } from 'wonka';\n\nconst { unsubscribe } = pipe(\n  client.query('{ test }', {\n    /* vars */\n  }),\n  subscribe(result => {\n    console.log(result); // OperationResult\n  })\n);\n\n// or with toPromise, which also limits this to one result\nclient\n  .query('{ test }', {\n    /* vars */\n  })\n  .toPromise()\n  .then(result => {\n    console.log(result); // OperationResult\n  });\n```\n\n[Read more about how to use this API on the \"Core Package\"\npage.](../basics/core.md#one-off-queries-and-mutations)\n\n### client.mutation\n\nThis is similar to [`client.query`](#clientquery), but dispatches mutations instead.\n\n[Read more about how to use this API on the \"Core Package\"\npage.](../basics/core.md#one-off-queries-and-mutations)\n\n### client.subscription\n\nThis is similar to [`client.query`](#clientquery), but does not provide a `toPromise()` helper method on the streams it returns.\n\n[Read more about how to use this API on the \"Subscriptions\" page.](../advanced/subscriptions.md)\n\n### client.reexecuteOperation\n\nThis method is commonly used in _Exchanges_ to reexecute an [`Operation`](#operation) on the\n`Client`. It will only reexecute when there are still subscribers for the given\n[`Operation`](#operation).\n\nFor an example, this method is used by the `cacheExchange` when an\n[`OperationResult`](#operationresult) is invalidated in the cache and needs to be refetched.\n\n### client.readQuery\n\nThis method is typically used to read data synchronously from a cache. It returns an [`OperationResult`](#operationresult) if a value is returned immediately or `null` if no value is returned while cancelling all side effects.\n\n## CombinedError\n\nThe `CombinedError` is used in `urql` to normalize network errors and `GraphQLError`s if anything\ngoes wrong during a GraphQL request.\n\n| Input           | Type                             | Description                                                                        |\n| --------------- | -------------------------------- | ---------------------------------------------------------------------------------- |\n| `networkError`  | `?Error`                         | An unexpected error that might've occurred when trying to send the GraphQL request |\n| `graphQLErrors` | `?Array<string \\| GraphQLError>` | GraphQL Errors (if any) that were returned by the GraphQL API                      |\n| `response`      | `?any`                           | The raw response object (if any) from the `fetch` call                             |\n\n[Read more about errors in `urql` on the \"Error\" page.](../basics/errors.md)\n\n## Types\n\n### GraphQLRequest\n\nThis often comes up as the **input** for every GraphQL request.\nIt consists of `query` and optionally `variables`.\n\n| Prop        | Type           | Description                                                                                                           |\n| ----------- | -------------- | --------------------------------------------------------------------------------------------------------------------- |\n| `key`       | `number`       | A unique key that identifies this exact combination of `query` and `variables`, which is derived using a stable hash. |\n| `query`     | `DocumentNode` | The query to be executed. Accepts as a plain string query or GraphQL DocumentNode.                                    |\n| `variables` | `?object`      | The variables to be used with the GraphQL request.                                                                    |\n\nThe `key` property is a hash of both the `query` and the `variables`, to uniquely\nidentify the request. When `variables` are passed it is ensured that they're stably stringified so\nthat the same variables in a different order will result in the same `key`, since variables are\norder-independent in GraphQL.\n\n[A `GraphQLRequest` may be manually created using the `createRequest` helper.](#createrequest)\n\n### OperationType\n\nThis determines what _kind of operation_ the exchanges need to perform.\nThis is one of:\n\n- `'subscription'`\n- `'query'`\n- `'mutation'`\n- `'teardown'`\n\nThe `'teardown'` operation is special in that it instructs exchanges to cancel\nany ongoing operations with the same key as the `'teardown'` operation that is\nreceived.\n\n### Operation\n\nThe input for every exchange that informs GraphQL requests.\nIt extends the [`GraphQLRequest` type](#graphqlrequest) and contains these additional properties:\n\n| Prop      | Type               | Description                                   |\n| --------- | ------------------ | --------------------------------------------- |\n| `kind`    | `OperationType`    | The type of GraphQL operation being executed. |\n| `context` | `OperationContext` | Additional metadata passed to exchange.       |\n\nAn `Operation` also contains the `operationName` property, which is a deprecated alias of the `kind`\nproperty and outputs a deprecation warning if it's used.\n\n### RequestPolicy\n\nThis determines the strategy that a cache exchange should use to fulfill an operation.\nWhen you implement a custom cache exchange it's recommended that these policies are\nhandled.\n\n- `'cache-first'` (default)\n- `'cache-only'`\n- `'network-only'`\n- `'cache-and-network'`\n\n[Read more about request policies on the \"Document Caching\" page.](../basics/document-caching.md#request-policies)\n\n### OperationContext\n\nThe context often carries options or metadata for individual exchanges, but may also contain custom\ndata that can be passed from almost all API methods in `urql` that deal with\n[`Operation`s](#operation).\n\nSome of these options are set when the `Client` is initialised, so in the following list of\nproperties you'll likely see some options that exist on the `Client` as well.\n\n| Prop                  | Type                                        | Description                                                                                                                     |\n| --------------------- | ------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------- |\n| `fetchOptions`        | `?RequestInit \\| (() => RequestInit)`       | Additional `fetchOptions` that `fetch` in `fetchExchange` should use to make a request.                                         |\n| `fetch`               | `typeof fetch`                              | An alternative implementation of `fetch` that will be used by the `fetchExchange` instead of `window.fetch`                     |\n| `requestPolicy`       | `RequestPolicy`                             | An optional [request policy](../basics/document-caching.md#request-policies) that should be used specifying the cache strategy. |\n| `url`                 | `string`                                    | The GraphQL endpoint, when using GET you should use absolute url's                                                              |\n| `meta`                | `?OperationDebugMeta`                       | Metadata that is only available in development for devtools.                                                                    |\n| `suspense`            | `?boolean`                                  | Whether suspense is enabled.                                                                                                    |\n| `preferGetMethod`     | `?boolean \\| 'force' \\| 'within-url-limit'` | Instructs the `fetchExchange` to use HTTP GET for queries.                                                                      |\n| `additionalTypenames` | `?string[]`                                 | Allows you to tell the operation that it depends on certain typenames (used in document-cache.)                                 |\n\nIt also accepts additional, untyped parameters that can be used to send more\ninformation to custom exchanges.\n\n### OperationResult\n\nThe result of every GraphQL request, i.e. an `Operation`. It's very similar to what comes back from\na typical GraphQL API, but slightly enriched and normalized.\n\n| Prop         | Type                   | Description                                                                                                                                       |\n| ------------ | ---------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------- |\n| `operation`  | `Operation`            | The operation that this is a result for                                                                                                           |\n| `data`       | `?any`                 | Data returned by the specified query                                                                                                              |\n| `error`      | `?CombinedError`       | A [`CombinedError`](#combinederror) instances that wraps network or `GraphQLError`s (if any)                                                      |\n| `extensions` | `?Record<string, any>` | Extensions that the GraphQL server may have returned.                                                                                             |\n| `stale`      | `?boolean`             | A flag that may be set to `true` by exchanges to indicate that the `data` is incomplete or out-of-date, and that the result will be updated soon. |\n\n### ExchangeInput\n\nThis is the input that an [`Exchange`](#exchange) receives when it's initialized by the\n[`Client`](#client)\n\n| Input     | Type         | Description                                                                                                             |\n| --------- | ------------ | ----------------------------------------------------------------------------------------------------------------------- |\n| `forward` | `ExchangeIO` | The unction responsible for receiving an observable operation and returning a result                                    |\n| `client`  | `Client`     | The urql application-wide client library. Each execute method starts a GraphQL request and returns a stream of results. |\n\n### Exchange\n\nAn exchange represents abstractions of small chunks of logic in `urql`.\nThey're small building blocks and similar to \"middleware\".\n\n[Read more about _Exchanges_ on the \"Authoring Exchanges\" page.](../advanced/authoring-exchanges.md)\n\nAn exchange is defined to be a function that receives [`ExchangeInput`](#exchangeinput) and returns\nan `ExchangeIO` function. The `ExchangeIO` function in turn will receive a stream of operations, and\nmust return a stream of results. If the exchange is purely transforming data, like the\n`mapExchange` for instance, it'll call `forward`, which is the next Exchange's `ExchangeIO`\nfunction to get a stream of results.\n\n```js\ntype ExchangeIO = (Source<Operation>) => Source<OperationResult>;\ntype Exchange = ExchangeInput => ExchangeIO;\n```\n\n[If you haven't yet seen streams you can read more about \"Stream Patterns\" on the \"Architecture\"\npage.](../architecture.md)\n\n## Exchanges\n\n### cacheExchange\n\nThe `cacheExchange` as [described on the \"Document Caching\" page.](../basics/document-caching.md). It's of type `Exchange`.\n\n### subscriptionExchange\n\nThe `subscriptionExchange` as [described on the \"Subscriptions\" page.](../advanced/subscriptions.md). It's of type `Options => Exchange`.\n\nIt accepts a single input: `{ forwardSubscription }`. This is a function that\nreceives an enriched operation and must return an Observable-like object that\nstreams `GraphQLResult`s with `data` and `errors`.\n\nThe `forwardSubscription` function is commonly connected to the [`subscriptions-transport-ws`\npackage](https://github.com/apollographql/subscriptions-transport-ws).\n\n### ssrExchange\n\nThe `ssrExchange` as [described on the \"Server-side Rendering\"\npage.](../advanced/server-side-rendering.md).\nIt's of type `Options => Exchange`.\n\nIt accepts three inputs, `initialState` which is completely\noptional and populates the server-side rendered data with\na rehydrated cache, `isClient` which can be set to\n`true` or `false` to tell the `ssrExchange` whether to\nwrite to (server-side) or read from (client-side) the cache, and\n`staleWhileRevalidate` which will treat rehydrated data as stale\nand refetch up-to-date data by reexecuring the operation using a `network-only` requests policy.\n\nBy default, `isClient` defaults to `true` when the `Client.suspense`\nmode is disabled and to `false` when the `Client.suspense` mode\nis enabled.\n\nThis can be used to extract data that has been queried on\nthe server-side, which is also described in the Basics section,\nand is also used on the client-side to restore server-side\nrendered data.\n\nWhen called, this function creates an `Exchange`, which also has\ntwo methods on it:\n\n- `.restoreData(data)` which can be used to inject data, typically\n  on the client-side.\n- `.extractData()` which is typically used on the server-side to\n  extract the server-side rendered data.\n\nBasically, the `ssrExchange` is a small cache that collects data\nduring the server-side rendering pass, and allows you to populate\nthe cache on the client-side with the same data.\n\nDuring React rehydration this cache will be emptied, and it will\nbecome inactive and won't change the results of queries after\nrehydration.\n\nIt needs to be used _after_ other caching Exchanges like the\n`cacheExchange`, but before any _asynchronous_ Exchange like\nthe `fetchExchange`.\n\n### debugExchange\n\nAn exchange that writes incoming `Operation`s to `console.log` and\nwrites completed `OperationResult`s to `console.log`.\n\nThis exchange is disabled in production and is based on the `mapExchange`.\nIf you'd like to customise it, you can replace it with a custom `mapExchange`.\n\n### fetchExchange\n\nThe `fetchExchange` of type `Exchange` is responsible for sending operations of type `'query'` and\n`'mutation'` to a GraphQL API using `fetch`.\n\n### mapExchange\n\nThe `mapExchange` allows you to:\n\n- react to or replace operations with `onOperation`,\n- react to or replace results with `onResult`,\n- and; react to errors in results with `onError`.\n\nIt can therefore be used to quickly react to the core events in the `Client` without writing a custom\nexchange, effectively allowing you to ship your own `debugExchange`.\n\n```ts\nmapExchange({\n  onOperation(operation) {\n    console.log('operation', operation);\n  },\n  onResult(result) {\n    console.log('result', result);\n  },\n});\n```\n\nIt can also be used to react only to errors, which is the same as checking for `result.error`:\n\n```ts\nmapExchange({\n  onError(error, operation) {\n    console.log(`The operation ${operation.key} has errored with:`, error);\n  },\n});\n```\n\nLastly, it can be used to map operations and results, which may be useful to update the\n`OperationContext` or perform other standard tasks that require you to wait for a result:\n\n```ts\nimport { mapExchange, makeOperation } from '@urql/core';\n\nmapExchange({\n  async onOperation(operation) {\n    // NOTE: This is only for illustration purposes\n    return makeOperation(operation.kind, operation, {\n      ...operation.context,\n      test: true,\n    });\n  },\n  async onResult(result) {\n    // NOTE: This is only for illustration purposes\n    if (result.data === undefined) result.data = null;\n    return result;\n  },\n});\n```\n\n### errorExchange (deprecated)\n\nAn exchange that lets you inspect errors. This can be useful for logging, or reacting to\ndifferent types of errors (e.g. logging the user out in case of a permission error).\n\nIn newer versions of `@urql/core`, it's identical to the `mapExchange` and its export has been\nreplaced as the `mapExchange` also allows you to pass an `onError` function.\n\n## Utilities\n\n### gql\n\nThis is a `gql` tagged template literal function, similar to the one that's also commonly known from\n`graphql-tag`. It can be used to write GraphQL documents in a tagged template literal and returns a\nparsed `DocumentNode` that's primed against the `createRequest`'s cache for `key`s.\n\n```js\nimport { gql } from '@urql/core';\n\nconst SharedFragment = gql`\n  fragment UserFrag on User {\n    id\n    name\n  }\n`;\n\ngql`\n  query {\n    user\n    ...UserFrag\n  }\n\n  ${SharedFragment}\n`;\n```\n\nUnlike `graphql-tag`, this function outputs a warning in development when names of fragments in the\ndocument are duplicated. It does not output warnings when fragment names were duplicated globally\nhowever.\n\n### stringifyVariables\n\nThis function is a variation of `JSON.stringify` that sorts any object's keys that is being\nstringified to ensure that two objects with a different order of keys will be stably stringified to\nthe same string.\n\n```js\nstringifyVariables({ a: 1, b: 2 }); // {\"a\":1,\"b\":2}\nstringifyVariables({ b: 2, a: 1 }); // {\"a\":1,\"b\":2}\n```\n\n### createRequest\n\nThis utility accepts a GraphQL query of type `string | DocumentNode` and optionally an object of\nvariables, and returns a [`GraphQLRequest` object](#graphqlrequest).\n\nSince the [`client.executeQuery`](#clientexecutequery) and other execute methods only accept\n[`GraphQLRequest`s](#graphqlrequest), this helper is commonly used to create that request first. The\n[`client.query`](#clientquery) and [`client.mutation`](#clientmutation) methods use this helper as\nwell to create requests.\n\nThe helper takes care of creating a unique `key` for the `GraphQLRequest`. This is a hash of the\n`query` and `variables` if they're passed. The `variables` will be stringified using\n[`stringifyVariables`](#stringifyvariables), which outputs a stable JSON string.\n\nAdditionally, this utility will ensure that the `query` reference will remain stable. This means\nthat if the same `query` will be passed in as a string or as a fresh `DocumentNode`, then the output\nwill always have the same `DocumentNode` reference.\n\n### makeOperation\n\nThis utility is used to either turn a [`GraphQLRequest` object](#graphqlrequest) into a new\n[`Operation` object](#operation) or to copy an `Operation`. It adds the `kind` property, and the\n`operationName` alias that outputs a deprecation warning.\n\nIt accepts three arguments:\n\n- An `Operation`'s `kind` (See [`OperationType`](#operationtype)\n- A [`GraphQLRequest` object](#graphqlrequest) or another [`Operation`](#operation) that should be\n  copied.\n- and; optionally a [partial `OperationContext` object.](#operationcontext). This argument may be\n  left out if the context is to be copied from the operation that may be passed as a second argument.\n\nHence some valid uses of the utility are:\n\n```js\n// Create a new operation from scratch\nmakeOperation('query', createRequest(query, variables), client.createOperationContext(opts));\n\n// Turn an operation into a 'teardown' operation\nmakeOperation('teardown', operation);\n\n// Copy an existing operation while modifying its context\nmakeOperation(operation.kind, operation, {\n  ...operation.context,\n  preferGetMethod: true,\n});\n```\n\n### makeResult\n\nThis is a helper function that converts a GraphQL API result to an\n[`OperationResult`](#operationresult).\n\nIt accepts an [`Operation`](#operation), the API result, and optionally the original `FetchResponse`\nfor debugging as arguments, in that order.\n\n### makeErrorResult\n\nThis is a helper function that creates an [`OperationResult`](#operationresult) for GraphQL API\nrequests that failed with a generic or network error.\n\nIt accepts an [`Operation`](#operation), the error, and optionally the original `FetchResponse`\nfor debugging as arguments, in that order.\n\n### formatDocument\n\nThis utility is used by the [`cacheExchange`](#cacheexchange) and by\n[Graphcache](../graphcache/README.md) to add `__typename` fields to GraphQL `DocumentNode`s.\n\n### composeExchanges\n\nThis utility accepts an array of `Exchange`s and composes them into a single one.\nIt chains them in the order that they're given, left to right.\n\n```js\nfunction composeExchanges(Exchange[]): Exchange;\n```\n\nThis can be used to combine some exchanges and is also used by [`Client`](#client)\nto handle the `exchanges` input.\n"
  },
  {
    "path": "docs/api/execute-exchange.md",
    "content": "---\ntitle: '@urql/exchange-execute'\norder: 6\n---\n\n# Execute Exchange\n\n> **Note:** These API docs are deprecated as we now keep TSDocs in all published packages.\n> You can view TSDocs while using these packages in your editor, as long as it supports the\n> TypeScript Language Server.\n> We're planning to replace these API docs with a separate web app soon.\n\nThe `@urql/exchange-execute` package contains an addon `executeExchange` for `urql` that may be used to\nexecute queries against a local schema. It is therefore a drop-in replacement for the default\n_fetchExchange_ and useful for the server-side, debugging, or testing.\n\n## Installation and Setup\n\nFirst install `@urql/exchange-execute` alongside `urql`:\n\n```sh\nyarn add @urql/exchange-execute\n# or\nnpm install --save @urql/exchange-execute\n```\n\nYou'll then need to add the `executeExchange`, exposed by this package, to your `Client`.\nIt'll typically replace the `fetchExchange` or similar exchanges and must be used last if possible,\nsince it'll handle operations and return results.\n\n```js\nimport { createClient, cacheExchange } from 'urql';\nimport { executeExchange } from '@urql/exchange-execute';\n\nconst client = createClient({\n  url: 'http://localhost:3000/graphql',\n  exchanges: [\n    cacheExchange,\n    executeExchange({\n      /* config */\n    }),\n  ],\n});\n```\n\nThe `executeExchange` accepts an object of options, which are all similar to the arguments that\n`graphql/execution/execute` accepts. Typically you'd pass it the `schema` option, some resolvers\nif your schema isn't already executable as `fieldResolver` / `typeResolver` / `rootValue`,\nand a `context` value or function.\n\n## Options\n\n| Option          | Description                                                                                                                                                                                                                                      |\n| --------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |\n| `schema`        | This is of type `GraphQLSchema` and accepts either a schema that is or isn't executable. This field is _required_ while all other fields are _optional_.                                                                                         |\n| `rootValue`     | The root value that `graphql`'s `execute` will use when starting to execute the schema.                                                                                                                                                          |\n| `fieldResolver` | A given field resolver function. Creating an executable schema may be easier than providing this, but this resolver will be passed on to `execute` as expected.                                                                                  |\n| `typeResolver`  | A given type resolver function. Creating an executable schema may be easier than providing this, but this resolver will be passed on to `execute` as expected.                                                                                   |\n| `context`       | This may either be a function that receives an [`Operation`](./core.md#operation) and returns the context value, or just a plain context value. Similarly to a GraphQL server this is useful as all resolvers will have access to your `context` |\n"
  },
  {
    "path": "docs/api/graphcache.md",
    "content": "---\ntitle: '@urql/exchange-graphcache'\norder: 4\n---\n\n# @urql/exchange-graphcache\n\n> **Note:** These API docs are deprecated as we now keep TSDocs in all published packages.\n> You can view TSDocs while using these packages in your editor, as long as it supports the\n> TypeScript Language Server.\n> We're planning to replace these API docs with a separate web app soon.\n\nThe `@urql/exchange-graphcache` package contains an addon `cacheExchange` for `urql` that may be\nused to replace the default [`cacheExchange`](./core.md#cacheexchange), which switches `urql` from\nusing [\"Document Caching\"](../basics/document-caching.md) to [\"Normalized\nCaching\"](../graphcache/normalized-caching.md).\n\n[Read more about how to use and configure _Graphcache_ in the \"Graphcache\"\nsection](../graphcache/README.md)\n\n## cacheExchange\n\nThe `cacheExchange` function, as exported by `@urql/exchange-graphcache`, accepts a single object of\noptions and returns an [`Exchange`](./core.md#exchange).\n\n| Input        | Description                                                                                                                                                                                                                   |\n| ------------ | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |\n| `keys`       | A mapping of key generator functions for types that are used to override the default key generation that _Graphcache_ uses to normalize data for given types.                                                                 |\n| `resolvers`  | A nested mapping of resolvers, which are used to override the record or entity that _Graphcache_ resolves for a given field for a type.                                                                                       |\n| `directives` | A mapping of directives, which are functions accepting directive arguments and returning a resolver, which can be referenced by `@localDirective` or `@_localDirective` in queries.                                           |\n| `updates`    | A nested mapping of updater functions for mutation and subscription fields, which may be used to add side-effects that update other parts of the cache when the given subscription or mutation field is written to the cache. |\n| `optimistic` | A mapping of mutation fields to resolvers that may be used to provide _Graphcache_ with an optimistic result for a given mutation field that should be applied to the cached data temporarily.                                |\n| `schema`     | A serialized GraphQL schema that is used by _Graphcache_ to resolve partial data, interfaces, and enums. The schema also used to provide helpful warnings for [schema awareness](../graphcache/schema-awareness.md).          |\n| `storage`    | A persisted storage interface that may be provided to preserve cache data for [offline support](../graphcache/offline.md).                                                                                                    |\n| `globalIDs`  | A boolean or list of typenames that have globally unique ids, this changes how graphcache internally keys the entities. This can be useful for complex interface relationships.                                               |\n| `logger`     | A function that will be invoked for warning/debug/... logs                                                                                                                                                                    |\n\nThe `@urql/exchange-graphcache` package also exports the `offlineExchange`; which is identical to\nthe `cacheExchange` but activates [offline support](../graphcache/offline.md) when the `storage` option is passed.\n\n### `keys` option\n\nThis is a mapping of typenames to `KeyGenerator` functions.\n\n```ts\ninterface KeyingConfig {\n  [typename: string]: (data: Data) => null | string;\n}\n```\n\nIt may be used to alter how _Graphcache_ generates the key it uses for normalization for individual\ntypes. The key generator function may also always return `null` when a type should always be\nembedded.\n\n[Read more about how to set up `keys` in the \"Key Generation\" section of the \"Normalized Caching\"\npage.](../graphcache/normalized-caching.md#key-generation)\n\n### `resolvers` option\n\nThis configuration is a mapping of typenames to field names to `Resolver` functions.\nA resolver may be defined to override the entity or record that a given field on a type should\nresolve on the cache.\n\n```ts\ninterface ResolverConfig {\n  [typeName: string]: {\n    [fieldName: string]: Resolver;\n  };\n}\n```\n\nA `Resolver` receives four arguments when it's called: `parent`, `args`, `cache`, and\n`info`.\n\n| Argument | Type     | Description                                                                                                 |\n| -------- | -------- | ----------------------------------------------------------------------------------------------------------- |\n| `parent` | `Data`   | The parent entity that the given field is on.                                                               |\n| `args`   | `object` | The arguments for the given field the updater is executed on.                                               |\n| `cache`  | `Cache`  | The cache using which data can be read or written. [See `Cache`.](#cache)                                   |\n| `info`   | `Info`   | Additional metadata and information about the current operation and the current field. [See `Info`.](#info) |\n\nWe can use the arguments it receives to either return new data based on just the arguments and other\ncache information, but we may also read information about the parent and return new data for the\ncurrent field.\n\n```js\n{\n  Todo: {\n    createdAt(parent, args, cache) {\n      // Read `createdAt` on the parent but return a Date instance\n      const date = cache.resolve(parent, 'createdAt');\n      return new Date(date);\n    }\n  }\n}\n```\n\n[Read more about how to set up `resolvers` on the \"Computed Queries\"\npage.](../graphcache/local-resolvers.md)\n\n### `updates` option\n\nThe `updates` configuration is a mapping of `'Mutation' | 'Subscription'` to field names to\n`UpdateResolver` functions. An update resolver may be defined to add side-effects that run when a\ngiven mutation field or subscription field is written to the cache. These side-effects are helpful\nto update data in the cache that is implicitly changed on the GraphQL API, that _Graphcache_ can't\nknow about automatically.\n\nFor mutation fields that don't have an updater, Graphcache has a fallback: if a returned entity\nisn't currently found in the cache, it assumes a create-mutation and invalidates cached\nentities of that type. This behavior was introduced in Graphcache v7 and is skipped once an updater\nfor the mutation field is added.\n\n```ts\ninterface UpdatesConfig {\n  Mutation: {\n    [fieldName: string]: UpdateResolver;\n  };\n  Subscription: {\n    [fieldName: string]: UpdateResolver;\n  };\n}\n```\n\nAn `UpdateResolver` receives four arguments when it's called: `result`, `args`, `cache`, and\n`info`.\n\n| Argument | Type     | Description                                                                                                 |\n| -------- | -------- | ----------------------------------------------------------------------------------------------------------- |\n| `result` | `any`    | Always the entire `data` object from the mutation or subscription.                                          |\n| `args`   | `object` | The arguments for the given field the updater is executed on.                                               |\n| `cache`  | `Cache`  | The cache using which data can be read or written. [See `Cache`.](#cache)                                   |\n| `info`   | `Info`   | Additional metadata and information about the current operation and the current field. [See `Info`.](#info) |\n\nIt's possible to derive more information about the current update using the `info` argument. For\ninstance this metadata contains the current `fieldName` of the updater which may be used to make an\nupdater function more reusable, along with `parentKey` and other key fields. It also contains\n`variables` and `fragments` which remain the same for the entire write operation, and additionally\nit may have the `error` field set to describe whether the current field is `null` because the API\nencountered a `GraphQLError`.\n\n[Read more about how to set up `updates` on the \"Custom Updates\"\npage.](../graphcache/cache-updates.md)\n\n### `optimistic` option\n\nThe `optimistic` configuration is a mapping of Mutation field names to `OptimisticMutationResolver`\nfunctions, which return optimistic mutation results for given fields. These results are used by\n_Graphcache_ to optimistically update the cache data, which provides an immediate and temporary\nchange to its data before a mutation completes.\n\n```ts\ninterface OptimisticMutationConfig {\n  [mutationFieldName: string]: OptimisticMutationResolver;\n}\n```\n\nA `OptimisticMutationResolver` receives three arguments when it's called: `variables`, `cache`, and\n`info`.\n\n| Argument | Type     | Description                                                                                                 |\n| -------- | -------- | ----------------------------------------------------------------------------------------------------------- |\n| `args`   | `object` | The arguments that the given mutation field received.                                                       |\n| `cache`  | `Cache`  | The cache using which data can be read or written. [See `Cache`.](#cache)                                   |\n| `info`   | `Info`   | Additional metadata and information about the current operation and the current field. [See `Info`.](#info) |\n\n[Read more about how to set up `optimistic` on the \"Custom Updates\"\npage.](../graphcache/cache-updates.md)\n\n### `schema` option\n\nThe `schema` option may be used to pass a `IntrospectionQuery` data to _Graphcache_, in other words\nit's used to provide schema information to it. This schema is then used to resolve and return\npartial results when querying, which are results that the cache can partially resolve as long as no\nrequired fields are missing.\n\n[Read more about how to use the `schema` option on the \"Schema Awareness\"\npage.](../graphcache/schema-awareness.md)\n\n### `storage` option\n\nThe `storage` option is an interface of methods that are used by the `offlineExchange` to persist\nthe cache's data to persisted storage on the user's device. it\n\n> **NOTE:** Offline Support is currently experimental! It hasn't been extensively tested yet and\n> may not always behave as expected. Please try it out with caution!\n\n| Method            | Type                                          | Description                                                                                                                                                                            |\n| ----------------- | --------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |\n| `writeData`       | `(delta: SerializedEntries) => Promise<void>` | This provided method must be able to accept an object of key-value entries that will be persisted to the storage. This method is called as a batch of updated entries becomes ready.   |\n| `readData`        | `() => Promise<SerializedEntries>`            | This provided method must be able to return a single combined object of previous key-value entries that have been previously preserved using `writeData`. It's only called on startup. |\n| `writeMetadata`   | `(json: SerializedRequest[]) => void`         | This provided method must be able to persist metadata for the cache. For backwards compatibility it should be able to accept any JSON data.                                            |\n| `readMetadata`    | `() => Promise<null \\| SerializedRequest[]>`  | This provided method must be able to read the persisted metadata that has previously been written using `writeMetadata`. It's only called on startup.                                  |\n| `onOnline`        | `(cb: () => void) => void`                    | This method must be able to accept a callback that is called when the user's device comes back online.                                                                                 |\n| `onCacheHydrated` | `() => void`                                  | This method will be called when the `cacheExchange` has finished hydrating the data coming from storage.                                                                               |\n\nThese options are split into three parts:\n\n- The `writeMetadata` and `readMetadata` methods are used to persist in-progress optimistic\n  mutations to a storage so that they may be retried if the app has been closed while some\n  optimistic mutations were still in progress.\n- The `writeData` and `readData` methods are used to persist any cache data. This is the normalized\n  data that _Graphcache_ usually keeps in memory. The `cacheExchange` will frequently call\n  `writeData` with a partial object of its cache data, which `readData` must then be able to return\n  in a single combined object on startup. We call the partial objects that `writeData` is called\n  with \"deltas\".\n- The `onOnline` method is only used to receive a trigger that determines whether the user's device\n  has come back online, which is used to retry optimistic mutations that have previously failed due\n  to being offline.\n\nThe `storage` option may also be used with the `cacheExchange` instead of the `offlineExchange`, but\nwill then only use `readData` and `writeData` to persist its cache data. This is not full offline\nsupport, but will rather be \"persistence support\".\n\n[Read more about how to use the `storage` option on the \"Offline Support\"\npage.](../graphcache/offline.md)\n\n## Cache\n\nAn instance of the `Cache` interface is passed to every resolvers and updater function. It may be\nused to read cached data or write cached data, which may be used in combination with the\n[`cacheExchange` configuration](#cacheexchange) to alter the default behaviour of _Graphcache_.\n\n### keyOfEntity\n\nThe `cache.keyOfEntity` method may be called with a partial `Data` object and will return the key\nfor that object, or `null` if it's not keyable.\n\nAn object may not be keyable if it's missing the `__typename` or `id` (which falls back to `_id`)\nfields. This method does take the [`keys` configuration](#keys-option) into account.\n\n```js\ncache.keyOfEntity({ __typename: 'Todo', id: 1 }); // 'Todo:1'\ncache.keyOfEntity({ __typename: 'Query' }); // 'Query'\ncache.keyOfEntity({ __typename: 'Unknown' }); // null\n```\n\nThere's an alternative method, `cache.keyOfField` which generates a key for a given field. This is\nonly rarely needed but similar to `cache.keyOfEntity`. This method accepts a field name and\noptionally a field's arguments.\n\n```js\ncache.keyOfField('todo'); // 'todo'\ncache.keyOfField('todo', { id: 1 }); // 'todo({\"id\":1})'\n```\n\nInternally, these are the keys that records and links are stored on per entity.\n\n### resolve\n\nThis method retrieves a value or link for a given field, given a partially keyable `Data` object or\nentity, a field name, and optionally the field's arguments. Internally this method accesses the\ncache by using `cache.keyOfEntity` and `cache.keyOfField`.\n\n```js\n// This may resolve a link:\ncache.resolve({ __typename: 'Query' }, 'todo', { id: 1 }); // 'Todo:1'\n\n// This may also resolve records / scalar values:\ncache.resolve({ __typename: 'Todo', id: 1 }, 'id'); // 1\n\n// You can also chain multiple calls to `cache.resolve`!\ncache.resolve(cache.resolve({ __typename: 'Query' }, 'todo', { id: 1 }), 'id'); // 1\n```\n\nAs you can see in the last example of this code snippet, the `Data` object can also be replaced by\nan entity key, which makes it possible to pass a key from `cache.keyOfEntity` or another call to\n`cache.resolve` instead of the partial entity.\n\n> **Note:** Because `cache.resolve` may return either a scalar value or another entity key, it may\n> be dangerous to use in some cases. It's a good idea to make sure first whether the field you're\n> reading will be a key or a value.\n\nThe `cache.resolve` method may also be called with a field key as generated by `cache.keyOfField`.\n\n```js\ncache.resolve({ __typename: 'Query' }, cache.keyOfField('todo', { id: 1 })); // 'Todo:1'\n```\n\nThis specialized case is likely only going to be useful in combination with\n[`cache.inspectFields`](#inspectfields).\n\n### inspectFields\n\nThe `cache.inspectFields` method may be used to interrogate the cache about all available fields on\na specific entity. It accepts a partial entity or an entity key, like [`cache.resolve`](#resolve)'s\nfirst argument.\n\nWhen calling the method this returns an array of `FieldInfo` objects, one per field (including\ndiffering arguments) that is known to the cache. The `FieldInfo` interface has three properties:\n`fieldKey`, `fieldName`, and `arguments`:\n\n| Argument    | Type             | Description                                                                     |\n| ----------- | ---------------- | ------------------------------------------------------------------------------- |\n| `fieldName` | `string`         | The field's name (without any arguments, just the name)                         |\n| `arguments` | `object \\| null` | The field's arguments, or `null` if the field doesn't have any arguments        |\n| `fieldKey`  | `string`         | The field's cache key, which is similar to what `cache.keyOfField` would return |\n\nThis works on any given entity. When calling this method the cache works in reverse on its data\nstructure, by parsing the entity's individual field keys.\np\n\n```js\ncache.inspectFields({ __typename: 'Query' });\n\n/*\n  [\n    { fieldName: 'todo', arguments: { id: 1 }, fieldKey: 'id({\"id\":1})' },\n    { fieldName: 'todo', arguments: { id: 2 }, fieldKey: 'id({\"id\":2})' },\n    ...\n  ]\n*/\n```\n\n### readFragment\n\n`cache.readFragment` accepts a GraphQL `DocumentNode` as the first argument and a partial entity or\nan entity key as the second, like [`cache.resolve`](#resolve)'s first argument.\n\nThe method will then attempt to read the entity according to the fragment entirely from the cached\ndata. If any data is uncached and missing it'll return `null`.\n\n```js\nimport { gql } from '@urql/core';\n\ncache.readFragment(\n  gql`\n    fragment _ on Todo {\n      id\n      text\n    }\n  `,\n  { id: 1 }\n); // Data or null\n```\n\nNote that the `__typename` may be left out on the partial entity if the fragment isn't on an\ninterface or union type, since in that case the `__typename` is already present on the fragment\nitself.\n\nIf any fields on the fragment require variables, you can pass them as the third argument like so:\n\n```js\nimport { gql } from '@urql/core';\n\ncache.readFragment(\n  gql`\n    fragment _ on User {\n      id\n      permissions(byGroupId: $groupId)\n    }\n  `,\n  { id: 1 }, // this identifies the fragment (User) entity\n  { groupId: 5 } // any additional field variables\n);\n```\n\nIf you need a specific fragment in a document containing multiple you can leverage\nthe fourth argument like this:\n\n```js\nimport { gql } from '@urql/core';\n\ncache.readFragment(\n  gql`\n    fragment todoFields on Todo {\n      id\n    }\n\n    fragment userFields on User {\n      id\n    }\n  `,\n  { id: 1 }, // this identifies the fragment (User) entity\n  undefined,\n  'userFields' // if not passed we take the first fragment, in this case todoFields\n);\n```\n\n[Read more about using `readFragment` on the [\"Local Resolvers\"\npage.](../graphcache/local-resolvers.md#reading-a-fragment)\n\n### readQuery\n\nThe `cache.readQuery` method is similar to `cache.readFragment`, but instead of reading a fragment\nfrom cache, it reads an entire query. The only difference between how these two methods are used is\n`cache.readQuery`'s input, which is an object instead of two arguments.\n\nThe method accepts a `{ query, variables }` object as the first argument, where `query` may either\nbe a `DocumentNode` or a `string` and variables may optionally be an object.\n\n```js\ncache.readQuery({\n  query: `\n    query ($id: ID!) {\n      todo(id: $id) { id, text }\n    }\n  `,\n  variables: {\n    id: 1\n  }\n); // Data or null\n```\n\n[Read more about using `readQuery` on the [\"Local Resolvers\"\npage.](../graphcache/local-resolvers.md#reading-a-query)\n\n### link\n\nCorresponding to [`cache.resolve`](#resolve), the `cache.link` method allows\nlinks in the cache to be updated. While the `cache.resolve` method reads both\nrecords and links from the cache, the `cache.link` method will only ever write\nlinks as fragments (See [`cache.writeFragment`](#writefragment) below) are more\nsuitable for updating scalar data in the cache.\n\nThe arguments for `cache.link` are identical to [`cache.resolve`](#resolve) and\nthe field's arguments are optional. However, the last argument must always be\na link, meaning `null`, an entity key, a keyable entity, or a list of these.\n\nIn other words, `cache.link` accepts an entity to write to as its first argument,\nwith the same arguments as `cache.keyOfEntity`. It then accepts one or two arguments\nthat are passed to `cache.keyOfField` to get the targeted field key. And lastly,\nyou may pass a list or a single entity (or an entity key).\n\n```js\n// Link Query.todo field to a todo item\ncache.link({ __typename: 'Query' }, 'todo', { __typename: 'Todo', id: 1 });\n\n// You may also pass arguments instead:\ncache.link({ __typename: 'Query' }, 'todo', { id: 1 }, { __typename: 'Todo', id: 1 });\n\n// Or use entity keys instead of the entities themselves:\ncache.link('Query', 'todo', cache.keyOfEntity({ __typename: 'Todo', id: 1 }));\n```\n\nThe method may [output a\nwarning](../graphcache/errors.md#12-cant-generate-a-key-for-writefragment-or-link) when any of the\nentities were passed as objects but aren't keyable, which is useful when a scalar or a non-keyable\nobject have been passed to `cache.link` accidentally.\n\n### writeFragment\n\nCorresponding to [`cache.readFragment`](#readfragments), the `cache.writeFragment` method allows\ndata in the cache to be updated.\n\nThe arguments for `cache.writeFragment` are identical to [`cache.readFragment`](#readfragment),\nhowever the second argument, `data`, should not only contain properties that are necessary to derive\nan entity key from the given data, but also the fields that will be written:\n\n```js\nimport { gql } from '@urql/core';\n\ncache.writeFragment(\n  gql`\n    fragment _ on Todo {\n      text\n    }\n  `,\n  { id: 1, text: 'New Todo Text' }\n);\n```\n\nIn the example we can see that the `writeFragment` method returns `undefined`. Furthermore we pass\n`id` in our `data` object so that an entity key can be written, but the fragment itself doesn't have\nto include these fields.\n\nIf you need a specific fragment in a document containing multiple you can leverage\nthe fourth argument like this:\n\n```js\nimport { gql } from '@urql/core';\n\ncache.writeFragment(\n  gql`\n    fragment todoFields on Todo {\n      id\n      text\n    }\n\n    fragment userFields on User {\n      id\n      name\n    }\n  `,\n  { id: 1, name: 'New Name' }\n  undefined,\n  'userFields' // if not passed we take the first fragment, in this case todoFields\n);\n```\n\n[Read more about using `writeFragment` on the [\"Custom Updates\"\npage.](../graphcache/cache-updates.md#cachewritefragment)\n\n### updateQuery\n\nSimilarly to [`cache.writeFragment`](#writefragment), there's an analogous method for\n[`cache.readQuery`](#readquery) that may be used to update query data.\n\nThe `cache.updateQuery` method accepts the same `{ query, variables }` object input as its first\nargument, which is the query we'd like to write to the cache. As a second argument the method\naccepts an updater function. This function will be called with the query data that is already in the\ncache (which may be `null` if the data is uncached) and must return the new data that should be\nwritten to the cache.\n\n```js\nconst TodoQuery = `\n  query ($id: ID!) {\n    todo(id: $id) { id, text }\n  }\n`;\n\ncache.updateQuery({ query: TodoQuery, variables: { id: 1 } }, data => {\n  if (!data) return null;\n  data.todo.text = 'New Todo Text';\n  return data;\n});\n```\n\nAs we can see, our updater may return `null` to cancel updating any data, which we do in case the\nquery data is uncached.\n\nWe can also see that data can simply be mutated and doesn't have to be altered immutably. This is\nbecause all data from the cache is already a deep copy and hence we can do to it whatever we want.\n\n[Read more about using `updateQuery` on the \"Custom Updates\"\npage.](../graphcache/cache-updates.md#cacheupdatequery)\n\n### invalidate\n\nThe `cache.invalidate` method can be used to delete (i.e. \"evict\") an entity from the cache\nentirely. This will cause it to disappear from all queries in _Graphcache_.\n\nIts arguments are identical to [`cache.resolve`](#resolve).\n\nSince deleting an entity will lead to some queries containing missing and uncached data, calling\n`invalidate` may lead to additional GraphQL requests being sent, unless you're using [_Graphcache_'s\n\"Schema Awareness\" feature](../graphcache/schema-awareness.md), which takes optional fields into\naccount.\n\nThis method accepts a partial entity or an entity key as its first argument, similar to\n[`cache.resolve`](#resolve)'s first argument.\n\n```js\ncache.invalidate({ __typename: 'Todo', id: 1 }); // Invalidates Todo:1\n```\n\nAdditionally `cache.invalidate` may be used to delete specific fields only, which can be useful when\nfor instance a list is supposed to be evicted from cache, where a full invalidation may be\nimpossible. This is often the case when a field on the root `Query` needs to be deleted.\n\nThis method therefore accepts two additional arguments, similar to [`cache.resolve`](#resolve).\n\n```js\n// Invalidates `Query.todos` with the `first: 10` argument:\ncache.invalidate('Query', 'todos', { first: 10 });\n```\n\n## Info\n\nThis is a metadata object that is passed to every resolver and updater function. It contains basic\ninformation about the current GraphQL document and query, and also some information on the current\nfield that a given resolver or updater is called on.\n\n| Argument         | Type                                         | Description                                                                                                                                                                                              |\n| ---------------- | -------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |\n| `parent`         | `Data`                                       | The field's parent entity's data, as it was written or read up until now, which means it may be incomplete. [Use `cache.resolve`](#resolve) to read from it.                                             |\n| `parentTypeName` | `string`                                     | The field's parent entity's typename                                                                                                                                                                     |\n| `parentKey`      | `string`                                     | The field's parent entity's cache key (if any)                                                                                                                                                           |\n| `parentFieldKey` | `string`                                     | The current key's cache key, which is the parent entity's key combined with the current field's key (This is mostly obsolete)                                                                            |\n| `fieldName`      | `string`                                     | The current field's name                                                                                                                                                                                 |\n| `fragments`      | `{ [name: string]: FragmentDefinitionNode }` | A dictionary of fragments from the current GraphQL document                                                                                                                                              |\n| `variables`      | `object`                                     | The current GraphQL operation's variables (may be an empty object)                                                                                                                                       |\n| `error`          | `GraphQLError \\| undefined`                  | The current GraphQLError for a given field. This will always be `undefined` for resolvers and optimistic updaters, but may be present for updaters when the API has returned an error for a given field. |\n| `partial`        | `?boolean`                                   | This may be set to `true` at any point in time (by your custom resolver or by _Graphcache_) to indicate that some data is uncached and missing                                                           |\n| `optimistic`     | `?boolean`                                   | This is only `true` when an optimistic mutation update is running                                                                                                                                        |\n\n> **Note:** Using `info` is regarded as a last resort. Please only use information from it if\n> there's no other solution to get to the metadata you need. We don't regard the `Info` API as\n> stable and may change it with a simple minor version bump.\n\n## The `/extras` import\n\nThe `extras` subpackage is published with _Graphcache_ and contains helpers and utilities that don't\nhave to be included in every app or aren't needed by all users of _Graphcache_.\nAll utilities from extras may be imported from `@urql/exchange-graphcache/extras`.\n\nCurrently the `extras` subpackage only contains the [pagination resolvers that have been mentioned\non the \"Computed Queries\" page.](../graphcache/local-resolvers.md#pagination)\n\n### simplePagination\n\nAccepts a single object of optional options and returns a resolver that can be inserted into the\n[`cacheExchange`'s](#cacheexchange) [`resolvers` configuration.](#resolvers-option)\n\n| Argument         | Type                  | Description                                                                                                                                                        |\n| ---------------- | --------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------ |\n| `offsetArgument` | `?string`             | The field arguments' property, as passed to the resolver, that contains the current offset, i.e. the number of items to be skipped. Defaults to `'skip'`.          |\n| `limitArgument`  | `?string`             | The field arguments' property, as passed to the resolver, that contains the current page size limit, i.e. the number of items on each page. Defaults to `'limit'`. |\n| `mergeMode`      | `'after' \\| 'before'` | This option defines whether pages are merged before or after preceding ones when paginating. Defaults to `'after'`.                                                |\n\nOnce set up, the resulting resolver is able to automatically concatenate all pages of a given field\nautomatically. Queries to this resolvers will from then on only return the infinite, combined list\nof all pages.\n\n[Read more about `simplePagination` on the \"Computed Queries\"\npage.](../graphcache/local-resolvers.md#simple-pagination)\n\n### relayPagination\n\nAccepts a single object of optional options and returns a resolver that can be inserted into the\n[`cacheExchange`'s](#cacheexchange) [`resolvers` configuration.](#resolvers-option)\n\n| Argument    | Type                      | Description                                                                                                                                                                                                                                                                      |\n| ----------- | ------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |\n| `mergeMode` | `'outwards' \\| 'inwards'` | With Relay pagination, pages can be queried forwards and backwards using `after` and `before` cursors. This option defines whether pages that have been queried backwards should be concatenated before (outwards) or after (inwards) all pages that have been queried forwards. |\n\nOnce set up, the resulting resolver is able to automatically concatenate all pages of a given field\nautomatically. Queries to this resolvers will from then on only return the infinite, combined list\nof all pages.\n\n[Read more about `relayPagnation` on the \"Computed Queries\"\npage.](../graphcache/local-resolvers.md#relay-pagination)\n\n## The `/default-storage` import\n\nThe `default-storage` subpackage is published with _Graphcache_ and contains a default storage\ninterface that may be used with the [`storage` option.](#storage-option)\n\nIt contains the `makeDefaultStorage` export which is a factory function that accepts a few options\nand returns a full [storage interface](#storage-option). This storage by default persists to\n[IndexedDB](https://developer.mozilla.org/en-US/docs/Web/API/IndexedDB_API).\n\n| Argument  | Type     | Description                                                                                                                                       |\n| --------- | -------- | ------------------------------------------------------------------------------------------------------------------------------------------------- |\n| `idbName` | `string` | The name of the IndexedDB database that is used and created if needed. By default this is set to `\"graphcache-v3\"`                                |\n| `maxAge`  | `number` | The maximum age of entries that the storage should use in whole days. By default the storage will discard entries that are older than seven days. |\n"
  },
  {
    "path": "docs/api/preact.md",
    "content": "---\ntitle: '@urql/preact'\norder: 2\n---\n\n# @urql/preact\n\n> **Note:** These API docs are deprecated as we now keep TSDocs in all published packages.\n> You can view TSDocs while using these packages in your editor, as long as it supports the\n> TypeScript Language Server.\n> We're planning to replace these API docs with a separate web app soon.\n\nThe `@urql/preact` API is the same as the React `urql` API.\nPlease refer to [the \"urql\" API docs](./urql.md) for details on the Preact API.\n"
  },
  {
    "path": "docs/api/refocus-exchange.md",
    "content": "---\ntitle: '@urql/exchange-refocus'\norder: 11\n---\n\n# Refocus Exchange\n\n> **Note:** These API docs are deprecated as we now keep TSDocs in all published packages.\n> You can view TSDocs while using these packages in your editor, as long as it supports the\n> TypeScript Language Server.\n> We're planning to replace these API docs with a separate web app soon.\n\n`@urql/exchange-refocus` is an exchange for the `urql` that tracks currently active operations and redispatches them when the\nwindow regains focus\n\n## Quick Start Guide\n\nFirst install `@urql/exchange-refocus` alongside `urql`:\n\n```sh\nyarn add @urql/exchange-refocus\n# or\nnpm install --save @urql/exchange-refocus\n```\n\nThen add it to your `Client`, preferably in front of your `cacheExchange`\n\n```js\nimport { createClient, cacheExchange, fetchExchange } from 'urql';\nimport { refocusExchange } from '@urql/exchange-refocus';\n\nconst client = createClient({\n  url: 'http://localhost:3000/graphql',\n  exchanges: [refocusExchange(), cacheExchange, fetchExchange],\n});\n```\n"
  },
  {
    "path": "docs/api/request-policy-exchange.md",
    "content": "---\ntitle: '@urql/exchange-request-policy'\norder: 9\n---\n\n# Request Policy Exchange\n\n> **Note:** These API docs are deprecated as we now keep TSDocs in all published packages.\n> You can view TSDocs while using these packages in your editor, as long as it supports the\n> TypeScript Language Server.\n> We're planning to replace these API docs with a separate web app soon.\n\nThe `@urql/exchange-request-policy` package contains an addon `requestPolicyExchange` for `urql`\nthat may be used to upgrade [Operations' Request Policies](./core.md#requestpolicy) on a\ntime-to-live basis.\n\n[Read more about request policies on the \"Document Caching\" page.](../basics/document-caching.md#request-policies)\n\nThis exchange will conditionally upgrade `cache-first` and `cache-only` operations to use\n`cache-and-network`, so that the client gets an opportunity to update its cached data, when the\noperation hasn't been seen within the given `ttl` time. This is often preferable to setting the\ndefault policy to `cache-and-network` to avoid an unnecessarily high amount of requests to be sent\nto the API when switching pages.\n\n## Installation and Setup\n\nFirst install `@urql/exchange-request-policy` alongside `urql`:\n\n```sh\nyarn add @urql/exchange-request-policy\n# or\nnpm install --save @urql/exchange-request-policy\n```\n\nThen add it to your `Client`, preferably in front of the `cacheExchange` and in front of any asynchronous\nexchanges, like the `fetchExchange`:\n\n```js\nimport { createClient, cacheExchange, fetchExchange } from 'urql';\nimport { requestPolicyExchange } from '@urql/exchange-request-policy';\n\nconst client = createClient({\n  url: 'http://localhost:3000/graphql',\n  exchanges: [\n    requestPolicyExchange({\n      /* config */\n    }),\n    cacheExchange,\n    fetchExchange,\n  ],\n});\n```\n\n## Options\n\n| Option          | Description                                                                                                                                                                                                                                                   |\n| --------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |\n| `ttl`           | The \"time-to-live\" until an `Operation` will be upgraded to the `cache-and-network` policy in milliseconds. By default 5 minutes is set.                                                                                                                      |\n| `shouldUpgrade` | An optional function that receives an `Operation` as the only argument and may return `true` or `false` depending on whether an operation should be upgraded. This can be used to filter out operations that should never be upgraded to `cache-and-network`. |\n"
  },
  {
    "path": "docs/api/retry-exchange.md",
    "content": "---\ntitle: '@urql/exchange-retry'\norder: 5\n---\n\n# Retry Exchange\n\n> **Note:** These API docs are deprecated as we now keep TSDocs in all published packages.\n> You can view TSDocs while using these packages in your editor, as long as it supports the\n> TypeScript Language Server.\n> We're planning to replace these API docs with a separate web app soon.\n\nThe `@urql/exchange-retry` package contains an addon `retryExchange` for `urql` that may be used to\nlet failed operations be retried, typically when a previous operation has failed with a network\nerror.\n\n[Read more about how to use and configure the `retryExchange` on the \"Retry Operations\"\npage.](../advanced/retry-operations.md)\n\n## Options\n\n| Option              | Description                                                                                                                                                                                                                                                                                                                                                                                      |\n| ------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |\n| `initialDelayMs`    | Specify at what interval the `retrying` should start, this means that if we specify `1000` that when our `operation` fails we'll wait 1 second and then retry it.                                                                                                                                                                                                                                |\n| `maxDelayMs`        | The maximum delay between retries. The `retryExchange` will keep increasing the time between retries so that the server doesn't receive simultaneous requests it can't complete. This time between requests will increase with a random `back-off` factor applied to the `initialDelayMs`, read more about the [thundering herd problem](https://en.wikipedia.org/wiki/Thundering_herd_problem). |\n| `randomDelay`       | Allows the randomized delay described above to be disabled. When this option is set to `false` there will be exactly a `initialDelayMs` wait between each retry.                                                                                                                                                                                                                                 |\n| `maxNumberAttempts` | Defines the maximum number of attempts (including the initial request). For example, `2` means one retry after the initial attempt.                                                                                                                                                                                                                                                              |\n| `retryIf`           | Apply a custom test to the returned error to determine whether it should be retried.                                                                                                                                                                                                                                                                                                             |\n| `retryWith`         | Apply a transform function allowing you to selectively replace a retried `Operation` or return a nullish value. This will act like `retryIf` where a truthy value retries (`retryIf` takes precedence and overrides this function.)                                                                                                                                                              |\n"
  },
  {
    "path": "docs/api/svelte.md",
    "content": "---\ntitle: '@urql/svelte'\norder: 3\n---\n\n# Svelte API\n\n> **Note:** These API docs are deprecated as we now keep TSDocs in all published packages.\n> You can view TSDocs while using these packages in your editor, as long as it supports the\n> TypeScript Language Server.\n> We're planning to replace these API docs with a separate web app soon.\n\n## queryStore\n\nThe `queryStore` factory accepts properties as inputs and returns a Svelte pausable, readable store\nof results, with type `OperationResultStore & Pausable`.\n\n| Argument        | Type                       | Description                                                                                              |\n| --------------- | -------------------------- | -------------------------------------------------------------------------------------------------------- |\n| `client`        | `Client`                   | The [`Client`](./core.md#Client) to use for the operation.                                               |\n| `query`         | `string \\| DocumentNode \\` | The query to be executed. Accepts as a plain string query or GraphQL DocumentNode.                       |\n| `variables`     | `?object`                  | The variables to be used with the GraphQL request.                                                       |\n| `requestPolicy` | `?RequestPolicy`           | An optional [request policy](./core.md#requestpolicy) that should be used specifying the cache strategy. |\n| `pause`         | `?boolean`                 | A boolean flag instructing [execution to be paused](../basics/vue.md#pausing-usequery).                  |\n| `context`       | `?object`                  | Holds the contextual information for the query.                                                          |\n\nThis store is pausable, which means that the result has methods on it to `pause()` or `resume()`\nthe subscription of the operation.\n\n[Read more about how to use the `queryStore` API on the \"Queries\" page.](../basics/svelte.md#queries)\n\n## mutationStore\n\nThe `mutationStore` factory accepts properties as inputs and returns a Svelte readable store of a result.\n\n| Argument    | Type                       | Description                                                                        |\n| ----------- | -------------------------- | ---------------------------------------------------------------------------------- |\n| `client`    | `Client`                   | The [`Client`](./core.md#Client) to use for the operation.                         |\n| `query`     | `string \\| DocumentNode \\` | The query to be executed. Accepts as a plain string query or GraphQL DocumentNode. |\n| `variables` | `?object`                  | The variables to be used with the GraphQL request.                                 |\n| `context`   | `?object`                  | Holds the contextual information for the query.                                    |\n\n[Read more about how to use the `mutation` API on the \"Mutations\"\npage.](../basics/svelte.md#mutations)\n\n## subscriptionStore\n\nThe `subscriptionStore` utility function accepts the same inputs as `queryStore` does as its first\nargument, [see above](#querystore).\n\nThe function also optionally accepts a second argument, a `handler` function. This function has the\nfollowing type signature:\n\n```js\ntype SubscriptionHandler<T, R> = (previousData: R | undefined, data: T) => R;\n```\n\nThis function will be called with the previous data (or `undefined`) and the new data that's\nincoming from a subscription event, and may be used to \"reduce\" the data over time, altering the\nvalue of `result.data`.\n\n[Read more about how to use the `subscription` API on the \"Subscriptions\"\npage.](../advanced/subscriptions.md#svelte)\n\n## OperationResultStore\n\nA Svelte Readble store of an [`OperationResult`](./core.md#operationresult).\nThis store will be updated as the incoming data changes.\n\n| Prop         | Type                   | Description                                                                                                                                        |\n| ------------ | ---------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------- |\n| `data`       | `?any`                 | Data returned by the specified query                                                                                                               |\n| `error`      | `?CombinedError`       | A [`CombinedError`](./core.md#combinederror) instances that wraps network or `GraphQLError`s (if any)                                              |\n| `extensions` | `?Record<string, any>` | Extensions that the GraphQL server may have returned.                                                                                              |\n| `stale`      | `boolean`              | A flag that may be set to `true` by exchanges to indicate that the `data` is incomplete or out-of-date, and that the result will be updated soon.  |\n| `fetching`   | `boolean`              | A flag that indicates whether the operation is currently in progress, which means that the `data` and `error` is out-of-date for the given inputs. |\n\n## Pausable\n\nThe `queryStore` and `subscriptionStore`'s stores are pausable. This means they inherit the\nfollowing properties from the `Pausable` store.\n\n| Prop        | Type                | Description                                                                                                                  |\n| ----------- | ------------------- | ---------------------------------------------------------------------------------------------------------------------------- |\n| `isPaused$` | `Readable<boolean>` | A Svelte readable store indicating whether the operation is currently paused. Essentially, this is equivalent to `!fetching` |\n| `pause()`   | `pause(): void`     | This method pauses the ongoing operation.                                                                                    |\n| `resume()`  | `resume(): void`    | This method resumes the previously paused operation.                                                                         |\n\n## Context API\n\nIn `urql`'s Svelte bindings, the [`Client`](./core.md#client) is passed into the factories for\nstores above manually. This is to cater to greater flexibility. However, for convenience's sake,\ninstead of keeping a `Client` singleton, we may also use [Svelte's Context\nAPI](https://svelte.dev/tutorial/context-api).\n\n`@urql/svelte` provides wrapper functions around Svelte's [`setContext`](https://svelte.dev/docs#run-time-svelte-setcontext) and\n[`getContext`](https://svelte.dev/docs#run-time-svelte-getcontext) functions:\n\n- `setContextClient`\n- `getContextClient`\n- `initContextClient` (a shortcut for `createClient` + `setContextClient`)\n"
  },
  {
    "path": "docs/api/urql.md",
    "content": "---\ntitle: urql (React)\norder: 1\n---\n\n# React API\n\n> **Note:** These API docs are deprecated as we now keep TSDocs in all published packages.\n> You can view TSDocs while using these packages in your editor, as long as it supports the\n> TypeScript Language Server.\n> We're planning to replace these API docs with a separate web app soon.\n\n## useQuery\n\nAccepts a single required options object as an input with the following properties:\n\n| Prop            | Type                     | Description                                                                                              |\n| --------------- | ------------------------ | -------------------------------------------------------------------------------------------------------- |\n| `query`         | `string \\| DocumentNode` | The query to be executed. Accepts as a plain string query or GraphQL DocumentNode.                       |\n| `variables`     | `?object`                | The variables to be used with the GraphQL request.                                                       |\n| `requestPolicy` | `?RequestPolicy`         | An optional [request policy](./core.md#requestpolicy) that should be used specifying the cache strategy. |\n| `pause`         | `?boolean`               | A boolean flag instructing [execution to be paused](../basics/react-preact.md#pausing-usequery).         |\n| `context`       | `?object`                | Holds the contextual information for the query.                                                          |\n\nThis hook returns a tuple of the shape `[result, executeQuery]`.\n\n- The `result` is an object with the shape of an [`OperationResult`](./core.md#operationresult) with\n  an added `fetching: boolean` property, indicating whether the query is being fetched.\n- The `executeQuery` function optionally accepts\n  [`Partial<OperationContext>`](./core.md#operationcontext) and reexecutes the current query when\n  it's called. When `pause` is set to `true` this executes the query, overriding the otherwise\n  paused hook.\n\n[Read more about how to use the `useQuery` API on the \"Queries\" page.](../basics/react-preact.md#queries)\n\n## useMutation\n\nAccepts a single `query` argument of type `string | DocumentNode` and returns a tuple of the shape\n`[result, executeMutation]`.\n\n- The `result` is an object with the shape of an [`OperationResult`](./core.md#operationresult) with\n  an added `fetching: boolean` property, indicating whether the mutation is being executed.\n- The `executeMutation` function accepts variables and optionally\n  [`Partial<OperationContext>`](./core.md#operationcontext) and may be used to start executing a\n  mutation. It returns a `Promise` resolving to an [`OperationResult`](./core.md#operationresult).\n\n[Read more about how to use the `useMutation` API on the \"Mutations\"\npage.](../basics/react-preact.md#mutations)\n\n## useSubscription\n\nAccepts a single required options object as an input with the following properties:\n\n| Prop        | Type                     | Description                                                                                      |\n| ----------- | ------------------------ | ------------------------------------------------------------------------------------------------ |\n| `query`     | `string \\| DocumentNode` | The query to be executed. Accepts as a plain string query or GraphQL DocumentNode.               |\n| `variables` | `?object`                | The variables to be used with the GraphQL request.                                               |\n| `pause`     | `?boolean`               | A boolean flag instructing [execution to be paused](../basics/react-preact.md#pausing-usequery). |\n| `context`   | `?object`                | Holds the contextual information for the query.                                                  |\n\nThe hook optionally accepts a second argument, which may be a handler function with a type signature\nof:\n\n```js\ntype SubscriptionHandler<T, R> = (previousData: R | undefined, data: T) => R;\n```\n\nThis function will be called with the previous data (or `undefined`) and the new data that's\nincoming from a subscription event, and may be used to \"reduce\" the data over time, altering the\nvalue of `result.data`.\n\nThis hook returns a tuple of the shape `[result, executeSubscription]`.\n\n- The `result` is an object with the shape of an [`OperationResult`](./core.md#operationresult).\n- The `executeSubscription` function optionally accepts\n  [`Partial<OperationContext>`](./core.md#operationcontext) and restarts the current subscription when\n  it's called. When `pause` is set to `true` this starts the subscription, overriding the otherwise\n  paused hook.\n\nThe `fetching: boolean` property on the `result` may change to `false` when the server proactively\nends the subscription. By default, `urql` is unable able to start subscriptions, since this requires\nsome additional setup.\n\n[Read more about how to use the `useSubscription` API on the \"Subscriptions\"\npage.](../advanced/subscriptions.md)\n\n## Query Component\n\nThis component is a wrapper around [`useQuery`](#usequery), exposing a [render prop\nAPI](https://reactjs.org/docs/render-props.html) for cases where hooks aren't desirable.\n\nThe API of the `Query` component mirrors the API of [`useQuery`](#usequery). The props that `<Query>`\naccepts are the same as `useQuery`'s options object.\n\nA function callback must be passed to `children` that receives the query result and must return a\nReact element. The second argument of the hook's tuple, `executeQuery` is passed as an added property\non the query result.\n\n## Mutation Component\n\nThis component is a wrapper around [`useMutation`](#usemutation), exposing a [render prop\nAPI](https://reactjs.org/docs/render-props.html) for cases where hooks aren't desirable.\n\nThe `Mutation` component accepts a `query` prop, and a function callback must be passed to `children`\nthat receives the mutation result and must return a React element. The second argument of\n`useMutation`'s returned tuple, `executeMutation` is passed as an added property on the mutation\nresult object.\n\n## Subscription Component\n\nThis component is a wrapper around [`useSubscription`](#usesubscription), exposing a [render prop\nAPI](https://reactjs.org/docs/render-props.html) for cases where hooks aren't desirable.\n\nThe API of the `Subscription` component mirrors the API of [`useSubscription`](#usesubscription).\nThe props that `<Mutation>` accepts are the same as `useSubscription`'s options object, with an\nadded, optional `handler` prop that may be passed, which for the `useSubscription` hook is instead\nthe second argument.\n\nA function callback must be passed to `children` that receives the subscription result and must\nreturn a React element. The second argument of the hook's tuple, `executeSubscription` is passed as\nan added property on the subscription result.\n\n## Context\n\n`urql` is used in React by adding a provider around where the [`Client`](./core.md#client) is\nsupposed to be used. Internally this means that `urql` creates a\n[React Context](https://reactjs.org/docs/context.html).\n\nAll created parts of this context are exported by `urql`, namely:\n\n- `Context`\n- `Provider`\n- `Consumer`\n\nTo keep examples brief, `urql` creates a default client with the `url` set to `'/graphql'`. This\nclient will be used when no `Provider` wraps any of `urql`'s hooks. However, to prevent this default\nclient from being used accidentally, a warning is output in the console for the default client.\n\n### useClient\n\n`urql` also exports a `useClient` hook, which is a convenience wrapper like the following:\n\n```js\nimport React from 'react';\nimport { Context } from 'urql';\n\nconst useClient = () => React.useContext(Context);\n```\n\nHowever, this hook is also responsible for outputting the default client warning that's mentioned\nabove, and should thus be preferred over manually using `useContext` with `urql`'s `Context`.\n"
  },
  {
    "path": "docs/api/vue.md",
    "content": "---\ntitle: '@urql/vue'\norder: 3\n---\n\n# Vue API\n\n> **Note:** These API docs are deprecated as we now keep TSDocs in all published packages.\n> You can view TSDocs while using these packages in your editor, as long as it supports the\n> TypeScript Language Server.\n> We're planning to replace these API docs with a separate web app soon.\n\n## useQuery\n\nAccepts a single required options object as an input with the following properties:\n\n| Prop            | Type                     | Description                                                                                              |\n| --------------- | ------------------------ | -------------------------------------------------------------------------------------------------------- |\n| `query`         | `string \\| DocumentNode` | The query to be executed. Accepts as a plain string query or GraphQL DocumentNode.                       |\n| `variables`     | `?object`                | The variables to be used with the GraphQL request.                                                       |\n| `requestPolicy` | `?RequestPolicy`         | An optional [request policy](./core.md#requestpolicy) that should be used specifying the cache strategy. |\n| `pause`         | `?boolean`               | A boolean flag instructing [execution to be paused](../basics/vue.md#pausing-usequery).                  |\n| `context`       | `?object`                | Holds the contextual information for the query.                                                          |\n\nEach of these inputs may also be [reactive](https://v3.vuejs.org/api/refs-api.html) (e.g. a `ref`)\nand are allowed to change over time which will issue a new query.\n\nThis function returns an object with the shape of an [`OperationResult`](./core.md#operationresult)\nwith an added `fetching` property, indicating whether the query is currently being fetched and an\n`isPaused` property which will indicate whether `useQuery` is currently paused and won't\nautomatically start querying.\n\nAll of the properties on this result object are also marked as\n[reactive](https://v3.vuejs.org/api/refs-api.html) using `ref` and will update accordingly as the\nquery is executed.\n\nThe result furthermore carries several utility methods:\n\n| Method               | Description                                                                                                                                                                                                                        |\n| -------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |\n| `pause()`            | This will pause automatic querying, which is equivalent to setting `pause.value = true`                                                                                                                                            |\n| `resume()`           | This will resume a paused automatic querying, which is equivalent to setting `pause.value = false`                                                                                                                                 |\n| `executeQuery(opts)` | This will execute a new query with the given partial [`Partial<OperationContext>`](./core.md#operationcontext) regardless of whether the query is currently paused or not. This also returns the result object again for chaining. |\n\nFurthermore the returned result object of `useQuery` is also a `PromiseLike`, which allows you to\ntake advantage of [Vue 3's experimental Suspense feature.](https://vuedose.tips/go-async-in-vue-3-with-suspense/)\nWhen the promise is used, e.g. you `await useQuery(...)` then the `PromiseLike` will only resolve\nonce a result from the API is available.\n\n[Read more about how to use the `useQuery` API on the \"Queries\" page.](../basics/vue.md#queries)\n\n## useMutation\n\nAccepts a single `query` argument of type `string | DocumentNode` and returns a result object with\nthe shape of an [`OperationResult`](./core.md#operationresult) with an added `fetching` property.\n\nAll of the properties on this result object are also marked as\n[reactive](https://v3.vuejs.org/api/refs-api.html) using `ref` and will update accordingly as the\nmutation is executed.\n\nThe object also carries a special `executeMutation` method, which accepts variables and optionally a\n[`Partial<OperationContext>`](./core.md#operationcontext) and may be used to start executing a\nmutation. It returns a `Promise` resolving to an [`OperationResult`](./core.md#operationresult)\n\n[Read more about how to use the `useMutation` API on the \"Mutations\"\npage.](../basics/vue.md#mutations)\n\n## useSubscription\n\nAccepts a single required options object as an input with the following properties:\n\n| Prop        | Type                     | Description                                                                             |\n| ----------- | ------------------------ | --------------------------------------------------------------------------------------- |\n| `query`     | `string \\| DocumentNode` | The query to be executed. Accepts as a plain string query or GraphQL DocumentNode.      |\n| `variables` | `?object`                | The variables to be used with the GraphQL request.                                      |\n| `pause`     | `?boolean`               | A boolean flag instructing [execution to be paused](../basics/vue.md#pausing-usequery). |\n| `context`   | `?object`                | Holds the contextual information for the subscription.                                  |\n\nEach of these inputs may also be [reactive](https://v3.vuejs.org/api/refs-api.html) (e.g. a `ref`)\nand are allowed to change over time which will issue a new query.\n\n`useSubscription` also optionally accepts a second argument, which may be a handler function with\na type signature of:\n\n```js\ntype SubscriptionHandler<T, R> = (previousData: R | undefined, data: T) => R;\n```\n\nThis function will be called with the previous data (or `undefined`) and the new data that's\nincoming from a subscription event, and may be used to \"reduce\" the data over time, altering the\nvalue of `result.data`.\n\nThis function returns an object with the shape of an [`OperationResult`](./core.md#operationresult)\nwith an added `fetching` property, indicating whether the subscription is currently running and an\n`isPaused` property which will indicate whether `useSubscription` is currently paused.\n\nAll of the properties on this result object are also marked as\n[reactive](https://v3.vuejs.org/api/refs-api.html) using `ref` and will update accordingly as the\nquery is executed.\n\nThe result furthermore carries several utility methods:\n\n| Method                      | Description                                                                                                                                                                                                                                    |\n| --------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |\n| `pause()`                   | This will pause the subscription, which is equivalent to setting `pause.value = true`                                                                                                                                                          |\n| `resume()`                  | This will resume the subscription, which is equivalent to setting `pause.value = false`                                                                                                                                                        |\n| `executeSubscription(opts)` | This will start a new subscription with the given partial [`Partial<OperationContext>`](./core.md#operationcontext) regardless of whether the subscription is currently paused or not. This also returns the result object again for chaining. |\n\n[Read more about how to use the `useSubscription` API on the \"Subscriptions\"\npage.](../advanced/subscriptions.md#vue)\n\n## useClientHandle\n\nThe `useClientHandle()` function may, like the other `use*` functions, be called either in\n`setup()` or another lifecycle hook, and returns a so called \"client handle\". Using this `handle` we\ncan access the [`Client`](./core.md#client) directly via the `client` property or call the other\n`use*` functions as methods, which will be directly bound to this `client`. This may be useful when\nchaining these methods inside an `async setup()` lifecycle function.\n\n| Method                 | Description                                                                                                               |\n| ---------------------- | ------------------------------------------------------------------------------------------------------------------------- |\n| `client`               | Contains the raw [`Client`](./core.md#client) reference, which allows the `Client` to be used directly.                   |\n| `useQuery(...)`        | Accepts the same arguments as the `useQuery` function, but will always use the `Client` from the handle's context.        |\n| `useMutation(...)`     | Accepts the same arguments as the `useMutation` function, but will always use the `Client` from the handle's context.     |\n| `useSubscription(...)` | Accepts the same arguments as the `useSubscription` function, but will always use the `Client` from the handle's context. |\n\n## Context API\n\nIn Vue the [`Client`](./core.md#client) is provided either to your app or to a parent component of a\ngiven subtree and is then subsequently injected whenever one of the above composition functions is\nused.\n\nYou can provide the `Client` from any of your components using the `provideClient` function.\nAlternatively, `@urql/vue` also has a default export of a [Vue Plugin function](https://v3.vuejs.org/guide/plugins.html#using-a-plugin).\n\nBoth `provideClient` and the plugin function either accept an [instance of\n`Client`](./core.md#client) or the same options that `createClient` accepts as inputs.\n"
  },
  {
    "path": "docs/architecture.md",
    "content": "---\ntitle: Architecture\norder: 3\n---\n\n# Architecture\n\n`urql` is a highly customizable and flexible GraphQL client.\nAs you use it in your app, it's split into three parts:\n\n- Bindings — such as for React, Preact, Vue, or Svelte — which interact with `@urql/core`'s\n  `Client`.\n- The Client — as created [with the core `@urql/core` package](./basics/core.md), which interacts with \"exchanges\" to execute GraphQL\n  operations, and which you can also use directly.\n- Exchanges, which provide functionality like fetching or caching to the `Client`.\n\nBy default, `urql` aims to provide the minimal amount of features that allow us to build an app\nquickly. However, `urql` has also been designed to be a GraphQL Client\nthat grows with our usage and demands. As we go from building our smallest or first GraphQL apps to\nutilising its full functionality, we have tools at our disposal to extend and customize `urql` to\nour liking.\n\n## Using GraphQL Clients\n\nYou may have worked with a GraphQL API previously and noticed that using GraphQL in your app can be\nas straightforward as sending a plain HTTP request with your query to fetch some data.\n\nGraphQL also provides an opportunity to abstract away a lot of the manual work that goes with\nsending these queries and managing the data. Ultimately, this lets you focus on building\nyour app without having to handle the technical details of state management in detail.\n\nSpecifically, `urql` simplifies three common aspects of using GraphQL:\n\n- Sending queries and mutations and receiving results _declaratively_\n- Abstracting _caching_ and state management internally\n- Providing a central point of _extensibility_ and integration with your API\n\nIn the following sections we'll talk about the way that `urql` solves these three problems and how the logic is abstracted away internally.\n\n## Requests and Operations on the Client\n\nIf `urql` was a train it would take several stops to arrive at its terminus, our API. It starts with us\ndefining queries or mutations by writing in GraphQL's query language.\n\nAny GraphQL request can be abstracted into its query documents and its variables.\n\n```js\nimport { gql } from '@urql/core';\n\nconst query = gql`\n  query ($name: String!) {\n    helloWorld(name: $name)\n  }\n`;\n\nconst request = createRequest(query, {\n  name: 'Urkel',\n});\n```\n\nIn `urql`, these GraphQL requests are treated as unique objects and each GraphQL request will have\na `key` generated for them. This `key` is a hash of the query document and the variables you provide\nand are set on the `key` property of a [`GraphQLRequest`](./api/core.md#graphqlrequest).\n\nWhenever we decide to send our GraphQL requests to a GraphQL API we start by using `urql`'s\n[`Client`](./api/core.md#client).\nThe `Client` accepts several options to configure its behaviour and the behaviour of exchanges,\nlike the `fetchExchange`. For instance, we can pass it a `url` which the `fetchExchange` will\nuse to make a `fetch` call to our GraphQL API.\n\n```js\nimport { Client, cacheExchange, fetchExchange } from '@urql/core';\n\nconst client = new Client({\n  url: 'http://localhost:3000/graphql',\n  exchanges: [cacheExchange, fetchExchange],\n});\n```\n\nAbove, we're defining a `Client` that is ready to accept our requests. It will apply basic\ndocument caching and will send uncached requests to the `url` we pass it.\nThe bindings that we've seen in [the \"Basics\" section](./basics/README.md), like `useQuery` for\nReact for example, interact with [the `Client`](./api/core.md#client) directly and are a thin\nabstraction.\n\nSome methods can be called on it directly however, as seen [on the \"Core Usage\"\npage](./basics/core.md#one-off-queries-and-mutations).\n\n```js\n// Given our request and client defined above, we can call\nconst subscription = client.executeQuery(request).subscribe(result => {\n  console.log(result.data);\n});\n```\n\nAs we've seen, `urql` defines our query documents and variables as\n[`GraphQLRequest`s](./api/core.md#graphqlrequest). However, since we have more metadata that is\nneeded, like our `url` option on the `Client`, `urql` internally creates [`Operation`s](./api/core.md#operation)\neach time a request is executed. The operations are then forwarded to the exchanges, like the\n`cacheExchange` and `fetchExchange`.\n\nAn \"Operation\" is an extension of `GraphQLRequest`s. Not only do they carry the `query`, `variables`,\nand a `key` property, they will also identify the `kind` of operation that is executed, like\n`\"query\"` or `\"mutation\"`, and they contain the `Client`'s options on `operation.context`.\n\n![Operations and Results](./assets/urql-event-hub.png)\n\nThis means, once we hand over a GraphQL request to the `Client`, it will create an `Operation`,\nand then hand it over to the exchanges until a result comes back.\n\nAs shown in the diagram, each operation is like an event or signal for a GraphQL request to start,\nand the exchanges will eventually send back a corresponding result.\nHowever, because the cache can send updates to us whenever it detects a change, or you could cancel\na GraphQL request before it finishes, a special \"teardown\" `Operation` also exists, which cancels\nongoing requests.\n\n## The Client and Exchanges\n\nTo reiterate, when we use `urql`'s bindings for our framework of choice, methods are called on the\n`Client`, but we never see the operations that are created in the background from our bindings. We\ncall a method like `client.executeQuery` (or it's called for us in the bindings), an operation is\nissued internally when we subscribe with a callback, and later, we're given results.\n\n![Operations stream and results stream](./assets/urql-client-architecture.png)\n\nWhile we know that, for us, we're only interested in a single [`Operation`](./api/core.md#operation)\nand its [`OperationResult`s](./api/core.md#operationresult) at a time, the `Client` treats these as\none big stream. The `Client` sees an incoming flow of all of our operations.\n\nAs we've learned before, each operation carries a `key` and each result we receive carries the\noriginal `operation`. Because an `OperationResult` also carries an `operation` property the `Client`\nwill always know which results correspond to an individual operation.\nHowever, internally, all of our operations are processed at the same time concurrently. However, from\nour perspective:\n\n- We subscribe to a \"stream\" and expect to get results on a callback\n- The `Client` issues the operation, and we'll receive some results back eventually as either the\n  cache responds (synchronously), or the request gets sent to our API.\n- We eventually unsubscribe, and the `Client` issues a \"teardown\" operation with the same `key` as\n  the original operation, which concludes our flow.\n\nThe `Client` itself doesn't actually know what to do with operations. Instead, it sends them through\n\"exchanges\". Exchanges are akin to [middleware in Redux](https://redux.js.org/advanced/middleware)\nand have access to all operations and all results. Multiple exchanges are chained to process our\noperations and to execute logic on them, one of them being the `fetchExchange`, which as the name\nimplies sends our requests to our API.\n\n### How operations get to exchanges\n\nWe now know how we get to operations and to the `Client`:\n\n- Any bindings or calls to the `Client` create an **operation**\n- This operation identifies itself as either a `\"query\"`, `\"mutation\"` or `\"subscription\"` and has a\n  unique `key`.\n- This operation is sent into the **exchanges** and eventually ends up at the `fetchExchange`\n  (or a similar exchange)\n- The operation is sent to the API and a **result** comes back, which is wrapped in an `OperationResult`\n- The `Client` filters the `OperationResult` by the `operation.key` and — via a callback — gives us\n  a **stream of results**.\n\nTo come back to our train analogy from earlier, an operation, like a train, travels from one end\nof the track to the terminus — our API. The results then come back on the same path as they're just\ntravelling the same line in reverse.\n\n### The Exchanges\n\nBy default, the `Client` doesn't do anything with GraphQL requests. It contains only the logic to\nmanage and differentiate between active and inactive requests and converts them to operations.\nTo actually do something with our GraphQL requests, it needs _exchanges_, which are like plugins\nthat you can pass to create a pipeline of how GraphQL operations are executed.\n\nBy default, you may want to add the `cacheExchange` and the `fetchExchange` from `@urql/core`:\n\n- `cacheExchange`: Caches GraphQL results with [\"Document Caching\"](./basics/document-caching.md)\n- `fetchExchange`: Executes GraphQL requests with a `fetch` HTTP call\n\n```js\nimport { Client, cacheExchange, fetchExchange } from '@urql/core';\n\nconst client = new Client({\n  url: 'http://localhost:3000/graphql',\n  exchanges: [cacheExchange, fetchExchange],\n});\n```\n\nAs we can tell, exchanges define not only how GraphQL requests are executed and handled, but also\nget control over caching. Exchanges can be used to change almost any behaviour in the `Client`,\nalthough internally they only handle incoming & outgoing requests and incoming & outgoing results.\n\nSome more exchanges that we can use with our `Client` are:\n\n- [`mapExchange`](./api/core.md#mapexchange): Allows changing and reacting to operations, results, and errors\n- [`ssrExchange`](./advanced/server-side-rendering.md): Allows for a server-side renderer to\n  collect results for client-side rehydration.\n- [`retryExchange`](./advanced/retry-operations.md): Allows operations to be retried on errors\n- [`persistedExchange`](./advanced/persistence-and-uploads.md#automatic-persisted-queries): Provides support for Automatic\n  Persisted Queries\n- [`authExchange`](./advanced/authentication.md): Allows refresh authentication to be implemented easily.\n- [`requestPolicyExchange`](./api/request-policy-exchange.md): Automatically refreshes results given a TTL.\n- `devtoolsExchange`: Provides the ability to use the [urql-devtools](https://github.com/urql-graphql/urql-devtools)\n\nWe can even swap out our [document cache](./basics/document-caching.md), which is implemented by\n`@urql/core`'s `cacheExchange`, with `urql`'s [normalized cache,\nGraphcache](./graphcache/README.md).\n\n[Read more about exchanges and how to write them from scratch on the \"Authoring Exchanges\"\npage.](./advanced/authoring-exchanges.md)\n\n## Stream Patterns in `urql`\n\nIn the previous sections we've learned a lot about how the `Client` works, but we've always learned\nit in vague terms — for instance, we've learned that we get a \"stream of results\" or `urql` sees all\noperations as \"one stream of operations\" that it sends to the exchanges.\nBut, **what are streams?**\n\nGenerally we refer to _streams_ as abstractions that allow us to program with asynchronous events\nover time. Within the context of JavaScript we're specifically thinking in terms of\n[Observables](https://github.com/tc39/proposal-observable)\nand [Reactive Programming with Observables.](http://reactivex.io/documentation/observable.html)\nThese concepts may sound intimidating, but from a high-level view what we're talking about can be\nthought of as a combination of promises and iterables (e.g. arrays). We're dealing with multiple\nevents, but our callback is called over time. It's like calling `forEach` on an array but expecting\nthe results to come in asynchronously.\n\nAs a user, if we're using the one framework bindings that we've seen in [the \"Basics\"\nsection](./basics/README.md), we may never see these streams in action or may never use them even,\nsince the bindings internally use them for us. But if we [use the `Client`\ndirectly](./basics/core.md#one-off-queries-and-mutations) or write exchanges then we'll see streams\nand will have to deal with their API.\n\n### Stream patterns with the client\n\nWhen we call methods on the `Client` like [`client.executeQuery`](./api/core.md#clientexecutequery)\nor [`client.query`](./api/core.md#clientquery) then these will return a \"stream\" of results.\n\nIt's normal for GraphQL subscriptions to deliver multiple results, however, even GraphQL queries can\ngive you multiple results in `urql`. This is because operations influence one another. When a cache\ninvalidates a query, this query may refetch, and a new result is delivered to your application.\n\nMultiple results mean that once you subscribe to a GraphQL query via the `Client`, you may receive\nnew results in the future.\n\n```js\nimport { gql } from '@urql/core';\n\nconst QUERY = gql`\n  query Test($id: ID!) {\n    getUser(id: $id) {\n      id\n      name\n    }\n  }\n`;\n\nclient.query(QUERY, { id: 'test' }).subscribe(result => {\n  console.log(result); // { data: ... }\n});\n```\n\nRead more about the available APIs on the `Client` in the [Core API docs](./api/core.md).\n\nInternally, these streams and all exchanges are written using a library called\n[`wonka`](https://wonka.kitten.sh/basics/background), which is a tiny Observable-like\nlibrary. It is used to write exchanges and when we interact with the `Client` it is used internally\nas well.\n"
  },
  {
    "path": "docs/basics/README.md",
    "content": "---\ntitle: Basics\norder: 2\n---\n\n# Basics\n\nIn this chapter we'll explain the basics of `urql` and how to get started with using it without any\nprior knowledge.\n\n- [**React/Preact**](./react-preact.md) covers how to work with the bindings for React/Preact.\n- [**Vue**](./vue.md) covers how to work with the bindings for Vue 3.\n- [**Svelte**](./svelte.md) covers how to work with the bindings for Svelte.\n- [**Core Package**](./core.md) defines why a shared package exists that contains the main\n  logic of `urql`, and how we can use it directly in Node.js.\n\nAfter reading the page for your bindings and the \"Core\" page you may want to the next two pages in\nthis section of the documentation:\n\n- [**Document Caching**](./document-caching.md) explains the default cache mechanism of `urql`, as opposed to the opt-in\n  [Normalized Cache](../graphcache/normalized-caching.md).\n- [**Errors**](../basics/errors.md) contains information on error handling in `urql`.\n- [**UI-Patterns**](../basics/ui-patterns.md) presents some common UI-patterns with `urql`.\n"
  },
  {
    "path": "docs/basics/core.md",
    "content": "---\ntitle: Core / Node.js\norder: 3\n---\n\n# Core and Node.js Usage\n\nThe `@urql/core` package contains `urql`'s `Client`, some common utilities, and some default\n_Exchanges_. These are the shared, default parts of `urql` that we will be using no matter which\nframework we're interacting with.\n\nAll framework bindings — meaning `urql`, `@urql/preact`, `@urql/svelte`, and `@urql/vue` — reexport\nall exports of our `@urql/core` core library. This means that if we want to use `urql`'s `Client`\nimperatively or with Node.js we'd use `@urql/core`'s utilities or the `Client` directly.\n\nIn other words, if we're using framework bindings then writing `import { Client } from \"@urql/vue\"`\nfor instance is the same as `import { Client } from \"@urql/core\"`.\nThis means that we can use the core utilities and exports that are shared between all bindings\ndirectly or install `@urql/core` separately. We can even use `@urql/core` directly without any\nframework bindings.\n\n## Installation\n\nAs we said above, if we are using bindings then those will already have installed `@urql/core` as\nthey depend on it. They also all re-export all exports from `@urql/core`, so we can use those\nregardless of which bindings we've installed. However, it's also possible to explicitly install\n`@urql/core` or use it standalone, e.g. in a Node.js environment.\n\n```sh\nyarn add @urql/core\n# or\nnpm install --save @urql/core\n```\n\nSince all bindings and all exchanges depend on `@urql/core`, we may sometimes run into problems\nwhere the package manager installs _two versions_ of `@urql/core`, which is a duplication problem.\nThis can cause type errors in TypeScript or cause some parts of our application to bundle two\ndifferent versions of the package or use slightly different utilities. We can fix this by\ndeduplicating our dependencies.\n\n```sh\n# npm\nnpm dedupe\n# pnpm\npnpm dedupe\n# yarn\nnpx yarn-deduplicate && yarn\n```\n\n## GraphQL Tags\n\nA notable utility function is the `gql` tagged template literal function, which is a drop-in\nreplacement for `graphql-tag`, if you're coming from other GraphQL clients.\n\nWherever `urql` accepts a query document, we can either pass a string or a `DocumentNode`. `gql` is\na utility that allows a `DocumentNode` to be created directly, and others to be interpolated into\nit, which is useful for fragments for instance. This function will often also mark GraphQL documents\nfor syntax highlighting in most code editors.\n\nIn most examples we may have passed a string to define a query document, like so:\n\n```js\nconst TodosQuery = `\n  query {\n    todos {\n      id\n      title\n    }\n  }\n`;\n```\n\nWe may also use the `gql` tag function to create a `DocumentNode` directly:\n\n```js\nimport { gql } from '@urql/core';\n\nconst TodosQuery = gql`\n  query {\n    todos {\n      id\n      title\n    }\n  }\n`;\n```\n\nSince all framework bindings also re-export `@urql/core`, we may also import `gql` from `'urql'`,\n`'@urql/svelte'` and other bindings directly.\n\nWe can also start interpolating other documents into the tag function. This is useful to compose\nfragment documents into a larger query, since it's common to define fragments across components of\nan app to spread out data dependencies. If we accidentally use a duplicate fragment name in a\ndocument, `gql` will log a warning, since GraphQL APIs won't accept duplicate names.\n\n```js\nimport { gql } from '@urql/core';\n\nconst TodoFragment = gql`\n  fragment SmallTodo on Todo {\n    id\n    title\n  }\n`;\n\nconst TodosQuery = gql`\n  query {\n    todos {\n      ...TodoFragment\n    }\n  }\n\n  ${TodoFragment}\n`;\n```\n\nThis usage will look familiar when coming from the `graphql-tag` package. The `gql` API is\nidentical, and its output is approximately the same. The two packages are also intercompatible.\nHowever, one small change in `@urql/core`'s implementation is that your fragment names don't\nhave to be globally unique, since it's possible to create some one-off fragments occasionally,\nespecially for `@urql/exchange-graphcache`'s configuration.\nIt also pre-generates a \"hash key\" for the `DocumentNode` which is what `urql` does anyway, thus\navoiding some extra work compared to when the `graphql-tag` package is used with `urql`.\n\n## Using the `urql` Client\n\nThe `Client` is the main \"hub\" and store for everything that `urql` does. It is used by all\nframework bindings and from the other pages in the \"Basics\" section we can see that creating a\n`Client` comes up across all bindings and use-cases for `urql`.\n\n[Read more about the `Client` and `urql`'s architecture on the \"Architecture\"\npage.](../architecture.md)\n\n### Setting up the `Client`\n\nThe `@urql/core` package exports a `Client` class, which we can use to\ncreate the GraphQL client. This central `Client` manages all of our GraphQL requests and results.\n\n```js\nimport { Client, cacheExchange, fetchExchange } from '@urql/core';\n\nconst client = new Client({\n  url: 'http://localhost:3000/graphql',\n  exchanges: [cacheExchange, fetchExchange],\n});\n```\n\nAt the bare minimum we'll need to pass an API's `url`, and the `fetchExchange`,\nwhen we create a `Client` to get started.\n\nAnother common option is `fetchOptions`. This option allows us to customize the options that will be\npassed to `fetch` when a request is sent to the given API `url`. We may pass in an options object, or\na function returning an options object.\n\nIn the following example we'll add a token to each `fetch` request that our `Client` sends to our\nGraphQL API.\n\n```js\nconst client = new Client({\n  url: 'http://localhost:3000/graphql',\n  exchanges: [cacheExchange, fetchExchange],\n  fetchOptions: () => {\n    const token = getToken();\n    return {\n      headers: { authorization: token ? `Bearer ${token}` : '' },\n    };\n  },\n});\n```\n\n### The `Client`s options\n\nAs we've seen above, the most important options for the `Client` are `url` and `exchanges`.\nThe `url` option is used by the `fetchExchange` to send GraphQL requests to an API.\n\nThe `exchanges` option is of particular importance however because it tells the `Client` what to do\nwith our GraphQL requests:\n\n```js\nimport { Client, cacheExchange, fetchExchange } from '@urql/core';\n\nconst client = new Client({\n  url: 'http://localhost:3000/graphql',\n  exchanges: [cacheExchange, fetchExchange],\n});\n```\n\nFor instance, here, the `Client`'s caching and fetching features are only available because we're\npassing it exchanges. In the above example, the `Client` will try to first read a GraphQL request\nfrom a local cache, and if this request isn't cached it'll make an HTTP request.\nThe caching in `urql` is also implemented as an exchange, so for instance, the behavior described\non the [\"Document Caching\" page](./document-caching.md) is all contained within the `cacheExchange`\nabove.\n\nLater, [in the \"Advanced\" section](../advanced/README.md) we'll see many more features that `urql`\nsupports by adding new exchanges to this list. On [the \"Architecture\" page](../architecture.md)\nwe'll also learn more about what exchanges are and why they exist.\n\n### One-off Queries and Mutations\n\nWhen you're using `urql` to send one-off queries or mutations — rather than in full framework code,\nwhere updates are important — it's common to convert the streams that we get to promises. The\n`client.query` and `client.mutation` methods have a shortcut to do just that.\n\n```js\nconst QUERY = `\n  query Test($id: ID!) {\n    getUser(id: $id) {\n      id\n      name\n    }\n  }\n`;\n\nclient\n  .query(QUERY, { id: 'test' })\n  .toPromise()\n  .then(result => {\n    console.log(result); // { data: ... }\n  });\n```\n\nIn the above example we're executing a query on the client, are passing some variables and are\ncalling the `toPromise()` method on the return value to execute the request immediately and get the\nresult as a promise. This may be useful when we don't plan on cancelling queries, or we don't\ncare about future updates to this data and are just looking to query a result once.\n\nThis can also be written using async/await by simply awaiting the return value of `client.query`:\n\n```js\nconst QUERY = `\n  query Test($id: ID!) {\n    getUser(id: $id) {\n      id\n      name\n    }\n  }\n`;\n\nasync function query() {\n  const result = await client.query(QUERY, { id: 'test' });\n  console.log(result); // { data: ... }\n}\n```\n\nThe same can be done for mutations by calling the `client.mutation` method instead of the\n`client.query` method.\n\nIt's worth noting that promisifying a query result will always only give us _one_ result, because\nwe're not calling `subscribe`. This means that we'll never see cache updates when we're asking for\na single result like we do above.\n\n#### Reading only cache data\n\nSimilarly there's a way to read data from the cache synchronously, provided that the cache has\nreceived a result for a given query before. The `Client` has a `readQuery` method, which is a\nshortcut for just that.\n\n```js\nconst QUERY = `\n  query Test($id: ID!) {\n    getUser(id: $id) {\n      id\n      name\n    }\n  }\n`;\n\nconst result = client.readQuery(QUERY, { id: 'test' });\n\nresult; // null or { data: ... }\n```\n\nIn the above example we call `readQuery` and receive a result immediately. This result will be\n`null` if the `cacheExchange` doesn't have any results cached for the given query.\n\n### Subscribing to Results\n\nGraphQL Clients are by their nature \"reactive\", meaning that when we execute a query, we expect to\nget future results for this query. [On the \"Document Caching\" page](./document-caching.md) we'll\nlearn how mutations can invalidate results in the cache. This process (and others just like it) can\ncause our query to be refetched.\n\nIn essence, if we're subscribing to results rather than using a promise, like we've seen above, then\nwe're able to see future changes for our query's results. If a mutation causes a query to be\nrefetched from our API in the background then we'll see a new result. If we execute a query\nsomewhere else then we'll get notified of the new API result as well, as long as we're subscribed.\n\n```js\nconst QUERY = `\n  query Test($id: ID!) {\n    getUser(id: $id) {\n      id\n      name\n    }\n  }\n`;\n\nconst { unsubscribe } = client.query(QUERY, { id: 'test' }).subscribe(result => {\n  console.log(result); // { data: ... }\n});\n```\n\nThis code example is similar to the one before. However, instead of sending a one-off query, we're\nsubscribing to the query. Internally, this causes the `Client` to do the same, but the\nsubscription means that our callback may be called repeatedly. We may get future results as well as\nthe first one.\n\nThis also works synchronously. As we've seen before `client.readQuery` can give us a result\nimmediately if our cache already has a result for the given query. The same principle applies here!\nOur callback will be called synchronously if the cache already has a result.\n\nOnce we're not interested in any results anymore, we need to clean up after ourselves by calling\n`unsubscribe`. This stops the subscription and makes sure that the `Client` doesn't actively update\nthe query anymore or refetches it. We can think of this pattern as being very similar to events or\nevent hubs.\n\nWe're using [the Wonka library for our streams](https://wonka.kitten.sh/basics/background), which\nwe'll learn more about [on the \"Architecture\" page](../architecture.md). But we can think of this as\nReact's effects being called over time, or as `window.addEventListener`.\n\n## Common Utilities in Core\n\nThe `@urql/core` package contains other utilities that are shared between multiple addon packages.\nThis is a short but non-exhaustive list. It contains,\n\n- [`CombinedError`](../api/core.md#combinederror) - our abstraction to combine one or more `GraphQLError`(s) and a `NetworkError`\n- `makeResult` and `makeErrorResult` - utilities to create _Operation Results_\n- [`createRequest`](../api/core.md#createrequest) - a utility function to create a request from a\n  query, and some variables (which generate a stable _Operation Key_)\n\nThere are other utilities not mentioned here. Read more about the `@urql/core` API in the [API docs](../api/core.md).\n\n## Reading on\n\nThis concludes the introduction for using `@urql/core` without any framework bindings. This showed\njust a couple of ways to use `gql` or the `Client`, however you may also want to learn more about\n[how to use `urql`'s streams](../architecture.md#stream-patterns-in-urql). Furthermore, apart from the framework\nbinding introductions, there are some other pages that provide more information on how to get fully\nset up with `urql`:\n\n- [How does the default \"document cache\" work?](./document-caching.md)\n- [How are errors handled and represented?](./errors.md)\n- [A quick overview of `urql`'s architecture and structure.](../architecture.md)\n- [Setting up other features, like authentication, uploads, or persisted queries.](../advanced/README.md)\n"
  },
  {
    "path": "docs/basics/document-caching.md",
    "content": "---\ntitle: Document Caching\norder: 4\n---\n\n# Document Caching\n\nBy default, `urql` uses a concept called _Document Caching_. It will avoid sending the same requests\nto a GraphQL API repeatedly by caching the result of each query.\n\nThis works like the cache in a browser. `urql` creates a key for each request that is sent based on\na query and its variables.\n\nThe default _document caching_ logic is implemented in the default `cacheExchange`. We'll learn more\nabout [\"Exchanges\" on the \"Architecture\" page.](../architecture.md)\n\n## Operation Keys\n\n![Keys for GraphQL Requests](../assets/urql-operation-keys.png)\n\nOnce a result comes in it's cached indefinitely by its key. This means that each unique request\ncan have exactly one cached result.\n\nHowever, we also need to invalidate the cached results so that requests are sent again and updated,\nwhen we know that some results are out-of-date. With document caching we assume that a result may\nbe invalidated by a mutation that executes on data that has been queried previously.\n\nIn GraphQL the client can request additional type information by adding the `__typename` field to a\nquery's _selection set_. This field returns the name of the type for an object in the results, and\nwe use it to detect commonalities and data dependencies between queries and mutations.\n\n![Document Caching](../assets/urql-document-caching.png)\n\nIn short, when we send a mutation that contains types that another query's results contains as well,\nthat query's result is removed from the cache.\n\nThis is an aggressive form of cache invalidation. However, it works well for content-driven sites,\nwhile it doesn't deal with normalized data or IDs.\n\n## Request Policies\n\nThe _request policy_ that is defined will alter what the default document cache does. By default, the\ncache will prefer cached results and will otherwise send a request, which is called `cache-first`.\nIn total there are four different policies that we can use:\n\n- `cache-first` (the default) prefers cached results and falls back to sending an API request when\n  no prior result is cached.\n- `cache-and-network` returns cached results but also always sends an API request, which is perfect\n  for displaying data quickly while keeping it up-to-date.\n- `network-only` will always send an API request and will ignore cached results.\n- `cache-only` will always return cached results or `null`.\n\nThe `cache-and-network` policy is particularly useful, since it allows us to display data instantly\nif it has been cached, but also refreshes data in our cache in the background. This means though\nthat `fetching` will be `false` for cached results although an API request may still be ongoing in\nthe background.\n\nFor this reason there's another field on results, `result.stale`, which indicates that the cached\nresult is either outdated or that another request is being sent in the background.\n\n[Read more about which request policies are available in the API\ndocs.](../api/core.md#requestpolicy-type)\n\n## Document Cache Gotchas\n\nThis cache has a small trade-off! If we request a list of data, and the API returns an empty list,\nthen the cache won't be able to see the `__typename` of said list and invalidate it.\n\nThere are two ways to fix this issue, supplying `additionalTypenames` to the context of your query or [switch to \"Normalized Caching\"\ninstead](../graphcache/normalized-caching.md).\n\n### Adding typenames\n\nThis will elaborate about the first fix for empty lists, the `additionalTypenames`.\n\nExample where this would occur:\n\n```js\nconst query = `query { todos { id name } }`;\nconst result = { todos: [] };\n```\n\nAt this point we don't know what types are possible for this query, so a best practice when using\nthe default cache is to add `additionalTypenames` for this query.\n\n```js\n// Keep the reference stable.\nconst context = useMemo(() => ({ additionalTypenames: ['Todo'] }), []);\nconst [result] = useQuery({ query, context });\n```\n\nNow the cache will know when to invalidate this query even when the list is empty.\n\nWe may also use this feature for mutations, since occasionally mutations must invalidate data that\nisn't directly connected to a mutation by a `__typename`.\n\n```js\nconst [result, execute] = useMutation(`mutation($name: String!) { createUser(name: $name) }`);\n\nconst onClick = () => {\n  execute({ name: 'newName' }, { additionalTypenames: ['Wallet'] });\n};\n```\n\nNow our `mutation` knows that when it completes it has an additional type to invalidate.\n"
  },
  {
    "path": "docs/basics/errors.md",
    "content": "---\ntitle: Errors\norder: 5\n---\n\n# Error handling\n\nWhen we use a GraphQL API there are two kinds of errors we may encounter: Network Errors and GraphQL\nErrors from the API. Since it's common to encounter either of them, there's a\n[`CombinedError`](../api/core.md#combinederror) class that can hold and abstract either.\n\nWe may encounter a `CombinedError` when using `urql` wherever an `error` may be returned, typically\nin results from the API. The `CombinedError` can have one of two properties that describe what went\nwrong.\n\n- The `networkError` property will contain any error that stopped `urql` from making a network\n  request.\n- The `graphQLErrors` property may be an array that contains [normalized `GraphQLError`s as they\n  were received in the `errors` array from a GraphQL API.](https://graphql.org/graphql-js/error/)\n\nAdditionally, the `message` of the error will be generated and combined from the errors for\ndebugging purposes.\n\n![Combined errors](../assets/urql-combined-error.png)\n\nIt's worth noting that an `error` can coexist and be returned in a successful request alongside\n`data`. This is because in GraphQL a query can have partially failed but still contain some data.\nIn that case `CombinedError` will be passed to us with `graphQLErrors`, while `data` may still be\nset.\n"
  },
  {
    "path": "docs/basics/react-preact.md",
    "content": "---\ntitle: React/Preact Bindings\norder: 0\n---\n\n# React/Preact\n\nThis guide covers how to install and setup `urql` and the `Client`, as well as query and mutate data,\nwith React and Preact. Since the `urql` and `@urql/preact` packages share most of their API and are\nused in the same way, when reading the documentation on React, all examples are essentially the same,\nexcept that we'd want to use the `@urql/preact` package instead of the `urql` package.\n\n## Getting started\n\n### Installation\n\nInstalling `urql` is as quick as you'd expect, and you won't need any other packages to get started\nwith at first. We'll install the package with our package manager of choice.\n\n```sh\nyarn add urql\n# or\nnpm install --save urql\n```\n\nTo use `urql` with Preact, we have to install `@urql/preact` instead of `urql` and import from\nthat package instead. Otherwise all examples for Preact will be the same.\n\nMost libraries related to GraphQL also need the `graphql` package to be installed as a peer\ndependency, so that they can adapt to your specific versioning requirements. That's why we'll need\nto install `graphql` alongside `urql`.\n\nBoth the `urql` and `graphql` packages follow [semantic versioning](https://semver.org) and all\n`urql` packages will define a range of compatible versions of `graphql`. Watch out for breaking\nchanges in the future however, in which case your package manager may warn you about `graphql` being\nout of the defined peer dependency range.\n\n### Setting up the `Client`\n\nThe `urql` and `@urql/preact` packages export a `Client` class, which we can use to\ncreate the GraphQL client. This central `Client` manages all of our GraphQL requests and results.\n\n```js\nimport { Client, cacheExchange, fetchExchange } from 'urql';\n\nconst client = new Client({\n  url: 'http://localhost:3000/graphql',\n  exchanges: [cacheExchange, fetchExchange],\n});\n```\n\nAt the bare minimum we'll need to pass an API's `url` and `exchanges` when we create a `Client`\nto get started.\n\nAnother common option is `fetchOptions`. This option allows us to customize the options that will be\npassed to `fetch` when a request is sent to the given API `url`. We may pass in an options object, or\na function returning an options object.\n\nIn the following example we'll add a token to each `fetch` request that our `Client` sends to our\nGraphQL API.\n\n```js\nconst client = new Client({\n  url: 'http://localhost:3000/graphql',\n  exchanges: [cacheExchange, fetchExchange],\n  fetchOptions: () => {\n    const token = getToken();\n    return {\n      headers: { authorization: token ? `Bearer ${token}` : '' },\n    };\n  },\n});\n```\n\n### Providing the `Client`\n\nTo make use of the `Client` in React & Preact we will have to provide it via the\n[Context API](https://reactjs.org/docs/context.html). This may be done with the help of\nthe `Provider` export.\n\n```jsx\nimport { Client, Provider, cacheExchange, fetchExchange } from 'urql';\n\nconst client = new Client({\n  url: 'http://localhost:3000/graphql',\n  exchanges: [cacheExchange, fetchExchange],\n});\n\nconst App = () => (\n  <Provider value={client}>\n    <YourRoutes />\n  </Provider>\n);\n```\n\nNow every component and element inside and under the `Provider` can use GraphQL queries that\nwill be sent to our API.\n\n## Queries\n\nBoth libraries offer a `useQuery` hook and a `Query` component. The latter accepts the same\nparameters, but we won't cover it in this guide. [Look it up in the API docs if you prefer\nrender-props components.](../api/urql.md#query-component)\n\n### Run a first query\n\nFor the following examples, we'll imagine that we're querying data from a GraphQL API that contains\ntodo items. Let's dive right into it!\n\n```jsx\nimport { gql, useQuery } from 'urql';\n\nconst TodosQuery = gql`\n  query {\n    todos {\n      id\n      title\n    }\n  }\n`;\n\nconst Todos = () => {\n  const [result, reexecuteQuery] = useQuery({\n    query: TodosQuery,\n  });\n\n  const { data, fetching, error } = result;\n\n  if (fetching) return <p>Loading...</p>;\n  if (error) return <p>Oh no... {error.message}</p>;\n\n  return (\n    <ul>\n      {data.todos.map(todo => (\n        <li key={todo.id}>{todo.title}</li>\n      ))}\n    </ul>\n  );\n};\n```\n\nHere we have implemented our first GraphQL query to fetch todos. We see that `useQuery` accepts\noptions and returns a tuple. In this case we've set the `query` option to our GraphQL query. The\ntuple we then get in return is an array that contains a result object, and a re-execute function.\n\nThe result object contains several properties. The `fetching` field indicates whether the hook is\nloading data, `data` contains the actual `data` from the API's result, and `error` is set when either\nthe request to the API has failed or when our API result contained some `GraphQLError`s, which\nwe'll get into later on the [\"Errors\" page](./errors.md).\n\n### Variables\n\nTypically we'll also need to pass variables to our queries, for instance, if we are dealing with\npagination. For this purpose the `useQuery` hook also accepts a `variables` option, which we can use\nto supply variables to our query.\n\n```jsx\nconst TodosListQuery = gql`\n  query ($from: Int!, $limit: Int!) {\n    todos(from: $from, limit: $limit) {\n      id\n      title\n    }\n  }\n`;\n\nconst Todos = ({ from, limit }) => {\n  const [result, reexecuteQuery] = useQuery({\n    query: TodosListQuery,\n    variables: { from, limit },\n  });\n\n  // ...\n};\n```\n\nAs when we're sending GraphQL queries manually using `fetch`, the variables will be attached to the\n`POST` request body that is sent to our GraphQL API.\n\nWhenever the `variables` (or the `query`) option on the `useQuery` hook changes `fetching` will\nswitch to `true`, and a new request will be sent to our API, unless a result has already been cached\npreviously.\n\n### Pausing `useQuery`\n\nIn some cases we may want `useQuery` to execute a query when a pre-condition has been met, and not\nexecute the query otherwise. For instance, we may be building a form and want a validation query to\nonly take place when a field has been filled out.\n\nSince hooks in React can't just be commented out, the `useQuery` hook accepts a `pause` option that\ntemporarily _freezes_ all changes and stops requests.\n\nIn the previous example we've defined a query with mandatory arguments. The `$from` and `$limit`\nvariables have been defined to be non-nullable `Int!` values.\n\nLet's pause the query we've just\nwritten to not execute when these variables are empty, to prevent `null` variables from being\nexecuted. We can do this by setting the `pause` option to `true`:\n\n```jsx\nconst Todos = ({ from, limit }) => {\n  const shouldPause = from === undefined || from === null || limit === undefined || limit === null;\n  const [result, reexecuteQuery] = useQuery({\n    query: TodosListQuery,\n    variables: { from, limit },\n    pause: shouldPause,\n  });\n\n  // ...\n};\n```\n\nNow whenever the mandatory `$from` or `$limit` variables aren't supplied the query won't be executed.\nThis also means that `result.data` won't change, which means we'll still have access to our old data\neven though the variables may have changed.\n\n### Request Policies\n\nAs has become clear in the previous sections of this page, the `useQuery` hook accepts more options\nthan just `query` and `variables`. Another option we should touch on is `requestPolicy`.\n\nThe `requestPolicy` option determines how results are retrieved from our `Client`'s cache. By\ndefault, this is set to `cache-first`, which means that we prefer to get results from our cache, but\nare falling back to sending an API request.\n\nRequest policies aren't specific to `urql`'s React API, but are a common feature in its core. [You\ncan learn more about how the cache behaves given the four different policies on the \"Document\nCaching\" page.](../basics/document-caching.md)\n\n```jsx\nconst [result, reexecuteQuery] = useQuery({\n  query: TodosListQuery,\n  variables: { from, limit },\n  requestPolicy: 'cache-and-network',\n});\n```\n\nSpecifically, a new request policy may be passed directly to the `useQuery` hook as an option.\nThis policy is then used for this specific query. In this case, `cache-and-network` is used and\nthe query will be refreshed from our API even after our cache has given us a cached result.\n\nInternally, the `requestPolicy` is just one of several \"**context** options\". The `context`\nprovides metadata apart from the usual `query` and `variables` we may pass. This means that\nwe may also change the `Client`'s default `requestPolicy` by passing it there.\n\n```js\nimport { Client, cacheExchange, fetchExchange } from 'urql';\n\nconst client = new Client({\n  url: 'http://localhost:3000/graphql',\n  exchanges: [cacheExchange, fetchExchange],\n  // every operation will by default use cache-and-network rather\n  // than cache-first now:\n  requestPolicy: 'cache-and-network',\n});\n```\n\n### Context Options\n\nAs mentioned, the `requestPolicy` option on `useQuery` is a part of `urql`'s context options.\nIn fact, there are several more built-in context options, and the `requestPolicy` option is\none of them. Another option we've already seen is the `url` option, which determines our\nAPI's URL. These options aren't limited to the `Client` and may also be passed per query.\n\n```jsx\nimport { useMemo } from 'react';\nimport { useQuery } from 'urql';\n\nconst Todos = ({ from, limit }) => {\n  const [result, reexecuteQuery] = useQuery({\n    query: TodosListQuery,\n    variables: { from, limit },\n    context: useMemo(\n      () => ({\n        requestPolicy: 'cache-and-network',\n        url: 'http://localhost:3000/graphql?debug=true',\n      }),\n      []\n    ),\n  });\n\n  // ...\n};\n```\n\nAs we can see, the `context` property for `useQuery` accepts any known `context` option and can be\nused to alter them per query rather than globally. The `Client` accepts a subset of `context`\noptions, while the `useQuery` option does the same for a single query.\n[You can find a list of all `Context` options in the API docs.](../api/core.md#operationcontext)\n\n### Reexecuting Queries\n\nThe `useQuery` hook updates and executes queries whenever its inputs, like the `query` or\n`variables` change, but in some cases we may find that we need to programmatically trigger a new\nquery. This is the purpose of the `reexecuteQuery` function, which is the second item in the tuple\nthat `useQuery` returns.\n\nTriggering a query programmatically may be useful in a couple of cases. It can for instance be used\nto refresh the hook's data. In these cases we may also override the `requestPolicy` of our query just\nonce and set it to `network-only` to skip the cache.\n\n```jsx\nconst Todos = ({ from, limit }) => {\n  const [result, reexecuteQuery] = useQuery({\n    query: TodosListQuery,\n    variables: { from, limit },\n  });\n\n  const refresh = () => {\n    // Refetch the query and skip the cache\n    reexecuteQuery({ requestPolicy: 'network-only' });\n  };\n};\n```\n\nCalling `refresh` in the above example will execute the query again forcefully, and will skip the\ncache, since we're passing `requestPolicy: 'network-only'`.\n\nFurthermore the `reexecuteQuery` function can also be used to programmatically start a query even\nwhen `pause` is set to `true`, which would usually stop all automatic queries. This can be used to\nperform one-off actions, or to set up polling.\n\n```jsx\nimport { useEffect } from 'react';\nimport { useQuery } from 'urql';\n\nconst Todos = ({ from, limit }) => {\n  const [result, reexecuteQuery] = useQuery({\n    query: TodosListQuery,\n    variables: { from, limit },\n    pause: true,\n  });\n\n  useEffect(() => {\n    if (result.fetching) return;\n\n    // Set up to refetch in one second, if the query is idle\n    const timerId = setTimeout(() => {\n      reexecuteQuery({ requestPolicy: 'network-only' });\n    }, 1000);\n\n    return () => clearTimeout(timerId);\n  }, [result.fetching, reexecuteQuery]);\n\n  // ...\n};\n```\n\nThere are some more tricks we can use with `useQuery`. [Read more about its API in the API docs for\nit.](../api/urql.md#usequery)\n\n## Mutations\n\nBoth libraries offer a `useMutation` hook and a `Mutation` component. The latter accepts the same\nparameters, but we won't cover it in this guide. [Look it up in the API docs if you prefer\nrender-props components.](../api/urql.md#mutation-component)\n\n### Sending a mutation\n\nLet's again pick up an example with an imaginary GraphQL API for todo items, and dive into an\nexample! We'll set up a mutation that _updates_ a todo item's title.\n\n```jsx\nconst UpdateTodo = `\n  mutation ($id: ID!, $title: String!) {\n    updateTodo (id: $id, title: $title) {\n      id\n      title\n    }\n  }\n`;\n\nconst Todo = ({ id, title }) => {\n  const [updateTodoResult, updateTodo] = useMutation(UpdateTodo);\n};\n```\n\nSimilar to the `useQuery` output, `useMutation` returns a tuple. The first item in the tuple again\ncontains `fetching`, `error`, and `data` — it's identical since this is a common pattern of how\n`urql` presents [operation results](../api/core.md#operationresult).\n\nUnlike the `useQuery` hook, the `useMutation` hook doesn't execute automatically. At this point in\nour example, no mutation will be performed. To execute our mutation we instead have to call the\nexecute function — `updateTodo` in our example — which is the second item in the tuple.\n\n### Using the mutation result\n\nWhen calling our `updateTodo` function we have two ways of getting to the result as it comes back\nfrom our API. We can either use the first value of the returned tuple, our `updateTodoResult`, or\nwe can use the promise that `updateTodo` returns.\n\n```jsx\nconst Todo = ({ id, title }) => {\n  const [updateTodoResult, updateTodo] = useMutation(UpdateTodo);\n\n  const submit = newTitle => {\n    const variables = { id, title: newTitle || '' };\n    updateTodo(variables).then(result => {\n      // The result is almost identical to `updateTodoResult` with the exception\n      // of `result.fetching` not being set.\n      // It is an OperationResult.\n    });\n  };\n};\n```\n\nThe result is useful when your UI has to display progress on the mutation, and the returned\npromise is particularly useful when you're adding side effects that run after the mutation has\ncompleted.\n\n### Handling mutation errors\n\nIt's worth noting that the promise we receive when calling the execute function will never\nreject. Instead it will always return a promise that resolves to a result.\n\nIf you're checking for errors, you should use `result.error` instead, which will be set\nto a `CombinedError` when any kind of errors occurred while executing your mutation.\n[Read more about errors on our \"Errors\" page.](./errors.md)\n\n```jsx\nconst Todo = ({ id, title }) => {\n  const [updateTodoResult, updateTodo] = useMutation(UpdateTodo);\n\n  const submit = newTitle => {\n    const variables = { id, title: newTitle || '' };\n    updateTodo(variables).then(result => {\n      if (result.error) {\n        console.error('Oh no!', result.error);\n      }\n    });\n  };\n};\n```\n\nThere are some more tricks we can use with `useMutation`.<br />\n[Read more about its API in the API docs for it.](../api/urql.md#usemutation)\n\n## Reading on\n\nThis concludes the introduction for using `urql` with React or Preact. The rest of the documentation\nis mostly framework-agnostic and will apply to either `urql` in general, or the `@urql/core` package,\nwhich is the same between all framework bindings. Hence, next we may want to learn more about one of\nthe following to learn more about the internals:\n\n- [How does the default \"document cache\" work?](./document-caching.md)\n- [How are errors handled and represented?](./errors.md)\n- [A quick overview of `urql`'s architecture and structure.](../architecture.md)\n- [Setting up other features, like authentication, uploads, or persisted queries.](../advanced/README.md)\n"
  },
  {
    "path": "docs/basics/solid-start.md",
    "content": "---\ntitle: SolidStart Bindings\norder: 3\n---\n\n# SolidStart\n\nThis guide covers how to use `@urql/solid-start` with SolidStart applications. The `@urql/solid-start` package integrates urql with SolidStart's native data fetching primitives like `query()`, `action()`, `createAsync()`, and `useAction()`.\n\n> **Note:** This guide is for SolidStart applications with SSR. If you're building a client-side only SolidJS app, see the [Solid guide](./solid.md) instead. See the [comparison section](#solidjs-vs-solidstart) below for key differences between the packages.\n\n## Getting started\n\n### Installation\n\nInstalling `@urql/solid-start` requires both the package and its peer dependencies:\n\n```sh\nyarn add @urql/solid-start @urql/solid @urql/core graphql\n# or\nnpm install --save @urql/solid-start @urql/solid @urql/core graphql\n# or\npnpm add @urql/solid-start @urql/solid @urql/core graphql\n```\n\nThe `@urql/solid-start` package depends on `@urql/solid` for shared utilities and re-exports some primitives that work identically on both client and server.\n\n### Setting up the `Client`\n\nThe `@urql/solid-start` package exports a `Client` class from `@urql/core`. This central `Client` manages all of our GraphQL requests and results.\n\n```js\nimport { createClient, cacheExchange, fetchExchange } from '@urql/solid-start';\n\nconst client = createClient({\n  url: 'http://localhost:3000/graphql',\n  exchanges: [cacheExchange, fetchExchange],\n});\n```\n\nAt the bare minimum we'll need to pass an API's `url` and `exchanges` when we create a `Client`.\n\nFor server-side requests, you'll often want to customize `fetchOptions` to include headers like cookies or authorization tokens:\n\n```js\nimport { getRequestEvent } from 'solid-js/web';\n\nconst client = createClient({\n  url: 'http://localhost:3000/graphql',\n  exchanges: [cacheExchange, fetchExchange],\n  fetchOptions: () => {\n    const event = getRequestEvent();\n    return {\n      headers: {\n        cookie: event?.request.headers.get('cookie') || '',\n      },\n    };\n  },\n});\n```\n\n### Providing the `Client`\n\nTo make use of the `Client` in SolidStart we will provide it via Solid's Context API using the `Provider` export. The Provider also needs the `query` and `action` functions from `@solidjs/router`:\n\n```jsx\n// src/root.tsx or src/app.tsx\nimport { Router, action, query } from '@solidjs/router';\nimport { FileRoutes } from '@solidjs/start/router';\nimport { Suspense } from 'solid-js';\nimport { createClient, Provider, cacheExchange, fetchExchange } from '@urql/solid-start';\n\nconst client = createClient({\n  url: 'http://localhost:3000/graphql',\n  exchanges: [cacheExchange, fetchExchange],\n});\n\nexport default function App() {\n  return (\n    <Router\n      root={props => (\n        <Provider value={{ client, query, action }}>\n          <Suspense>{props.children}</Suspense>\n        </Provider>\n      )}\n    >\n      <FileRoutes />\n    </Router>\n  );\n}\n```\n\nNow every route and component inside the `Provider` can use GraphQL queries and mutations that will be sent to our API. The `query` and `action` functions are provided in context so that `createQuery` and `createMutation` can access them automatically.\n\n## Queries\n\nThe `@urql/solid-start` package offers a `createQuery` primitive that integrates with SolidStart's `query()` and `createAsync()` primitives for optimal server-side rendering and streaming.\n\n### Run a first query\n\nFor the following examples, we'll imagine that we're querying data from a GraphQL API that contains todo items.\n\n```jsx\n// src/routes/todos.tsx\nimport { Suspense, For, Show } from 'solid-js';\nimport { createAsync } from '@solidjs/router';\nimport { gql } from '@urql/core';\nimport { createQuery } from '@urql/solid-start';\n\nconst TodosQuery = gql`\n  query {\n    todos {\n      id\n      title\n    }\n  }\n`;\n\nexport default function Todos() {\n  const queryTodos = createQuery(TodosQuery, 'todos-list');\n  const result = createAsync(() => queryTodos());\n\n  return (\n    <Suspense fallback={<p>Loading...</p>}>\n      <Show when={result()?.data}>\n        <ul>\n          <For each={result()!.data.todos}>\n            {(todo) => <li>{todo.title}</li>}\n          </For>\n        </ul>\n      </Show>\n    </Suspense>\n  );\n}\n```\n\nThe `createQuery` primitive integrates with SolidStart's data fetching system:\n\n1. It wraps SolidStart's `query()` function to execute URQL queries with proper router context\n2. The `query` function is automatically retrieved from the URQL context (no manual injection needed)\n3. The second parameter is a cache key (string) for SolidStart's router\n4. The returned function is wrapped with `createAsync()` to get the reactive result\n5. `createQuery` must be called inside a component where it has access to the context\n\nThe query automatically executes on both the server (during SSR) and the client, with SolidStart handling serialization and hydration.\n\n### Variables\n\nTypically we'll also need to pass variables to our queries. Pass variables as an option in the fourth parameter:\n\n```jsx\n// src/routes/todos/[page].tsx\nimport { Suspense, For, Show } from 'solid-js';\nimport { useParams, createAsync } from '@solidjs/router';\nimport { gql } from '@urql/core';\nimport { createQuery } from '@urql/solid-start';\n\nconst TodosListQuery = gql`\n  query ($from: Int!, $limit: Int!) {\n    todos(from: $from, limit: $limit) {\n      id\n      title\n    }\n  }\n`;\n\nexport default function TodosPage() {\n  const params = useParams();\n\n  const queryTodos = createQuery(TodosListQuery, 'todos-paginated', {\n    variables: {\n      from: parseInt(params.page) * 10,\n      limit: 10,\n    },\n  });\n\n  const result = createAsync(() => queryTodos());\n\n  return (\n    <Suspense fallback={<p>Loading...</p>}>\n      <Show when={result()?.data}>\n        <ul>\n          <For each={result()!.data.todos}>\n            {(todo) => <li>{todo.title}</li>}\n          </For>\n        </ul>\n      </Show>\n    </Suspense>\n  );\n}\n```\n\nFor dynamic variables that change based on reactive values, you'll need to recreate the query function when dependencies change.\n\n### Request Policies\n\nThe `requestPolicy` option determines how results are retrieved from the cache:\n\n```jsx\nconst queryTodos = createQuery(TodosQuery, 'todos-list', {\n  requestPolicy: 'cache-and-network',\n});\nconst result = createAsync(() => queryTodos());\n```\n\nAvailable policies:\n\n- `cache-first` (default): Prefer cached results, fall back to network\n- `cache-only`: Only use cached results, never send network requests\n- `network-only`: Always send a network request, ignore cache\n- `cache-and-network`: Return cached results immediately, then fetch from network\n\n[Learn more about request policies on the \"Document Caching\" page.](./document-caching.md)\n\n### Revalidation\n\nThere are two approaches to revalidating data in SolidStart with urql:\n\n1. **urql's cache invalidation** - Invalidates specific queries or entities in urql's cache, causing automatic refetches\n2. **SolidStart's revalidation** - Uses SolidStart's router revalidation to reload route data\n\nBoth approaches work well, and you can choose based on your needs. urql's invalidation is more granular and works at the query level, while SolidStart's revalidation works at the route level.\n\n#### Manual Revalidation with urql\n\nYou can manually revalidate queries using urql's cache invalidation with the `keyFor` helper. This invalidates specific queries in urql's cache and triggers automatic refetches:\n\n```jsx\n// src/routes/todos.tsx\nimport { Suspense, For, Show } from 'solid-js';\nimport { createAsync } from '@solidjs/router';\nimport { gql, keyFor } from '@urql/core';\nimport { createQuery, useClient } from '@urql/solid-start';\n\nconst TodosQuery = gql`\n  query {\n    todos {\n      id\n      title\n    }\n  }\n`;\n\nexport default function Todos() {\n  const client = useClient();\n  const queryTodos = createQuery(TodosQuery, 'todos-list');\n  const result = createAsync(() => queryTodos());\n\n  const handleRefresh = () => {\n    // Invalidate the todos query using keyFor\n    const key = keyFor(TodosQuery);\n    client.reexecuteOperation(client.createRequestOperation('query', {\n      key,\n      query: TodosQuery\n    }));\n  };\n\n  return (\n    <div>\n      <button onClick={handleRefresh}>Refresh Todos</button>\n      <Suspense fallback={<p>Loading...</p>}>\n        <Show when={result()?.data}>\n          <ul>\n            <For each={result()!.data.todos}>\n              {(todo) => <li>{todo.title}</li>}\n            </For>\n          </ul>\n        </Show>\n      </Suspense>\n    </div>\n  );\n}\n```\n\n#### Manual Revalidation with SolidStart\n\nAlternatively, you can use SolidStart's built-in `revalidate` function to reload route data. This is useful when you want to refresh all queries on a specific route:\n\n```jsx\n// src/routes/todos.tsx\nimport { Suspense, For, Show } from 'solid-js';\nimport { createAsync, revalidate } from '@solidjs/router';\nimport { gql } from '@urql/core';\nimport { createQuery } from '@urql/solid-start';\n\nconst TodosQuery = gql`\n  query {\n    todos {\n      id\n      title\n    }\n  }\n`;\n\nexport default function Todos() {\n  const queryTodos = createQuery(TodosQuery, 'todos-list');\n  const result = createAsync(() => queryTodos());\n\n  const handleRefresh = async () => {\n    // Revalidate the current route - refetches all queries on this page\n    await revalidate();\n  };\n\n  return (\n    <div>\n      <button onClick={handleRefresh}>Refresh Todos</button>\n      <Suspense fallback={<p>Loading...</p>}>\n        <Show when={result()?.data}>\n          <ul>\n            <For each={result()!.data.todos}>\n              {(todo) => <li>{todo.title}</li>}\n            </For>\n          </ul>\n        </Show>\n      </Suspense>\n    </div>\n  );\n}\n```\n\n#### Revalidation After Mutations\n\nA common pattern is to revalidate after a mutation succeeds. You can choose either approach:\n\n**Using urql's cache invalidation:**\n\n```jsx\n// src/routes/todos/new.tsx\nimport { useNavigate } from '@solidjs/router';\nimport { gql, keyFor } from '@urql/core';\nimport { createMutation, useClient } from '@urql/solid-start';\n\nconst TodosQuery = gql`\n  query {\n    todos {\n      id\n      title\n    }\n  }\n`;\n\nconst CreateTodo = gql`\n  mutation ($title: String!) {\n    createTodo(title: $title) {\n      id\n      title\n    }\n  }\n`;\n\nexport default function NewTodo() {\n  const navigate = useNavigate();\n  const client = useClient();\n  const [state, createTodo] = createMutation(CreateTodo);\n\n  const handleSubmit = async (e: Event) => {\n    e.preventDefault();\n    const formData = new FormData(e.target as HTMLFormElement);\n    const title = formData.get('title') as string;\n\n    const result = await createTodo({ title });\n\n    if (!result.error) {\n      // Invalidate todos query using keyFor\n      const key = keyFor(TodosQuery);\n      client.reexecuteOperation(client.createRequestOperation('query', {\n        key,\n        query: TodosQuery\n      }));\n      navigate('/todos');\n    }\n  };\n\n  return (\n    <form onSubmit={handleSubmit}>\n      <input name=\"title\" type=\"text\" required />\n      <button type=\"submit\" disabled={state.fetching}>\n        {state.fetching ? 'Creating...' : 'Create Todo'}\n      </button>\n    </form>\n  );\n}\n```\n\n**Using SolidStart's revalidation:**\n\n```jsx\n// src/routes/todos/new.tsx\nimport { useNavigate } from '@solidjs/router';\nimport { gql } from '@urql/core';\nimport { createMutation } from '@urql/solid-start';\nimport { revalidate } from '@solidjs/router';\n\nconst CreateTodo = gql`\n  mutation ($title: String!) {\n    createTodo(title: $title) {\n      id\n      title\n    }\n  }\n`;\n\nexport default function NewTodo() {\n  const navigate = useNavigate();\n  const [state, createTodo] = createMutation(CreateTodo);\n\n  const handleSubmit = async (e: Event) => {\n    e.preventDefault();\n    const formData = new FormData(e.target as HTMLFormElement);\n    const title = formData.get('title') as string;\n\n    const result = await createTodo({ title });\n\n    if (!result.error) {\n      // Revalidate the /todos route to refetch all its queries\n      await revalidate('/todos');\n      navigate('/todos');\n    }\n  };\n\n  return (\n    <form onSubmit={handleSubmit}>\n      <input name=\"title\" type=\"text\" required />\n      <button type=\"submit\" disabled={state.fetching}>\n        {state.fetching ? 'Creating...' : 'Create Todo'}\n      </button>\n    </form>\n  );\n}\n```\n\n#### Automatic Revalidation with Actions\n\nWhen using SolidStart actions, you can configure automatic revalidation by returning the appropriate response:\n\n```jsx\nimport { action, revalidate } from '@solidjs/router';\nimport { gql } from '@urql/core';\n\nconst createTodoAction = action(async (formData: FormData) => {\n  const title = formData.get('title') as string;\n\n  // Perform mutation\n  const result = await client.mutation(CreateTodo, { title }).toPromise();\n\n  if (!result.error) {\n    // Revalidate multiple routes if needed\n    await revalidate(['/todos', '/']);\n  }\n\n  return result;\n});\n```\n\n#### Choosing Between Approaches\n\n**Use urql's `keyFor` and `reexecuteOperation` when:**\n\n- You need to refetch a specific query after a mutation\n- You want fine-grained control over which queries to refresh\n- You're working with multiple queries on the same route and only want to refetch one\n\n**Use SolidStart's `revalidate` when:**\n\n- You want to refresh all data on a route\n- You're navigating to a different route and want to ensure fresh data\n- You want to leverage SolidStart's routing system for cache management\n\nBoth approaches are valid and can even be used together depending on your application's needs.\n\n### Context Options\n\nContext options can be passed to customize the query behavior:\n\n```jsx\nconst queryTodos = createQuery(TodosQuery, 'todos-list', {\n  context: {\n    requestPolicy: 'cache-and-network',\n    fetchOptions: {\n      headers: {\n        'X-Custom-Header': 'value',\n      },\n    },\n  },\n});\nconst result = createAsync(() => queryTodos());\n```\n\n[You can find a list of all `Context` options in the API docs.](../api/core.md#operationcontext)\n\n## Mutations\n\nThe `@urql/solid-start` package offers a `createMutation` primitive that integrates with SolidStart's `action()` and `useAction()` primitives.\n\n### Sending a mutation\n\nMutations in SolidStart are executed using actions. Here's an example of updating a todo item:\n\n```jsx\n// src/routes/todos/[id]/edit.tsx\nimport { gql } from '@urql/core';\nimport { createMutation } from '@urql/solid-start';\nimport { useParams, useNavigate } from '@solidjs/router';\nimport { Show } from 'solid-js';\n\nconst UpdateTodo = gql`\n  mutation ($id: ID!, $title: String!) {\n    updateTodo(id: $id, title: $title) {\n      id\n      title\n    }\n  }\n`;\n\nexport default function EditTodo() {\n  const params = useParams();\n  const navigate = useNavigate();\n  const [state, updateTodo] = createMutation(UpdateTodo);\n\n  const handleSubmit = async (e: Event) => {\n    e.preventDefault();\n    const formData = new FormData(e.target as HTMLFormElement);\n    const title = formData.get('title') as string;\n\n    const result = await updateTodo({\n      id: params.id,\n      title,\n    });\n\n    if (!result.error) {\n      navigate(`/todos/${params.id}`);\n    }\n  };\n\n  return (\n    <form onSubmit={handleSubmit}>\n      <input name=\"title\" type=\"text\" required />\n      <button type=\"submit\" disabled={state.fetching}>\n        {state.fetching ? 'Saving...' : 'Save'}\n      </button>\n      <Show when={state.error}>\n        <p style={{ color: 'red' }}>Error: {state.error.message}</p>\n      </Show>\n    </form>\n  );\n}\n```\n\nThe `createMutation` primitive returns a tuple:\n\n1. A reactive state object containing `fetching`, `error`, and `data`\n2. An execute function that triggers the mutation\n\nYou can optionally provide a custom `key` parameter to control how mutations are cached by SolidStart's router:\n\n```jsx\nconst [state, updateTodo] = createMutation(UpdateTodo, 'update-todo-mutation');\n```\n\n### Progressive enhancement with actions\n\nSolidStart actions work with and without JavaScript enabled. Here's how to set up a mutation that works progressively:\n\n```jsx\nimport { action, redirect } from '@solidjs/router';\nimport { gql } from '@urql/core';\nimport { createMutation } from '@urql/solid-start';\n\nconst CreateTodo = gql`\n  mutation ($title: String!) {\n    createTodo(title: $title) {\n      id\n      title\n    }\n  }\n`;\n\nexport default function NewTodo() {\n  const [state, createTodo] = createMutation(CreateTodo);\n\n  const handleSubmit = async (formData: FormData) => {\n    const title = formData.get('title') as string;\n    const result = await createTodo({ title });\n\n    if (!result.error) {\n      return redirect('/todos');\n    }\n  };\n\n  return (\n    <form action={handleSubmit} method=\"post\">\n      <input name=\"title\" type=\"text\" required />\n      <button type=\"submit\" disabled={state.fetching}>\n        {state.fetching ? 'Creating...' : 'Create Todo'}\n      </button>\n      <Show when={state.error}>\n        <p style={{ color: 'red' }}>Error: {state.error.message}</p>\n      </Show>\n    </form>\n  );\n}\n```\n\n### Using mutation results\n\nThe mutation state is reactive and updates automatically as the mutation progresses:\n\n```jsx\nconst [state, updateTodo] = createMutation(UpdateTodo);\n\ncreateEffect(() => {\n  if (state.data) {\n    console.log('Mutation succeeded:', state.data);\n  }\n  if (state.error) {\n    console.error('Mutation failed:', state.error);\n  }\n  if (state.fetching) {\n    console.log('Mutation in progress...');\n  }\n});\n```\n\nThe execute function also returns a promise that resolves to the result:\n\n```jsx\nconst [state, updateTodo] = createMutation(UpdateTodo);\n\nconst handleUpdate = async () => {\n  const result = await updateTodo({ id: '1', title: 'Updated' });\n\n  if (result.error) {\n    console.error('Oh no!', result.error);\n  } else {\n    console.log('Success!', result.data);\n  }\n};\n```\n\n### Handling mutation errors\n\nMutation promises never reject. Instead, check the `error` field on the result:\n\n```jsx\nconst [state, updateTodo] = createMutation(UpdateTodo);\n\nconst handleUpdate = async () => {\n  const result = await updateTodo({ id: '1', title: 'Updated' });\n\n  if (result.error) {\n    // CombinedError with network or GraphQL errors\n    console.error('Mutation failed:', result.error);\n\n    // Check for specific error types\n    if (result.error.networkError) {\n      console.error('Network error:', result.error.networkError);\n    }\n    if (result.error.graphQLErrors.length > 0) {\n      console.error('GraphQL errors:', result.error.graphQLErrors);\n    }\n  }\n};\n```\n\n[Read more about error handling on the \"Errors\" page.](./errors.md)\n\n## Subscriptions\n\nFor GraphQL subscriptions, `@urql/solid-start` provides a `createSubscription` primitive that uses the same SolidStart `Provider` context as `createQuery` and `createMutation`:\n\n```jsx\nimport { gql } from '@urql/core';\nimport { createSubscription } from '@urql/solid-start';\nimport { createSignal, For } from 'solid-js';\n\nconst NewTodos = gql`\n  subscription {\n    newTodos {\n      id\n      title\n    }\n  }\n`;\n\nexport default function TodoSubscription() {\n  const [todos, setTodos] = createSignal([]);\n\n  const handleSubscription = (previousData, newData) => {\n    setTodos(current => [...current, newData.newTodos]);\n    return newData;\n  };\n\n  const [result] = createSubscription(\n    {\n      query: NewTodos,\n    },\n    handleSubscription\n  );\n\n  return (\n    <div>\n      <h2>Live Updates</h2>\n      <ul>\n        <For each={todos()}>{todo => <li>{todo.title}</li>}</For>\n      </ul>\n    </div>\n  );\n}\n```\n\nNote that GraphQL subscriptions typically require WebSocket support. You'll need to configure your client with a subscription exchange like `subscriptionExchange` from `@urql/core`.\n\n## Server-Side Rendering\n\nSolidStart automatically handles server-side rendering and hydration. The `createQuery` primitive works seamlessly on both server and client:\n\n1. On the server, queries execute during SSR and their results are serialized\n2. On the client, SolidStart hydrates the data without refetching\n3. Subsequent navigations use the standard cache policies\n\n### SSR Considerations\n\nWhen using `createQuery` in SolidStart:\n\n- Queries execute on the server during initial page load\n- Results are automatically streamed to the client\n- The client hydrates with the server data\n- No manual script injection or data serialization needed\n- SolidStart handles all the complexity automatically\n\n### Handling cookies and authentication\n\nFor authenticated requests, forward cookies and headers from the server request:\n\n```jsx\nimport { getRequestEvent } from 'solid-js/web';\nimport { createClient, cacheExchange, fetchExchange } from '@urql/solid-start';\n\nconst client = createClient({\n  url: 'http://localhost:3000/graphql',\n  exchanges: [cacheExchange, fetchExchange],\n  fetchOptions: () => {\n    const event = getRequestEvent();\n    const headers: Record<string, string> = {};\n\n    // Forward cookies for authenticated requests\n    if (event) {\n      const cookie = event.request.headers.get('cookie');\n      if (cookie) {\n        headers.cookie = cookie;\n      }\n    }\n\n    return { headers };\n  },\n});\n```\n\n## SolidJS vs SolidStart\n\n### When to Use Each Package\n\n| Use Case           | Package             | Why                                                              |\n| ------------------ | ------------------- | ---------------------------------------------------------------- |\n| Client-side SPA    | `@urql/solid`       | Optimized for client-only apps, uses SolidJS reactivity patterns |\n| SolidStart SSR App | `@urql/solid-start` | Integrates with SolidStart's routing, SSR, and action system     |\n\n### Key Differences\n\n#### Queries\n\n**@urql/solid** (Client-side):\n\n```tsx\nimport { createQuery } from '@urql/solid';\n\nconst [result] = createQuery({ query: TodosQuery });\n// Returns: [Accessor<OperationResult>, Accessor<ReExecute>]\n```\n\n**@urql/solid-start** (SSR):\n\n```tsx\nimport { createQuery } from '@urql/solid-start';\nimport { createAsync } from '@solidjs/router';\n\nconst queryTodos = createQuery(TodosQuery, 'todos');\nconst todos = createAsync(() => queryTodos());\n// Returns: Accessor<OperationResult | undefined>\n// Works with SSR and SolidStart's caching\n```\n\n#### Mutations\n\n**@urql/solid** (Client-side):\n\n```tsx\nimport { createMutation } from '@urql/solid';\n\nconst [result, executeMutation] = createMutation(AddTodoMutation);\nawait executeMutation({ title: 'New Todo' });\n// Returns: [Accessor<OperationResult>, ExecuteMutation]\n```\n\n**@urql/solid-start** (SSR with Actions):\n\n```tsx\nimport { createMutation } from '@urql/solid-start';\nimport { useAction, useSubmission } from '@solidjs/router';\n\nconst addTodoAction = createMutation(AddTodoMutation, 'add-todo');\nconst addTodo = useAction(addTodoAction);\nconst submission = useSubmission(addTodoAction);\nawait addTodo({ title: 'New Todo' });\n// Integrates with SolidStart's action system for progressive enhancement\n```\n\n### Why Different APIs?\n\n- **SSR Support**: SolidStart queries run on the server and stream to the client\n- **Router Integration**: Automatic caching and invalidation with SolidStart's router\n- **Progressive Enhancement**: Actions work without JavaScript enabled\n- **Suspense**: Native support for SolidJS Suspense boundaries\n\n### Migration\n\nIf you're moving from a SolidJS SPA to SolidStart:\n\n1. Change imports from `@urql/solid` to `@urql/solid-start`\n2. Wrap queries with `createAsync()`\n3. Update mutations to use the action pattern with `useAction()` and `useSubmission()`\n\nFor more details, see the [Solid bindings documentation](./solid.md).\n\n## Reading on\n\nThis concludes the introduction for using `@urql/solid-start` with SolidStart. For more information:\n\n- [Solid bindings documentation](./solid.md) - for client-only features\n- [How does the default \"document cache\" work?](./document-caching.md)\n- [How are errors handled and represented?](./errors.md)\n- [A quick overview of `urql`'s architecture and structure.](../architecture.md)\n- [Setting up other features, like authentication, uploads, or persisted queries.](../advanced/README.md)\n"
  },
  {
    "path": "docs/basics/solid.md",
    "content": "---\ntitle: Solid Bindings\norder: 3\n---\n\n# Solid\n\nThis guide covers how to install and setup `@urql/solid` and the `Client`, as well as query and mutate data with Solid. The `@urql/solid` package provides reactive primitives that integrate seamlessly with Solid's fine-grained reactivity system.\n\n> **Note:** This guide is for client-side SolidJS applications. If you're building a SolidStart application with SSR, see the [SolidStart guide](./solid-start.md) instead. The packages use different APIs optimized for their respective use cases.\n\n## Getting started\n\n### Installation\n\nInstalling `@urql/solid` is quick and you won't need any other packages to get started with at first. We'll install the package with our package manager of choice.\n\n```sh\nyarn add @urql/solid graphql\n# or\nnpm install --save @urql/solid graphql\n# or\npnpm add @urql/solid graphql\n```\n\nMost libraries related to GraphQL also need the `graphql` package to be installed as a peer dependency, so that they can adapt to your specific versioning requirements. That's why we'll need to install `graphql` alongside `@urql/solid`.\n\nBoth the `@urql/solid` and `graphql` packages follow [semantic versioning](https://semver.org) and all `@urql/solid` packages will define a range of compatible versions of `graphql`. Watch out for breaking changes in the future however, in which case your package manager may warn you about `graphql` being out of the defined peer dependency range.\n\n### Setting up the `Client`\n\nThe `@urql/solid` package exports a `Client` class from `@urql/core`, which we can use to create the GraphQL client. This central `Client` manages all of our GraphQL requests and results.\n\n```js\nimport { createClient, cacheExchange, fetchExchange } from '@urql/solid';\n\nconst client = createClient({\n  url: 'http://localhost:3000/graphql',\n  exchanges: [cacheExchange, fetchExchange],\n});\n```\n\nAt the bare minimum we'll need to pass an API's `url` and `exchanges` when we create a `Client` to get started.\n\nAnother common option is `fetchOptions`. This option allows us to customize the options that will be passed to `fetch` when a request is sent to the given API `url`. We may pass in an options object, or a function returning an options object.\n\nIn the following example we'll add a token to each `fetch` request that our `Client` sends to our GraphQL API.\n\n```js\nconst client = createClient({\n  url: 'http://localhost:3000/graphql',\n  exchanges: [cacheExchange, fetchExchange],\n  fetchOptions: () => {\n    const token = getToken();\n    return {\n      headers: { authorization: token ? `Bearer ${token}` : '' },\n    };\n  },\n});\n```\n\n### Providing the `Client`\n\nTo make use of the `Client` in Solid we will have to provide it via Solid's Context API. This may be done with the help of the `Provider` export.\n\n```jsx\nimport { render } from 'solid-js/web';\nimport { createClient, Provider, cacheExchange, fetchExchange } from '@urql/solid';\n\nconst client = createClient({\n  url: 'http://localhost:3000/graphql',\n  exchanges: [cacheExchange, fetchExchange],\n});\n\nconst App = () => (\n  <Provider value={client}>\n    <YourRoutes />\n  </Provider>\n);\n\nrender(() => <App />, document.getElementById('root'));\n```\n\nNow every component inside and under the `Provider` can use GraphQL queries that will be sent to our API.\n\n## Queries\n\nThe `@urql/solid` package offers a `createQuery` primitive that integrates with Solid's fine-grained reactivity system.\n\n### Run a first query\n\nFor the following examples, we'll imagine that we're querying data from a GraphQL API that contains todo items. Let's dive right into it!\n\n```jsx\nimport { Suspense, For } from 'solid-js';\nimport { gql } from '@urql/core';\nimport { createQuery } from '@urql/solid';\n\nconst TodosQuery = gql`\n  query {\n    todos {\n      id\n      title\n    }\n  }\n`;\n\nconst Todos = () => {\n  const [result] = createQuery({\n    query: TodosQuery,\n  });\n\n  return (\n    <Suspense fallback={<p>Loading...</p>}>\n      <ul>\n        <For each={result().data.todos}>\n          {(todo) => <li>{todo.title}</li>}\n        </For>\n      </ul>\n    </Suspense>\n  );\n};\n```\n\nHere we have implemented our first GraphQL query to fetch todos. We see that `createQuery` accepts options and returns a tuple. In this case we've set the `query` option to our GraphQL query. The tuple we then get in return is an array where the first item is an accessor function that returns the result object.\n\nThe result object contains several properties. The `fetching` field indicates whether the query is loading data, `data` contains the actual `data` from the API's result, and `error` is set when either the request to the API has failed or when our API result contained some `GraphQLError`s, which we'll get into later on the [\"Errors\" page](./errors.md).\n\n### Variables\n\nTypically we'll also need to pass variables to our queries, for instance, if we are dealing with pagination. For this purpose `createQuery` also accepts a `variables` option, which can be reactive.\n\n```jsx\nconst TodosListQuery = gql`\n  query ($from: Int!, $limit: Int!) {\n    todos(from: $from, limit: $limit) {\n      id\n      title\n    }\n  }\n`;\n\nconst Todos = (props) => {\n  const [result] = createQuery({\n    query: TodosListQuery,\n    variables: () => ({ from: props.from, limit: props.limit }),\n  });\n\n  // ...\n};\n```\n\nThe `variables` option can be passed as a static object or as an accessor function that returns the variables. When using an accessor, the query will automatically re-execute when the variables change.\n\n```jsx\nimport { Suspense, For, createSignal } from 'solid-js';\nimport { gql } from '@urql/core';\nimport { createQuery } from '@urql/solid';\n\nconst TodosListQuery = gql`\n  query ($from: Int!, $limit: Int!) {\n    todos(from: $from, limit: $limit) {\n      id\n      title\n    }\n  }\n`;\n\nconst Todos = () => {\n  const [from, setFrom] = createSignal(0);\n  const limit = 10;\n\n  const [result] = createQuery({\n    query: TodosListQuery,\n    variables: () => ({ from: from(), limit }),\n  });\n\n  return (\n    <div>\n      <Suspense fallback={<p>Loading...</p>}>\n        <ul>\n          <For each={result().data.todos}>\n            {(todo) => <li>{todo.title}</li>}\n          </For>\n        </ul>\n      </Suspense>\n      <button onClick={() => setFrom(f => f + 10)}>Next Page</button>\n    </div>\n  );\n};\n```\n\nWhenever the variables change, `fetching` will switch to `true`, and a new request will be sent to our API, unless a result has already been cached previously.\n\n### Pausing `createQuery`\n\nIn some cases we may want `createQuery` to execute a query when a pre-condition has been met, and not execute the query otherwise. For instance, we may be building a form and want a validation query to only take place when a field has been filled out.\n\nThe `createQuery` primitive accepts a `pause` option that temporarily stops the query from executing.\n\n```jsx\nconst Todos = (props) => {\n  const shouldPause = () => props.from == null || props.limit == null;\n  \n  const [result] = createQuery({\n    query: TodosListQuery,\n    variables: () => ({ from: props.from, limit: props.limit }),\n    pause: shouldPause,\n  });\n\n  // ...\n};\n```\n\nNow whenever the mandatory variables aren't supplied the query won't be executed. This also means that `result().data` won't change, which means we'll still have access to our old data even though the variables may have changed.\n\n### Request Policies\n\nThe `createQuery` primitive accepts a `requestPolicy` option that determines how results are retrieved from our `Client`'s cache. By default, this is set to `cache-first`, which means that we prefer to get results from our cache, but are falling back to sending an API request.\n\nRequest policies aren't specific to `@urql/solid`, but are a common feature in urql's core. [You can learn more about how the cache behaves given the four different policies on the \"Document Caching\" page.](./document-caching.md)\n\n```jsx\nconst [result] = createQuery({\n  query: TodosListQuery,\n  variables: () => ({ from: props.from, limit: props.limit }),\n  requestPolicy: 'cache-and-network',\n});\n```\n\nThe `requestPolicy` can be passed as a static string or as an accessor function. When using `cache-and-network`, the query will be refreshed from our API even after our cache has given us a cached result.\n\n### Context Options\n\nThe `requestPolicy` option is part of urql's context options. In fact, there are several more built-in context options. These options can be passed via the `context` parameter.\n\n```jsx\nconst [result] = createQuery({\n  query: TodosListQuery,\n  variables: () => ({ from: props.from, limit: props.limit }),\n  context: () => ({\n    requestPolicy: 'cache-and-network',\n    url: 'http://localhost:3000/graphql?debug=true',\n  }),\n});\n```\n\n[You can find a list of all `Context` options in the API docs.](../api/core.md#operationcontext)\n\n### Reexecuting Queries\n\nThe `createQuery` primitive updates and executes queries automatically when reactive inputs change, but in some cases we may need to programmatically trigger a new query. This is the purpose of the second item in the tuple that `createQuery` returns.\n\n```jsx\nconst Todos = () => {\n  const [result, reexecuteQuery] = createQuery({\n    query: TodosListQuery,\n    variables: { from: 0, limit: 10 },\n  });\n\n  const refresh = () => {\n    // Refetch the query and skip the cache\n    reexecuteQuery({ requestPolicy: 'network-only' });\n  };\n\n  return (\n    <div>\n      <Suspense fallback={<p>Loading...</p>}>\n        <ul>\n          <For each={result().data.todos}>\n            {(todo) => <li>{todo.title}</li>}\n          </For>\n        </ul>\n      </Suspense>\n      <button onClick={refresh}>Refresh</button>\n    </div>\n  );\n};\n```\n\nCalling `refresh` in the above example will execute the query again forcefully, and will skip the cache, since we're passing `requestPolicy: 'network-only'`.\n\n## Mutations\n\nThe `@urql/solid` package offers a `createMutation` primitive for executing GraphQL mutations.\n\n### Sending a mutation\n\nLet's again pick up an example with an imaginary GraphQL API for todo items. We'll set up a mutation that updates a todo item's title.\n\n```jsx\nimport { gql } from '@urql/core';\nimport { createMutation } from '@urql/solid';\n\nconst UpdateTodo = gql`\n  mutation ($id: ID!, $title: String!) {\n    updateTodo (id: $id, title: $title) {\n      id\n      title\n    }\n  }\n`;\n\nconst Todo = (props) => {\n  const [result, updateTodo] = createMutation(UpdateTodo);\n\n  const handleSubmit = (newTitle) => {\n    updateTodo({ id: props.id, title: newTitle });\n  };\n\n  return (\n    <div>\n      <Show when={result().fetching}>\n        <p>Updating...</p>\n      </Show>\n      <Show when={result().error}>\n        <p>Error: {result().error.message}</p>\n      </Show>\n      {/* Your form UI here */}\n    </div>\n  );\n};\n```\n\nSimilar to `createQuery`, `createMutation` returns a tuple. The first item is an accessor that returns the result object containing `fetching`, `error`, and `data` — identical to query results. The second item is the execute function that triggers the mutation.\n\nUnlike `createQuery`, `createMutation` doesn't execute automatically. We must call the execute function with the mutation variables.\n\n### Using the mutation result\n\nThe mutation result is available both through the reactive accessor and through the promise returned by the execute function.\n\n```jsx\nconst Todo = (props) => {\n  const [result, updateTodo] = createMutation(UpdateTodo);\n\n  const handleSubmit = (newTitle) => {\n    const variables = { id: props.id, title: newTitle };\n    \n    updateTodo(variables).then((result) => {\n      // The result is almost identical to result() from the accessor\n      // It is an OperationResult.\n      if (!result.error) {\n        console.log('Todo updated!', result.data);\n      }\n    });\n  };\n\n  return (\n    <div>\n      <Show when={result().fetching}>\n        <p>Updating...</p>\n      </Show>\n      {/* Your form UI here */}\n    </div>\n  );\n};\n```\n\nThe reactive accessor is useful when your UI needs to display progress on the mutation, and the returned promise is particularly useful for side effects that run after the mutation completes.\n\n### Handling mutation errors\n\nThe promise returned by the execute function will never reject. Instead it will always return a promise that resolves to a result.\n\nIf you're checking for errors, you should use `result.error`, which will be set to a `CombinedError` when any kind of errors occurred while executing your mutation. [Read more about errors on our \"Errors\" page.](./errors.md)\n\n```jsx\nconst Todo = (props) => {\n  const [result, updateTodo] = createMutation(UpdateTodo);\n\n  const handleSubmit = (newTitle) => {\n    const variables = { id: props.id, title: newTitle };\n    \n    updateTodo(variables).then((result) => {\n      if (result.error) {\n        console.error('Oh no!', result.error);\n      }\n    });\n  };\n\n  // ...\n};\n```\n\n## Subscriptions\n\nThe `@urql/solid` package offers a `createSubscription` primitive for handling GraphQL subscriptions with Solid's reactive system.\n\n### Setting up a subscription\n\nGraphQL subscriptions allow you to receive real-time updates from your GraphQL API. Here's an example of how to set up a subscription:\n\n```jsx\nimport { gql } from '@urql/core';\nimport { createSubscription } from '@urql/solid';\n\nconst NewTodos = gql`\n  subscription {\n    newTodos {\n      id\n      title\n    }\n  }\n`;\n\nconst TodoSubscription = () => {\n  const [result] = createSubscription({\n    query: NewTodos,\n  });\n\n  return (\n    <div>\n      <Show when={result().fetching}>\n        <p>Waiting for updates...</p>\n      </Show>\n      <Show when={result().error}>\n        <p>Error: {result().error.message}</p>\n      </Show>\n      <Show when={result().data}>\n        <p>New todo: {result().data.newTodos.title}</p>\n      </Show>\n    </div>\n  );\n};\n```\n\n### Handling subscription data\n\nUnlike queries and mutations, subscriptions can emit multiple results over time. You can use a `handler` function to accumulate or process subscription events:\n\n```jsx\nimport { createSignal } from 'solid-js';\n\nconst TodoSubscription = () => {\n  const [todos, setTodos] = createSignal([]);\n\n  const handleSubscription = (previousData, newData) => {\n    setTodos(current => [...current, newData.newTodos]);\n    return newData;\n  };\n\n  const [result] = createSubscription(\n    {\n      query: NewTodos,\n    },\n    handleSubscription\n  );\n\n  return (\n    <ul>\n      <For each={todos()}>\n        {(todo) => <li>{todo.title}</li>}\n      </For>\n    </ul>\n  );\n};\n```\n\nThe handler function receives the previous data and the new data from the subscription, allowing you to accumulate results or transform them as needed.\n\n## Reading on\n\nThis concludes the introduction for using `@urql/solid` with Solid. The rest of the documentation is mostly framework-agnostic and will apply to either `urql` in general, or the `@urql/core` package, which is the same between all framework bindings. Hence, next we may want to learn more about one of the following:\n\n- [How does the default \"document cache\" work?](./document-caching.md)\n- [How are errors handled and represented?](./errors.md)\n- [A quick overview of `urql`'s architecture and structure.](../architecture.md)\n- [Setting up other features, like authentication, uploads, or persisted queries.](../advanced/README.md)\n"
  },
  {
    "path": "docs/basics/svelte.md",
    "content": "---\ntitle: Svelte Bindings\norder: 2\n---\n\n# Svelte\n\n## Getting started\n\nThis \"Getting Started\" guide covers how to install and set up `urql` and provide a `Client` for\nSvelte. The `@urql/svelte` package, which provides bindings for Svelte, doesn't fundamentally\nfunction differently from `@urql/preact` or `urql` and uses the same [Core Package and\n`Client`](./core.md).\n\n### Installation\n\nInstalling `@urql/svelte` is quick and no other packages are immediately necessary.\n\n```sh\nyarn add @urql/svelte\n# or\nnpm install --save @urql/svelte\n```\n\nMost libraries related to GraphQL also need the `graphql` package to be installed as a peer\ndependency, so that they can adapt to your specific versioning requirements. That's why we'll need\nto install `graphql` alongside `@urql/svelte`.\n\nBoth the `@urql/svelte` and `graphql` packages follow [semantic versioning](https://semver.org) and\nall `@urql/svelte` packages will define a range of compatible versions of `graphql`. Watch out\nfor breaking changes in the future however, in which case your package manager may warn you about\n`graphql` being out of the defined peer dependency range.\n\nNote: if using Vite as your bundler, you might stumble upon the error `Function called outside component initialization`, which will prevent the page from loading. To fix it, you must add `@urql/svelte` to Vite's configuration property [`optimizeDeps.exclude`](https://vitejs.dev/config/#dep-optimization-options):\n\n```js\n{\n  optimizeDeps: {\n    exclude: ['@urql/svelte'],\n  }\n  // other properties\n}\n```\n\n### Setting up the `Client`\n\nThe `@urql/svelte` package exports a `Client` class, which we can use to create\nthe GraphQL client. This central `Client` manages all of our GraphQL requests and results.\n\n```js\nimport { Client, cacheExchange, fetchExchange } from '@urql/svelte';\n\nconst client = new Client({\n  url: 'http://localhost:3000/graphql',\n  exchanges: [cacheExchange, fetchExchange],\n});\n```\n\nAt the bare minimum we'll need to pass an API's `url` and `exchanges`\nwhen we create a `Client` to get started.\n\nAnother common option is `fetchOptions`. This option allows us to customize the options that will be\npassed to `fetch` when a request is sent to the given API `url`. We may pass in an options object or\na function returning an options object.\n\nIn the following example we'll add a token to each `fetch` request that our `Client` sends to our\nGraphQL API.\n\n```js\nconst client = new Client({\n  url: 'http://localhost:3000/graphql',\n  exchanges: [cacheExchange, fetchExchange],\n  fetchOptions: () => {\n    const token = getToken();\n    return {\n      headers: { authorization: token ? `Bearer ${token}` : '' },\n    };\n  },\n});\n```\n\n### Providing the `Client`\n\nTo make use of the `Client` in Svelte we will have to provide it via the\n[Context API](https://svelte.dev/tutorial/context-api). From a parent component to its child\ncomponents. This will share one `Client` with the rest of our app, if we for instance provide the\n`Client`\n\n```html\n<script>\n  import { Client, setContextClient, cacheExchange, fetchExchange } from '@urql/svelte';\n\n  const client = new Client({\n    url: 'http://localhost:3000/graphql',\n    exchanges: [cacheExchange, fetchExchange],\n  });\n\n  setContextClient(client);\n</script>\n```\n\nThe `setContextClient` method internally calls [Svelte's `setContext`\nfunction](https://svelte.dev/docs#run-time-svelte-setcontext). The `@urql/svelte` package also exposes a `getContextClient`\nfunction that uses [`getContext`](https://svelte.dev/docs#run-time-svelte-getcontext) to retrieve the `Client` in\nchild components. This is used to input the client into `@urql/svelte`'s API.\n\n## Queries\n\nWe'll implement queries using the `queryStore` function from `@urql/svelte`.\n\nThe `queryStore` function creates a [Svelte Writable store](https://svelte.dev/docs#writable).\nYou can use it to initialise a data container in `urql`. This store holds on to our query inputs,\nlike the GraphQL query and variables, which we can change to launch new queries. It also exposes\nthe query's eventual result, which we can then observe.\n\n### Run a first query\n\nFor the following examples, we'll imagine that we're querying data from a GraphQL API that contains\ntodo items. Let's dive right into it!\n\n```js\n<script>\n  import { queryStore, gql, getContextClient } from '@urql/svelte';\n\n  const todos = queryStore({\n    client: getContextClient(),\n    query: gql`\n      query {\n        todos {\n          id\n          title\n        }\n      }\n    `,\n  });\n</script>\n\n{#if $todos.fetching}\n<p>Loading...</p>\n{:else if $todos.error}\n<p>Oh no... {$todos.error.message}</p>\n{:else}\n<ul>\n  {#each $todos.data.todos as todo}\n  <li>{todo.title}</li>\n  {/each}\n</ul>\n{/if}\n```\n\nHere we have implemented our first GraphQL query to fetch todos. We're first creating a\n`queryStore` which will start our GraphQL query.\n\nThe `todos` store can now be used like any other Svelte store using a\n[reactive auto-subscription](https://svelte.dev/tutorial/auto-subscriptions) in Svelte. This means\nthat we prefix `$todos` with a dollar symbol, which automatically subscribes us to its changes.\n\n### Variables\n\nTypically we'll also need to pass variables to our queries, for instance, if we are dealing with\npagination. For this purpose the `queryStore` also accepts a `variables` argument, which we can\nuse to supply variables to our query.\n\n```js\n<script>\n  import { queryStore, getContextClient, gql } from '@urql/svelte';\n\n  $: todos = queryStore({\n    client: getContextClient(),\n    query: gql`\n      query ($from: Int!, $limit: Int!) {\n        todos(from: $from, limit: $limit) {\n          id\n          title\n        }\n      }\n    `,\n    variables: { from, limit }\n  });\n</script>\n...\n```\n\n> Note that we prefix the variable with `$` so Svelte knows that this store is reactive\n\nAs when we're sending GraphQL queries manually using `fetch`, the variables will be attached to the\n`POST` request body that is sent to our GraphQL API.\n\nThe `queryStore` also supports being actively changed. This will hook into Svelte's reactivity\nmodel as well and cause the `query` utility to start a new operation.\n\n```js\n<script>\n  import { queryStore, getContextClient, gql } from '@urql/svelte';\n\n  let limit = 10;\n  let from = 0;\n  $: todos = queryStore({\n    client: getContextClient(),\n    query: gql`\n      query ($from: Int!, $limit: Int!) {\n        todos(from: $from, limit: $limit) {\n          id\n          title\n        }\n      }\n    `,\n    variables: { from, limit }\n  );\n\n  function nextPage() {\n    from = from + 10\n  }\n</script>\n\n<button on:click={nextPage}>Next page<button></button></button>\n```\n\n### Pausing Queries\n\nIn some cases we may want our queries to not execute until a pre-condition has been met. Since the\n`query` operation exists for the entire component lifecycle however, it can't just be stopped and\nstarted at will. Instead, the `queryStore` accepts a key named `pause` that will tell the store that\nis starts out as paused.\n\nFor instance, we may start out with a paused store and then unpause it once a callback is invoked:\n\n```html\n<script>\n  import { queryStore, gql, getContextClient } from '@urql/svelte';\n\n  $: todos = queryStore({\n    client: getContextClient(),\n    query: gql`\n      query {\n        todos {\n          id\n          title\n        }\n      }\n    `,\n    pause: true,\n  });\n\n  function unpause() {\n    todos.resume();\n  }\n</script>\n\n<button on:click=\"{unpause}\">Unpause</button>\n```\n\n### Request Policies\n\nThe `queryStore` also accepts another key apart from `query` and `variables`. Optionally\nyou may pass a `requestPolicy`.\n\nThe `requestPolicy` option determines how results are retrieved from our `Client`'s cache. By\ndefault, this is set to `cache-first`, which means that we prefer to get results from our cache, but\nare falling back to sending an API request.\n\nRequest policies aren't specific to `urql`'s Svelte bindings, but are a common feature in its core.\n[You can learn more about how the cache behaves given the four different policies on the \"Document\nCaching\" page.](../basics/document-caching.md)\n\n```js\n<script>\n  import { queryStore, gql, getContextClient } from '@urql/svelte';\n\n  $: todos = queryStore({\n    client: getContextClient(),\n    query: gql`\n      query {\n        todos {\n          id\n          title\n        }\n      }\n    `,\n    requestPolicy: 'cache-and-network'\n  });\n</script>\n\n...\n```\n\nAs we can see, the `requestPolicy` is easily changed by passing it directly as a \"context option\"\nwhen creating a `queryStore`.\n\nInternally, the `requestPolicy` is just one of several \"**context** options\". The `context`\nprovides metadata apart from the usual `query` and `variables` we may pass. This means that\nwe may also change the `Client`'s default `requestPolicy` by passing it there.\n\n```js\nimport { Client, cacheExchange, fetchExchange } from '@urql/svelte';\n\nconst client = new Client({\n  url: 'http://localhost:3000/graphql',\n  exchanges: [cacheExchange, fetchExchange],\n  // every operation will by default use cache-and-network rather\n  // than cache-first now:\n  requestPolicy: 'cache-and-network',\n});\n```\n\n### Context Options\n\nAs mentioned, the `requestPolicy` option that we're passing to the `queryStore` is a part of\n`urql`'s context options. In fact, there are several more built-in context options, and the\n`requestPolicy` option is one of them. Another option we've already seen is the `url` option, which\ndetermines our API's URL.\n\n```js\n<script>\n  import { queryStore, gql, getContextClient } from '@urql/svelte';\n\n  $: todos = queryStore({\n    client: getContextClient(),\n    query: gql`\n      query {\n        todos {\n          id\n          title\n        }\n      }\n    `,\n    context: { url: 'http://localhost:3000/graphql?debug=true', }\n  });\n</script>\n\n...\n```\n\nAs we can see, the `context` argument for `queryStore` accepts any known `context` option and\ncan be used to alter them per query rather than globally. The `Client` accepts a subset of `context`\noptions, while the `queryStore` argument does the same for a single query. They're then merged\nfor your operation and form a full `Context` object for each operation, which means that any given\nquery is able to override them as needed.\n\n[You can find a list of all `Context` options in the API docs.](../api/core.md#operationcontext)\n\n### Reexecuting queries\n\nSometimes we'll need to arbitrarly reexecute a query to check for new data on the server, this can be done through:\n\n```jsx\n<script>\n  import { queryStore, gql, getContextClient } from '@urql/svelte';\n\n  const client = getContextClient();\n  const query = gql`\n    query {\n      todos {\n        id\n        title\n      }\n    }\n  `\n  $: todos = queryStore({\n    client,\n    query,\n  });\n\n  function refresh() {\n    todos.reexecute({\n      requestPolicy: 'network-only'\n    });\n  }\n</script>\n```\n\nWe use the `requestPolicy` with value `network-only` so we don't hit our cache and dispatch a refresh,\nif it updates the data the `todos` will be updated due to our cache updating.\n\n### Reading on\n\nThere are some more tricks we can use with `queryStore`.\n[Read more about its API in the API docs for it.](../api/svelte.md#queryStore)\n\n## Mutations\n\nThe `mutationStore` function is similar to the `queryStore` function but is triggered manually and\ncan accept a [`GraphQLRequest` object](../api/core.md#graphqlrequest).\n\n### Sending a mutation\n\nLet's again pick up an example with an imaginary GraphQL API for todo items, and dive into an\nexample! We'll set up a mutation that _updates_ a todo item's title.\n\n```html\n<script>\n  import { mutationStore, gql, getContextClient } from '@urql/svelte';\n\n  export let id;\n\n  let result;\n  let client = getContextClient();\n  const updateTodo = ({ id, title }) => {\n    result = mutationStore({\n      client,\n      query: gql`\n        mutation ($id: ID!, $title: String!) {\n          updateTodo(id: $id, title: $title) {\n            id\n            title\n          }\n        }\n      `,\n      variables: { id, title },\n    });\n  };\n</script>\n```\n\nThis small call to `mutationStore` accepts a `query` property (besides the `variables` property) and\nreturns the `OperationResult` as a store.\n\nUnlike the `query` function, we don't want the mutation to start automatically hence we enclose it in\na function. The `result` will be updated with the `fetching`, `data`, ... as a normal query would which\nyou can in-turn use in your UI.\n\n### Handling mutation errors\n\nIt's worth noting that the promise we receive when calling the execute function will never\nreject. Instead it will always return a promise that resolves to an `mutationStore`, even if the\nmutation has failed.\n\nIf you're checking for errors, you should use `mutationStore.error` instead, which will be set\nto a `CombinedError` when any kind of errors occurred while executing your mutation.\n[Read more about errors on our \"Errors\" page.](./errors.md)\n\n```jsx\nmutateTodo({ id, title: newTitle }).then(result => {\n  if (result.error) {\n    console.error('Oh no!', result.error);\n  }\n});\n```\n\n## Reading on\n\nThis concludes the introduction for using `urql` with Svelte. The rest of the documentation\nis mostly framework-agnostic and will apply to either `urql` in general, or the `@urql/core` package,\nwhich is the same between all framework bindings. Hence, next we may want to learn more about one of\nthe following to learn more about the internals:\n\n- [How does the default \"document cache\" work?](./document-caching.md)\n- [How are errors handled and represented?](./errors.md)\n- [A quick overview of `urql`'s architecture and structure.](../architecture.md)\n- [Setting up other features, like authentication, uploads, or persisted queries.](../advanced/README.md)\n"
  },
  {
    "path": "docs/basics/typescript-integration.md",
    "content": "---\ntitle: TypeScript integration\norder: 7\n---\n\n# URQL and TypeScript\n\nURQL, with the help of [GraphQL Code Generator](https://www.the-guild.dev/graphql/codegen), can leverage the typed-design of GraphQL Schemas to generate TypeScript types on the flight.\n\n## Getting started\n\n### Installation\n\nTo get and running, install the following packages:\n\n```sh\nyarn add -D graphql typescript @graphql-codegen/cli @graphql-codegen/client-preset\n# or\nnpm install -D graphql typescript @graphql-codegen/cli @graphql-codegen/client-preset\n```\n\nThen, add the following script to your `package.json`:\n\n```json\n{\n  \"scripts\": {\n    \"codegen\": \"graphql-codegen\"\n  }\n}\n```\n\nNow, let's create a configuration file for our current framework setup:\n\n### Configuration\n\n#### React project configuration\n\nCreate the following `codegen.ts` configuration file:\n\n```ts\nimport { CodegenConfig } from '@graphql-codegen/cli';\n\nconst config: CodegenConfig = {\n  schema: '<YOUR_GRAPHQL_API_URL>',\n  documents: ['src/**/*.tsx'],\n  ignoreNoDocuments: true, // for better experience with the watcher\n  generates: {\n    './src/gql/': {\n      preset: 'client',\n      plugins: [],\n    },\n  },\n};\n\nexport default config;\n```\n\n#### Vue project configuration\n\nCreate the following `codegen.ts` configuration file:\n\n```ts\nimport type { CodegenConfig } from '@graphql-codegen/cli';\n\nconst config: CodegenConfig = {\n  schema: '<YOUR_GRAPHQL_API_URL>',\n  documents: ['src/**/*.vue'],\n  ignoreNoDocuments: true, // for better experience with the watcher\n  generates: {\n    './src/gql/': {\n      preset: 'client',\n      config: {\n        useTypeImports: true,\n      },\n      plugins: [],\n    },\n  },\n};\n\nexport default config;\n```\n\n## Typing queries, mutations and subscriptions\n\nNow that your project is properly configured, let's start codegen in watch mode:\n\n```sh\nyarn codegen\n# or\nnpm run codegen\n```\n\nThis will generate a `./src/gql` folder that exposes a `graphql()` function.\n\nLet's use this `graphql()` function to write our GraphQL Queries, Mutations and Subscriptions.\n\nHere, an example with the React bindings, however, the usage remains the same for Vue and Svelte bindings:\n\n```tsx\nimport React from 'react';\nimport { useQuery } from 'urql';\n\nimport './App.css';\nimport Film from './Film';\nimport { graphql } from '../src/gql';\n\nconst allFilmsWithVariablesQueryDocument = graphql(/* GraphQL */ `\n  query allFilmsWithVariablesQuery($first: Int!) {\n    allFilms(first: $first) {\n      edges {\n        node {\n          ...FilmItem\n        }\n      }\n    }\n  }\n`);\n\nfunction App() {\n  // `data` is typed!\n  const [{ data }] = useQuery({\n    query: allFilmsWithVariablesQueryDocument,\n    variables: { first: 10 },\n  });\n  return (\n    <div className=\"App\">\n      {data && (\n        <ul>\n          {data.allFilms?.edges?.map(\n            (e, i) => e?.node && <Film film={e?.node} key={`film-${i}`} />\n          )}\n        </ul>\n      )}\n    </div>\n  );\n}\n\nexport default App;\n```\n\n_Examples with Vue are available [in the GraphQL Code Generator repository](https://github.com/dotansimha/graphql-code-generator/tree/master/examples/vue/urql)_.\n\nUsing the generated `graphql()` function to write your GraphQL document results in instantly typed result and variables for queries, mutations and subscriptions!\n\nLet's now see how to go further with GraphQL fragments.\n\n## Getting further with Fragments\n\n> Using GraphQL Fragments helps to explicitly declaring the data dependencies of your UI component and safely accessing only the data it needs.\n\nOur `<Film>` component relies on the `FilmItem` definition, passed through the `film` props:\n\n```tsx\n// ...\nimport Film from './Film';\nimport { graphql } from '../src/gql';\n\nconst allFilmsWithVariablesQueryDocument = graphql(/* GraphQL */ `\n  query allFilmsWithVariablesQuery($first: Int!) {\n    allFilms(first: $first) {\n      edges {\n        node {\n          ...FilmItem\n        }\n      }\n    }\n  }\n`);\n\nfunction App() {\n  // ...\n  return (\n    <div className=\"App\">\n      {data && (\n        <ul>\n          {data.allFilms?.edges?.map(\n            (e, i) => e?.node && <Film film={e?.node} key={`film-${i}`} />\n          )}\n        </ul>\n      )}\n    </div>\n  );\n}\n// ...\n```\n\nGraphQL Code Generator generates type helpers to type your component props based on Fragments (for example, the `film=` prop) and retrieve your fragment's data (see example below).\n\nAgain, here is an example with the React bindings:\n\n```tsx\nimport { FragmentType, useFragment } from './gql/fragment-masking';\nimport { graphql } from '../src/gql';\n\n// again, we use the generated `graphql()` function to write GraphQL documents 👀\nexport const FilmFragment = graphql(/* GraphQL */ `\n  fragment FilmItem on Film {\n    id\n    title\n    releaseDate\n    producers\n  }\n`);\n\nconst Film = (props: {\n  // `film` property has the correct type 🎉\n  film: FragmentType<typeof FilmFragment>;\n}) => {\n  // `film` is of type `FilmFragment`, with no extraneous properties ⚡️\n  const film = useFragment(FilmFragment, props.film);\n  return (\n    <div>\n      <h3>{film.title}</h3>\n      <p>{film.releaseDate}</p>\n    </div>\n  );\n};\n\nexport default Film;\n```\n\n_Examples with Vue are available [in the GraphQL Code Generator repository](https://github.com/dotansimha/graphql-code-generator/tree/master/examples/vue/urql)_.\n\nYou will notice that our `<Film>` component leverages 2 imports from our generated code (from `../src/gql`): the `FragmentType<T>` type helper and the `useFragment()` function.\n\n- we use `FragmentType<typeof FilmFragment>` to get the corresponding Fragment TypeScript type\n- later on, we use `useFragment()` to retrieve the properly film property\n"
  },
  {
    "path": "docs/basics/ui-patterns.md",
    "content": "---\ntitle: UI-Patterns\norder: 6\n---\n\n# UI Patterns\n\n> This page is incomplete. You can help us expanding it by suggesting more patterns or asking us about common problems you're facing on [GitHub Discussions](https://github.com/urql-graphql/urql/discussions).\n\nGenerally, `urql`'s API surface is small and compact. Some common problems that we're facing when building apps may look like they're not a built-in feature, however, there are several patterns that even a lean UI can support.\nThis page is a collection of common UI patterns and problems we may face with GraphQL and how we can tackle them in\n`urql`. These examples will be written in React but apply to any other framework.\n\n## Infinite scrolling\n\n\"Infinite Scrolling\" is the approach of loading more data into a page's list without splitting that list up across multiple pages.\n\nThere are a few ways of going about this. In our [normalized caching chapter on the topic](../graphcache/local-resolvers.md#pagination)\nwe see an approach with `urql`'s normalized cache, which is suitable to get started quickly. However, this approach also requires some UI code as well to keep track of pages.\nLet's have a look at how we can create a UI implementation that makes use of this normalized caching feature.\n\n```js\nimport React from 'react';\nimport { useQuery, gql } from 'urql';\n\nconst PageQuery = gql`\n  query Page($first: Int!, $after: String) {\n    todos(first: $first, after: $after) {\n      nodes {\n        id\n        name\n      }\n      pageInfo {\n        hasNextPage\n        endCursor\n      }\n    }\n  }\n`;\n\nconst SearchResultPage = ({ variables, isLastPage, onLoadMore }) => {\n  const [{ data, fetching, error }] = useQuery({ query: PageQuery, variables });\n  const todos = data?.todos;\n\n  return (\n    <div>\n      {error && <p>Oh no... {error.message}</p>}\n      {fetching && <p>Loading...</p>}\n      {todos && (\n        <>\n          {todos.nodes.map(todo => (\n            <div key={todo.id}>\n              {todo.id}: {todo.name}\n            </div>\n          ))}\n          {isLastPage && todos.pageInfo.hasNextPage && (\n            <button onClick={() => onLoadMore(todos.pageInfo.endCursor)}>load more</button>\n          )}\n        </>\n      )}\n    </div>\n  );\n};\n\nconst Search = () => {\n  const [pageVariables, setPageVariables] = useState([\n    {\n      first: 10,\n      after: '',\n    },\n  ]);\n\n  return (\n    <div>\n      {pageVariables.map((variables, i) => (\n        <SearchResultPage\n          key={'' + variables.after}\n          variables={variables}\n          isLastPage={i === pageVariables.length - 1}\n          onLoadMore={after => setPageVariables([...pageVariables, { after, first: 10 }])}\n        />\n      ))}\n    </div>\n  );\n};\n```\n\nHere we keep an array of all `variables` we've encountered and use them to render their\nrespective `result` page. This only rerenders the additional page rather than having a long\nlist that constantly changes. [You can find a full code example of this pattern in our example folder on the topic of pagination.](https://github.com/urql-graphql/urql/tree/main/examples/with-pagination)\n\nThis code doesn't take changing variables into account, which will affect the cursors. For an\nexample that takes full infinite scrolling into account, [you can find a full code example of an\nextended pattern in our example folder on the topic of infinite pagination.](https://github.com/urql-graphql/urql/tree/main/examples/with-infinite-pagination)\n\n## Prefetching data\n\nWe sometimes find it necessary to load data for a new page before that page is opened, for instance while a JS bundle is still loading. We may\ndo this with help of the `Client`, by calling methods without using the React bindings directly.\n\n```js\nimport React from 'react';\nimport { useClient, gql } from 'urql';\n\nconst TodoQuery = gql`\n  query Todo($id: ID!) {\n    todo(id: $id) {\n      id\n      name\n    }\n  }\n`;\n\nconst Component = () => {\n  const client = useClient();\n  const router = useRouter();\n\n  const transitionPage = React.useCallback(async id => {\n    const loadJSBundle = import('./page.js');\n    const loadData = client.query(TodoQuery, { id }).toPromise();\n    await Promise.all([loadJSBundle, loadData]);\n    router.push(`/todo/${id}`);\n  }, []);\n\n  return <button onClick={() => transitionPage('1')}>Go to todo 1</button>;\n};\n```\n\nHere we're calling `client.query` to prepare a query when the transition begins.\nWe then call `toPromise()` on this query which activates it. Our `Client` and its cache share results, which means that we've already kicked off or even completed the query before we're on the new page.\n\n## Lazy query\n\nIt's often required to \"lazily\" start a query, either at a later point or imperatively. This means that we don't start a query when a new component is mounted immediately.\n\nParts of `urql` that automatically start, like the `useQuery` hook, have a concept of a [`pause` option.](./react-preact.md#pausing-usequery) This option is used to prevent the hook from automatically starting a new query.\n\n```js\nimport React from 'react';\nimport { useQuery, gql } from 'urql';\n\nconst TodoQuery = gql`\n  query Todos {\n    todos {\n      id\n      name\n    }\n  }\n`;\n\nconst Component = () => {\n  const [result, fetch] = useQuery({ query: TodoQuery, pause: true });\n  const router = useRouter();\n\n  return <button onClick={fetch}>Load todos</button>;\n};\n```\n\nWe can unpause the hook to start fetching, or, like in this example, call its returned function to manually kick off the query.\n\n## Reacting to focus and stale time\n\nIn urql we leverage our extensibility pattern named \"Exchanges\" to manipulate the way\ndata comes in and goes out of our client.\n\n- [Stale time](https://github.com/urql-graphql/urql/tree/main/exchanges/request-policy)\n- [Focus](https://github.com/urql-graphql/urql/tree/main/exchanges/refocus)\n\nWhen we want to introduce one of these patterns we add the package and add it to the `exchanges`\nproperty of our `Client`. In the case of these two we'll have to add it before the cache\nelse our requests will never get upgraded.\n\n```js\nimport { Client, cacheExchange, fetchExchange } from 'urql';\nimport { refocusExchange } from '@urql/exchange-refocus';\n\nconst client = new Client({\n  url: 'some-url',\n  exchanges: [refocusExchange(), cacheExchange, fetchExchange],\n});\n```\n\nThat's all we need to do to react to these patterns.\n"
  },
  {
    "path": "docs/basics/vue.md",
    "content": "---\ntitle: Vue Bindings\norder: 1\n---\n\n# Vue\n\n## Getting started\n\nThe `@urql/vue` bindings have been written with [Vue\n3](https://github.com/vuejs/vue-next/releases/tag/v3.0.0) in mind and use Vue's newer [Composition\nAPI](https://v3.vuejs.org/guide/composition-api-introduction.html). This gives the `@urql/vue`\nbindings capabilities to be more easily integrated into your existing `setup()` functions.\n\n### Installation\n\nInstalling `@urql/vue` is quick and no other packages are immediately necessary.\n\n```sh\nyarn add @urql/vue graphql\n# or\nnpm install --save @urql/vue graphql\n```\n\nMost libraries related to GraphQL also need the `graphql` package to be installed as a peer\ndependency, so that they can adapt to your specific versioning requirements. That's why we'll need\nto install `graphql` alongside `@urql/vue`.\n\nBoth the `@urql/vue` and `graphql` packages follow [semantic versioning](https://semver.org) and\nall `@urql/vue` packages will define a range of compatible versions of `graphql`. Watch out\nfor breaking changes in the future however, in which case your package manager may warn you about\n`graphql` being out of the defined peer dependency range.\n\n### Setting up the `Client`\n\nThe `@urql/vue` package exports a `Client` class, which we can use to create\nthe GraphQL client. This central `Client` manages all of our GraphQL requests and results.\n\n```js\nimport { Client, cacheExchange, fetchExchange } from '@urql/vue';\n\nconst client = new Client({\n  url: 'http://localhost:3000/graphql',\n  exchanges: [cacheExchange, fetchExchange],\n});\n```\n\nAt the bare minimum we'll need to pass an API's `url` and `exchanges` when we create a `Client`\nto get started.\n\nAnother common option is `fetchOptions`. This option allows us to customize the options that will be\npassed to `fetch` when a request is sent to the given API `url`. We may pass in an options object or\na function returning an options object.\n\nIn the following example we'll add a token to each `fetch` request that our `Client` sends to our\nGraphQL API.\n\n```js\nconst client = new Client({\n  url: 'http://localhost:3000/graphql',\n  exchanges: [cacheExchange, fetchExchange],\n  fetchOptions: () => {\n    const token = getToken();\n    return {\n      headers: { authorization: token ? `Bearer ${token}` : '' },\n    };\n  },\n});\n```\n\n### Providing the `Client`\n\nTo make use of the `Client` in Vue we will have to provide from a parent component to its child\ncomponents. This will share one `Client` with the rest of our app. In `@urql/vue` there are two\ndifferent ways to achieve this.\n\nThe first method is to use `@urql/vue`'s `provideClient` function. This must be called in any of\nyour parent components and accepts either a `Client` directly or just the options that you'd pass to\n`Client`.\n\n```html\n<script>\n  import { Client, provideClient, cacheExchange, fetchExchange } from '@urql/vue';\n\n  const client = new Client({\n    url: 'http://localhost:3000/graphql',\n    exchanges: [cacheExchange, fetchExchange],\n  });\n\n  provideClient(client);\n</script>\n```\n\nAlternatively we may use the exported `install` function and treat `@urql/vue` as a plugin by\nimporting its default export and using it [as a plugin](https://v3.vuejs.org/guide/plugins.html#using-a-plugin).\n\n```js\nimport { createApp } from 'vue';\nimport Root from './App.vue';\nimport urql, { cacheExchange, fetchExchange } from '@urql/vue';\n\nconst app = createApp(Root);\n\napp.use(urql, {\n  url: 'http://localhost:3000/graphql',\n  exchanges: [cacheExchange, fetchExchange],\n});\n\napp.mount('#app');\n```\n\nThe plugin also accepts `Client`'s options or a `Client` as its inputs.\n\n## Queries\n\nWe'll implement queries using the `useQuery` function from `@urql/vue`.\n\n### Run a first query\n\nFor the following examples, we'll imagine that we're querying data from a GraphQL API that contains\ntodo items. Let's dive right into it!\n\n```jsx\n<template>\n  <div v-if=\"fetching\">\n    Loading...\n  </div>\n  <div v-else-if=\"error\">\n    Oh no... {{error}}\n  </div>\n  <div v-else>\n    <ul v-if=\"data\">\n      <li v-for=\"todo in data.todos\" :key=\"todo.id\">{{ todo.title }}</li>\n    </ul>\n  </div>\n</template>\n\n<script>\nimport { gql, useQuery } from '@urql/vue';\n\nexport default {\n  setup() {\n    const result = useQuery({\n      query: gql`\n        {\n          todos {\n            id\n            title\n          }\n        }\n      `\n    });\n\n    return {\n      fetching: result.fetching,\n      data: result.data,\n      error: result.error,\n    };\n  }\n};\n</script>\n```\n\nHere we have implemented our first GraphQL query to fetch todos. We see that `useQuery` accepts\noptions and returns a result object. In this case we've set the `query` option to our GraphQL query.\n\nThe result object contains several properties. The `fetching` field indicates whether we're currently\nloading data, `data` contains the actual `data` from the API's result, and `error` is set when either\nthe request to the API has failed or when our API result contained some `GraphQLError`s, which\nwe'll get into later on the [\"Errors\" page](./errors.md).\n\nAll of these properties on the result are derived from the [shape of\n`OperationResult`](../api/core.md#operationresult) and are marked as [reactive\n](https://v3.vuejs.org/guide/reactivity-fundamentals.html), which means they may\nupdate while the query is running, which will automatically update your UI.\n\n### Variables\n\nTypically we'll also need to pass variables to our queries, for instance, if we are dealing with\npagination. For this purpose `useQuery` also accepts a `variables` input, which we can\nuse to supply variables to our query.\n\n```jsx\n<template>\n  ...\n</template>\n\n<script>\nimport { gql, useQuery } from '@urql/vue';\n\nexport default {\n  props: ['from', 'limit'],\n  setup({ from, limit }) {\n    return useQuery({\n      query: gql`\n        query ($from: Int!, $limit: Int!) {\n          todos(from: $from, limit: $limit) {\n            id\n            title\n          }\n        }\n      `,\n      variables: { from, limit }\n    });\n  }\n};\n</script>\n```\n\nAs when we're sending GraphQL queries manually using `fetch`, the variables will be attached to the\n`POST` request body that is sent to our GraphQL API.\n\nAll inputs that are passed to `useQuery` may also be [reactive\nstate](https://v3.vuejs.org/guide/reactivity-fundamentals.html). This means that both the inputs and\noutputs of `useQuery` are reactive and may change over time.\n\n```jsx\n<template>\n  <ul v-if=\"data\">\n    <li v-for=\"todo in data.todos\" :key=\"todo.id\">{{ todo.title }}</li>\n  </ul>\n  <button @click=\"from += 10\">Next Page</button>\n</template>\n\n<script>\nimport { gql, useQuery } from '@urql/vue';\n\nexport default {\n  setup() {\n    const from = ref(0);\n\n    const result = useQuery({\n      query: gql`\n        query ($from: Int!, $limit: Int!) {\n          todos(from: $from, limit: $limit) {\n            id\n            title\n          }\n        }\n      `,\n      variables: { from, limit: 10 }\n    });\n\n    return {\n      from,\n      data: result.data,\n    };\n  }\n};\n</script>\n```\n\n### Pausing `useQuery`\n\nIn some cases we may want `useQuery` to execute a query when a pre-condition has been met, and not\nexecute the query otherwise. For instance, we may be building a form and want a validation query to\nonly take place when a field has been filled out.\n\nSince with Vue 3's Composition API we won't just conditionally call `useQuery` we can instead pass a\nreactive `pause` input to `useQuery`.\n\nIn the previous example we've defined a query with mandatory arguments. The `$from` and `$limit`\nvariables have been defined to be non-nullable `Int!` values.\n\nLet's pause the query we've just written to not execute when these variables are empty, to\nprevent `null` variables from being executed. We can do this by computing `pause` to become `true`\nwhenever these variables are falsy:\n\n```js\nimport { reactive } from 'vue'\nimport { gql, useQuery } from '@urql/vue';\n\nexport default {\n  props: ['from', 'limit'],\n  setup({ from, limit }) {\n    const shouldPause = computed(() => from == null || limit == null);\n    return useQuery({\n      query: gql`\n        query ($from: Int!, $limit: Int!) {\n          todos(from: $from, limit: $limit) {\n            id\n            title\n          }\n        }\n      `,\n      variables: { from, limit },\n      pause: shouldPause\n    });\n  }\n};\n</script>\n```\n\nNow whenever the mandatory `$from` or `$limit` variables aren't supplied the query won't be executed.\nThis also means that `result.data` won't change, which means we'll still have access to our old data\neven though the variables may have changed.\n\nIt's worth noting that depending on whether `from` and `limit` are reactive or not you may have to\nchange how `pause` is computed. But there's also an imperative alternative to this API. Not only\ndoes the result you get back from `useQuery` have an `isPaused` ref, it also has `pause()` and\n`resume()` methods.\n\n```jsx\n<template>\n  <div v-if=\"fetching\">\n    Loading...\n  </div>\n  <button @click=\"isPaused ? resume() : pause()\">Toggle Query</button>\n</template>\n\n<script>\nimport { gql, useQuery } from '@urql/vue';\n\nexport default {\n  setup() {\n    return useQuery({\n      query: gql`\n        {\n          todos {\n            id\n            title\n          }\n        }\n      `\n    });\n  }\n};\n</script>\n```\n\nThis means that no matter whether you're in or outside of `setup()` or rather supplying the inputs\nto `useQuery` or using the outputs, you'll have access to ways to pause or unpause the query.\n\n### Request Policies\n\nAs has become clear in the previous sections of this page, the `useQuery` hook accepts more options\nthan just `query` and `variables`. Another option we should touch on is `requestPolicy`.\n\nThe `requestPolicy` option determines how results are retrieved from our `Client`'s cache. By\ndefault this is set to `cache-first`, which means that we prefer to get results from our cache, but\nare falling back to sending an API request.\n\nRequest policies aren't specific to `urql`'s Vue bindings, but are a common feature in its core.\n[You can learn more about how the cache behaves given the four different policies on the \"Document\nCaching\" page.](../basics/document-caching.md)\n\n```js\nimport { useQuery } from '@urql/vue';\n\nexport default {\n  setup() {\n    return useQuery({\n      query: TodosQuery,\n      requestPolicy: 'cache-and-network',\n    });\n  },\n};\n```\n\nSpecifically, a new request policy may be passed directly to `useQuery` as an option.\nThis policy is then used for this specific query. In this case, `cache-and-network` is used and\nthe query will be refreshed from our API even after our cache has given us a cached result.\n\nInternally, the `requestPolicy` is just one of several \"**context** options\". The `context`\nprovides metadata apart from the usual `query` and `variables` we may pass. This means that\nwe may also change the `Client`'s default `requestPolicy` by passing it there.\n\n```js\nimport { Client, cacheExchange, fetchExchange } from '@urql/vue';\n\nconst client = new Client({\n  url: 'http://localhost:3000/graphql',\n  exchanges: [cacheExchange, fetchExchange],\n  // every operation will by default use cache-and-network rather\n  // than cache-first now:\n  requestPolicy: 'cache-and-network',\n});\n```\n\n### Context Options\n\nAs mentioned, the `requestPolicy` option on `useQuery` is a part of `urql`'s context options.\nIn fact, there are several more built-in context options, and the `requestPolicy` option is\none of them. Another option we've already seen is the `url` option, which determines our\nAPI's URL. These options aren't limited to the `Client` and may also be passed per query.\n\n```jsx\nimport { useQuery } from '@urql/vue';\n\nexport default {\n  setup() {\n    return useQuery({\n      query: TodosQuery,\n      context: {\n        requestPolicy: 'cache-and-network',\n        url: 'http://localhost:3000/graphql?debug=true',\n      },\n    });\n  },\n};\n```\n\nAs we can see, the `context` property for `useQuery` accepts any known `context` option and can be\nused to alter them per query rather than globally. The `Client` accepts a subset of `context`\noptions, while the `useQuery` option does the same for a single query.\n[You can find a list of all `Context` options in the API docs.](../api/core.md#operationcontext)\n\n### Reexecuting Queries\n\nThe `useQuery` hook updates and executes queries whenever its inputs, like the `query` or\n`variables` change, but in some cases we may find that we need to programmatically trigger a new\nquery. This is the purpose of the `executeQuery` method which is a method on the result object\nthat `useQuery` returns.\n\nTriggering a query programmatically may be useful in a couple of cases. It can for instance be used\nto refresh data that is currently being displayed. In these cases we may also override the\n`requestPolicy` of our query just once and set it to `network-only` to skip the cache.\n\n```js\nimport { gql, useQuery } from '@urql/vue';\n\nexport default {\n  setup() {\n    const result = useQuery({\n      query: gql`\n        {\n          todos {\n            id\n            title\n          }\n        }\n      `,\n    });\n\n    return {\n      data: result.data,\n      fetching: result.fetching,\n      error: result.error,\n      refresh() {\n        result.executeQuery({\n          requestPolicy: 'network-only',\n        });\n      },\n    };\n  },\n};\n```\n\nCalling `refresh` in the above example will execute the query again forcefully, and will skip the\ncache, since we're passing `requestPolicy: 'network-only'`.\n\nFurthermore the `executeQuery` function can also be used to programmatically start a query even\nwhen `pause` is set to `true`, which would usually stop all automatic queries. This can be used to\nperform one-off actions, or to set up polling.\n\n### Vue Suspense\n\nIn Vue 3 a [new feature was introduced](https://vuedose.tips/go-async-in-vue-3-with-suspense/) that\nnatively allows components to suspend while data is loading, which works universally on the server\nand on the client, where a replacement loading template is rendered on a parent while data is\nloading.\n\nAny component's `setup()` function can be updated to instead be an `async setup()` function, in\nother words, to return a `Promise` instead of directly returning its data. This means that we can\nupdate any `setup()` function to make use of Suspense.\n\nThe `useQuery`'s returned result supports this, since it is a `PromiseLike`. We can update one of\nour examples to have a suspending component by changing our usage of `useQuery`:\n\n```jsx\n<template>\n  <ul>\n    <li v-for=\"todo in data.todos\" :key=\"todo.id\">{{ todo.title }}</li>\n  </ul>\n</template>\n\n<script>\nimport { gql, useQuery } from '@urql/vue';\n\nexport default {\n  async setup() {\n    const { data, error } = await useQuery({\n      query: gql`\n        {\n          todos {\n            id\n            title\n          }\n        }\n      `\n    });\n\n    return { data };\n  }\n};\n</script>\n```\n\nAs we can see, `await useQuery(...)` here suspends the component and what we render will not have to\nhandle the loading states of `useQuery` at all. Instead in Vue Suspense we'll have to wrap a parent\ncomponent in a \"Suspense boundary.\" This boundary is what switches a parent to a loading state while\nparts of its children are fetching data. The suspense promise is in essence \"bubbling up\" until it\nfinds a \"Suspense boundary\".\n\n```\n<template>\n <Suspense>\n   <template #default>\n     <MyAsyncComponent />\n   </template>\n   <template #fallback>\n     <span>Loading...</span>\n   </template>\n </Suspense>\n</template>\n```\n\nAs long as any parent component is wrapping our component which uses `async setup()` in this\nboundary, we'll get Vue Suspense to work correctly and trigger this loading state. When a child\nsuspends this component will switch to using its `#fallback` template rather than its `#default`\ntemplate.\n\n### Chaining calls in Vue Suspense\n\nAs shown [above](#vue-suspense), in Vue Suspense the `async setup()` lifecycle function can be used\nto set up queries in advance, wait for them to have fetched some data, and then let the component\nrender as usual.\n\nHowever, because the `async setup()` function can be used with `await`-ed promise calls, we may run\ninto situations where we're trying to call functions like `useQuery()` after we've already awaited\nanother promise and will be outside of the synchronous scope of the `setup()` lifecycle. This means\nthat the `useQuery` (and `useSubscription` & `useMutation`) functions won't have access to the\n`Client` anymore that we'd have set up using `provideClient`.\n\nTo prevent this, we can create something called a \"client handle\" using the `useClientHandle`\nfunction.\n\n```js\nimport { gql, useClientHandle } from '@urql/vue';\n\nexport default {\n  async setup() {\n    const handle = useClientHandle();\n\n    await Promise.resolve(); // NOTE: This could be any await call\n\n    const result = await handle.useQuery({\n      query: gql`\n        {\n          todos {\n            id\n            title\n          }\n        }\n      `,\n    });\n\n    return { data: result.data };\n  },\n};\n```\n\nAs we can see, when we use `handle.useQuery()` we're able to still create query results although we've\ninterrupted the synchronous `setup()` lifecycle with a `Promise.resolve()` delay. This would also\nallow us to create chained queries by using\n[`computed`](https://v3.vuejs.org/guide/reactivity-computed-watchers.html#computed-values) to use an\noutput from a preceding result in a next `handle.useQuery()` call.\n\n### Reading on\n\nThere are some more tricks we can use with `useQuery`. [Read more about its API in the API docs for\nit.](../api/vue.md#usequery)\n\n## Mutations\n\nThe `useMutation` function is similar to `useQuery` but is triggered manually and accepts\nonly a `DocumentNode` or `string` as an input.\n\n### Sending a mutation\n\nLet's again pick up an example with an imaginary GraphQL API for todo items, and dive into an\nexample! We'll set up a mutation that _updates_ a todo item's title.\n\n```js\nimport { gql, useMutation } from '@urql/vue';\n\nexport default {\n  setup() {\n    const { executeMutation: updateTodo } = useMutation(gql`\n      mutation ($id: ID!, $title: String!) {\n        updateTodo(id: $id, title: $title) {\n          id\n          title\n        }\n      }\n    `);\n\n    return { updateTodo };\n  },\n};\n```\n\nSimilar to the `useQuery` output, `useMutation` returns a result object, which reflects the data of\nan executed mutation. That means it'll contain the familiar `fetching`, `error`, and `data`\nproperties — it's identical since this is a common pattern of how `urql`\npresents [operation results](../api/core.md#operationresult).\n\nUnlike the `useQuery` hook, the `useMutation` hook doesn't execute automatically. At this point in\nour example, no mutation will be performed. To execute our mutation we instead have to call the\n`executeMutation` method on the result with some variables.\n\n### Using the mutation result\n\nWhen calling our `updateTodo` function we have two ways of getting to the result as it comes back\nfrom our API. We can either use the result itself, since all properties related to the last\n[operation result](../api/core.md#operationresult) are marked as [reactive\n](https://v3.vuejs.org/guide/reactivity-fundamentals.html) — or we can use the promise that the\n`executeMutation` method returns when it's called:\n\n```js\nimport { gql, useMutation } from '@urql/vue';\n\nexport default {\n  setup() {\n    const updateTodoResult = useMutation(gql`\n      mutation ($id: ID!, $title: String!) {\n        updateTodo(id: $id, title: $title) {\n          id\n          title\n        }\n      }\n    `);\n\n    return {\n      updateTodo(id, title) {\n        const variables = { id, title: title || '' };\n        updateTodoResult.executeMutation(variables).then(result => {\n          // The result is almost identical to `updateTodoResult` with the exception\n          // of `result.fetching` not being set and its properties not being reactive.\n          // It is an OperationResult.\n        });\n      },\n    };\n  },\n};\n```\n\nThe reactive result that `useMutation` returns is useful when your UI has to display progress or\nresults on the mutation, and the returned promise is particularly useful when you're adding\nside-effects that run after the mutation has completed.\n\n### Handling mutation errors\n\nIt's worth noting that the promise we receive when calling the execute function will never\nreject. Instead it will always return a promise that resolves to a result.\n\nIf you're checking for errors, you should use `result.error` instead, which will be set\nto a `CombinedError` when any kind of errors occurred while executing your mutation.\n[Read more about errors on our \"Errors\" page.](./errors.md)\n\n```js\nimport { gql, useMutation } from '@urql/vue';\n\nexport default {\n  setup() {\n    const updateTodoResult = useMutation(gql`\n      mutation ($id: ID!, $title: String!) {\n        updateTodo(id: $id, title: $title) {\n          id\n          title\n        }\n      }\n    `);\n\n    return {\n      updateTodo(id, title) {\n        const variables = { id, title: title || '' };\n        updateTodoResult.executeMutation(variables).then(result => {\n          if (result.error) {\n            console.error('Oh no!', result.error);\n          }\n        });\n      },\n    };\n  },\n};\n```\n\nThere are some more tricks we can use with `useMutation`.<br />\n[Read more about its API in the API docs for it.](../api/vue.md#usemutation)\n\n## Reading on\n\nThis concludes the introduction for using `urql` with Vue. The rest of the documentation\nis mostly framework-agnostic and will apply to either `urql` in general or the `@urql/core` package,\nwhich is the same between all framework bindings. Hence, next we may want to learn more about one of\nthe following to learn more about the internals:\n\n- [How does the default \"document cache\" work?](./document-caching.md)\n- [How are errors handled and represented?](./errors.md)\n- [A quick overview of `urql`'s architecture and structure.](../architecture.md)\n- [Setting up other features, like authentication, uploads, or persisted queries.](../advanced/README.md)\n"
  },
  {
    "path": "docs/comparison.md",
    "content": "---\ntitle: Comparison\norder: 8\n---\n\n# Comparison\n\n> This comparison page aims to be detailed, unbiased, and up-to-date. If you see any information that\n> may be inaccurate or could be improved otherwise, please feel free to suggest changes.\n\nThe most common question that you may encounter with GraphQL is what client to choose when you are\ngetting started. We aim to provide an unbiased and detailed comparison of several options on this\npage, so that you can make an **informed decision**.\n\nAll options come with several drawbacks and advantages, and all of these clients have been around\nfor a while now. A little known fact is that `urql` in its current form and architecture has already\nexisted since February 2019, and its normalized cache has been around since September 2019.\n\nOverall, we would recommend to make your decision based on whether your required features are\nsupported, which patterns you'll use (or restrictions thereof), and you may want to look into\nwhether all the parts and features you're interested in are well maintained.\n\n## Comparison by Features\n\nThis section is a list of commonly used features of a GraphQL client and how it's either supported\nor not by our listed alternatives. We're using Relay and Apollo to compare against as the other most\ncommon choices of GraphQL clients.\n\nAll features are marked to indicate the following:\n\n- ✅ Supported 1st-class and documented.\n- 🔶 Supported and documented, but requires custom user-code to implement.\n- 🟡 Supported, but as an unofficial 3rd-party library. (Provided it's commonly used)\n- 🛑 Not officially supported or documented.\n\n### Core Features\n\n|                                            | urql                                           | Apollo                                                                                           | Relay                                                                                                            |\n| ------------------------------------------ | ---------------------------------------------- | ------------------------------------------------------------------------------------------------ | ---------------------------------------------------------------------------------------------------------------- |\n| Extensible on a network level              | ✅ Exchanges                                   | ✅ Links                                                                                         | ✅ Network Layers                                                                                                |\n| Extensible on a cache / control flow level | ✅ Exchanges                                   | 🛑                                                                                               | 🛑                                                                                                               |\n| Base Bundle Size                           | **10kB** (11kB with bindings)                  | ~50kB (55kB with React hooks)                                                                    | 45kB (66kB with bindings)                                                                                        |\n| Devtools                                   | ✅                                             | ✅                                                                                               | ✅                                                                                                               |\n| Subscriptions                              | 🔶 [Docs](./advanced/subscriptions.md)         | 🔶 [Docs](https://www.apollographql.com/docs/react/data/subscriptions/#setting-up-the-transport) | 🔶 [Docs](https://relay.dev/docs/guided-tour/updating-data/graphql-subscriptions/#configuring-the-network-layer) |\n| Client-side Rehydration                    | ✅ [Docs](./advanced/server-side-rendering.md) | ✅ [Docs](https://www.apollographql.com/docs/react/performance/server-side-rendering)            | 🛑                                                                                                               |\n| Polled Queries                             | 🔶                                             | ✅                                                                                               | ✅                                                                                                               |\n| Lazy Queries                               | ✅                                             | ✅                                                                                               | ✅                                                                                                               |\n| Stale while Revalidate / Cache and Network | ✅                                             | ✅                                                                                               | ✅                                                                                                               |\n| Focus Refetching                           | ✅ `@urql/exchange-refocus`                    | 🛑                                                                                               | 🛑                                                                                                               |\n| Stale Time Configuration                   | ✅ `@urql/exchange-request-policy`             | ✅                                                                                               | 🛑                                                                                                               |\n| Persisted Queries                          | ✅ `@urql/exchange-persisted`                  | ✅ `apollo-link-persisted-queries`                                                               | 🔶                                                                                                               |\n| Batched Queries                            | 🛑                                             | ✅ `apollo-link-batch-http`                                                                      | 🟡 `react-relay-network-layer`                                                                                   |\n| Live Queries                               | ✅ (via Incremental Delivery)                  | 🛑                                                                                               | ✅                                                                                                               |\n| Defer & Stream Directives                  | ✅                                             | ✅ / 🛑 (`@defer` is supported in >=3.7.0, `@stream` is not yet supported)                       | 🟡 (unreleased)                                                                                                  |\n| Switching to `GET` method                  | ✅                                             | ✅                                                                                               | 🟡 `react-relay-network-layer`                                                                                   |\n| File Uploads                               | ✅                                             | 🟡 `apollo-upload-client`                                                                        | 🛑                                                                                                               |\n| Retrying Failed Queries                    | ✅ `@urql/exchange-retry`                      | ✅ `apollo-link-retry`                                                                           | ✅ `DefaultNetworkLayer`                                                                                         |\n| Easy Authentication Flows                  | ✅ `@urql/exchange-auth`                       | 🛑 (no docs for refresh-based authentication)                                                    | 🟡 `react-relay-network-layer`                                                                                   |\n| Automatic Refetch after Mutation           | ✅ (with document cache)                       | 🛑                                                                                               | ✅                                                                                                               |\n\nTypically these are all additional addon features that you may expect from a GraphQL client, no\nmatter which framework you use it with. It's worth mentioning that all three clients support some\nkind of extensibility API, which allows you to change when and how queries are sent to an API. These\nare easy to use primitives particularly in Apollo, with links, and in `urql` with exchanges. The\nmajor difference in `urql` is that all caching logic is abstracted in exchanges too, which makes\nit easy to swap the caching logic or other behavior out (and hence makes `urql` slightly more\ncustomizable.)\n\nA lot of the added exchanges for persisted queries, file uploads, retrying, and other features are\nimplemented by the urql-team, while there are some cases where first-party support isn't provided\nin Relay or Apollo. This doesn't mean that these features can't be used with these clients, but that\nyou'd have to lean on community libraries or maintaining/implementing them yourself.\n\nOne thing of note is our lack of support for batched queries in `urql`. We explicitly decided not to\nsupport this in our [first-party\npackages](https://github.com/urql-graphql/urql/issues/800#issuecomment-626342821) as the benefits\nare not present anymore in most cases with HTTP/2 and established patterns by Relay that recommend\nhoisting all necessary data requirements to a page-wide query.\n\n### Framework Bindings\n\n|                                | urql           | Apollo              | Relay              |\n| ------------------------------ | -------------- | ------------------- | ------------------ |\n| React Bindings                 | ✅             | ✅                  | ✅                 |\n| React Concurrent Hooks Support | ✅             | ✅                  | ✅                 |\n| React Suspense                 | ✅             | 🛑                  | ✅                 |\n| Next.js Integration            | ✅ `next-urql` | 🟡                  | 🔶                 |\n| Preact Support                 | ✅             | 🔶                  | 🔶                 |\n| Svelte Bindings                | ✅             | 🟡 `svelte-apollo`  | 🟡 `svelte-relay`  |\n| Vue Bindings                   | ✅             | 🟡 `vue-apollo`     | 🟡 `vue-relay`     |\n| Angular Bindings               | 🛑             | 🟡 `apollo-angular` | 🟡 `relay-angular` |\n| Initial Data on mount          | ✅             | ✅                  | ✅                 |\n\n### Caching and State\n\n|                                                         | urql                                                                  | Apollo                              | Relay                                          |\n| ------------------------------------------------------- | --------------------------------------------------------------------- | ----------------------------------- | ---------------------------------------------- |\n| Caching Strategy                                        | Document Caching, Normalized Caching with `@urql/exchange-graphcache` | Normalized Caching                  | Normalized Caching (schema restrictions apply) |\n| Added Bundle Size                                       | +8kB (with Graphcache)                                                | +0 (default)                        | +0 (default)                                   |\n| Automatic Garbage Collection                            | ✅                                                                    | 🔶                                  | ✅                                             |\n| Local State Management                                  | 🛑                                                                    | ✅                                  | ✅                                             |\n| Pagination Support                                      | 🔶                                                                    | 🔶                                  | ✅                                             |\n| Optimistic Updates                                      | ✅                                                                    | ✅                                  | ✅                                             |\n| Local Updates                                           | ✅                                                                    | ✅                                  | ✅                                             |\n| Out-of-band Cache Updates                               | 🛑 (stays true to server data)                                        | ✅                                  | ✅                                             |\n| Local Resolvers and Redirects                           | ✅                                                                    | ✅                                  | 🛑                                             |\n| Complex Resolvers (nested non-normalized return values) | ✅                                                                    | 🛑                                  | 🛑                                             |\n| Commutativity Guarantees                                | ✅                                                                    | 🛑                                  | ✅                                             |\n| Partial Results                                         | ✅                                                                    | ✅                                  | 🛑                                             |\n| Safe Partial Results (schema-based)                     | ✅                                                                    | 🔶 (experimental via `useFragment`) | 🛑                                             |\n| Persistence Support                                     | ✅                                                                    | ✅ `apollo-cache-persist`           | 🟡 `@wora/relay-store`                         |\n| Offline Support                                         | ✅                                                                    | 🛑                                  | 🟡 `@wora/relay-offline`                       |\n\n`urql` is the only of the three clients that doesn't pick [normalized\ncaching](./graphcache/normalized-caching.md) as its default caching strategy. Typically this is seen\nby users as easier and quicker to get started with. All entries in this table for `urql` typically\nrefer to the optional `@urql/exchange-graphcache` package.\n\nOnce you need the same features that you'll find in Relay and Apollo, it's possible to migrate to\nGraphcache. Graphcache is also slightly different from Apollo's cache and more opinionated as it\ndoesn't allow arbitrary cache updates to be made.\n\nLocal state management is not provided by choice, but could be implemented as an exchange. For more details, [see discussion here](https://github.com/urql-graphql/urql/issues/323#issuecomment-756226783).\n\n`urql` is the only library that provides [Offline Support](./graphcache/offline.md) out of the\nbox as part of Graphcache's feature set. There are a number of options for Apollo and Relay including\nwriting your own logic for offline caching, which can be particularly successful in Relay, but for\n`@urql/exchange-graphcache` we chose to include it as a feature since it also strengthened other\nguarantees that the cache makes.\n\nRelay does in fact have similar guarantees as [`urql`'s Commutativity\nGuarantees](./graphcache/normalized-caching/#deterministic-cache-updates),\nwhich are more evident when applying list updates out of order under more complex network\nconditions.\n\n## About Bundle Size\n\n`urql` is known and often cited as a \"lightweight GraphQL client,\" which is one of its advantages\nbut not its main goal. It manages to be this small by careful size management, just like other\nlibraries like Preact.\n\nYou may find that adding features like `@urql/exchange-persisted-fetch` and\n`@urql/exchange-graphcache` only slightly increases your bundle size as we're aiming to reduce bloat,\nbut often this comparison is hard to make. When you start comparing bundle sizes of these three\nGraphQL clients you should keep in mind that:\n\n- Some dependencies may be external and the above sizes listed are total minified+gzipped sizes\n  - `@urql/core` imports from `wonka` for stream utilities and `@0no-co/graphql.web` for GraphQL query\n    language utilities\n  - Other GraphQL clients may import other exernal dependencies.\n- All `urql` packages reuse parts of `@urql/core` and `wonka`, which means adding all their total\n  sizes up doesn't give you a correct result of their total expected bundle size.\n"
  },
  {
    "path": "docs/graphcache/README.md",
    "content": "---\ntitle: Graphcache\norder: 5\n---\n\n# Graphcache\n\nIn `urql`, caching is fully configurable via [exchanges](../architecture.md), and the default\n`cacheExchange` in `urql` offers a [\"Document Cache\"](../basics/document-caching.md), which is\nusually enough for sites that heavily rely on static content. However as an app grows more\ncomplex it's likely that the data and state that `urql` manages, will also grow more complex and\nintroduce interdependencies between data.\n\nTo solve this problem most GraphQL clients resort to caching data in a normalized format, similar to\nhow [data is often structured in\nRedux.](https://redux.js.org/recipes/structuring-reducers/normalizing-state-shape/)\n\nIn `urql`, normalized caching is an opt-in feature, which is provided by the\n`@urql/exchange-graphcache` package, _Graphcache_ for short.\n\n## Features\n\nThe following pages introduce different features in _Graphcache_, which together make it a compelling\nalternative to the standard [document cache](../basics/document-caching.md) that `urql` uses by\ndefault.\n\n- 🔁 [**Fully reactive, normalized caching.**](./normalized-caching.md) _Graphcache_ stores data in\n  a normalized data structure. Query, mutation and subscription results may update one another if\n  they share data, and the app will rerender or refetch data accordingly. This often allows your app\n  to make fewer API requests, since data may already be in the cache.\n- 💾 [**Custom cache resolvers**](./local-resolvers.md) Since all queries are fully resolved in the\n  cache before and after they're sent, you can add custom resolvers that enable you to format data,\n  implement pagination, or implement cache redirects.\n- 💭 [**Subscription and Mutation updates**](./cache-updates.md) You can implement update functions\n  that tell _Graphcache_ how to update its data after a mutation has been executed, or whenever a\n  subscription sends a new event. This allows the cache to reactively update itself without queries\n  having to perform a refetch.\n- 🏃 [**Optimistic mutation updates**](./cache-updates.md) When implemented, optimistic updates can\n  provide the data that the GraphQL API is expected to send back before the request succeeds, which\n  allows the app to instantly render an update while the GraphQL mutation is executed in the\n  background.\n- 🧠 [**Opt-in schema awareness**](./schema-awareness.md) _Graphcache_ also optionally accepts your\n  entire schema, which allows it to resolve _partial data_ before making a request to the GraphQL\n  API, allowing an app to render everything that's cached before receiving all missing data. It also\n  allows _Graphcache_ to output more helpful warnings and to handle interfaces and enums correctly\n  without heuristics.\n- 📡 [**Offline support**](./offline.md) _Graphcache_ can persist and rehydrate its entire state,\n  allowing an offline application to be built that is able to execute queries against the cache\n  although the device is offline.\n- 🐛 [**Errors and warnings**](./errors.md). All potential errors are documented with information on\n  how you may be able to fix them.\n\n## Installation and Setup\n\nWe can add _Graphcache_ by installing the `@urql/exchange-graphcache` package.\nUsing the package won't increase your bundle size by as much as platforms like\n[Bundlephobia](https://bundlephobia.com/result?p=@urql/exchange-graphcache) may suggest, since it\nshares the dependency on `wonka` and `@urql/core` with the framework bindings package, e.g. `urql`\nor `@urql/preact`, that you're already using.\n\n```sh\nyarn add @urql/exchange-graphcache\n# or\nnpm install --save @urql/exchange-graphcache\n```\n\nThe package exports the `cacheExchange` which replaces the default `cacheExchange` in `@urql/core`.\nThis new `cacheExchange` must be instantiated using some options, which are used to customise\n_Graphcache_ as introduced in the [\"Features\" section above.](#features) However, you can get started\nwithout passing any options.\n\n```js\nimport { Client, fetchExchange } from 'urql';\nimport { cacheExchange } from '@urql/exchange-graphcache';\n\nconst client = new Client({\n  url: 'http://localhost:3000/graphql',\n  exchanges: [cacheExchange({}), fetchExchange],\n});\n```\n\nThis will automatically enable normalized caching, and you may find that in a lot of cases,\n_Graphcache_ already does what you'd expect it to do without any additional configuration. We'll\nexplore how to customize and set up different parts of _Graphcache_ on the following pages.\n\n[Read more about \"Normalized Caching\" on the next page.](./normalized-caching.md)\n"
  },
  {
    "path": "docs/graphcache/cache-updates.md",
    "content": "---\ntitle: Cache Updates\norder: 4\n---\n\n# Cache Updates\n\nAs we've learned [on the page on \"Normalized\nCaching\"](./normalized-caching.md#normalizing-relational-data), when Graphcache receives an API\nresult it will traverse and store all its data to its cache in a normalized structure. Each entity\nthat is found in a result will be stored under the entity's key.\n\nA query's result is represented as a graph, which can also be understood as a tree structure,\nstarting from the root `Query` entity, which then connects to other entities via links, which are\nrelations stored as keys, where each entity has records that store scalar values, which are the\ntree's leafs. On the previous page, on [\"Local Resolvers\"](./local-resolvers.md), we've seen how\nresolvers can be attached to fields to manually resolve other entities (or transform record fields).\nLocal Resolvers passively _compute_ results and change how Graphcache traverses and sees its locally\ncached data, however, for **mutations** and **subscriptions** we cannot passively compute data.\n\nWhen Graphcache receives a mutation or subscription result it still traverses it using the query\ndocument as we've learned when reading about how Graphcache stores normalized data,\n[quote](./normalized-caching.md/#storing-normalized-data):\n\n> Any mutation or subscription can also be written to this data structure. Once Graphcache finds a\n> keyable entity in their results it's written to its relational table, which may update other\n> queries in our application.\n\nThis means that mutations and subscriptions still write and update entities in the cache. These\nupdates are then reflected on all active queries that our app uses. However, there are limitations to this.\nWhile resolvers can be used to passively change data for queries, for mutations\nand subscriptions we sometimes have to write **updaters** to update links and relations.\nThis is often necessary when a given mutation or subscription deliver a result that is more granular\nthan the cache needs to update all affected entities.\n\nPreviously, we've learned about cache updates [on the \"Normalized Caching\"\npage](./normalized-caching.md#manual-cache-updates).\n\nThe `updates` option on `cacheExchange` accepts a map for `Mutation` or `Subscription` keys on which\nwe can add \"updater functions\" to react to mutation or subscription results. These `updates`\nfunctions look similar to [\"Local Resolvers\"](./local-resolvers.md) that we've seen in the last\nsection and similar to [GraphQL.js' resolvers on the\nserver-side](https://www.graphql-tools.com/docs/resolvers/).\n\n```js\ncacheExchange({\n  updates: {\n    Mutation: {\n      mutationField: (result, args, cache, info) => {\n        // ...\n      },\n    },\n    Subscription: {\n      subscriptionField: (result, args, cache, info) => {\n        // ...\n      },\n    },\n  },\n});\n```\n\n## Default mutation invalidation\n\nStarting in [Graphcache v7](https://github.com/urql-graphql/urql/blob/main/exchanges/graphcache/CHANGELOG.md#700),\nmutations without a configured `updates.Mutation.<fieldName>` updater have a fallback behavior:\n\n- If the mutation returns an entity that can't be found in the cache yet, Graphcache treats this as\n  a \"create\" mutation.\n- Graphcache then invalidates cached entities of the same `__typename` as the one returned from the mutation, which can trigger related queries to refetch.\n\nAs soon as you define an updater for that mutation field, this fallback behavior no longer runs and\nyour updater fully controls what happens after the mutation write.\n\nAn \"updater\" may be attached to a `Mutation` or `Subscription` field and accepts four positional\narguments, which are the same as [the resolvers' arguments](./local-resolvers.md):\n\n- `result`: The full API result that's being written to the cache. Typically we'd want to\n  avoid coupling by only looking at the current field that the updater is attached to, but it's\n  worth noting that we can access any part of the result.\n- `args`: The arguments that the field has been called with, which will be replaced with an empty\n  object if the field hasn't been called with any arguments.\n- `cache`: The `cache` instance, which gives us access to methods allowing us to interact with the\n  local cache. Its full API can be found [in the API docs](../api/graphcache.md#cache). On this page\n  we use it frequently to read from and write to the cache.\n- `info`: This argument shouldn't be used frequently, but it contains running information about the\n  traversal of the query document. It allows us to make resolvers reusable or to retrieve\n  information about the entire query. Its full API can be found [in the API\n  docs](../api/graphcache.md#info).\n\nThe cache updaters return value is disregarded (and typed as `void` in TypeScript), which makes any\nmethod that they call on the `cache` instance a side effect, which may trigger additional cache\nchanges and updates all affected queries as we modify them.\n\n## Why do we need cache updates?\n\nWhen we’re designing a GraphQL schema well, we won’t need to write many cache updaters for\nGraphcache.\n\nFor example, we may have a mutation to update a username on a `User`, which can trivially\nupdate the cache without us writing an updater because it resolves the `User`.\n\n```graphql\nquery User($id: ID!) {\n  user(id: $id) {\n    __typename # \"User\"\n    id\n    username\n  }\n}\n\nmutation UpdateUsername($id: ID!, $username: String!) {\n  updateUser(id: $id, username: $username) {\n    __typename # \"User\"\n    id\n    username\n  }\n}\n```\n\nIn the above example, `Query.user` returns a `User`, which is then updated by a mutation on\n`Mutation.updateUser`. Since the mutation also queries the `User`, the updated username will\nautomatically be applied by Graphcache. If the mutation field didn’t return a `User`, then this\nwouldn’t be possible, and while we can write an updater in Graphcache for it, we should consider\nthis poor schema design.\n\nAn updater instead becomes absolutely necessary when a mutation can’t reasonably return what has\nchanged or when we can’t manually define a selection set that’d be even able to select all fields\nthat may update. Some examples may include:\n\n- `Mutation.deleteUser`, since we’ll need to invalidate an entity\n- `Mutation.createUser`, since a list may now have to include a new entity\n- `Mutation.createBook`, since a given entity, e.g. `User` may have a field `User.books` that now\n  needs to be updated.\n\nIn short, we may need to write a cache updater for any **relation** (i.e. link) that we can’t query\nvia our GraphQL mutation directly, since there’ll be changes to our data that Graphcache won’t be\nable to see and store.\n\nIn a later section on this page, [we’ll learn about the `cache.link` method.](#writing-links-individually)\nThis method is used to update a field to point at a different entity. In other words, `cache.link`\nis used to update a relation from one entity field to one or more other child entities.\nThis is the most common update we’ll need and it’s preferable to always try to use `cache.link`,\nunless we need to update a scalar.\n\n## Manually updating entities\n\nIf a mutation field's result isn't returning the full entity it updates then it becomes impossible\nfor Graphcache to update said entity automatically. For instance, we may have a mutation like the\nfollowing:\n\n```graphql\nmutation UpdateTodo($todoId: ID!, $date: String!) {\n  updateTodoDate(id: $todoId, date: $date)\n}\n```\n\nIn this hypothetical case instead of `Mutation.updateDate` resolving to the full `Todo` object type\nit instead results in a scalar. This could be fixed by changing the `Mutation` in our API's schema\nto instead return the full `Todo` entity, which would allow us to run the mutation as such, which\nupdates the `Todo` in our cache automatically:\n\n```graphql\nmutation UpdateTodo($todoId: ID!, $date: String!) {\n  updateTodoDate(id: $todoId, date: $date) {\n    ...Todo_date\n  }\n}\n\nfragment Todo_date on Todo {\n  id\n  updatedAt\n}\n```\n\nHowever, if this isn't possible we can instead write an updater that updates our `Todo` entity\nmanually by using the `cache.writeFragment` method:\n\n```js\nimport { gql } from '@urql/core';\n\ncacheExchange({\n  updates: {\n    Mutation: {\n      updateTodoDate(_result, args, cache, _info) {\n        const fragment = gql`\n          fragment _ on Todo {\n            id\n            updatedAt\n          }\n        `;\n\n        cache.writeFragment(fragment, { id: args.id, updatedAt: args.date });\n      },\n    },\n  },\n});\n```\n\nThe `cache.writeFragment` method is similar to the `cache.readFragment` method that we've seen [on\nthe \"Local Resolvers\" page before](./local-resolvers.md#reading-a-fragment). Instead of reading data\nfor a given fragment it instead writes data to the cache.\n\n> **Note:** In the above example, we've used\n> [the `gql` tag function](../api/core.md#gql) because `writeFragment` only accepts\n> GraphQL `DocumentNode`s as inputs, and not strings.\n\n### Cache Updates outside updaters\n\nCache updates are **not** possible outside `updates`'s functions. If we attempt to store the `cache`\nin a variable and call its methods outside any `updates` functions (or functions, like `resolvers`)\nthen Graphcache will throw an error.\n\nMethods like these cannot be called outside the `cacheExchange`'s `updates` functions, because\nall updates are isolated to be _reactive_ to mutations and subscription events. In Graphcache,\nout-of-band updates aren't permitted because the cache attempts to only represent the server's\nstate. This limitation keeps the data of the cache true to the server data we receive from API\nresults and makes its behaviour much more predictable.\n\nIf we still manage to call any of the cache's methods outside its callbacks in its configuration,\nwe will receive [a \"(2) Invalid Cache Call\" error](./errors.md#2-invalid-cache-call).\n\n### Updaters on arbitrary types\n\nCache updates **may** be configured for arbitrary types and not just for `Mutation` or\n`Subscription` fields. However, this can potentially be **dangerous** and is an easy trap\nto fall into. It is allowed though because it allows for some nice tricks and workarounds.\n\nGiven an updater on an arbitrary type, e.g. `Todo.author`, we can chain updates onto this field\nwhenever it’s written. The updater can then be triggerd by Graphcache during _any_ operation;\nmutations, queries, and subscriptions. When this update is triggered, it allows us to add more\narbitrary updates onto this field.\n\n> **Note:** If you’re looking to use this because you’re nesting mutations onto other object types,\n> e.g. `Mutation.author.updateName`, please consider changing your schema first before using this.\n> Namespacing mutations is not recommended and changes the execution order to be concurrent rather\n> than sequential when you use multiple nested mutation fields.\n\n## Updating lists or links\n\nMutations that create new entities are pretty common, and it's not uncommon to attempt to update the\ncache when a mutation result for these \"creation\" mutations come back, since this avoids an\nadditional roundtrip to our APIs.\n\nWhile it's possible for these mutations to return any affected entities that carry the lists as\nwell, often these lists live on fields on or below the `Query` root type, which means that we'd be\nsending a rather large API result. For large amounts of pages this is especially infeasible.\nInstead, most schemas opt to instead just return the entity that's just been created:\n\n```graphql\nmutation NewTodo($text: String!) {\n  createTodo(id: $todoId, text: $text) {\n    id\n    text\n  }\n}\n```\n\nIf we have a corresponding field on `Query.todos` that contains all of our `Todo` entities then this\nmeans that we'll need to create an updater that automatically adds the `Todo` to our list:\n\n```js\ncacheExchange({\n  updates: {\n    Mutation: {\n      createTodo(result, _args, cache, _info) {\n        const TodoList = gql`\n          {\n            todos {\n              id\n            }\n          }\n        `;\n\n        cache.updateQuery({ query: TodoList }, data => {\n          return {\n            ...data,\n            todos: [...data.todos, result.createTodo],\n          };\n        });\n      },\n    },\n  },\n});\n```\n\nHere we use the `cache.updateQuery` method, which is similar to the [`cache.readQuery` method](./local-resolvers.md#reading-a-query) that\nwe've seen on the \"Local Resolvers\" page before.\n\nThis method accepts a callback, which will give us the `data` of the query, as read from the locally\ncached data, and we may return an updated version of this data. While we may want to instinctively\nopt for immutably copying and modifying this data, we're actually allowed to mutate it directly,\nsince it's just a copy of the data that's been read by the cache.\n\nThis `data` may also be `null` if the cache doesn't actually have enough locally cached information\nto fulfil the query. This is important because resolvers aren't actually applied to cache methods in\nupdaters. All resolvers are ignored, so it becomes impossible to accidentally commit transformed data\nto our cache. We could safely add a resolver for `Todo.createdAt` and wouldn't have to worry about\nan updater accidentally writing it to the cache's internal data structure.\n\n### Writing links individually\n\nAs long as we're only updating links (as in 'relations') then we may also use the [`cache.link`\nmethod](../api/graphcache.md#link). This method is the \"write equivalent\" of [the `cache.resolve`\nmethod, as seen on the \"Local Resolvers\" page before.](./local-resolvers.md#resolving-other-fields)\n\nWe can use this method to update any relation in our cache, so the example above could also be\nrewritten to use `cache.link` and `cache.resolve` rather than `cache.updateQuery`.\n\n```js\ncacheExchange({\n  updates: {\n    Mutation: {\n      createTodo(result, _args, cache, _info) {\n        const todos = cache.resolve('Query', 'todos');\n        if (Array.isArray(todos)) {\n          cache.link('Query', 'todos', [...todos, result.createTodo]);\n        }\n      },\n    },\n  },\n});\n```\n\nThis method can be combined with more than just `cache.resolve`, for instance, it's a good fit with\n`cache.inspectFields`. However, when you're writing records (as in 'scalar' values)\n`cache.writeFragment` and `cache.updateQuery` are still the only methods that you can use.\nBut since this kind of data is often written automatically by the normalized cache, often updating a\nlink is the only modification we may want to make.\n\n## Updating many unknown links\n\nIn the previous section we've seen how to update data, like a list, when a mutation result enters\nthe cache. However, we've used a rather simple example when we've looked at a single list on a known\nfield.\n\nIn many schemas pagination is quite common, and when we for instance delete a todo then knowing the\nlists to update becomes unknowable. We cannot know ahead of time how many pages (and its variables)\nwe've already accessed. This knowledge in fact _shouldn't_ be available to Graphcache. Querying the\n`Client` is an entirely separate concern that's often colocated with some part of our\nUI code.\n\n```graphql\nmutation RemoveTodo($id: ID!) {\n  removeTodo(id: $id)\n}\n```\n\nSuppose we have the above mutation, which deletes a `Todo` entity by its ID. Our app may query a list\nof these items over many pages with separate queries being sent to our API, which makes it hard to\nknow the fields that should be checked:\n\n```graphql\nquery PaginatedTodos($skip: Int) {\n  todos(skip: $skip) {\n    id\n    text\n  }\n}\n```\n\nInstead, we can **introspect an entity's fields** to find the fields we may want to update\ndynamically. This is possible thanks to [the `cache.inspectFields`\nmethod](../api/graphcache.md#inspectfields). This method accepts a key, or a keyable entity like the\n`cache.keyOfEntity` method that [we've seen on the \"Local Resolvers\"\npage](./local-resolvers.md#resolving-by-keys) or the `cache.resolve` method's first argument.\n\n```js\ncacheExchange({\n  updates: {\n    Mutation: {\n      removeTodo(_result, args, cache, _info) {\n        const TodoList = gql`\n          query (skip: $skip) {\n            todos(skip: $skip) { id }\n          }\n        `;\n\n        const fields = cache\n          .inspectFields('Query')\n          .filter(field => field.fieldName === 'todos')\n          .forEach(field => {\n            cache.updateQuery(\n              {\n                query: TodoList,\n                variables: { skip: field.arguments.skip },\n              },\n              data => {\n                data.todos = data.todos.filter(todo => todo.id !== args.id);\n                return data;\n              }\n            );\n          });\n      },\n    },\n  },\n});\n```\n\nTo implement an updater for our example's `removeTodo` mutation field we may use the\n`cache.inspectFields('Query')` method to retrieve a list of all fields on the `Query` root entity.\nThis list will contain all known fields on the `\"Query\"` entity. Each field is described as an\nobject with three properties:\n\n- `fieldName`: The field's name; in this case we're filtering for all `todos` listing fields.\n- `arguments`: The arguments for the given field, since each field that accepts arguments can be\n  accessed multiple times with different arguments. In this example we're looking at\n  `arguments.skip` to find all unique pages.\n- `fieldKey`: This is the field's key, which can come in useful to retrieve a field using\n  `cache.resolve(entityKey, fieldKey)` to prevent the arguments from having to be stringified\n  repeatedly.\n\nTo summarise, we filter the list of fields in our example down to only the `todos` fields and\niterate over each of our `arguments` for the `todos` field to filter all lists to remove the `Todo`\nfrom them.\n\n### Inspecting arbitrary entities\n\nWe're not required to only inspecting fields on the `Query` root entity. Instead, we can inspect\nfields on any entity by passing a different partial, keyable entity or key to `cache.inspectFields`.\n\nFor instance, if we had a `Todo` entity and wanted to get all of its known fields then we could pass\nin a partial `Todo` entity just as well:\n\n```js\ncache.inspectFields({\n  __typename: 'Todo',\n  id: args.id,\n});\n```\n\n## Invalidating Entities\n\nAdmittedly, it's sometimes almost impossible to write updaters for all mutations. It's often even\nhard to predict what our APIs may do when they receive a mutation. An update of an entity may change\nthe sorting of a list, or remove an item from a list in a way we can't predict, since we don't have\naccess to a full database to run the API locally.\n\nIn cases like these it may be advisable to trigger a refetch instead and let the cache update itself\nby sending queries that have invalidated data associated to them to our API again. This process is\ncalled **invalidation** since it removes data from Graphcache's locally cached data.\n\nWe may use the cache's [`cache.invalidate` method](../api/graphcache.md#invalidate) to either\ninvalidate entire entities or individual fields. It has the same signature as [the `cache.resolve`\nmethod](../api/graphcache.md#resolve), which we've already seen [on the \"Local Resolvers\" page as\nwell](./local-resolvers.md#resolving-other-fields). We can simplify the previous update we've written\nwith a call to `cache.invalidate`:\n\n```js\ncacheExchange({\n  updates: {\n    Mutation: {\n      removeTodo(_result, args, cache, _info) {\n        cache.invalidate({\n          __typename: 'Todo',\n          id: args.id,\n        });\n      },\n    },\n  },\n});\n```\n\nLike any other cache update, this will cause all queries that use this `Todo` entity to be updated\nagainst the cache. Since we've invalidated the `Todo` item they're using these queries will be\nrefetched and sent to our API.\n\nIf we're using [\"Schema Awareness\"](./schema-awareness.md) then these queries' results may actually\nbe temporarily updated with a partial result, but in general we should observe that queries with\ndata that has been invalidated will be refetched as some of their data isn't cached anymore.\n\n### Invalidating individual fields\n\nWe may also want to only invalidate individual fields, since maybe not all queries have to be\nimmediately updated. We can pass a field (and optional arguments) to the `cache.invalidate` method\nas well to only invalidate a single field.\n\nFor instance, we can use this to invalidate our lists instead of invalidating the entity itself.\nThis can be useful if we know that modifying an entity will cause our list to be sorted differently,\nfor instance.\n\n```js\ncacheExchange({\n  updates: {\n    Mutation: {\n      updateTodo(_result, args, cache, _info) {\n        const key = 'Query';\n        const fields = cache\n          .inspectFields(key)\n          .filter(field => field.fieldName === 'todos')\n          .forEach(field => {\n            cache.invalidate(key, field.fieldKey);\n            // or alternatively:\n            cache.invalidate(key, field.fieldName, field.arguments);\n          });\n      },\n    },\n  },\n});\n```\n\nIn this example we've attached an updater to a `Mutation.updateTodo` field. We react to this\nmutation by enumerating all `todos` listing fields using `cache.inspectFields` and targetedly\ninvalidate only these fields, which causes all queries using these listing fields to be refetched.\n\n### Invalidating a type\n\nWe can also invalidate all the entities of a given type, this could be handy in the case of a\nlist update or when you aren't sure what entity is affected.\n\nThis can be done by only passing the relevant `__typename` to the `invalidate` function.\n\n```js\ncacheExchange({\n  updates: {\n    Mutation: {\n      deleteTodo(_result, args, cache, _info) {\n        cache.invalidate('Todo');\n      },\n    },\n  },\n});\n```\n\n## Optimistic updates\n\nIf we know what result a mutation may return, why wait for the GraphQL API to fulfill our mutations?\n\nIn addition to the `updates` configuration, we can also pass an `optimistic` option to the\n`cacheExchange`. This option is a factory function that allows us to create a \"virtual\" result for a\nmutation. This temporary result can be applied immediately to the cache to give our users the\nillusion that mutations were executed immediately, which is a great method to reduce waiting time\nand to make our apps feel snappier.\nThis technique is often used with one-off mutations that are assumed to succeed, like starring a\nrepository, or liking a tweet. In such cases it's often desirable to make the interaction feel\nas instant as possible.\n\nThe `optimistic` configuration is similar to our `resolvers` or `updates` configuration, except that\nit only receives a single map for mutation fields. We can attach optimistic functions to any\nmutation field to make it generate an optimistic that is applied to the cache while the `Client`\nwaits for a response from our API. An \"optimistic\" function accepts three positional arguments,\nwhich are the same as the resolvers' or updaters' arguments, except for the first one:\n\nThe `optimistic` functions receive the same arguments as `updates` functions, except for `parent`,\nsince we don't have any server data to work with:\n\n- `args`: The arguments that the field has been called with, which will be replaced with an empty\n  object if the field hasn't been called with any arguments.\n- `cache`: The `cache` instance, which gives us access to methods allowing us to interact with the\n  local cache. Its full API can be found [in the API docs](../api/graphcache.md#cache). On this page\n  we use it frequently to read from and write to the cache.\n- `info`: This argument shouldn't be used frequently, but it contains running information about the\n  traversal of the query document. It allows us to make resolvers reusable or to retrieve\n  information about the entire query. Its full API can be found [in the API\n  docs](../api/graphcache.md#info).\n\nThe usual `parent` argument isn't present since optimistic functions don't have any server data to\nhandle or deal with and instead create this data. When a mutation is run that contains one or more\noptimistic mutation fields, Graphcache picks these up and generates immediate changes, which it\napplies to the cache. The `resolvers` functions also trigger as if the results were real server\nresults.\n\nThis modification is temporary. Once a result from the API comes back it's reverted, which leaves us\nin a state where the cache can apply the \"real\" result to the cache.\n\n> Note: While optimistic mutations are waiting for results from the API all queries that may alter\n> our optimistic data are paused (or rather queued up) and all optimistic mutations will be reverted\n> at the same time. This means that optimistic results can stack but will never accidentally be\n> confused with \"real\" data in your configuration.\n\nIn the following example we assume that we'd like to implement an optimistic result for a\n`favoriteTodo` mutation, like such:\n\n```graphql\nmutation FavoriteTodo(id: $id) {\n  favoriteTodo(id: $id) {\n    id\n    favorite\n    updatedAt\n  }\n}\n```\n\nThe mutation is rather simple and all we have to do is create a function\nthat imitates the result that the API is assumed to send back:\n\n```js\nconst cache = cacheExchange({\n  optimistic: {\n    favoriteTodo(args, cache, info) {\n      return {\n        __typename: 'Todo',\n        id: args.id,\n        favorite: true,\n      };\n    },\n  },\n});\n```\n\nThis optimistic mutation will be applied to the cache. If any `updates` configuration exists for\n`Mutation.favoriteTodo` then it will be executed using the optimistic result.\nOnce the mutation result comes back from our API this temporary change will be rolled back and\ndiscarded.\n\nIn the above example optimistic mutation function we also see that `updatedAt` is not present in our\noptimistic return value. That’s because we don’t always have to (or can) match our mutations’\nselection sets perfectly. Instead, Graphcache will skip over fields and use cached fields for any we\nleave out. This can even work on nested entities and fields.\n\nHowever, leaving out fields can sometimes cause the optimistic update to not apply when we\naccidentally cause any query that needs to update accordingly to only be partially cached. In other\nwords, if our optimistic updates cause a cache miss, we won’t see them being applied.\n\nSometimes we may need to apply optimistic updates to fields that accept arguments. For instance, our\n`favorite` field may have a date cut-off:\n\n```graphql\nmutation FavoriteTodo(id: $id) {\n  favoriteTodo(id: $id) {\n    id\n    favorite(since: ONE_MONTH_AGO)\n    updatedAt\n  }\n}\n```\n\nTo solve this, we can return a method on the optimistic result our `optimistic` update function\nreturns:\n\n```js\nconst cache = cacheExchange({\n  optimistic: {\n    favoriteTodo(args, cache, info) {\n      return {\n        __typename: 'Todo',\n        id: args.id,\n        favorite(_args, cache, info) {\n          return true;\n        },\n      },\n    },\n  },\n});\n```\n\nThe function signature and arguments it receives is identical to the toplevel optimistic function\nyou define, and is basically like a nested optimistic function.\n\n### Variables for Optimistic Updates\n\nSometimes it's not possible for us to retrieve all data that an optimistic update requires to create\na \"fake result\" from the cache or from all existing variables.\n\nThis is why Graphcache allows for a small escape hatch for these scenarios, which allows us to access\nadditional variables, which we may want to pass from our UI code to the mutation. For instance, given\na mutation like the following we may add more variables than the mutation specifies:\n\n```graphql\nmutation UpdateTodo($id: ID!, $text: ID!) {\n  updateTodo(id: $id, text: $text) {\n    id\n    text\n  }\n}\n```\n\nIn the above mutation we've only defined an `$id` and `$text` variable. Graphcache typically filters\nvariables using our query document definitions, which means that our API will never receive any\nvariables other than the ones we've defined.\n\nHowever, we're able to pass additional variables to our mutation, e.g. `{ extra }`, and since\n`$extra` isn't defined it will be filtered once the mutation is sent to the API. An optimistic\nmutation however will still be able to access this variable, like so:\n\n```js\ncacheExchange({\n  updates: {\n    Mutation: {\n      updateTodo(_result, _args, _cache, info) {\n        const extraVariable = info.variables.extra;\n      },\n    },\n  },\n});\n```\n\n### Reading on\n\n[On the next page we'll learn about \"Schema Awareness\".](./schema-awareness.md)\n"
  },
  {
    "path": "docs/graphcache/errors.md",
    "content": "---\ntitle: Errors\norder: 8\n---\n\n# Help!\n\n**This document lists out all errors and warnings in `@urql/exchange-graphcache`.**\n\nAny unexpected behaviour or condition will be marked by an error or warning\nin development. This will output as a helpful little message. Sometimes, however, this\nmessage may not actually tell you about everything that's going on.\n\nThis is a supporting document that explains every error and attempts to give more\ninformation on how you may be able to fix some issues or avoid these errors/warnings.\n\n## (1) Invalid GraphQL document\n\n> Invalid GraphQL document: All GraphQL documents must contain an OperationDefinition\n> node for a query, subscription or mutation.\n\nThere are multiple places where you're passing in GraphQL documents, either through\nmethods on `Cache` (e.g. `cache.updateQuery`) or via `urql` using the `Client` or\nhooks like `useQuery`.\n\nYour queries must always contain a main operation, one of: query, mutation, or\nsubscription. This error occurs when this is missing, because the `DocumentNode`\nis maybe empty or only contains fragments.\n\n## (2) Invalid Cache call\n\n> Invalid Cache call: The cache may only be accessed or mutated during\n> operations like write or query, or as part of its resolvers, updaters,\n> or optimistic configs.\n\nIf you're somehow accessing the `Cache` (an instance of `Store`) outside any\nof the usual operations then this error will be thrown.\n\nPlease make sure that you're only calling methods on the `cache` as part of\nconfigs that you pass to your `cacheExchange`. Outside these functions the cache\nmust not be changed.\n\nHowever when you're not using the `cacheExchange` and are trying to use the\n`Store` on its own, then you may run into issues where its global state wasn't\ninitialised correctly.\n\nThis is a safe-guard to prevent any asynchronous work to take place, or to\navoid mutating the cache outside any normal operation.\n\n## (3) Invalid Object type\n\n> Invalid Object type: The type `???` is not an object in the defined schema,\n> but the GraphQL document is traversing it.\n\nWhen you're passing an introspected schema to the cache exchange, it is\nable to check whether all your queries are valid.\nThis error occurs when an unknown type is found as part of a query or\nfragment.\n\nCheck whether your schema is up-to-date or whether you're using an invalid\ntypename somewhere, maybe due to a typo.\n\n## (4) Invalid field\n\n> Invalid field: The field `???` does not exist on `???`,\n> but the GraphQL document expects it to exist.<br />\n> Traversal will continue, however this may lead to undefined behavior!\n\nSimilarly to the previous warning, when you're passing an introspected\nschema to the cache exchange, it is able to check whether all your queries are valid.\nThis warning occurs when an unknown field is found on a selection set as part\nof a query or fragment.\n\nCheck whether your schema is up-to-date or whether you're using an invalid\nfield somewhere, maybe due to a typo.\n\nAs the warning states, this won't lead any operation to abort, or an error\nto be thrown!\n\n## (5) Invalid Abstract type\n\n> Invalid Abstract type: The type `???` is not an Interface or Union type\n> in the defined schema, but a fragment in the GraphQL document is using it\n> as a type condition.\n\nWhen you're passing an introspected schema to the cache exchange, it becomes\nable to deterministically check whether an entity in the cache matches a fragment's\ntype condition.\n\nThis applies to full fragments (`fragment _ on Interface`) or inline fragments\n(`... on Interface`), that apply to interfaces instead of to a concrete object typename.\n\nCheck whether your schema is up-to-date or whether you're using an invalid\nfield somewhere, maybe due to a typo.\n\n## (6) readFragment(...) was called with an empty fragment\n\n> readFragment(...) was called with an empty fragment.\n> You have to call it with at least one fragment in your GraphQL document.\n\nYou probably have called `cache.readFragment` with a GraphQL\ndocument that doesn't contain a main fragment.\n\nThis error occurs when no main fragment can be found, because the `DocumentNode`\nis maybe empty or does not contain fragments.\n\nWhen you're calling a fragment method, please ensure that you're only passing fragments\nin your GraphQL document. The first fragment will be used to start writing data.\n\nThis also occurs when you pass in a `fragmentName` but a fragment with the given name\ncan't be found in the `DocumentNode`.\n\n## (7) Can't generate a key for readFragment(...)\n\n> Can't generate a key for readFragment(...).\n> You have to pass an `id` or `_id` field or create a custom `keys` config for `???`.\n\nYou probably have called `cache.readFragment` with data that the cache can't generate a\nkey for.\n\nThis may either happen because you're missing the `id` or `_id` field or some other\nfields for your custom `keys` config.\n\nPlease make sure that you include enough properties on your data so that `readFragment`\ncan generate a key.\n\n## (8) Invalid resolver data\n\n> Invalid resolver value: The resolver at `???` returned an invalid typename that\n> could not be reconciled with the cache.\n\nThis error may occur when you provide a cache resolver for a field using `resolvers` config.\n\nThe value that you returns needs to contain a `__typename` field and this field must\nmatch the `__typename` field that exists in the cache, if any. This is because it's not\npossible to return a different type for a single field.\n\nPlease check your schema for the type that your resolver has to return, then add a\n`__typename` field to your returned resolver value that matches this type.\n\n## (9) Invalid resolver value\n\n> Invalid resolver value: The field at `???` is a scalar (number, boolean, etc),\n> but the GraphQL query expects a selection set for this field.\n\nThe GraphQL query that has been walked contains a selection set at the place where\nyour resolver is located.\n\nThis means that a full entity object needs to be returned, but instead the cache\nreceived a number, boolean, or another scalar from your resolver.\n\nPlease check that your resolvers return scalars where there's no selection set,\nand entities where there is one.\n\n## (10) writeOptimistic(...) was called with an operation that isn't a mutation\n\n> writeOptimistic(...) was called with an operation that is not a mutation.\n> This case is unsupported and should never occur.\n\nThis should never happen, please open an issue if it does. This occurs when `writeOptimistic`\nattempts to write an optimistic result for a query or subscription, instead of a mutation.\n\n## (11) writeFragment(...) was called with an empty fragment\n\n> writeFragment(...) was called with an empty fragment.\n> You have to call it with at least one fragment in your GraphQL document.\n\nYou probably have called `cache.writeFragment` with a GraphQL\ndocument that doesn't contain a main fragment.\n\nThis error occurs when no main fragment can be found, because the `DocumentNode`\nis maybe empty or does not contain fragments.\n\nWhen you're calling a fragment method, please ensure that you're only passing fragments\nin your GraphQL document. The first fragment will be used to start writing data.\n\nThis also occurs when you pass in a `fragmentName` but a fragment with the given name\ncan't be found in the `DocumentNode`.\n\n## (12) Can't generate a key for writeFragment(...) or link(...)\n\n> Can't generate a key for writeFragment(...) [or link(...) data.\n> You have to pass an `id` or `_id` field or create a custom `keys` config for `???`.\n\nYou probably have called `cache.writeFragment` or `cache.link` with data that the cache\ncan't generate a key for.\n\nThis may either happen because you're missing the `id` or `_id` field or some other\nfields for your custom `keys` config.\n\nPlease make sure that you include enough properties on your data so that `writeFragment`\nor `cache.link` can generate a key. On `cache.link` the entities must either be\nan existing entity key, or a keyable entity.\n\n## (13) Invalid undefined\n\n> Invalid undefined: The field at `???` is `undefined`, but the GraphQL query expects a\n> scalar (number, boolean, etc) / selection set for this field.\n\nAs data is written to the cache, this warning is issued when `undefined` is encountered.\nGraphQL results should never contain an `undefined` value, so this warning will let you\nknow the part of your result that did contain `undefined`.\n\n## (14) Couldn't find \\_\\_typename when writing.\n\n> Couldn't find `__typename` when writing.\n> If you're writing to the cache manually have to pass a `__typename` property on each entity in your data.\n\nYou probably have called `cache.writeFragment` or `cache.updateQuery` with data that is missing a\n`__typename` field for an entity where your document contains a selection set. The cache won't be\nable to generate a key for entities that are missing the `__typename` field.\n\nPlease make sure that you include enough properties on your data so that `write` can generate a key.\n\n## (15) Invalid key\n\n> Invalid key: The GraphQL query at the field at `???` has a selection set,\n> but no key could be generated for the data at this field.\n> You have to request `id` or `_id` fields for all selection sets or create a\n> custom `keys` config for `???`.\n> Entities without keys will be embedded directly on the parent entity.\n> If this is intentional, create a `keys` config for `???` that always returns null.\n\nThis error occurs when the cache can't generate a key for an entity. The key\nwould then effectively be `null`, and the entity won't be cached by a key.\n\nConceptually this means that an entity won't be normalized but will indeed\nbe cached by the parent's key and field, which is displayed in the first\npart of the warning.\n\nThis may mean that you forgot to include an `id` or `_id` field.\n\nBut if your entity at that place doesn't have any `id` fields, then you may\nhave to create a custom `keys` config. This `keys` function either needs to\nreturn a unique ID for your entity, or it needs to explicitly return `null` to silence\nthis warning.\n\n## (16) Heuristic Fragment Matching\n\n> Heuristic Fragment Matching: A fragment is trying to match against the `???` type,\n> but the type condition is `???`. Since GraphQL allows for interfaces `???` may be\n> an interface.\n> A schema needs to be defined for this match to be deterministic, otherwise\n> the fragment will be matched heuristically!\n\nThis warning is issued on fragment matching. Fragment matching is the process\nof matching a fragment against a piece of data in the cache and that data's `__typename`\nfield.\n\nWhen the `__typename` field doesn't match the fragment's type, then we may be\ndealing with an interface and/or enum. In such a case the fragment may _still match_\nif it's referring to an interface (`... on Interface`). Graphcache is supposed to be\nusable without much config, so what it does in this case is apply a heuristic match.\n\nIn a heuristic fragment match we check whether all fields on the fragment are present\nin the cache, which is then treated as a fragment match.\n\nWhen you pass an introspected schema to the cache, this warning will never be displayed\nas the cache can then do deterministic fragment matching using schema information.\n\n## (17) Invalid type\n\n> Invalid type: The type `???` is used with @populate but does not exist.\n\nWhen you're using the populate exchange with an introspected schema and add the\n`@populate` directive to fields it first checks whether the type is valid and\nexists on the schema.\n\nIf the field does not have enough type information because it doesn't exist\non the schema or does not match expectations then this warning is logged.\n\nCheck whether your schema is up-to-date or whether you're using an invalid\nfield somewhere, maybe due to a typo.\n\n## (18) Invalid TypeInfo state\n\n> Invalid TypeInfo state: Found no flat schema type when one was expected.\n\nWhen you're using the populate exchange with an introspected schema, it will\nstart collecting used fragments and selection sets on all of your queries.\nThis error may occur if it hits unexpected types or inexistent types when doing so.\n\nCheck whether your schema is up-to-date or whether you're using an invalid\nfield somewhere, maybe due to a typo.\n\nPlease open an issue if it happens on a query that you expect to be supported\nby the `populateExchange`.\n\n## (19) Can't generate a key for invalidate(...)\n\n> Can't generate a key for invalidate(...).\n> You need to pass in a valid key (**typename:id) or an object with the \"**typename\" property and an \"id\" or \"\\_id\" property.\n\nYou probably have called `cache.invalidate` with data that the cache can't generate a key for.\n\nThis may either happen because you're missing the `__typename` and `id` or `_id` field or if the last two\naren't applicable to this entity a custom `keys` entry.\n\n## (20) Invalid Object type\n\n> Invalid Object type: The type `???` is not an object in the defined schema,\n> but the `keys` option is referencing it.\n\nWhen you're passing an introspected schema to the cache exchange, it is\nable to check whether your `opts.keys` is valid.\nThis error occurs when an unknown type is found in `opts.keys`.\n\nCheck whether your schema is up-to-date, or whether you're using an invalid\ntypename in `opts.keys`, maybe due to a typo.\n\n## (21) Invalid updates type\n\n> Invalid updates field: The type `???` is not an object in the defined schema,\n> but the `updates` config is referencing it.\n\nWhen you're passing an introspected schema to the cache exchange, it is\nable to check whether your `opts.updates` config is valid.\nThis error occurs when an unknown type is found in the `opts.updates` config.\n\nCheck whether your schema is up-to-date, or whether you've got a typo in `opts.updates`.\n\n## (22) Invalid updates field\n\n> Invalid updates field: `???` on `???` is not in the defined schema,\n> but the `updates` config is referencing it.\n\nWhen you're passing an introspected schema to the cache exchange, it is\nable to check whether your `opts.updates` config is valid.\nThis error occurs when an unknown field is found in `opts.updates[typename]`.\n\nCheck whether your schema is up-to-date, or whether you're using an invalid\nfield name in `opts.updates`, maybe due to a typo.\n\n## (23) Invalid resolver\n\n> Invalid resolver: `???` is not in the defined schema, but the `resolvers`\n> option is referencing it.\n\nWhen you're passing an introspected schema to the cache exchange, it is\nable to check whether your `opts.resolvers` is valid.\nThis error occurs when an unknown query, type or field is found in `opts.resolvers`.\n\nCheck whether your schema is up-to-date, or whether you've got a typo in `opts.resolvers`.\n\n## (24) Invalid optimistic mutation\n\n> Invalid optimistic mutation field: `???` is not a mutation field in the defined schema,\n> but the `optimistic` option is referencing it.\n\nWhen you're passing an introspected schema to the cache exchange, it is\nable to check whether your `opts.optimistic` is valid.\nThis error occurs when a field in `opts.optimistic` is not in the schema's `Mutation` fields.\n\nCheck whether your schema is up-to-date, or whether you've got a typo in `Mutation` or `opts.optimistic`.\n\n## (25) Invalid root traversal\n\n> Invalid root traversal: A selection was being read on `???` which is an uncached root type.\n> The `Mutation` and `Subscription` types are special Operation Root Types and cannot be read back\n> from the cache.\n\nIn GraphQL every schema has three [Operation Root\nTypes](https://spec.graphql.org/June2018/#sec-Root-Operation-Types). The `Query` type is the only\none that is cached in Graphcache's normalized cache, since it's the root of all normalized cache\ndata, i.e. all data is linked and connects back to the `Query` type.\n\nThe `Subscription` and `Mutation` types are special and uncached; they may link to entities that\nwill be updated in the normalized cache data, but are themselves not cached, since they're never\ndirectly queried.\n\nWhen your schema treats `Mutation` or `Subscription` like regular entity types you may get this\nwarning. This may happen because you've used the default reserved names `Mutation` or `Subscription`\nfor entities rather than as special Operation Root Types, and haven't specified this in the schema.\nHence this issue can often be fixed by either enabling\n[Schema Awareness](./schema-awareness.md) or by\nadding a `schema` definition to your GraphQL Schema like so:\n\n```graphql\nschema {\n  query: Query\n  mutation: YourMutation\n  subscription: YourSubscription\n}\n```\n\nWhere `YourMutation` and `YourSubscription` are your custom Operation Root Types, instead of relying\non the default names `\"Mutation\"` and `\"Subscription\"`.\n\n## (26) Invalid abstract resolver\n\n> Invalid resolver: `???` does not map to a concrete type in the schema,\n> but the resolvers option is referencing it. Implement the resolver for the types that `??` instead.\n\nWhen you're passing an introspected schema to the cache exchange, it is\nable to check whether your `opts.resolvers` is valid.\nThis error occurs when you are using an `interface` or `union` rather than an\nimplemented type for these.\n\nCheck the type mentioned and change it to one of the specific types.\n\n## (27) Invalid Cache write\n\n> Invalid Cache write: You may not write to the cache during cache reads.\n> Accesses to `cache.writeFragment`, `cache.updateQuery`, and `cache.link` may\n> not be made inside `resolvers` for instance.\n\nIf you're using the `Cache` inside your `cacheExchange` config you receive it\neither inside callbacks that are called when the cache is queried (e.g.\n`resolvers`) or when data is written to the cache (e.g. `updates`). You may not\nwrite to the cache when it's being queried.\n\nPlease make sure that you're not calling `cache.updateQuery`,\n`cache.writeFragment`, or `cache.link` inside `resolvers`.\n\n## (28) Resolver and directive match the same field\n\nWhen you have a resolver defined on a field you shouln't be combining it with a directive as the directive\nwill apply and the resolver will be void.\n"
  },
  {
    "path": "docs/graphcache/local-directives.md",
    "content": "---\ntitle: Local Directives\norder: 3\n---\n\n# Local Directives\n\nPreviously, we've learned about local resolvers [on the \"Normalized Caching\"\npage](./normalized-caching.md#manually-resolving-entities) and [the \"Local Resolvers\" page](./local-resolvers.md).\n\nResolvers allow us to change the data that Graphcache resolvers for a given field on a given type.\nThis, in turn, allows us to change which links and data are returned in a query’s result, which\notherwise may not be cached or be returned in a different shape.\n\nResolvers are useful to globally change how a field behaves, for instance, to tell Graphcache that\na `Query.item(id: $id)` field returns an item of type `Item` with the `id` field, or to transform\na value before it’s used in the UI.\n\nHowever, resolvers are limited to changing the behaviour globally, not to change a field’s behaviour\nper query. This is why **local directives** exist.\n\n## Adding client-only directives\n\nAny directive in our GraphQL documents that’s prefixed with an underscore character (`_`) will be\nfiltered by `@urql/core`. This means that our GraphQL API never sees it and it becomes\na “client-only directive”.\n\nNo matter whether we prefix a directive or not however, we can define local resolvers for directives\nin Graphcache’s configuration and make conditional local resolvers.\n\n```js\ncacheExchange({\n  directives: {\n    pagination(directiveArgs) {\n      // This resolver is called for @_pagination directives\n      return (parent, args, cache, info) => {\n        return null;\n      };\n    },\n  },\n});\n```\n\nOnce we define a directive on the `directives` configuration object, we can reference it in our\nGraphQL queries.\n\nAs per the above example, if we now reference `@_pagination` in a query, the resolver that’s\nreturned in the configuration will be applied to the field, just like a local resolver.\n\nWe can also reference the directive using `@pagination`, however, this will mean that it’s\nalso sent to the API, so this usually isn’t what we want.\n\n## Client-controlled Nullability\n\nGraphcache comes with two directives built-in by default. The `optional` and `required` directives.\nThese directives can be used as an alternative to [the Schema Awareness\nfeature’s](./schema-awareness.md) ability to generate partial results.\n\nIf we were to write a query that contains `@_optional` on a field, then the field is always allowed to be\nnullable. In case it’s not cached, Graphcache will be able to replace it with a `null`\nvalue.\n\nSimilarly, if we annotate a field with `@_required`, the value is not optional and, even if the\ncache knows the value is set to `null`, it will become required and Graphcache will either cascade\nto the next higher parent field annotated with `@_optional`, or will mark a query as a cache-miss.\n\n## Pagination\n\nPreviously, in [the “Local Resolvers” page’s Pagination section](./local-resolvers.md#pagination) we\ndefined a local resolver to add infinite pagination to a given type’s field.\n\nIf we add the `simplePagination` or `relayPagination` helpers as directives instead, we can still\nuse our schema’s pagination field as normal, and instead, only use infinite pagination as required.\n\n```js\nimport { simplePagination } from '@urql/exchange-graphcache/extras';\nimport { relayPagination } from '@urql/exchange-graphcache/extras';\n\ncacheExchange({\n  directives: {\n    simplePagination: options => simplePagination({ ...options }),\n    relayPagination: options => relayPagination({ ...options }),\n  },\n});\n```\n\nDefining directives for our resolver factory functions means that we can now use them selectively.\n\n```graphql\n{\n  todos(first: 10) @_relayPagination(mergeMode: \"outwards\") {\n    id\n    text\n  }\n}\n```\n\n### Reading on\n\n[On the next page we'll learn about \"Cache Updates\".](./cache-updates.md)\n"
  },
  {
    "path": "docs/graphcache/local-resolvers.md",
    "content": "---\ntitle: Local Resolvers\norder: 2\n---\n\n# Local Resolvers\n\nPreviously, we've learned about local resolvers [on the \"Normalized Caching\"\npage](./normalized-caching.md#manually-resolving-entities). They allow us to change the data that\nGraphcache reads as it queries against its local cache, return links that would otherwise not be\ncached, or even transform scalar records on the fly.\n\nThe `resolvers` option on `cacheExchange` accepts a map of types with a nested map of fields, which\nmeans that we can add local resolvers to any field of any type. For example:\n\n```js\ncacheExchange({\n  resolvers: {\n    Todo: {\n      updatedAt: parent => new Date(parent.updatedAt),\n    },\n  },\n});\n```\n\nIn the above example, what Graphcache does when it encounters the `updatedAt` field on `Todo` types.\nSimilarly to how Graphcache knows [how to generate\nkeys](./normalized-caching.md#custom-keys-and-non-keyable-entities) and looks up our custom `keys`\nconfiguration functions per `__typename`, it also uses our `resolvers` configuration on each field\nit queries from its locally cached data.\n\nA local resolver function in Graphcache has a similar signature to [GraphQL.js' resolvers on the\nserver-side](https://www.graphql-tools.com/docs/resolvers/), so their shape should look familiar to\nus.\n\n```js\n{\n  TypeName: {\n    fieldName: (parent, args, cache, info) => {\n      return null; // new value\n    },\n  },\n}\n```\n\nA resolver may be attached to any type's field and accepts four positional arguments:\n\n- `parent`: The object on which the field will be added to, which contains the data as it's being\n  queried. It will contain the current field's raw value if it's a scalar, which allows us to\n  manipulate scalar values, like `parent.updatedAt` in the previous example.\n- `args`: The arguments that the field is being called with, which will be replaced with an empty\n  object if the field hasn't been called with any arguments. For example, if the field is queried as\n  `name(capitalize: true)` then `args` would be `{ capitalize: true }`.\n- `cache`: Unlike in GraphQL.js this will not be the context, but a `cache` instance, which gives us\n  access to methods allowing us to interact with the local cache. Its full API can be found [in the\n  API docs](../api/graphcache.md#cache).\n- `info`: This argument shouldn't be used frequently, but it contains running information about the\n  traversal of the query document. It allows us to make resolvers reusable or to retrieve\n  information about the entire query. Its full API can be found [in the API\n  docs](../api/graphcache.md#info).\n\nThe local resolvers may return any value that fits the query document's shape, however we must\nensure that what we return matches the types of our schema. It, for instance, isn't possible to turn a\nrecord field into a link, i.e. replace a scalar with an entity. Instead, local resolvers are useful\nto transform records, like dates in our previous example, or to imitate server-side logic to allow\nGraphcache to retrieve more data from its cache without sending a query to our API.\n\nFurthermore, while we see on this page that we get access to methods like `cache.resolve` and other\nmethods to read from our cache, only [\"Cache Updates\"](./cache-updates.md) get to write and change\nthe cache. If you call `cache.updateQuery`, `cache.writeFragment`, or `cache.link` in resolvers,\nyou‘ll get an error, since it‘s not possible to update the cache while reading from it.\n\nWhen writing a resolver you’ll mostly use `cache.resolve`, which can be chained, to read field\nvalues from the cache. When a field points to another entity we may get a key, but resolvers are\nallowed to return keys or partial entities containing keys.\n\n> **Note:** This essentially means that resolvers can return either scalar values for fields without\n> selection sets, and either partial entities or keys for fields with selection sets, i.e.\n> links / relations. When we return `null`, this will be interpreted a the literal GraphQL Null scalar,\n> while returning `undefined` will cause a cache miss.\n\n## Transforming Records\n\nAs we've explored in the [\"Normalized Caching\" page's section on\nrecords](./normalized-caching.md#storing-normalized-data), \"records\" are scalars and any fields in\nyour query without selection sets. This could be a field with a string value, number, or any other\nfield that resolves to a [scalar type](https://graphql.org/learn/schema/#scalar-types) rather than\nanother entity i.e. object type.\n\nAt the beginning of this page we've already seen an example of a local resolver that we've attached\nto a record field where we've added a resolver to a `Todo.updatedAt` field:\n\n```js\ncacheExchange({\n  resolvers: {\n    Todo: {\n      updatedAt: parent => new Date(parent.updatedAt),\n    },\n  },\n});\n```\n\nA query that contains this field may look like `{ todo { updatedAt } }`, which clearly shows us that\nthis field is a scalar since it doesn't have any selection set on the `updatedAt` field. In our\nexample, we access this field's value and parse it as a `new Date()`.\n\nThis shows us that it doesn't matter for scalar fields what kind of value we return. We may parse\nstrings into more granular JS-native objects or replace values entirely.\n\nWe may also run into situations where we'd like to generalise the resolver and not make it dependent\non the exact field it's being attached to. In these cases, the [`info`\nobject](../api/graphcache.md#info) can be very helpful as it provides us information about the\ncurrent query traversal, and the part of the query document the cache is processing. The\n`info.fieldName` property is one of these properties and lets us know the field that the resolver is\noperating on. Hence, we can create a reusable resolver like so:\n\n```js\nconst transformToDate = (parent, _args, _cache, info) => new Date(parent[info.fieldName]);\n\ncacheExchange({\n  resolvers: {\n    Todo: { updatedAt: transformToDate },\n  },\n});\n```\n\nThe resolver is now much more reusable, which is particularly handy if we're creating resolvers that\nwe'd like to apply to multiple fields. The [`info` object has several more\nfields](../api/graphcache.md#info) that are all similarly useful to abstract our resolvers.\n\nWe also haven't seen yet how to handle a field's arguments.\nIf we have a field that accepts arguments we can use those as well as they're passed to us with the\nsecond argument of a resolver:\n\n```js\ncacheExchange({\n  resolvers: {\n    Todo: {\n      text: (parent, args) => {\n        return args.capitalize && parent.text ? parent.text.toUpperCase() : parent.text;\n      },\n    },\n  },\n});\n```\n\nThis is actually unlikely to be of use with records and scalar values as our API will have to be\nable to use these arguments just as well. In other words, while you may be able to pass any\narguments to a field in your query, your GraphQL API's schema must accept these arguments in the\nfirst place. However, this is still useful if we're trying to imitate what the API is doing, which\nwill become more relevant in the following examples and sections.\n\n## Resolving Entities\n\nWe've already briefly seen that resolvers can be used to replace a link in Graphcache's local data\non the [\"Normalized Caching\" page](./normalized-caching.md#manually-resolving-entities).\n\nGiven that Graphcache [stores entities in a normalized data\nstructure](./normalized-caching.md#storing-normalized-data) there may be multiple fields on a given\nschema that can be used to get to the same entity. For instance, the schema may allow for the same\nentity to be looked up by an ID while this entity may also appear somewhere else in a list or on an\nentirely different field.\n\nWhen links (or relations) like these are cached by Graphcache it is able to look up the entities\nautomatically, e.g. if we've sent a `{ todo(id: 1) { id } }` query to our API once then Graphcache\nwill have seen that this field leads to the entity it returns and can query it automatically from\nits cache.\n\nHowever, if we have a list like `{ todos { id } }` we may have seen and cached a specific entity,\nbut as we browse the app and query for `{ todo(id: 1) { id } }`, Graphcache isn't able to\nautomatically find this entity even if it has cached it already and will send a request to our API.\n\nIn many cases we can create a local resolvers to instead tell the cache where to look for a specific\nentity by returning partial information for it. Any resolver on a relational field, meaning any\nfield that links to an object type (or a list of object types) in the schema, may return a partial\nentity that tells the cache how to resolve it. Hence, we're able to implement a resolver for the\npreviously shown `todo(id: $id)` field as such:\n\n```js\ncacheExchange({\n  resolvers: {\n    Query: {\n      todo: (_, args) => ({ __typename: 'Todo', id: args.id }),\n    },\n  },\n});\n```\n\nThe `__typename` field is required. Graphcache will [use its keying\nlogic](./normalized-caching.md#custom-keys-and-non-keyable-entities), and your custom `keys`\nconfiguration to generate a key for this entity and will then be able to look this entity up in its\nlocal cache. As with regular queries, the resolver is known to return a link since the `todo(id: $id) { id }` will be used with a selection set, querying fields on the entity.\n\n### Resolving by keys\n\nResolvers can also directly return keys. We've previously learned [on the \"Normalized Caching\"\npage](./normalized-caching.md#custom-keys-and-non-keyable-entities) that the key for our example above\nwould look something like `\"Todo:1\"` for `todo(id: 1)`. While it isn't advisable to create keys\nmanually in your resolvers, if you returned a key directly this would still work.\n\nEssentially, returning `{ __typename, id }` may sometimes be the same as returning the key manually.\nThe `cache` that we receive as an argument on resolvers has a method for this logic, [the\n`cache.keyOfEntity` method](../api/graphcache.md#keyofentity).\n\nWhile it doesn't make much sense in this case, our example can be rewritten as:\n\n```js\ncacheExchange({\n  resolvers: {\n    Query: {\n      todo: (_, args, cache) => cache.keyOfEntity({ __typename: 'Todo', id: args.id }),\n    },\n  },\n});\n```\n\nAnd while it's not advisable to create keys ourselves, the resolvers' `cache` and `info` arguments\ngive us ample opportunities to use and pass around keys.\n\nOne example is the `info.parentKey` property. This property [on the `info`\nobject](../api/graphcache.md#info) will always be set to the key of the entity that the resolver is\ncurrently run on. For instance, for the above resolver it may be `\"Query\"`, for for a resolver on\n`Todo.updatedAt` it may be `\"Todo:1\"`.\n\n## Resolving other fields\n\nIn the above two examples we've seen how a resolver can replace Graphcache's logic, which usually\nreads links and records only from its locally cached data. We've seen how a field on a record can\nuse `parent[fieldName]` to access its cached record value and transform it and how a resolver for a\nlink can return a partial entity [or a key](#resolving-by-keys).\n\nHowever sometimes we'll need to resolve data from other fields in our resolvers.\n\n> **Note:** For records, if the other field is on the same `parent` entity, it may seem logical to access it on\n> `parent[otherFieldName]` as well, however the `parent` object will only be sparsely populated with\n> fields that the cache has already queried prior to reaching the resolver.\n> In the previous example, where we've created a resolver for `Todo.updatedAt` and accessed\n> `parent.updatedAt` to transform its value the `parent.updatedAt` field is essentially a shortcut\n> that allows us to get to the record quickly.\n\nInstead we can use [the `cache.resolve` method](../api/graphcache.md#resolve). This method\nallows us to access Graphcache's cached data directly. It is used to resolve records or links on any\ngiven entity and accepts three arguments:\n\n- `entity`: This is the entity on which we'd like to access a field. We may either pass a keyable,\n  partial entity, e.g. `{ __typename: 'Todo', id: 1 }` or a key. It takes the same inputs as [the\n  `cache.keyOfEntity` method](../api/graphcache.md#keyofentity), which we've seen earlier in the\n  [\"Resolving by keys\" section](#resolving-by-keys). It also accepts `null` which causes it to\n  return `null`, which is useful for chaining multiple `resolve` calls for deeply accessing a field.\n- `fieldName`: This is the field's name we'd like to access. If we're looking for the record on\n  `Todo.updatedAt` we would pass `\"updatedAt\"` and would receive the record value for this field. If\n  we pass a field that is a _link_ to another entity then we'd pass that field's name (e.g.\n  `\"author\"` for `Todo.author`) and `cache.resolve` will return a key instead of a record value.\n- `fieldArgs`: Optionally, as the third argument we may pass the field's arguments, e.g. `{ id: 1 }`\n  if we're trying to access `todo(id: 1)` for instance.\n\nThis means that we can rewrite our original `Todo.updatedAt` example as follows, if we'd like to\navoid using the `parent[fieldName]` shortcut:\n\n```js\ncacheExchange({\n  resolvers: {\n    Todo: {\n      updatedAt: (parent, _args, cache) => new Date(cache.resolve(parent, 'updatedAt')),\n    },\n  },\n});\n```\n\nWhen we call `cache.resolve(parent, \"updatedAt\")`, the cache will look up the `\"updatedAt\"` field on\nthe `parent` entity, i.e. on the current `Todo` entity.\n\n> **Note:** We've also previously learned that `parent` may not contain all fields that the entity may have and\n> may hence be missing its keyable fields, like `id`, so why does this then work?\n> It works because `cache.resolve(parent)` is a shortcut for `cache.resolve(info.parentKey)`.\n\nLike the `info.fieldName` property `info.parentKey` gives us information about the current state of\nGraphcache's query operation. In this case, `info.parentKey` tells us what the parent's key is.\nHowever, since `cache.resolve(parent)` is much more intuitive we can write that instead since this\nis a supported shortcut.\n\nFrom this follows that we may also use `cache.resolve` to access other fields. Let's suppose we'd\nwant `updatedAt` to default to the entity's `createdAt` field when it's actually `null`. In such a\ncase we could write a resolver like so:\n\n```js\ncacheExchange({\n  resolvers: {\n    Todo: {\n      updatedAt: (parent, _args, cache) => parent.updatedAt || cache.resolve(parent, 'createdAt'),\n    },\n  },\n});\n```\n\nAs we can see, we're effortlessly able to access other records from the cache, provided these fields\nare actually cached. If they aren't `cache.resolve` will return `null` instead.\n\nBeyond records, we're also able to resolve links and hence jump to records from another entity.\nLet's suppose we have an `author { id, createdAt }` field on the `Todo` and would like\n`Todo.createdAt` to simply copy the author's `createdAt` field. We can chain `cache.resolve` calls\nto get to this value:\n\n```js\ncacheExchange({\n  resolvers: {\n    Todo: {\n      createdAt: (parent, _args, cache) =>\n        cache.resolve(cache.resolve(parent, 'author') /* \"Author:1\" */, 'createdAt'),\n    },\n  },\n});\n```\n\nThe return value of `cache.resolve` changes depending on what data the cache has stored. While it\nmay return records for fields without selection sets, in other cases it may give you the key of\nother entities (\"links\") instead. It can even give you arrays of keys or records when the field's\nvalue contains a list.\n\nWhen a value is not present in the cache, `cache.resolve` will instead return `undefined` to signal\nthat a value is uncached. Similarly, a resolver may return `undefined` to tell Graphcache that the\nfield isn’t cached and that a call to the API is necessary.\n\n`cache.resolve` is a pretty flexible method that allows us to access arbitrary values from our cache,\nhowever, we have to be careful about what value will be resolved by it, since the cache can't know\nitself what type of value it may return.\n\nThe last trick this method allows you to apply is to access arbitrary fields on the root `Query`\ntype. If we call `cache.resolve(\"Query\", ...)` then we're also able to access arbitrary fields\nstarting from the root `Query` of the cached data. (If you're using [Schema\nAwareness](./schema-awareness.md) the name `\"Query\"` may vary for you depending on your schema.)\nWe're not constrained to accessing fields on the `parent` of a resolver but can also attempt to\nbreak out and access fields on any other entity we know of.\n\n## Resolving Partial Data\n\nLocal resolvers also allow for more advanced use-cases when it comes to links and object types.\nPreviously we've seen how a resolver is able to link up a given field to an entity, which causes\nthis field to resolve an entity directly instead of it being checked against any cached links:\n\n```js\ncacheExchange({\n  resolvers: {\n    Query: {\n      todo: (_, args) => ({ __typename: 'Todo', id: args.id }),\n    },\n  },\n});\n```\n\nIn this example, while `__typename` and `id` are required to make this entity keyable, we're also\nable to add on more fields to this object to override values later on in our selection.\n\nFor instance, we can write a resolver that links `Query.todo` directly to our `Todo` entity but also\nonly updates the `createdAt` field directly in the same resolver, if it is indeed accessed via the\n`Query.todo` field:\n\n```js\ncacheExchange({\n  resolvers: {\n    Query: {\n      todo: (_, args) => ({\n        __typename: 'Todo',\n        id: args.id,\n        createdAt: new Date().toString(),\n      }),\n    },\n  },\n});\n```\n\nHere we've replaced the `createdAt` value of the `Todo` when it's accessed via this manual resolver.\nIf it was accessed someplace else, for instance via a `Query.todos` listing field, this override\nwouldn't apply.\n\nWe can even apply overrides to nested fields, which helps us to create complex resolvers for other\nuse cases like pagination.\n\n[Read more on the topic of \"Pagination\" in the section below.](#pagination)\n\n## Computed Queries\n\nWe've now seen how the `cache` has several powerful methods, like [the `cache.resolve`\nmethod](../api/graphcache.md#resolve), which allow us to access any data in the cache while writing\nresolvers for individual fields.\n\nAdditionally the cache has more methods that allow us to access more data at a time, like\n`cache.readQuery` and `cache.readFragment`.\n\n### Reading a query\n\nAt any point, the `cache` allows us to read entirely separate queries in our resolvers, which starts\na separate virtual operation in our resolvers. When we call `cache.readQuery` with a query and\nvariables we can execute an entirely new GraphQL query against our cached data:\n\n```js\nimport { gql } from '@urql/core';\nimport { cacheExchange } from '@urql/exchange-graphcache';\n\nconst cache = cacheExchange({\n  updates: {\n    Mutation: {\n      addTodo: (result, args, cache) => {\n        const data = cache.readQuery({ query: Todos, variables: { from: 0, limit: 10 } });\n      },\n    },\n  },\n});\n```\n\nThis way we'll get the stored data for the `TodosQuery` for the given `variables`.\n\n[Read more about `cache.readQuery` in the Graphcache API docs.](../api/graphcache.md#readquery)\n\n### Reading a fragment\n\nThe store also allows us to read a fragment for any given entity. The `cache.readFragment` method\naccepts a `fragment` and an `id`. This looks like the following.\n\n```js\nimport { gql } from '@urql/core';\nimport { cacheExchange } from '@urql/exchange-graphcache';\n\nconst cache = cacheExchange({\n  resolvers: {\n    Query: {\n      Todo: (parent, args, cache) => {\n        return cache.readFragment(\n          gql`\n            fragment _ on Todo {\n              id\n              text\n            }\n          `,\n          { id: 1 }\n        );\n      },\n    },\n  },\n});\n```\n\n> **Note:** In the above example, we've used\n> [the `gql` tag function](../api/core.md#gql) because `readFragment` only accepts\n> GraphQL `DocumentNode`s as inputs, and not strings.\n\nThis way we'll read the entire fragment that we've passed for the `Todo` for the given key, in this\ncase `{ id: 1 }`.\n\n[Read more about `cache.readFragment` in the Graphcache API docs.](../api/graphcache.md#readfragment)\n\n### Cache methods outside of `resolvers`\n\nThe cache read methods are not possible outside of GraphQL operations. This means these methods will\nbe limited to the different `Graphcache` configuration methods.\n\n## Living with limitations of Local Resolvers\n\nLocal Resolvers are powerful tools using which we can tell Graphcache what to do with a certain\nfield beyond using results it’s seen on prior API results. However, it’s limitations come from this\nvery intention they were made for.\n\nResolvers are meant to augment Graphcache and teach it what to do with some fields. Sometimes this\nis trivial and simple (like most examples on this page), but other times, fields are incredibly\ncomplex to reproduce and hence resolvers become more complex.\n\nThis section is not exhaustive, but documents some of the more commonly asked for features of\nresolvers. However, beyond the cases listed below, resolvers are limited and:\n\n- can't manipulate or see other fields on the current entity, or fields above it.\n- can't update the cache (they're only “computations” but don't change the cache)\n- can't change the query document that's sent to the API\n\n### Writing reusable resolvers\n\nAs we've seen before in the [\"Transforming Records\" section above](#transforming-records), we can\nwrite generic resolvers by using the fourth argument that resolvers receive, the `ResolveInfo`\nobject.\n\nThis `info` object gives our resolvers some context on where they’re being executed and gives it\ninformation about the current field and its surroundings.\n\nFor instance, while Graphcache has a convenience helper to access a current record on the parent\nobject for scalar values, it doesn't for links. Hence, if we're trying to read relationships we have\nto use `cache.resolve`.\n\n```js\ncacheExchange({\n  resolvers: {\n    Todo: {\n      // This works:\n      updatedAt: parent => parent.updatedAt,\n      // This won't work:\n      author: parent => parent.author,\n    },\n  },\n});\n```\n\nThe `info` object actually gives us two ways of accessing the original field's value:\n\n```js\nconst resolver = (parent, args, cache, info) => {\n  // This is the full version\n  const original = cache.resolve(info.parentKey, info.fieldName, args);\n  // But we can replace `info.parentKey` with `parent` as a shortcut\n  const original = cache.resolve(parent, info.fieldName, args);\n  // And we can also avoid re-using arguments by using `fieldKey`\n  const original = cache.resolve(parent, info.fieldKey);\n};\n```\n\nApart from telling us how to access the originally cached field value, we can also get more\ninformation from `info` about our field. For instance, we can:\n\n- Read the current field's name using `info.fieldName`\n- Read the current field's key using `info.parentFieldKey`\n- Read the current parent entity's key using `info.parentKey`\n- Read the current parent entity's typename using `info.parentTypename`\n- Access the current operation's raw variables using `info.variables`\n- Access the current operation's raw fragments using `info.fragments`\n\n### Causing cache misses and partial misses\n\nWhen we write resolvers we provide Graphcache with a value for the current field, or rather with\n\"behavior\", that it will execute no matter whether this field is also cached or not.\n\nThis means that, unless our resolver returns `undefined`, if the query doesn't have any other cache\nmisses, Graphcache will consider the field a cache hit and will, unless other cache misses occur,\nnot make a network request.\n\n> **Note:** An exception for this is [Schema Awareness](./schema-awareness.md), which can\n> automatically cause partial cache misses.\n\nHowever, sometimes we may want a resolver to return a result, while still sending a GraphQL API\nrequest in the background to update our resolver’s values.\n\nTo achieve this we can update the `info.partial` field.\n\n```js\ncacheExchange({\n  resolvers: {\n    Todo: {\n      author(parent, args, cache, info) {\n        const author = cache.resolve(parent, info.fieldKey);\n        if (author === null) {\n          info.partial = true;\n        }\n        return author;\n      },\n    },\n  },\n});\n```\n\nSuppose we have a field that our GraphQL schema _sometimes_ returns a `null` value for, but that may\nbe upated with a value in the future. In the above example, we wrote a resolver that sets\n`info.partial = true` if a field’s value is `null`. This causes Graphcache to consider the result\n“partial and stale” and will cause it to make a background request to the API, while still\ndelivering the outdated result.\n\n### Conditionally applying resolvers\n\nWe may not always want a resolver to be used. While sometimes this can be dangerous (if your\nresolver affects the shape and types of your fields), in other cases this is necessary.\nFor instance, if your resolver handles infinite-scroll pagination, like the examples [in the next\nsection](#pagination), then you may not always want to apply this resolver.\n\nFor this reason, Graphcache also supports [“local directives”, which are introduced on the next docs\npage.](./local-directives.md)\n\n## Pagination\n\n`Graphcache` offers some preset `resolvers` to help us out with endless scrolling pagination, also\nknown as \"infinite pagination\". It comes with two more advanced but generalised resolvers that can\nbe applied to two specific pagination use-cases.\n\nThey're not meant to implement infinite pagination for _any app_, instead they're useful when we'd\nlike to add infinite pagination to an app quickly to try it out or if we're unable to replace it\nwith separate components per page in environments like React Native, where a `FlatList` would\nrequire a flat, infinite list of items.\n\n> **Note:** If you don't need a flat array of results, you can also achieve infinite pagination\n> with only UI code. [You can find a code example of UI infinite pagination in our example folder.](https://github.com/urql-graphql/urql/tree/main/examples/with-pagination)\n\n[You can find a code example of infinite pagination with Graphcahce in our example folder.](https://github.com/urql-graphql/urql/tree/main/examples/with-graphcache-pagination).\nPlease keep in mind that this patterns has some limitations when you're handling cache updates.\nDeleting old pages from the cache selectively may be difficult, so the UI pattern in the above\nnote is preferred.\n\n### Simple Pagination\n\nGiven we have a schema that uses some form of `offset` and `limit` based pagination, we can use the\n`simplePagination` exported from `@urql/exchange-graphcache/extras` to achieve an endless scroller.\n\nThis helper will concatenate all queries performed to one long data structure.\n\n```js\nimport { cacheExchange } from '@urql/exchange-graphcache';\nimport { simplePagination } from '@urql/exchange-graphcache/extras';\n\nconst cache = cacheExchange({\n  resolvers: {\n    Query: {\n      todos: simplePagination(),\n    },\n  },\n});\n```\n\nThis form of pagination accepts an object as an argument, we can specify two\noptions in here `limitArgument` and `offsetArgument` these will default to `limit`\nand `skip` respectively. This way we can use the keywords that are in our queries.\n\nWe may also add the `mergeMode` option, which defaults to `'after'` and can otherwise\nbe set to `'before'`. This will handle in which order pages are merged when paginating.\nThe default `after` mode assumes that pages that come in last should be merged\n_after_ the first pages. The `'before'` mode assumes that pages that come in last\nshould be merged _before_ the first pages, which can be helpful in a reverse\nendless scroller (E.g. Chat App).\n\nExample series of requests:\n\n```\n// An example where mergeMode: after works better\nskip: 0, limit: 3 => 1, 2, 3\nskip: 3, limit: 3 => 4, 5, 6\n\nmergeMode: after => 1, 2, 3, 4, 5, 6 ✔️\nmergeMode: before => 4, 5, 6, 1, 2, 3\n\n// An example where mergeMode: before works better\nskip: 0, limit: 3 => 4, 5, 6\nskip: 3, limit: 3 => 1, 2, 3\n\nmergeMode: after => 4, 5, 6, 1, 2, 3\nmergeMode: before => 1, 2, 3, 4, 5, 6 ✔️\n```\n\n### Relay Pagination\n\nGiven we have a [relay-compatible schema](https://facebook.github.io/relay/graphql/connections.htm)\non our backend, we can offer the possibility of endless data resolving.\nThis means that when we fetch the next page in our data\nreceived in `useQuery` we'll see the previous pages as well. This is useful for\nendless scrolling.\n\nWe can achieve this by importing `relayPagination` from `@urql/exchange-graphcache/extras`.\n\n```js\nimport { cacheExchange } from '@urql/exchange-graphcache';\nimport { relayPagination } from '@urql/exchange-graphcache/extras';\n\nconst cache = cacheExchange({\n  resolvers: {\n    Query: {\n      todos: relayPagination(),\n    },\n    // Or if the pagination happens in a nested field:\n    User: {\n      todos: relayPagination(),\n    },\n  },\n});\n```\n\n`relayPagination` accepts an object of options, for now we are offering one\noption and that is the `mergeMode`. This defaults to `inwards` and can otherwise\nbe set to `outwards`. This will handle how pages are merged when we paginate\nforwards and backwards at the same time. outwards pagination assumes that pages\nthat come in last should be merged before the first pages, so that the list\ngrows outwards in both directions. The default inwards pagination assumes that\npagination last pages is part of the same list and come after first pages.\nHence it merges pages so that they converge in the middle.\n\nExample series of requests:\n\n```\nfirst: 1 => node 1, endCursor: a\nfirst: 1, after: a => node 2, endCursor: b\n...\nlast: 1 => node 99, startCursor: c\nlast: 1, before: c => node 89, startCursor: d\n```\n\nWith inwards merging the nodes will be in this order: `[1, 2, ..., 89, 99]`\nAnd with outwards merging: `[..., 89, 99, 1, 2, ...]`\n\nThe helper happily supports schema that return nodes rather than\nindividually-cursored edges. For each paginated type, we must either\nalways request nodes, or always request edges -- otherwise the lists\ncannot be stiched together.\n\n### Reading on\n\n[On the next page we'll learn about \"Cache Directives\".](./local-directives.md)\n"
  },
  {
    "path": "docs/graphcache/normalized-caching.md",
    "content": "---\ntitle: Normalized Caching\norder: 1\n---\n\n# Normalized Caching\n\nIn GraphQL, like its name suggests, we create schemas that express the relational nature of our\ndata. When we create and query against a `Query` type we walk a graph that starts at the root\n`Query` type and walks through relational types. Rather than querying for normalized data, in\nGraphQL our queries request a specific shape of denormalized data, a view into our relational data\nthat can be re-normalized automatically.\n\nAs the GraphQL API walks our query documents it may read from a relational database and _entities_\nand scalar values are copied into a JSON document that matches our query document. The type\ninformation of our entities isn't lost however. A query document may still ask the GraphQL API about\nwhat entity it's dealing with using the `__typename` field, which dynamically introspects an\nentity's type. This means that GraphQL clients can automatically re-normalize data as results come\nback from the API by using the `__typename` field and keyable fields like an `id` or `_id` field,\nwhich are already common conventions in GraphQL schemas. In other words, normalized caches can build\nup a relational database of tables in-memory for our application.\n\nFor our apps normalized caches can enable more sophisticated use-cases, where different API requests\nupdate data in other parts of the app and automatically update data in our cache as we query our\nGraphQL API. Normalized caches can essentially keep the UI of our applications up-to-date when\nrelational data is detected across multiple queries, mutations, or subscriptions.\n\n## Normalizing Relational Data\n\nAs previously mentioned, a GraphQL schema creates a tree of types where our application's data\nalways starts from the `Query` root type and is modified by other data that's incoming from either a\nselection on `Mutation` or `Subscription`. All data that we query from the `Query` type will contain\nrelations between \"entities\", JSON objects that are hierarchical.\n\nA normalized cache seeks to turn this denormalized JSON blob back into a relational data structure,\nwhich stores all entities by a key that can be looked up directly. Since GraphQL documents give the\nAPI a strict specification on how it traverses a schema, the JSON data that the cache receives from\nthe API will always match the GraphQL query document that has been used to query this data.\nA common misconception is that normalized caches in GraphQL store data by the query document somehow,\nhowever, the only thing a normalized cache cares about is that it can use our GraphQL query documents\nto walk the structure of the JSON data it received from the API.\n\n```graphql\n{\n  __typename\n  todo(id: 1) {\n    __typename\n    id\n    title\n    author {\n      __typename\n      id\n      name\n    }\n  }\n}\n```\n\n```json\n{\n  \"__typename\": \"Query\",\n  \"todo\": {\n    \"__typename\": \"Todo\",\n    \"id\": 1,\n    \"title\": \"implement graphcache\",\n    \"author\": {\n      \"__typename\": \"Author\",\n      \"id\": 1,\n      \"name\": \"urql-team\"\n    }\n  }\n}\n```\n\nAbove, we see an example of a GraphQL query document and a corresponding JSON result from a GraphQL\nAPI. In GraphQL, we never lose access to the underlying types of the data. Normalized caches can\nask for the `__typename` field in selection sets automatically and will find out which type a JSON\nobject corresponds to.\n\nGenerally, a normalized cache must do one of two things with a query document like the above:\n\n- It must be able to walk the query document and JSON data of the result and cache the data,\n  normalizing it in the process and storing it in relational tables.\n- It must later be able to walk the query document and recreate this JSON data just by reading data\n  from its cache, by reading entries from its in-memory relational tables.\n\nWhile the normalized cache can't know the exact type of each field, thanks to the GraphQL query\nlanguage it can make a couple of assumptions. The normalized cache can walk the query document. Each\nfield that has no selection set (like `title` in the above example) must be a \"record\", a field that\nmay only be set to a scalar. Each field that does have a selection set must be another \"entity\" or a\nlist of \"entities\". The latter fields with selection sets are our relations between entities, like a\nforeign key in relational databases.\nFurthermore, the normalized cache can then read the `__typename` field on related entities. This is\ncalled _Type Name Introspection_ and is how it finds out about the types of each entity.\nFrom the above document we can assume the following relations:\n\n- `Query.todo(id: 1)` → `Todo`\n- `Todo.author` → `Author`\n\nHowever, this isn't quite enough yet to store the relations from GraphQL results. The normalized\ncache must also generate primary keys for each entity so that it can store them in table-like data\nstructures. This is for instance why [Relay\nenforces](https://relay.dev/docs/guides/graphql-server-specification/#object-identification) that\neach entity must have an `id` field. This allows it to assume that there's an obvious primary key\nfor each entity it may query. Instead, `urql`'s Graphcache and Apollo assume that there _may_ be an\n`id` or `_id` field in a given selection set. If Graphcache can't find these two fields it'll issue\na warning, however a custom `keys` configuration may be used to generate custom keys for a given\ntype. With this logic the normalized cache will actually create the following \"links\" between its\nrelational data:\n\n- `\"Query\"`, `.todo(id: 1)` → `\"Todo:1\"`\n- `\"Todo:1\"`, `.author` → `\"Author:1\"`\n\nAs we can see, the `Query` root type itself has a constant key of `\"Query\"`. All relational data\noriginates here, since the GraphQL schema is a graph and, like a tree, all selections on a GraphQL\nquery document originate from it.\nInternally, the normalized cache now stores field values on entities by their primary keys. The\nabove can also be said or written as:\n\n- The `Query` entity's `todo` field with `{\"id\": 1}` arguments points to the `Todo:1` entity.\n- The `Todo:1` entity's `author` field points to the `Author:1` entity.\n\nIn Graphcache, these \"links\" are stored in a nested structure per-entity. \"Records\" are kept\nseparate from this relational data.\n\n![Normalization is based on types, keys, and relations. This information can all be inferred from\nthe query document.](../assets/query-document-info.png)\n\n## Storing Normalized Data\n\nAt its core, normalizing data means that we take individual fields and store them in a table. In our\ncase we store all values of fields in a dictionary of their primary key, generated from an ID or\nother key and type name, and the field’s name and arguments, if it has any.\n\n| Primary Key            | Field                                           | Value                    |\n| ---------------------- | ----------------------------------------------- | ------------------------ |\n| Type name and ID (Key) | Field name (not alias) and optionally arguments | Scalar value or relation |\n\nTo reiterate we have three pieces of information that are stored in tables:\n\n- The entity's key can be derived from its type name via the `__typename` field and a keyable field.\n  By default _Graphcache_ will check the `id` and `_id` fields, however this is configurable.\n- The field's name (like `todo`) and optional arguments. If the field has any arguments then we can\n  normalize it by JSON stringifying the arguments, making sure that the JSON key is stable by\n  sorting its keys.\n- Lastly, we may store relations as either `null`, a primary key that refers to another entity, or a\n  list of such. For storing \"records\" we can store the scalars in a separate table.\n\nIn _Graphcache_ the data structure for these tables looks a little like the following, where each\nentity has a record from fields to other entity keys:\n\n```js\n{\n  links: Map {\n    'Query': Record {\n      'todo({\"id\":1})': 'Todo:1'\n    },\n    'Todo:1': Record {\n      'author': 'Author:1'\n    },\n    'Author:1': Record { },\n  }\n}\n```\n\nWe can see how the normalized cache is now able to traverse a GraphQL query by starting on the\n`Query` entity and retrieve relations for other fields.\nTo retrieve \"records\" which are all fields with scalar values and no selection sets, _Graphcache_\nkeeps a second table around with an identical structure. This table only contains scalar values,\nwhich keeps our non-relational data away from our \"links\":\n\n```js\n{\n  records: Map {\n    'Query': Record {\n      '__typename': 'Query'\n    },\n    'Todo:1': Record {\n      '__typename': 'Todo',\n      'id': 1,\n      'title': 'implement graphcache'\n    },\n    'Author:1': Record {\n      '__typename': 'Author',\n      'id': 1,\n      'name': 'urql-team'\n    },\n  }\n}\n```\n\nThis is very similar to how we'd go about creating a state management store manually, except that\n_Graphcache_ can use the GraphQL document to perform this normalization automatically.\n\nWhat we gain from this normalization is that we have a data structure that we can both read from and\nwrite to, to reproduce the API results for GraphQL query documents. Any mutation or subscription can\nalso be written to this data structure. Once _Graphcache_ finds a keyable entity in their results\nit's written to its relational table which may update other queries in our application.\nSimilarly queries may share data between one another which means that they effectively share\nentities using this approach and can update one another.\nIn other words, once we have a primary key like `\"Todo:1\"` we may find this primary key again in\nother entities in other GraphQL results.\n\n## Custom Keys and Non-Keyable Entities\n\nIn the above introduction we've learned that while _Graphcache_ doesn't enforce `id` fields on each\nentity, it checks for the `id` and `_id` fields by default. There are many situations in which\nentities may either not have a key field or have different keys.\n\nAs _Graphcache_ traverses JSON data and a GraphQL query document to write data to the cache you may\nsee a warning from it along the lines of [\"Invalid key: [...] No key could be generated for the data\nat this field.\"](./errors.md/#15-invalid-key) _Graphcache_ has many warnings like these that attempt\nto detect undesirable behaviour and helps us to update our configuration or queries accordingly.\n\nIn the simplest cases, we may simply have forgotten to add the `id` field to the selection set of\nour GraphQL query document. However, what if the field is instead called `uuid` and our query looks\naccordingly different?\n\n```graphql\n{\n  item {\n    uuid\n  }\n}\n```\n\nIn the above selection set we have an `item` field that has a `uuid` field rather than an `id`\nfield. This means that _Graphcache_ won't automatically be able to generate a primary key for this\nentity. Instead, we have to help it generate a key by passing it a custom `keys` config:\n\n```js\ncacheExchange({\n  keys: {\n    Item: data => data.uuid,\n  },\n});\n```\n\nWe may add a function as an entry to the `keys` configuration. The property here, `\"Item\"` must be\nthe typename of the entity for which we're generating a key. The function may return an arbitarily\ngenerated key. So for our `item` field, which in our example schema gives us an `Item` entity, we\ncan create a `keys` configuration entry that creates a key from the `uuid` field rather than the\n`id` field.\n\nThis also raises a question, **what does _Graphcache_ do with unkeyable data by default? And, what\nif my data has no key?**<br />\nThis special case is what we call \"embedded data\". Not all types in a GraphQL schema will have\nkeyable fields and some types may just abstract data without themselves being relational. They may\nbe \"edges\", entities that have a field pointing to other entities that simply connect two entities,\nor data types like a `GeoJson` or `Image` type.\n\nIn these cases, where the normalized cache encounters unkeyable types, it will create an embedded\nkey by using the parent's primary key and combining it with the field key. This means that\n\"embedded entities\" are only reachable from a specific field on their parent entities. They're\nglobally unique and aren't strictly speaking relational data.\n\n```graphql\n{\n  __typename\n  todo(id: 1) {\n    id\n    image {\n      url\n      width\n      height\n    }\n  }\n}\n```\n\nIn the above example we're querying an `Image` type on a `Todo`. This imaginary `Image` type has no\nkey because the image is embedded data and will only ever be associated to this `Todo`. In other\nwords, the API's schema doesn't consider it necessary to have a primary key field for this type.\nMaybe it doesn't even have an ID in our backend's database. We _could_ assign this type an imaginary\nkey (maybe based on the `url`) but in fact if it's not shared data it wouldn't make much sense to\ndo so.\n\nWhen _Graphcache_ attempts to store this entity it will issue the previously mentioned warning.\nInternally, it'll then generate an embedded key for this entity based on the parent entity. If\nthe parent entity's key is `Todo:1` then the embedded key for our `Image` will become\n`Todo:1.image`. This is also how this entity will be stored internally by _Graphcache_:\n\n```js\n{\n  records: Map {\n    'Todo:1.image': Record {\n      '__typename': 'Image',\n      'url': '...',\n      'width': 1024,\n      'height': 768\n    },\n  }\n}\n```\n\nThis doesn't however mute the warning that _Graphcache_ outputs, since it believes we may have made a\nmistake. The warning itself gives us advice on how to mute it:\n\n> If this is intentional, create a keys config for `Image` that always returns null.\n\nMeaning, that we can add an entry to our `keys` config for our non-keyable type that explicitly\nreturns `null`, which tells _Graphcache_ that the entity has no key:\n\n```js\ncacheExchange({\n  keys: {\n    Image: () => null,\n  },\n});\n```\n\n### Flexible Key Generation\n\nIn some cases, you may want to create a pattern for your key generation. For instance, you may want\nto say \"create a special key for every type ending in `'Node'`. In such a case we recommend creating\na small JS `Proxy` to take care of key generation for you and making the keys functional.\n\n```js\ncacheExchange({\n  keys: new Proxy(\n    {\n      Image: () => null,\n    },\n    {\n      get(target, prop, receiver) {\n        if (prop.endsWith('Node')) {\n          return data => data.uid;\n        }\n        const fallback = data => data.uuid;\n        return target[prop] || fallback;\n      },\n    }\n  ),\n});\n```\n\nIn the above example, we dynamically change the key generator depending on the typename. When\na typename ends in `'Node'`, we return a key generator that uses the `uid` field. We still fall back\nto an object of manual key generation functions however. Lastly though, when a type doesn't have\na predefined key generator, we change the default behavior from using `id` and `_id` fields to using\n`uuid` fields.\n\n## Non-Automatic Relations and Updates\n\nWhile _Graphcache_ is able to store and update our entities in an in-memory relational data\nstructure, which keeps the same entities in singular unique locations, a GraphQL API may make a lot\nof implicit changes to the relations of data as it runs or have trivial relations that our cache\ndoesn't need to see to resolve. Like with the `keys` config, we have two more configuration options\nto combat this: `resolvers` and `updates`.\n\n### Manually resolving entities\n\nSome fields in our configuration can be resolved without checking the GraphQL API for relations. The\n`resolvers` config allows us to create a list of client-side resolvers where we can read from the\ncache directly as _Graphcache_ creates a local GraphQL result from its cached data.\n\n```graphql\n{\n  todo(id: 1) {\n    id\n  }\n}\n```\n\nPreviously we've looked at the above query to illustrate how data from a GraphQL API may be written\nto _Graphcache_'s relational data structure to store the links and entities in a result against this\nGraphQL query document. However, it may be possible for another query to have already written this\n`Todo` entity to the cache. So, **how do we resolve a relation manually?**\n\nIn such a case, _Graphcache_ may have seen and stored the `Todo` entity but isn't aware of the\nrelation between `Query.todo({\"id\":1})` and the `Todo:1` entity. However, we can tell _Graphcache_\nwhich entity it should look for when it accesses the `Query.todo` field by creating a resolver for\nit:\n\n```js\ncacheExchange({\n  resolvers: {\n    Query: {\n      todo(parent, args, cache, info) {\n        return { __typename: 'Todo', id: args.id };\n      },\n    },\n  },\n});\n```\n\nA resolver is a function that's similar to [GraphQL.js' resolvers on the\nserver-side](https://www.graphql-tools.com/docs/resolvers/). They receive the parent data, the\nfield's arguments, access to _Graphcache_'s cached data, and an `info` object. [The entire function\nsignature and more explanations can be found in the API docs.](../api/graphcache.md#resolvers-option)\nSince it can access the field's arguments from the GraphQL query document, we can return a partial\n`Todo` entity. As long as this\nobject is keyable, it will tell _Graphcache_ what the key of the returned entity is. In other words,\nwe've told it how to get to a `Todo` from the `Query.todo` field.\n\nThis mechanism is immensely more powerful than this example. We have other use-cases that\nresolvers may be used for:\n\n- Resolvers can be applied to fields with records, which means that it can be used to change or\n  transform scalar values. For instance, we can update a string or parse a `Date` right inside a\n  resolver.\n- Resolvers can return deeply nested results, which will be layered on top of the in-memory\n  relational cached data of _Graphcache_, which means that it can emulate infinite pagination and\n  other complex behaviour.\n- Resolvers can change when a cache miss or hit occurs. Returning `null` means that a field’s value\n  is literally `null`, which will not cause a cache miss, while returning `undefined` will mean\n  a field’s value is uncached.\n- Resolvers can return either partial entities or keys, so we can chain `cache.resolve` calls to\n  read fields from the cache, even when a field is pointing at another entity, since we can return\n  keys to the other entity directly.\n\n[Read more about resolvers on the following page about \"Local Resolvers\".](./local-resolvers.md)\n\n### Manual cache updates\n\nWhile `resolvers`, as shown above, operate while _Graphcache_ is reading from its in-memory cache,\n`updates` are a configuration option that operate while _Graphcache_ is writing to its cached data.\nSpecifically, these functions can be used to add more updates onto what a `Mutation` or\n`Subscription` may automatically update.\n\nAs stated before, a GraphQL schema's data may undergo a lot of implicit changes when we send it a\n`Mutation` or `Subscription`. A new item that we create may for instance manipulate a completely\ndifferent item or even a list. Often mutations and subscriptions alter relations that their\nselection sets wouldn't necessarily see. Since mutations and subscriptions operate on a different\nroot type, rather than the `Query` root type, we often need to update links in the rest of our data\nwhen a mutation is executed.\n\n```graphql\nquery TodosList {\n  todos {\n    id\n    title\n  }\n}\n\nmutation AddTodo($title: String!) {\n  addTodo(title: $title) {\n    id\n    title\n  }\n}\n```\n\nIn a simple example, like the one above, we have a list of todos in a query and create a new todo\nusing the `Mutation.addTodo` mutation field. When the mutation is executed and we get the result\nback, _Graphcache_ already writes the `Todo` item to its normalized cache. However, we also want to\nadd the new `Todo` item to the list on `Query.todos`:\n\n```js\nimport { gql } from '@urql/core';\n\ncacheExchange({\n  updates: {\n    Mutation: {\n      addTodo(result, args, cache, info) {\n        const query = gql`\n          {\n            todos {\n              id\n            }\n          }\n        `;\n        cache.updateQuery({ query }, data => {\n          data.todos.push(result.addTodo);\n          return data;\n        });\n      },\n    },\n  },\n});\n```\n\nIn this code example we can first see that the signature of the `updates` entry is very similar to\nthe one of `resolvers`. However, we're seeing the `cache` in use for the first time. The `cache`\nobject (as [documented in the API docs](../api/graphcache.md#cache)) gives us\naccess to _Graphcache_'s mechanisms directly. Not only can we resolve data using it, we can directly\nstart sub-queries or sub-writes manually. These are full normalized cache runs inside other runs. In\nthis case we're calling `cache.updateQuery` on a list of `Todo` items while the `Mutation` that\nadded the `Todo` is already being written to the cache.\n\nAs we can see, we may perform manual changes inside of `updates` functions, which can be used to\naffect other parts of the cache (like `Query.todos` here) beyond the automatic updates that a\nnormalized cache is expected to perform.\n\nWe get methods like `cache.updateQuery`, `cache.writeFragment`, and `cache.link` in our updater\nfunctions, which aren't available to us in local resolvers, and can only be used in these `updates`\nentries to change the data that the cache holds.\n\n[Read more about writing cache updates on the \"Cache Updates\" page.](./cache-updates.md)\n\n## Deterministic Cache Updates\n\nAbove, in [the \"Storing Normalized Data\" section](#storing-normalized-data), we've talked about how\nGraphcache is able to store normalized data. However, apart from storing this data there are a\ncouple of caveats that many applications simply ignore, skip, or simplify when they implement a\nstore to cache their data in.\n\nAmongst features like [Optimistic Updates](./cache-updates.md#optimistic-updates) and [Offline\nSupport](./offline.md), Graphcache supports several features that allow our API results to be more\nunreliable. Essentially we don't expect API results to always come back in order or on time.\nHowever, we expect Graphcache to prevent us from making \"indeterministic cache updates\", meaning\nthat we expect it to handle API results that come back in a random order and delayed gracefully.\n\nIn terms of the [\"Manual Cache Updates\"](#manual-cache-updates) that we've talked about above and\n[Optimistic Updates](./cache-updates.md#optimistic-updates) the limitations are pretty simple at\nfirst and if we use Graphcache as usual we may not even notice them:\n\n- When we make an _optimistic_ change, we define what a mutation's result may look like once the API\n  responds in the future and apply this temporary result immediately. We store this temporary data\n  in a separate \"layer\". Once the real result comes back this layer can be deleted and the real API\n  result can be applied as usual.\n- When multiple _optimistic updates_ are made at the same time, we never allow these layers to be\n  deleted separately. Instead Graphcache waits for all mutations to complete before deleting the\n  optimistic layers and applying the real API result. This means that a mutation update cannot\n  accidentally commit optimistic data to the cache permanently.\n- While an _optimistic update_ has been applied, Graphcache stops refetching any queries that contain\n  this optimistic data so that it doesn't \"flip back\" to its non-optimistic state without the\n  optimistic update being applied. Otherwise we'd see a \"flicker\" in the UI.\n\nThese three principles are the basic mechanisms we can expect from Graphcache. The summary is:\n**Graphcache groups optimistic mutations and pauses queries so that optimistic updates look as\nexpected,** which is an implementation detail we can mostly ignore when using it.\n\nHowever, one implementation detail we cannot ignore is the last mechanism in Graphcache which is\ncalled **\"Commutativity\"**. As we can tell, \"optimistic updates\" need to store their normalized\nresults on a separate layer. This means that the previous data structure we've seen in Graphcache is\nactually more like a list, with many tables of links and entities.\n\nEach layer may contain optimistic results and have an order of preference. However, this order also\napplies to queries. Since queries are run in one order but their API results can come back to us in\na very different order, if we access enough pages in a random order things can sometimes look rather\nweird. We may see that in an application on a slow network connection the results may vary depending\non when their results came back.\n\n![Commutativity means that we store data in separate layers.](../assets/commutative-layers.png)\n\nInstead, Graphcache actually uses layers for any API result it receives. In case, an API result\narrives out-of-order, it sorts them by precedence — or rather by when they've been requested.\nOverall, we don't have to worry about this, but Graphcache has mechanisms that keep our updates\nsafe.\n\n## Reading on\n\nThis concludes the introduction to Graphcache with a short overview of how it works, what it\nsupports, and some hidden mechanisms and internals. Next we may want to learn more about how to use\nit and more of its features:\n\n- [How do we write \"Local Resolvers\"?](./local-resolvers.md)\n- [How to set up \"Cache Updates\" and \"Optimistic Updates\"?](./cache-updates.md)\n- [What is Graphcache's \"Schema Awareness\" feature for?](./schema-awareness.md)\n- [How do I enable \"Offline Support\"?](./offline.md)\n"
  },
  {
    "path": "docs/graphcache/offline.md",
    "content": "---\ntitle: Offline Support\norder: 7\n---\n\n# Offline Support\n\n_Graphcache_ allows you to build an offline-first app with built-in offline and persistence support,\nby adding a `storage` interface. In combination with its [Schema\nAwareness](./schema-awareness.md) support and [Optimistic\nUpdates](./cache-updates.md#optimistic-updates) this can be used to build an application that\nserves cached data entirely from memory when a user's device is offline and still display\noptimistically executed mutations.\n\n## Setup\n\nEverything that's needed to set up offline-support is already packaged in the\n`@urql/exchange-graphcache` package.\n\nWe initially recommend setting up the [Schema Awareness](./schema-awareness.md). This adds our\nserver-side schema information to the cache, which allows it to make decisions on what partial data\ncomplies with the schema. This is useful since the offline cache may often be lacking some data but\nmay then be used to display the partial data we do have, as long as missing data is actually marked\nas optional in the schema.\n\nFurthermore, if we have any mutations that the user doesn't interact with after triggering them (for\ninstance, \"liking a post\"), we can set up [Optimistic\nUpdates](./cache-updates.md#optimistic-updates) for these mutations, which allows them to be\nreflected in our UI before sending a request to the API.\n\nTo actually now set up offline support, we'll swap out the `cacheExchange` with the\n`offlineExchange` that's also exported by `@urql/exchange-graphcache`.\n\n```js\nimport { Client, fetchExchange } from 'urql';\nimport { offlineExchange } from '@urql/exchange-graphcache';\n\nconst cache = offlineExchange({\n  schema,\n  updates: {\n    /* ... */\n  },\n  optimistic: {\n    /* ... */\n  },\n});\n\nconst client = new Client({\n  url: 'http://localhost:3000/graphql',\n  exchanges: [cache, fetchExchange],\n});\n```\n\nThis activates offline support, however we'll also need to provide the `storage` option to the\n`offlineExchange`. The `storage` is an adapter that contains methods for storing cache data in a\npersisted storage interface on the user's device.\n\nBy default, we can use the default storage option that `@urql/exchange-graphcache` comes with. This\ndefault storage uses [IndexedDB](https://developer.mozilla.org/en-US/docs/Web/API/IndexedDB_API) to\npersist the cache's data. We can use this default storage by importing the `makeDefaultStorage`\nfunction from `@urql/exchange-graphcache/default-storage`.\n\n```js\nimport { Client, fetchExchange } from 'urql';\nimport { offlineExchange } from '@urql/exchange-graphcache';\nimport { makeDefaultStorage } from '@urql/exchange-graphcache/default-storage';\n\nconst storage = makeDefaultStorage({\n  idbName: 'graphcache-v3', // The name of the IndexedDB database\n  maxAge: 7, // The maximum age of the persisted data in days\n});\n\nconst cache = offlineExchange({\n  schema,\n  storage,\n  updates: {\n    /* ... */\n  },\n  optimistic: {\n    /* ... */\n  },\n});\n\nconst client = new Client({\n  url: 'http://localhost:3000/graphql',\n  exchanges: [cache, fetchExchange],\n});\n```\n\n## React Native\n\nFor React Native, we can use the async storage package `@urql/storage-rn`.\n\nBefore installing the [library](https://github.com/urql-graphql/urql/tree/main/packages/storage-rn), ensure you have installed the necessary peer dependencies:\n\n- NetInfo ([RN](https://github.com/react-native-netinfo/react-native-netinfo) | [Expo](https://docs.expo.dev/versions/latest/sdk/netinfo/)) and\n- AsyncStorage ([RN](https://react-native-async-storage.github.io/async-storage/docs/install) | [Expo](https://docs.expo.dev/versions/v42.0.0/sdk/async-storage/)).\n\n```sh\nyarn add @urql/storage-rn\n# or\nnpm install --save @urql/storage-rn\n```\n\nYou can then create the custom storage and use it in the offline exchange:\n\n```js\nimport { makeAsyncStorage } from '@urql/storage-rn';\n\nconst storage = makeAsyncStorage({\n  dataKey: 'graphcache-data', // The AsyncStorage key used for the data (defaults to graphcache-data)\n  metadataKey: 'graphcache-metadata', // The AsyncStorage key used for the metadata (defaults to graphcache-metadata)\n  maxAge: 7, // How long to persist the data in storage (defaults to 7 days)\n});\n```\n\n## Offline Behavior\n\n_Graphcache_ applies several mechanisms that improve the consistency of the cache and how it behaves\nwhen it's used in highly cached-dependent scenarios, including when it's used with its offline\nsupport. We've previously read about some of these guarantees on the [\"Normalized Caching\"\npage.](./normalized-caching.md)\n\nWhile the client is offline, _Graphcache_ will also apply some opinionated mechanisms to queries and\nmutations.\n\nWhen a query fails with a Network Error, which indicates that the client is\noffline the `offlineExchange` won't deliver the error for this query to avoid it from being\nsurfaced to the user. This works particularly well in combination with [\"Schema\nAwareness\"](./schema-awareness.md) which will deliver as much of a partial query result as possible.\nIn combination with the [`cache-and-network` request policy](../basics/document-caching.md#request-policies)\nwe can now ensure that we display as much data as possible when the user is offline while still\nkeeping the cache up-to-date when the user is online.\n\nA similar mechanism is applied to optimistic mutations when the user is offline. Normal\nnon-optimistic mutations are executed as usual and may fail with a network error. Optimistic\nmutations however will be queued up and may be retried when the app is restarted or when the user\ncomes back online.\n\nIf we wish to customize when an operation result from the API is deemed an operation that has failed\nbecause the device is offline, we can pass a custom `isOfflineError` function to the\n`offlineExchange`, like so:\n\n```js\nconst cache = offlineExchange({\n  isOfflineError(error, _result) {\n    return !!error.networkError;\n  },\n  // ...\n});\n```\n\nHowever, this is optional, and the default function checks for common offline error messages and\nchecks `navigator.onLine` for you.\n\n## Custom Storages\n\nIn the [Setup section](#setup) we've learned how to use the default storage engine to store\npersisted cache data in IndexedDB. You can also write custom storage engines, if the default one\ndoesn't align with your expectations or requirements.\nOne limitation of our default storage engine is for instance that data is stored time limited with a\nmaximum age, which prevents the database from becoming too full, but a custom storage engine may\nhave different strategies for dealing with this.\n\n[The API docs list the entire interface for the `storage` option.](../api/graphcache.md#storage-option)\nThere we can see the methods we need to implement to implement a custom storage engine.\n\nFollowing is an example of the simplest possible storage engine, which uses the browser's\n[Local Storage](https://developer.mozilla.org/en-US/docs/Web/API/Window/localStorage).\nInitially we'll implement the basic persistence methods, `readData` and `writeData`.\n\n```js\nconst makeLocalStorage = () => {\n  const cache = {};\n\n  return {\n    writeData(delta) {\n      return Promise.resolve().then(() => {\n        Object.assign(cache, delta);\n        localStorage.setItem('data', JSON.stringify(cache));\n      });\n    },\n    readData() {\n      return Promise.resolve().then(() => {\n        const local = localStorage.getItem('data') || null;\n        Object.assign(cache, JSON.parse(local));\n        return cache;\n      });\n    },\n  };\n};\n```\n\nAs we can see, the `writeData` method only sends us \"deltas\", partial objects that only describe\nupdated cache data rather than all cache data. The implementation of `writeMetadata` and\n`readMetadata` will however be even simpler, since it always sends us complete data.\n\n```js\nconst makeLocalStorage = () => {\n  return {\n    /* ... */\n    writeMetadata(data) {\n      localStorage.setItem('metadata', JSON.stringify(data));\n    },\n    readMetadata() {\n      return Promise.resolve().then(() => {\n        const metadataJson = localStorage.getItem('metadata') || null;\n        return JSON.parse(metadataJson);\n      });\n    },\n  };\n};\n```\n\nLastly, the `onOnline` method will likely always look the same, as long as your `storage` is\nintended to work for browsers only:\n\n```js\nconst makeLocalStorage = () => {\n  return {\n    /* ... */\n    onOnline(cb: () => void) {\n      window.addEventListener('online', () => {\n        cb();\n      });\n    },\n  };\n};\n```\n"
  },
  {
    "path": "docs/graphcache/schema-awareness.md",
    "content": "---\ntitle: Schema Awareness\norder: 5\n---\n\n# Schema Awareness\n\nPreviously, [on the \"Normalized Caching\" page](./normalized-caching.md) we've seen how Graphcache\nstores normalized data in its store and how it traverses GraphQL documents to do so. What we've seen\nis that just using the GraphQL document for traversal, and the `__typename` introspection field\nGraphcache is able to build a normalized caching structure that keeps our application up-to-date\nacross API results, allows it to store data by entities and keys, and provides us configuration\noptions to write [manual cache updates](./cache-updates.md) and [local\nresolvers](./local-resolvers.md).\n\nWhile this is all possible without any information about a GraphQL API's schema, the `schema` option\non `cacheExchange` allows us to pass an introspected schema to Graphcache:\n\n```js\nconst introspectedSchema = {\n  __schema: {\n    queryType: { name: 'Query' },\n    mutationType: { name: 'Mutation' },\n    subscriptionType: { name: 'Subscription' },\n  },\n};\n\ncacheExchange({ schema: introspectedSchema });\n```\n\nIn GraphQL, [APIs allow for the entire schema to be\n\"introspected\"](https://graphql.org/learn/introspection/), which are special GraphQL queries that\ngive us information on what the API supports. This information can either be retrieved from a\nGraphQL API directly or from the GraphQL.js Schema and contains a list of all types, the types'\nfields, scalars, and other information.\n\nIn Graphcache we can pass this schema information to enable several features that aren't enabled if\nwe don't pass any information to this option:\n\n- Fragments will be matched deterministically: A fragment can be written to be on an interface type\n  or multiple fragments can be spread for separate union'ed types in a selection set. In many cases,\n  if Graphcache doesn't have any schema information then it won't know what possible types a field\n  can return and may sometimes make a guess and [issue a\n  warning](./errors.md#16-heuristic-fragment-matching). If we pass Graphcache a `schema` then it'll\n  be able to match fragments deterministically.\n- A schema may have non-default names for its root types; `Query`, `Mutation`, and `Subscription`.\n  The names can be changed by passing `schema` information to `cacheExchange` which is important\n  if the root type appears elsewhere in the schema, e.g. if the `Query` can be accessed on a\n  `Mutation` field's result.\n- We may write a lot of configuration for our `cacheExchange` but if we pass a `schema` then it'll\n  start checking whether any of the configuration options actually don't exist, maybe because we've\n  typo'd them. This is a small detail but can make a large difference in a longer configuration.\n- Lastly; a schema contains information on **which fields are optional or required**. When\n  Graphcache has a schema it knows optional fields that may be left out, and it'll be able to generate\n  \"partial results\".\n\n### Partial Results\n\nAs we navigate an app that uses Graphcache we may be in states where some of our data is already\ncached while some aren't. Graphcache normalizes data and stores it in tables for links and records for\neach entity, which means that sometimes it can maybe even execute a query against its cache that it\nhasn't sent to the API before.\n\n[On the \"Local Resolvers\" page](./local-resolvers.md#resolving-entities) we've seen how to write\nresolvers that resolve entities without having to have seen a link from an API result before. If\nGraphcache uses these resolvers and previously cached data we often run into situations where a\n\"partial result\" could already be generated, which is what Graphcache does when it has `schema`\ninformation.\n\n![A \"partial result\" is an incomplete result of information that Graphcache already had cached\nbefore it sent an API result.](../assets/partial-results.png)\n\nWithout a `schema` and information on which fields are optional, Graphcache will consider a \"partial\nresult\" as a cache miss. If we don't have all the information for a query then we can't execute\nit against the locally cached data after all. However, an API's schema contains information on which\nfields are required and optional, and if our apps are typed with this schema and\nTypeScript, can't we then use and handle these partial results before a request is sent to the API?\n\nThis is the idea behind \"Schema Awareness\" and \"Partial Results\". When Graphcache has `schema`\ninformation it may give us partial results [with the `stale` flag\nset](../api/core.md#operationresult) while it fetches the full result from the API in the\nbackground. This allows our apps to show some information while more is loading.\n\n## Getting your schema\n\nBut how do you get an introspected `schema`? The process of introspecting a schema is running an\nintrospection query on the GraphQL API, which will give us our `IntrospectionQuery` result. So an\nintrospection is just another query we can run against our GraphQL APIs or schemas.\n\nAs long as `introspection` is turned on and permitted, we can download an introspection schema by\nrunning a normal GraphQL query against the API and save the result in a JSON file.\n\n```js\nimport { getIntrospectionQuery } from 'graphql';\nimport fetch from 'node-fetch'; // or your preferred request in Node.js\nimport * as fs from 'fs';\n\nfetch('http://localhost:3000/graphql', {\n  method: 'POST',\n  headers: { 'Content-Type': 'application/json' },\n  body: JSON.stringify({\n    variables: {},\n    query: getIntrospectionQuery({ descriptions: false }),\n  }),\n})\n  .then(result => result.json())\n  .then(({ data }) => {\n    fs.writeFile('./schema.json', JSON.stringify(data), err => {\n      if (err) {\n        console.error('Writing failed:', err);\n        return;\n      }\n      console.log('Schema written!');\n    });\n  });\n```\n\nAlternatively, if you're already using [GraphQL Code Generator](https://graphql-code-generator.com/)\nyou can use [their `@graphql-codegen/introspection`\nplugin](https://graphql-code-generator.com/docs/plugins/introspection) to do the same automatically\nagainst a local schema. Furthermore it's also possible to\n[`execute`](https://graphql.org/graphql-js/execution/#execute) the introspection query directly\nagainst your `GraphQLSchema`.\n\n## Optimizing a schema\n\nAn `IntrospectionQuery` JSON blob from a GraphQL API can without modification become quite large.\nThe shape of this data is `{ \"__schema\": ... }` and this _schema_ data will contain information on\nall directives, types, input objects, scalars, deprecation, enums, and more. This can quickly add up and one of the\nlargest schemas, the GitHub GraphQL API's schema, has an introspection size of about 1.1MB, or about\n50KB gzipped.\n\nHowever, we can use the `@urql/introspection` package's `minifyIntrospectionQuery` helper to reduce\nthe size of this introspection data. This helper strips out information on directives, scalars,\ninput types, deprecation, enums, and redundant fields to only leave information that _Graphcache_\nactually requires.\n\nIn the example of the GitHub GraphQL API this reduces the introspected data to around 20kB gzipped,\nwhich is much more acceptable.\n\n### Installation & Setup\n\nFirst, install the `@urql/introspection` package:\n\n```sh\nyarn add @urql/introspection\n# or\nnpm install --save @urql/introspection\n```\n\nYou'll then need to integrate it into your introspection script or in another place where it can\noptimise the introspection data. For this example, we'll just add it to the fetching script from\n[above](#getting-your-schema).\n\n```js\nimport { getIntrospectionQuery } from 'graphql';\nimport fetch from 'node-fetch'; // or your preferred request in Node.js\nimport * as fs from 'fs';\n\nimport { getIntrospectedSchema, minifyIntrospectionQuery } from '@urql/introspection';\n\nfetch('http://localhost:3000/graphql', {\n  method: 'POST',\n  headers: { 'Content-Type': 'application/json' },\n  body: JSON.stringify({\n    variables: {},\n    query: getIntrospectionQuery({ descriptions: false }),\n  }),\n})\n  .then(result => result.json())\n  .then(({ data }) => {\n    const minified = minifyIntrospectionQuery(getIntrospectedSchema(data));\n    fs.writeFileSync('./schema.json', JSON.stringify(minified));\n  });\n```\n\nThe `getIntrospectionSchema ` doesn't only accept `IntrospectionQuery` JSON data as inputs, but also\nallows you to pass a JSON string, `GraphQLSchema`, or GraphQL Schema SDL strings. It's a convenience\nhelper and not needed in the above example.\n\n## Integrating a schema\n\nOnce we have a schema that's already saved to a JSON file, we can load it and pass it to the\n`cacheExchange`'s `schema` option:\n\n```js\nimport schema from './schema.json';\n\nconst cache = cacheExchange({ schema });\n```\n\nIt may be worth checking what your bundler or framework does when you import a JSON file. Typically\nyou can reduce the parsing time by making sure it's turned into a string and parsed using\n`JSON.parse`\n"
  },
  {
    "path": "docs/showcase.md",
    "content": "---\ntitle: Showcase\norder: 7\n---\n\n# Showcase\n\n`urql` wouldn't be the same without our growing and loving community of users,\nmaintainers and supporters. This page is specifically dedicated to all of you!\n\n## Used by folks at\n\n<a href=\"https://tripadvisor.com\">\n<img alt=\"TripAdvisor\" height=\"60\" src=\"./assets/logos/tripadvisor.png\" />\n</a>\n\n<a href=\"https://github.com\">\n<img alt=\"GitHub\" height=\"60\" src=\"./assets/logos/github.png\" />\n</a>\n\n<a href=\"https://egghead.io\">\n<img alt=\"Egghead\" height=\"60\" src=\"./assets/logos/egghead.png\" />\n</a>\n\n<a href=\"https://gatsbyjs.org\">\n<img alt=\"Gatsby\" height=\"60\" src=\"./assets/logos/gatsby.png\" />\n</a>\n\n<a href=\"https://theatlantic.com/science/\">\n<img alt=\"The Atlantic\" height=\"60\" src=\"./assets/logos/the-atlantic.png\" />\n</a>\n\n<a href=\"https://www.loveholidays.com\">\n<img alt=\"loveholidays\" height=\"60\" src=\"./assets/logos/loveholidays.png\" />\n</a>\n\n<a href=\"https://www.swan.io/\">\n<img alt=\"Swan\" height=\"60\" src=\"./assets/logos/swan.png\" />\n</a>\n\n<a href=\"https://www.getopensocial.com\">\n<img alt=\"Open Social\" height=\"60\" src=\"./assets/logos/open-social.png\" />\n</a>\n\n<a href=\"https://getsturdy.com/\">\n<img alt=\"Sturdy\" height=\"60\" src=\"./assets/logos/sturdy.png\" />\n</a>\n\n## Articles & Tutorials\n\n- [Egghead Course](https://egghead.io/lessons/graphql-set-up-an-urql-graphql-provider-in-react?pl=introduction-to-urql-a-react-graphql-client-faaa2bf5)\n  by [Ian Jones](https://twitter.com/_jonesian).\n- [How To GraphQL: React + urql](https://www.howtographql.com/react-urql/0-introduction/)\n\n## Community packages\n\n- [`reason-urql`](https://github.com/FormidableLabs/reason-urql): The official Reason bindings for\n  `urql`.\n- [`urql-persisted-queries`](https://github.com/Daniel15/urql-persisted-queries): Support for\n  Apollo-style persisted queries.\n- [`urql-computed-queries`](https://github.com/Drawbotics/urql-computed-exchange): An exchange to\n  compute fields on-the-fly using the `@computed` directive.\n- [`graphql-code-generator`](https://graphql-code-generator.com/docs/plugins/typescript-urql): A plugin\n  that helps you make typesafe hooks/components with urql.\n- [`urql-custom-scalars-exchange`](https://github.com/clentfort/urql-custom-scalars-exchange): An exchange\n  to automatically convert scalars.\n- [`@grafbase/urql-exchange`](https://github.com/grafbase/playground/tree/main/packages/grafbase-urql-exchange): URQL-exchange for handling Server Sent Events (SSE) with Grafbase GraphQL Live Queries.\n  to automatically convert scalars.\n- [`urql-rest-exchange`](https://github.com/iamsavani/urql-rest-exchange): A custom exchange for URQL that supports GraphQL queries/mutations via REST endpoints\n- [`urql-exhaustive-additional-typenames-exchange`](https://github.com/route06/urql-exhaustive-additional-typenames-exchange): URQL-exchange that add all list fields of the operation to additionalTypenames to help document caching\n"
  },
  {
    "path": "examples/README.md",
    "content": "<table>\n<thead>\n  <tr>\n    <th>Example</th>\n    <th></th>\n    <th></th>\n  </tr>\n</thead>\n<tbody>\n\n<tr>\n  <td>\n    <a href=\"./with-react\"><strong>with-react</strong></a><br />\n  </td>\n  <td>\n    Shows a basic query in <code>urql</code> with React.\n  </td>\n  <td>\n    <a href=\"https://stackblitz.com/github/urql-graphql/urql/tree/main/examples/with-react\">\n      <img\n        alt=\"Open in StackBlitz\"\n        src=\"https://img.shields.io/badge/open_in_stackblitz-1269D3?logo=stackblitz\"\n      />\n    </a>\n    <a href=\"https://codesandbox.io/p/sandbox/github/urql-graphql/urql/tree/main/examples/with-react\">\n      <img\n        alt=\"Open in CodeSandbox\"\n        src=\"https://img.shields.io/badge/open_in_codesandbox-151515?logo=codesandbox\"\n      />\n    </a>\n  </td>\n</tr>\n\n<tr>\n  <td>\n    <a href=\"./with-react-native\"><strong>with-react-native</strong></a><br />\n  </td>\n  <td>\n    Shows a basic query in <code>urql</code> with React Native.\n  </td>\n  <td>\n    <a href=\"https://stackblitz.com/github/urql-graphql/urql/tree/main/examples/with-react-native\">\n      <img\n        alt=\"Open in StackBlitz\"\n        src=\"https://img.shields.io/badge/open_in_stackblitz-1269D3?logo=stackblitz\"\n      />\n    </a>\n    <a href=\"https://codesandbox.io/p/sandbox/github/urql-graphql/urql/tree/main/examples/with-react-native\">\n      <img\n        alt=\"Open in CodeSandbox\"\n        src=\"https://img.shields.io/badge/open_in_codesandbox-151515?logo=codesandbox\"\n      />\n    </a>\n  </td>\n</tr>\n\n<tr>\n  <td>\n    <a href=\"./with-svelte\"><strong>with-svelte</strong></a><br />\n  </td>\n  <td>\n    Shows a basic query in <code>@urql/svelte</code> with Svelte.\n  </td>\n  <td>\n    <a href=\"https://stackblitz.com/github/urql-graphql/urql/tree/main/examples/with-svelte\">\n      <img\n        alt=\"Open in StackBlitz\"\n        src=\"https://img.shields.io/badge/open_in_stackblitz-1269D3?logo=stackblitz\"\n      />\n    </a>\n    <a\n    href=\"https://codesandbox.io/p/sandbox/github/urql-graphql/urql/tree/main/examples/with-svelte\">\n      <img\n        alt=\"Open in CodeSandbox\"\n        src=\"https://img.shields.io/badge/open_in_codesandbox-151515?logo=codesandbox\"\n      />\n    </a>\n  </td>\n</tr>\n\n<tr>\n  <td>\n    <a href=\"./with-vue3\"><strong>with-vue3</strong></a><br />\n  </td>\n  <td>\n    Shows a basic query in <code>@urql/vue</code> with Vue 3.\n  </td>\n  <td>\n    <a href=\"https://stackblitz.com/github/urql-graphql/urql/tree/main/examples/with-vue3\">\n      <img\n        alt=\"Open in StackBlitz\"\n        src=\"https://img.shields.io/badge/open_in_stackblitz-1269D3?logo=stackblitz\"\n      />\n    </a>\n    <a href=\"https://codesandbox.io/p/sandbox/github/urql-graphql/urql/tree/main/examples/with-vue3\">\n      <img\n        alt=\"Open in CodeSandbox\"\n        src=\"https://img.shields.io/badge/open_in_codesandbox-151515?logo=codesandbox\"\n      />\n    </a>\n  </td>\n</tr>\n\n<tr>\n  <td>\n    <a href=\"./with-next\"><strong>with-next</strong></a><br />\n  </td>\n  <td>\n    Shows a basic query in <code>next-urql</code> with Next.js.\n  </td>\n  <td>\n    <a href=\"https://stackblitz.com/github/urql-graphql/urql/tree/main/examples/with-next\">\n      <img\n        alt=\"Open in StackBlitz\"\n        src=\"https://img.shields.io/badge/open_in_stackblitz-1269D3?logo=stackblitz\"\n      />\n    </a>\n    <a href=\"https://codesandbox.io/p/sandbox/github/urql-graphql/urql/tree/main/examples/with-next\">\n      <img\n        alt=\"Open in CodeSandbox\"\n        src=\"https://img.shields.io/badge/open_in_codesandbox-151515?logo=codesandbox\"\n      />\n    </a>\n  </td>\n</tr>\n\n<tr>\n  <td>\n    <a href=\"./with-pagination\"><strong>with-pagination</strong></a><br />\n  </td>\n  <td>\n    Shows how to generically set up pagination with <code>urql</code> in UI code.\n  </td>\n  <td>\n    <a href=\"https://stackblitz.com/github/urql-graphql/urql/tree/main/examples/with-pagination\">\n      <img\n        alt=\"Open in StackBlitz\"\n        src=\"https://img.shields.io/badge/open_in_stackblitz-1269D3?logo=stackblitz\"\n      />\n    </a>\n    <a\n    href=\"https://codesandbox.io/p/sandbox/github/urql-graphql/urql/tree/main/examples/with-pagination\">\n      <img\n        alt=\"Open in CodeSandbox\"\n        src=\"https://img.shields.io/badge/open_in_codesandbox-151515?logo=codesandbox\"\n      />\n    </a>\n  </td>\n</tr>\n\n<tr>\n  <td>\n    <a href=\"./with-infinite-pagination\"><strong>with-infinite-pagination</strong></a><br />\n  </td>\n  <td>\n    Shows how to generically set up infinite scrolling pagination with <code>urql</code> in UI code.\n  </td>\n  <td>\n    <a href=\"https://stackblitz.com/github/urql-graphql/urql/tree/main/examples/with-infinite-pagination\">\n      <img\n        alt=\"Open in StackBlitz\"\n        src=\"https://img.shields.io/badge/open_in_stackblitz-1269D3?logo=stackblitz\"\n      />\n    </a>\n    <a\n    href=\"https://codesandbox.io/p/sandbox/github/urql-graphql/urql/tree/main/examples/with-infinite-pagination\">\n      <img\n        alt=\"Open in CodeSandbox\"\n        src=\"https://img.shields.io/badge/open_in_codesandbox-151515?logo=codesandbox\"\n      />\n    </a>\n  </td>\n</tr>\n\n<tr>\n  <td>\n    <a href=\"./with-apq\"><strong>with-apq</strong></a><br />\n  </td>\n  <td>\n    Shows Automatic Persisted Queries with <code>@urql/exchange-persisted</code>.\n  </td>\n  <td>\n    <a href=\"https://stackblitz.com/github/urql-graphql/urql/tree/main/examples/with-apq\">\n      <img\n        alt=\"Open in StackBlitz\"\n        src=\"https://img.shields.io/badge/open_in_stackblitz-1269D3?logo=stackblitz\"\n      />\n    </a>\n    <a\n    href=\"https://codesandbox.io/p/sandbox/github/urql-graphql/urql/tree/main/examples/with-apq\">\n      <img\n        alt=\"Open in CodeSandbox\"\n        src=\"https://img.shields.io/badge/open_in_codesandbox-151515?logo=codesandbox\"\n      />\n    </a>\n  </td>\n</tr>\n\n<tr>\n  <td>\n    <a href=\"./with-graphcache-updates\"><strong>with-graphcache-updates</strong></a><br />\n  </td>\n  <td>\n    Shows manual cache updates with <code>@urql/exchange-graphcache</code>.\n  </td>\n  <td>\n    <a href=\"https://stackblitz.com/github/urql-graphql/urql/tree/main/examples/with-graphcache-updates\">\n      <img\n        alt=\"Open in StackBlitz\"\n        src=\"https://img.shields.io/badge/open_in_stackblitz-1269D3?logo=stackblitz\"\n      />\n    </a>\n    <a href=\"https://codesandbox.io/p/sandbox/github/urql-graphql/urql/tree/main/examples/with-graphcache-updates\">\n      <img\n        alt=\"Open in CodeSandbox\"\n        src=\"https://img.shields.io/badge/open_in_codesandbox-151515?logo=codesandbox\"\n      />\n    </a>\n  </td>\n</tr>\n\n<tr>\n  <td>\n    <a href=\"./with-graphcache-pagination\"><strong>with-graphcache-pagination</strong></a><br />\n  </td>\n  <td>\n    Shows the automatic infinite pagination helpers from <code>@urql/exchange-graphcache</code>.\n  </td>\n  <td>\n    <a\n    href=\"https://stackblitz.com/github/urql-graphql/urql/tree/main/examples/with-graphcache-pagination\">\n      <img\n        alt=\"Open in StackBlitz\"\n        src=\"https://img.shields.io/badge/open_in_stackblitz-1269D3?logo=stackblitz\"\n      />\n    </a>\n    <a href=\"https://codesandbox.io/p/sandbox/github/urql-graphql/urql/tree/main/examples/with-graphcache-pagination\">\n      <img\n        alt=\"Open in CodeSandbox\"\n        src=\"https://img.shields.io/badge/open_in_codesandbox-151515?logo=codesandbox\"\n      />\n    </a>\n  </td>\n</tr>\n\n<tr>\n  <td>\n    <a href=\"./with-multipart\"><strong>with-multipart</strong></a><br />\n  </td>\n  <td>\n    Shows file upload support integrated in <code>@urql/core</code>.\n  </td>\n  <td>\n    <a href=\"https://stackblitz.com/github/urql-graphql/urql/tree/main/examples/with-multipart\">\n      <img\n        alt=\"Open in StackBlitz\"\n        src=\"https://img.shields.io/badge/open_in_stackblitz-1269D3?logo=stackblitz\"\n      />\n    </a>\n    <a href=\"https://codesandbox.io/p/sandbox/github/urql-graphql/urql/tree/main/examples/with-multipart\">\n      <img\n        alt=\"Open in CodeSandbox\"\n        src=\"https://img.shields.io/badge/open_in_codesandbox-151515?logo=codesandbox\"\n      />\n    </a>\n  </td>\n</tr>\n\n<tr>\n  <td>\n    <a href=\"./with-refresh-auth\"><strong>with-refresh-auth</strong></a><br />\n  </td>\n  <td>\n    Shows authentication with refresh tokens using <code>@urql/exchange-auth</code>.\n  </td>\n  <td>\n    <a href=\"https://stackblitz.com/github/urql-graphql/urql/tree/main/examples/with-refresh-auth\">\n      <img\n        alt=\"Open in StackBlitz\"\n        src=\"https://img.shields.io/badge/open_in_stackblitz-1269D3?logo=stackblitz\"\n      />\n    </a>\n    <a href=\"https://codesandbox.io/p/sandbox/github/urql-graphql/urql/tree/main/examples/with-refresh-auth\">\n      <img\n        alt=\"Open in CodeSandbox\"\n        src=\"https://img.shields.io/badge/open_in_codesandbox-151515?logo=codesandbox\"\n      />\n    </a>\n  </td>\n</tr>\n\n<tr>\n  <td>\n    <a href=\"./with-retry\"><strong>with-retry</strong></a><br />\n  </td>\n  <td>\n    Shows retrying of failed operations with <code>@urql/exchange-retry</code>.\n  </td>\n  <td>\n    <a href=\"https://stackblitz.com/github/urql-graphql/urql/tree/main/examples/with-retry\">\n      <img\n        alt=\"Open in StackBlitz\"\n        src=\"https://img.shields.io/badge/open_in_stackblitz-1269D3?logo=stackblitz\"\n      />\n    </a>\n    <a href=\"https://codesandbox.io/p/sandbox/github/urql-graphql/urql/tree/main/examples/with-retry\">\n      <img\n        alt=\"Open in CodeSandbox\"\n        src=\"https://img.shields.io/badge/open_in_codesandbox-151515?logo=codesandbox\"\n      />\n    </a>\n  </td>\n</tr>\n\n<tr>\n  <td>\n    <a href=\"./with-defer-stream-directives\"><strong>with-defer-stream-directives</strong></a><br />\n  </td>\n  <td>\n    Demonstrates <code>urql</code> and <code>@urql/exchange-graphcache</code> with built-in support for <code>@defer</code> and <code>@stream</code>.\n  </td>\n  <td>\n    <a\n    href=\"https://stackblitz.com/github/urql-graphql/urql/tree/main/examples/with-defer-stream-directives\">\n      <img\n        alt=\"Open in StackBlitz\"\n        src=\"https://img.shields.io/badge/open_in_stackblitz-1269D3?logo=stackblitz\"\n      />\n    </a>\n    <a\n    href=\"https://codesandbox.io/p/sandbox/github/urql-graphql/urql/tree/main/examples/with-defer-stream-directives\">\n      <img\n        alt=\"Open in CodeSandbox\"\n        src=\"https://img.shields.io/badge/open_in_codesandbox-151515?logo=codesandbox\"\n      />\n    </a>\n  </td>\n</tr>\n\n<tr>\n  <td>\n    <a href=\"./with-subscriptions-via-fetch\"><strong>with-subscriptions-via-fetch</strong></a><br />\n  </td>\n  <td>\n    Demonstrates <code>@urql/core</code>'s built-in support for executing subscriptions with a GraphQL Yoga API via the <code>fetchExchange</code>.\n  </td>\n  <td>\n    <a\n    href=\"https://stackblitz.com/github/urql-graphql/urql/tree/main/examples/with-subscriptions-via-fetch\">\n      <img\n        alt=\"Open in StackBlitz\"\n        src=\"https://img.shields.io/badge/open_in_stackblitz-1269D3?logo=stackblitz\"\n      />\n    </a>\n    <a\n    href=\"https://codesandbox.io/p/sandbox/github/urql-graphql/urql/tree/main/examples/with-subscriptions-via-fetch\">\n      <img\n        alt=\"Open in CodeSandbox\"\n        src=\"https://img.shields.io/badge/open_in_codesandbox-151515?logo=codesandbox\"\n      />\n    </a>\n  </td>\n</tr>\n\n</tbody>\n</table>\n"
  },
  {
    "path": "examples/pnpm-workspace.yaml",
    "content": "packages:\n  - '*'\n"
  },
  {
    "path": "examples/with-apq/README.md",
    "content": "# With Automatic Persisted Queries\n\n<p>\n  <a href=\"https://stackblitz.com/github/urql-graphql/urql/tree/main/examples/with-apq\">\n    <img\n      alt=\"Open in StackBlitz\"\n      src=\"https://img.shields.io/badge/open_in_stackblitz-1269D3?logo=stackblitz&style=for-the-badge\"\n    />\n  </a>\n  <a href=\"https://codesandbox.io/p/sandbox/github/urql-graphql/urql/tree/main/examples/with-apq\">\n    <img\n      alt=\"Open in CodeSandbox\"\n      src=\"https://img.shields.io/badge/open_in_codesandbox-151515?logo=codesandbox&style=for-the-badge\"\n    />\n  </a>\n</p>\n\nThis example shows `urql` in use with `@urql/exchange-persisted-fetch`'s `persistedFetchExchange`\nto support [Automatic Persisted\nQueries](https://www.apollographql.com/docs/apollo-server/performance/apq/). This largely follows\nthe [\"Persisted Queries\" docs\npage](https://formidable.com/open-source/urql/docs/advanced/persistence-and-uploads/#automatic-persisted-queries)\nand uses the [`trygql.formidable.dev/graphql/apq-weather` schema](https://github.com/FormidableLabs/trygql).\n\nTo run this example install dependencies and run the `start` script:\n\n```sh\nyarn install\nyarn run start\n# or\nnpm install\nnpm run start\n```\n\nThis example contains:\n\n- The `urql` bindings and a React app with a client set up in [`src/App.jsx`](src/App.jsx)\n- The `persistedFetchExchange` from `@urql/exchange-persisted-fetch` in [`src/App.jsx`](src/App.jsx)\n- A query for locations in [`src/LocationsList.jsx`](src/pages/LocationsList.jsx)\n"
  },
  {
    "path": "examples/with-apq/index.html",
    "content": "<!doctype html>\n<html lang=\"en\">\n  <head>\n    <meta charset=\"UTF-8\" />\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\" />\n    <title>with-apq</title>\n    <style>\n      body {\n        margin: 0;\n        font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto',\n          'Oxygen', 'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans',\n          'Helvetica Neue', sans-serif;\n        -webkit-font-smoothing: antialiased;\n        -moz-osx-font-smoothing: grayscale;\n      }\n\n      code {\n        font-family: source-code-pro, Menlo, Monaco, Consolas, 'Courier New',\n          monospace;\n      }\n    </style>\n  </head>\n  <body>\n    <div id=\"root\"></div>\n    <script type=\"module\" src=\"/src/index.jsx\"></script>\n  </body>\n</html>\n"
  },
  {
    "path": "examples/with-apq/package.json",
    "content": "{\n  \"name\": \"with-apq\",\n  \"version\": \"0.0.0\",\n  \"private\": true,\n  \"scripts\": {\n    \"start\": \"vite\"\n  },\n  \"dependencies\": {\n    \"@urql/core\": \"^6.0.1\",\n    \"@urql/exchange-persisted\": \"^5.0.1\",\n    \"graphql\": \"^16.6.0\",\n    \"react\": \"^18.2.0\",\n    \"react-dom\": \"^18.2.0\",\n    \"urql\": \"^5.0.1\"\n  },\n  \"devDependencies\": {\n    \"@vitejs/plugin-react\": \"^3.1.0\",\n    \"vite\": \"^4.2.0\"\n  }\n}\n"
  },
  {
    "path": "examples/with-apq/src/App.jsx",
    "content": "import React from 'react';\nimport { Client, Provider, fetchExchange } from 'urql';\nimport { persistedExchange } from '@urql/exchange-persisted';\n\nimport LocationsList from './LocationsList';\n\nconst client = new Client({\n  url: 'https://trygql.formidable.dev/graphql/apq-weather',\n  exchanges: [\n    persistedExchange({\n      preferGetForPersistedQueries: true,\n    }),\n    fetchExchange,\n  ],\n});\n\nfunction App() {\n  return (\n    <Provider value={client}>\n      <LocationsList />\n    </Provider>\n  );\n}\n\nexport default App;\n"
  },
  {
    "path": "examples/with-apq/src/LocationsList.jsx",
    "content": "import React from 'react';\nimport { gql, useQuery } from 'urql';\n\nconst LOCATIONS_QUERY = gql`\n  query Locations($query: String!) {\n    locations(query: $query) {\n      id\n      name\n    }\n  }\n`;\n\nconst LocationsList = () => {\n  const [result] = useQuery({\n    query: LOCATIONS_QUERY,\n    variables: { query: 'LON' },\n  });\n\n  const { data, fetching, error } = result;\n\n  return (\n    <div>\n      {fetching && <p>Loading...</p>}\n\n      {error && <p>Oh no... {error.message}</p>}\n\n      {data && (\n        <ul>\n          {data.locations.map(location => (\n            <li key={location.id}>{location.name}</li>\n          ))}\n        </ul>\n      )}\n    </div>\n  );\n};\n\nexport default LocationsList;\n"
  },
  {
    "path": "examples/with-apq/src/index.jsx",
    "content": "import React from 'react';\nimport { createRoot } from 'react-dom/client';\n\nimport App from './App';\n\ncreateRoot(document.getElementById('root')).render(<App />);\n"
  },
  {
    "path": "examples/with-apq/vite.config.js",
    "content": "import { defineConfig } from 'vite';\nimport react from '@vitejs/plugin-react';\n\n// https://vitejs.dev/config/\nexport default defineConfig({\n  plugins: [react()],\n});\n"
  },
  {
    "path": "examples/with-defer-stream-directives/README.md",
    "content": "# With `@defer` / `@stream` Directives\n\n<p>\n  <a href=\"https://stackblitz.com/github/urql-graphql/urql/tree/main/examples/with-defer-stream-directives\">\n    <img\n      alt=\"Open in StackBlitz\"\n      src=\"https://img.shields.io/badge/open_in_stackblitz-1269D3?logo=stackblitz&style=for-the-badge\"\n    />\n  </a>\n  <a\n  href=\"https://codesandbox.io/p/sandbox/github/urql-graphql/urql/tree/main/examples/with-defer-stream-directives\">\n    <img\n      alt=\"Open in CodeSandbox\"\n      src=\"https://img.shields.io/badge/open_in_codesandbox-151515?logo=codesandbox&style=for-the-badge\"\n    />\n  </a>\n</p>\n\nThis example shows `urql` in use [with `@defer` and `@stream`\ndirectives](https://graphql.org/blog/2020-12-08-improving-latency-with-defer-and-stream-directives)\nin GraphQL.\n\nTo run this example install dependencies and run the `start` script:\n\n```sh\nyarn install\nyarn run start\n# or\nnpm install\nnpm run start\n```\n\nThis example contains:\n\n- The `urql` bindings and a React app with a client set up in [`src/App.jsx`](src/App.jsx)\n- A local `graphql-yoga` server set up to test deferred and streamed results in [`server/`](server/).\n"
  },
  {
    "path": "examples/with-defer-stream-directives/index.html",
    "content": "<!doctype html>\n<html lang=\"en\">\n  <head>\n    <meta charset=\"UTF-8\" />\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\" />\n    <title>with-defer-stream-directives</title>\n    <style>\n      body {\n        margin: 0;\n        font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto',\n          'Oxygen', 'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans',\n          'Helvetica Neue', sans-serif;\n        -webkit-font-smoothing: antialiased;\n        -moz-osx-font-smoothing: grayscale;\n      }\n\n      code {\n        font-family: source-code-pro, Menlo, Monaco, Consolas, 'Courier New',\n          monospace;\n      }\n    </style>\n  </head>\n  <body>\n    <div id=\"root\"></div>\n    <script type=\"module\" src=\"/src/index.jsx\"></script>\n  </body>\n</html>\n"
  },
  {
    "path": "examples/with-defer-stream-directives/package.json",
    "content": "{\n  \"name\": \"with-defer-stream-directives\",\n  \"version\": \"0.0.0\",\n  \"private\": true,\n  \"scripts\": {\n    \"server:apollo\": \"node server/apollo-server.js\",\n    \"server:yoga\": \"node server/graphql-yoga.js\",\n    \"client\": \"vite\",\n    \"start\": \"run-p client server:yoga\"\n  },\n  \"pnpm\": {\n    \"peerDependencyRules\": {\n      \"allowedVersions\": {\n        \"graphql\": \"17\"\n      }\n    }\n  },\n  \"dependencies\": {\n    \"@graphql-yoga/plugin-defer-stream\": \"^1.7.1\",\n    \"@urql/core\": \"^6.0.1\",\n    \"@urql/exchange-graphcache\": \"^9.0.0\",\n    \"graphql\": \"17.0.0-alpha.2\",\n    \"react\": \"^18.2.0\",\n    \"react-dom\": \"^18.2.0\",\n    \"urql\": \"^5.0.1\"\n  },\n  \"devDependencies\": {\n    \"@apollo/server\": \"^4.4.1\",\n    \"@vitejs/plugin-react\": \"^3.1.0\",\n    \"graphql-yoga\": \"^3.7.1\",\n    \"npm-run-all\": \"^4.1.5\",\n    \"vite\": \"^4.2.0\"\n  }\n}\n"
  },
  {
    "path": "examples/with-defer-stream-directives/server/apollo-server.js",
    "content": "// NOTE: This currently fails because responses for @defer/@stream are not sent\n// as multipart responses, but the request fails silently with an empty JSON response payload\n\nconst { ApolloServer } = require('@apollo/server');\nconst { startStandaloneServer } = require('@apollo/server/standalone');\nconst { schema } = require('./schema');\n\nconst server = new ApolloServer({ schema });\n\nstartStandaloneServer(server, {\n  listen: {\n    port: 3004,\n  },\n});\n"
  },
  {
    "path": "examples/with-defer-stream-directives/server/graphql-yoga.js",
    "content": "const { createYoga } = require('graphql-yoga');\nconst { useDeferStream } = require('@graphql-yoga/plugin-defer-stream');\nconst { createServer } = require('http');\nconst { schema } = require('./schema');\n\nconst yoga = createYoga({\n  schema,\n  plugins: [useDeferStream()],\n});\n\nconst server = createServer(yoga);\n\nserver.listen(3004);\n"
  },
  {
    "path": "examples/with-defer-stream-directives/server/schema.js",
    "content": "const {\n  GraphQLList,\n  GraphQLObjectType,\n  GraphQLSchema,\n  GraphQLString,\n} = require('graphql');\n\nconst schema = new GraphQLSchema({\n  query: new GraphQLObjectType({\n    name: 'Query',\n    fields: () => ({\n      alphabet: {\n        type: new GraphQLList(\n          new GraphQLObjectType({\n            name: 'Alphabet',\n            fields: {\n              char: {\n                type: GraphQLString,\n              },\n            },\n          })\n        ),\n        resolve: async function* () {\n          for (let letter = 65; letter <= 90; letter++) {\n            await new Promise(resolve => setTimeout(resolve, 500));\n            yield { char: String.fromCharCode(letter) };\n          }\n        },\n      },\n      song: {\n        type: new GraphQLObjectType({\n          name: 'Song',\n          fields: () => ({\n            firstVerse: {\n              type: GraphQLString,\n              resolve: () => \"Now I know my ABC's.\",\n            },\n            secondVerse: {\n              type: GraphQLString,\n              resolve: () =>\n                new Promise(resolve =>\n                  setTimeout(\n                    () => resolve(\"Next time won't you sing with me?\"),\n                    5000\n                  )\n                ),\n            },\n          }),\n        }),\n        resolve: () =>\n          new Promise(resolve => setTimeout(() => resolve('goodbye'), 1000)),\n      },\n    }),\n  }),\n});\n\nmodule.exports = { schema };\n"
  },
  {
    "path": "examples/with-defer-stream-directives/src/App.jsx",
    "content": "import React from 'react';\nimport { Client, Provider, fetchExchange } from 'urql';\n\nimport { cacheExchange } from '@urql/exchange-graphcache';\n\nimport Songs from './Songs';\n\nconst cache = cacheExchange({\n  keys: {\n    Alphabet: data => data.char,\n    Song: () => null,\n  },\n});\n\nconst client = new Client({\n  url: 'http://localhost:3004/graphql',\n  exchanges: [cache, fetchExchange],\n});\n\nfunction App() {\n  return (\n    <Provider value={client}>\n      <Songs />\n    </Provider>\n  );\n}\n\nexport default App;\n"
  },
  {
    "path": "examples/with-defer-stream-directives/src/Songs.jsx",
    "content": "import React from 'react';\nimport { gql, useQuery } from 'urql';\n\nconst SecondVerseFragment = gql`\n  fragment secondVerseFields on Song {\n    secondVerse\n  }\n`;\n\nconst SONGS_QUERY = gql`\n  query App_Query {\n    song {\n      firstVerse\n      ...secondVerseFields @defer\n    }\n    alphabet @stream(initialCount: 3) {\n      char\n    }\n  }\n\n  ${SecondVerseFragment}\n`;\n\nconst Song = React.memo(function Song({ song }) {\n  return (\n    <section>\n      <p>{song.firstVerse}</p>\n      <p>{song.secondVerse}</p>\n    </section>\n  );\n});\n\nconst LocationsList = () => {\n  const [result] = useQuery({\n    query: SONGS_QUERY,\n  });\n\n  const { data } = result;\n\n  return (\n    <div>\n      {data && (\n        <>\n          <Song song={data.song} />\n          {data.alphabet.map(i => (\n            <div key={i.char}>{i.char}</div>\n          ))}\n        </>\n      )}\n    </div>\n  );\n};\n\nexport default LocationsList;\n"
  },
  {
    "path": "examples/with-defer-stream-directives/src/index.jsx",
    "content": "import React from 'react';\nimport { createRoot } from 'react-dom/client';\n\nimport App from './App';\n\ncreateRoot(document.getElementById('root')).render(<App />);\n"
  },
  {
    "path": "examples/with-defer-stream-directives/vite.config.js",
    "content": "import { defineConfig } from 'vite';\nimport react from '@vitejs/plugin-react';\n\n// https://vitejs.dev/config/\nexport default defineConfig({\n  plugins: [react()],\n});\n"
  },
  {
    "path": "examples/with-graphcache-pagination/README.md",
    "content": "# With Graphcache's Pagination\n\n<p>\n  <a\n  href=\"https://stackblitz.com/github/urql-graphql/urql/tree/main/examples/with-graphcache-pagination\">\n    <img\n      alt=\"Open in StackBlitz\"\n      src=\"https://img.shields.io/badge/open_in_stackblitz-1269D3?logo=stackblitz&style=for-the-badge\"\n    />\n  </a>\n  <a\n  href=\"https://codesandbox.io/p/sandbox/github/urql-graphql/urql/tree/main/examples/with-graphcache-pagination\">\n    <img\n      alt=\"Open in CodeSandbox\"\n      src=\"https://img.shields.io/badge/open_in_codesandbox-151515?logo=codesandbox&style=for-the-badge\"\n    />\n  </a>\n</p>\n\nThis example shows `urql` in use with `@urql/exchange-graphcache`'s infinite pagination helpers to\nmerge several pages of a Relay-compliant schema into an infinite list.\nThis largely follows the [\"Pagination\" section on the \"Local Resolvers\" docs\npage](https://formidable.com/open-source/urql/docs/graphcache/local-resolvers/#pagination)\nand uses the [`trygql.formidable.dev/graphql/relay-npm` schema](https://github.com/FormidableLabs/trygql).\n\nTo run this example install dependencies and run the `start` script:\n\n```sh\nyarn install\nyarn run start\n# or\nnpm install\nnpm run start\n```\n\nThis example contains:\n\n- The `urql` bindings and a React app with a client set up in [`src/App.js`](src/App.js)\n- The `cacheExchange` from `@urql/exchange-graphcache` in [`src/App.js`](src/App.js)\n- A paginated query for packages in [`src/pages/PaginatedNpmSearch.js`](src/pages/PaginatedNpmSearch.js)\n"
  },
  {
    "path": "examples/with-graphcache-pagination/index.html",
    "content": "<!doctype html>\n<html lang=\"en\">\n  <head>\n    <meta charset=\"UTF-8\" />\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\" />\n    <title>with-graphcache-pagination</title>\n    <style>\n      body {\n        margin: 0;\n        font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto',\n          'Oxygen', 'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans',\n          'Helvetica Neue', sans-serif;\n        -webkit-font-smoothing: antialiased;\n        -moz-osx-font-smoothing: grayscale;\n      }\n\n      code {\n        font-family: source-code-pro, Menlo, Monaco, Consolas, 'Courier New',\n          monospace;\n      }\n    </style>\n  </head>\n  <body>\n    <div id=\"root\"></div>\n    <script type=\"module\" src=\"/src/index.jsx\"></script>\n  </body>\n</html>\n"
  },
  {
    "path": "examples/with-graphcache-pagination/package.json",
    "content": "{\n  \"name\": \"with-graphcache-pagination\",\n  \"version\": \"0.0.0\",\n  \"private\": true,\n  \"scripts\": {\n    \"start\": \"vite\"\n  },\n  \"dependencies\": {\n    \"@urql/core\": \"^6.0.1\",\n    \"@urql/exchange-graphcache\": \"^9.0.0\",\n    \"graphql\": \"^16.6.0\",\n    \"react\": \"^18.2.0\",\n    \"react-dom\": \"^18.2.0\",\n    \"urql\": \"^5.0.1\"\n  },\n  \"devDependencies\": {\n    \"@vitejs/plugin-react\": \"^3.1.0\",\n    \"vite\": \"^4.2.0\"\n  }\n}\n"
  },
  {
    "path": "examples/with-graphcache-pagination/src/App.jsx",
    "content": "import React from 'react';\nimport { Client, Provider, fetchExchange } from 'urql';\nimport { cacheExchange } from '@urql/exchange-graphcache';\nimport { relayPagination } from '@urql/exchange-graphcache/extras';\n\nimport PaginatedNpmSearch from './PaginatedNpmSearch';\n\nconst client = new Client({\n  url: 'https://trygql.formidable.dev/graphql/relay-npm',\n  exchanges: [\n    cacheExchange({\n      resolvers: {\n        Query: {\n          search: relayPagination(),\n        },\n      },\n    }),\n    fetchExchange,\n  ],\n});\n\nfunction App() {\n  return (\n    <Provider value={client}>\n      <PaginatedNpmSearch />\n    </Provider>\n  );\n}\n\nexport default App;\n"
  },
  {
    "path": "examples/with-graphcache-pagination/src/PaginatedNpmSearch.jsx",
    "content": "import React, { useState } from 'react';\nimport { gql, useQuery } from 'urql';\n\nconst limit = 5;\nconst query = 'graphql';\n\nconst NPM_SEARCH = gql`\n  query Search($query: String!, $first: Int!, $after: String) {\n    search(query: $query, first: $first, after: $after) {\n      edges {\n        node {\n          id\n          name\n        }\n      }\n      pageInfo {\n        hasNextPage\n        endCursor\n      }\n    }\n  }\n`;\n\nconst PaginatedNpmSearch = () => {\n  const [after, setAfter] = useState('');\n\n  const [result] = useQuery({\n    query: NPM_SEARCH,\n    variables: { query, first: limit, after },\n  });\n\n  const { data, fetching, error } = result;\n\n  const searchResults = data?.search;\n\n  return (\n    <div>\n      {error && <p>Oh no... {error.message}</p>}\n\n      {fetching && <p>Loading...</p>}\n\n      {searchResults && (\n        <>\n          {searchResults.edges.map(({ node }) => (\n            <div key={node.id}>\n              {node.id}: {node.name}\n            </div>\n          ))}\n\n          {searchResults.pageInfo.hasNextPage && (\n            <button onClick={() => setAfter(searchResults.pageInfo.endCursor)}>\n              load more\n            </button>\n          )}\n        </>\n      )}\n    </div>\n  );\n};\n\nexport default PaginatedNpmSearch;\n"
  },
  {
    "path": "examples/with-graphcache-pagination/src/index.jsx",
    "content": "import React from 'react';\nimport { createRoot } from 'react-dom/client';\n\nimport App from './App';\n\ncreateRoot(document.getElementById('root')).render(<App />);\n"
  },
  {
    "path": "examples/with-graphcache-pagination/vite.config.js",
    "content": "import { defineConfig } from 'vite';\nimport react from '@vitejs/plugin-react';\n\n// https://vitejs.dev/config/\nexport default defineConfig({\n  plugins: [react()],\n});\n"
  },
  {
    "path": "examples/with-graphcache-updates/README.md",
    "content": "# With Graphcache's Pagination\n\n<p>\n  <a\n  href=\"https://stackblitz.com/github/urql-graphql/urql/tree/main/examples/with-graphcache-updates\">\n    <img\n      alt=\"Open in StackBlitz\"\n      src=\"https://img.shields.io/badge/open_in_stackblitz-1269D3?logo=stackblitz&style=for-the-badge\"\n    />\n  </a>\n  <a\n  href=\"https://codesandbox.io/p/sandbox/github/urql-graphql/urql/tree/main/examples/with-graphcache-updates\">\n    <img\n      alt=\"Open in CodeSandbox\"\n      src=\"https://img.shields.io/badge/open_in_codesandbox-151515?logo=codesandbox&style=for-the-badge\"\n    />\n  </a>\n</p>\n\nThis example shows `urql` in use with `@urql/exchange-graphcache` and demonstrates a manual cache\nupdate, as explained in [the \"Cache Updates\" docs page](https://formidable.com/open-source/urql/docs/graphcache/cache-updates/).\nThis example uses the [`trygql.formidable.dev/graphql/web-collections`\nschema](https://github.com/FormidableLabs/trygql) and builds on top of the [`with-refresh-auth`\nexample](../with-refresh-auth) so that we can authenticate with the schema before creating links on\nit.\n\nTo run this example install dependencies and run the `start` script:\n\n```sh\nyarn install\nyarn run start\n# or\nnpm install\nnpm run start\n```\n\nThis example contains:\n\n- The `urql` bindings and a React app with a client set up in [`src/client.js`](src/client.js)\n- The `cacheExchange` from `@urql/exchange-graphcache` in [`src/client.js`](src/client.js)\n- A links list and link creation in [`src/pages/Links.jsx`](src/pages/Links.jsx)\n"
  },
  {
    "path": "examples/with-graphcache-updates/index.html",
    "content": "<!doctype html>\n<html lang=\"en\">\n  <head>\n    <meta charset=\"UTF-8\" />\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\" />\n    <title>with-graphcache-updates</title>\n    <style>\n      body {\n        margin: 0;\n        font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto',\n          'Oxygen', 'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans',\n          'Helvetica Neue', sans-serif;\n        -webkit-font-smoothing: antialiased;\n        -moz-osx-font-smoothing: grayscale;\n      }\n\n      code {\n        font-family: source-code-pro, Menlo, Monaco, Consolas, 'Courier New',\n          monospace;\n      }\n    </style>\n  </head>\n  <body>\n    <div id=\"root\"></div>\n    <script type=\"module\" src=\"/src/index.jsx\"></script>\n  </body>\n</html>\n"
  },
  {
    "path": "examples/with-graphcache-updates/package.json",
    "content": "{\n  \"name\": \"with-graphcache-updates\",\n  \"version\": \"0.0.0\",\n  \"private\": true,\n  \"scripts\": {\n    \"start\": \"vite\"\n  },\n  \"dependencies\": {\n    \"@urql/core\": \"^6.0.1\",\n    \"@urql/exchange-auth\": \"^3.0.0\",\n    \"@urql/exchange-graphcache\": \"^9.0.0\",\n    \"graphql\": \"^16.6.0\",\n    \"react\": \"^18.2.0\",\n    \"react-dom\": \"^18.2.0\",\n    \"urql\": \"^5.0.1\"\n  },\n  \"devDependencies\": {\n    \"@vitejs/plugin-react\": \"^3.1.0\",\n    \"vite\": \"^4.2.0\"\n  }\n}\n"
  },
  {
    "path": "examples/with-graphcache-updates/src/App.jsx",
    "content": "import React, { useState, useEffect } from 'react';\nimport { Provider } from 'urql';\n\nimport client from './client';\nimport Links from './pages/Links';\nimport LoginForm from './pages/LoginForm';\n\nconst Home = () => {\n  const [isLoggedIn, setIsLoggedIn] = useState(false);\n\n  const onLoginSuccess = auth => {\n    localStorage.setItem('authToken', auth.token);\n    setIsLoggedIn(true);\n  };\n\n  useEffect(() => {\n    if (localStorage.getItem('authToken')) {\n      setIsLoggedIn(true);\n    }\n  }, []);\n\n  return isLoggedIn ? <Links /> : <LoginForm onLoginSuccess={onLoginSuccess} />;\n};\n\nfunction App() {\n  return (\n    <Provider value={client}>\n      <Home />\n    </Provider>\n  );\n}\n\nexport default App;\n"
  },
  {
    "path": "examples/with-graphcache-updates/src/client.js",
    "content": "import { Client, fetchExchange, gql } from 'urql';\nimport { authExchange } from '@urql/exchange-auth';\nimport { cacheExchange } from '@urql/exchange-graphcache';\n\nconst cache = cacheExchange({\n  updates: {\n    Mutation: {\n      createLink(result, _args, cache, _info) {\n        const LinksList = gql`\n          query Links($first: Int!) {\n            links(first: $first) {\n              nodes {\n                id\n              }\n            }\n          }\n        `;\n\n        const linksPages = cache\n          .inspectFields('Query')\n          .filter(field => field.fieldName === 'links');\n\n        if (linksPages.length > 0) {\n          const lastField = linksPages[linksPages.length - 1];\n\n          cache.updateQuery(\n            {\n              query: LinksList,\n              variables: { first: lastField.arguments.first },\n            },\n            data => {\n              return {\n                ...data,\n                links: {\n                  ...data.links,\n                  nodes: [...data.links.nodes, result.createLink.node],\n                },\n              };\n            }\n          );\n        }\n      },\n    },\n  },\n});\n\nconst auth = authExchange(async utilities => {\n  let token = localStorage.getItem('authToken');\n\n  return {\n    addAuthToOperation(operation) {\n      if (!token) return operation;\n      return token\n        ? utilities.appendHeaders(operation, {\n            Authorization: `Bearer ${token}`,\n          })\n        : operation;\n    },\n    didAuthError(error) {\n      return error.graphQLErrors.some(\n        e => e.extensions?.code === 'UNAUTHORIZED'\n      );\n    },\n    willAuthError(operation) {\n      if (!token) {\n        // Detect our login mutation and let this operation through:\n        return (\n          operation.kind !== 'mutation' ||\n          // Here we find any mutation definition with the \"signin\" field\n          !operation.query.definitions.some(definition => {\n            return (\n              definition.kind === 'OperationDefinition' &&\n              definition.selectionSet.selections.some(node => {\n                // The field name is just an example, since register may also be an exception\n                return node.kind === 'Field' && node.name.value === 'signin';\n              })\n            );\n          })\n        );\n      }\n      return false;\n    },\n    async refreshAuth() {\n      token = localStorage.getItem('authToken');\n      if (!token) {\n        // This is where auth has gone wrong and we need to clean up and redirect to a login page\n        localStorage.clear();\n        window.location.reload();\n      }\n    },\n  };\n});\n\nconst client = new Client({\n  url: 'https://trygql.formidable.dev/graphql/web-collections',\n  exchanges: [cache, auth, fetchExchange],\n});\n\nexport default client;\n"
  },
  {
    "path": "examples/with-graphcache-updates/src/index.jsx",
    "content": "import React from 'react';\nimport { createRoot } from 'react-dom/client';\n\nimport App from './App';\n\ncreateRoot(document.getElementById('root')).render(<App />);\n"
  },
  {
    "path": "examples/with-graphcache-updates/src/pages/Links.jsx",
    "content": "import React from 'react';\nimport { gql, useQuery, useMutation } from 'urql';\n\nconst LINKS_QUERY = gql`\n  query Links($first: Int!) {\n    links(first: $first) {\n      nodes {\n        id\n        title\n        canonicalUrl\n      }\n    }\n  }\n`;\n\nconst CREATE_LINK_MUTATION = gql`\n  mutation CreateLink($url: URL!) {\n    createLink(url: $url) {\n      node {\n        id\n        title\n        canonicalUrl\n      }\n    }\n  }\n`;\n\nconst Links = () => {\n  const [linksResult] = useQuery({\n    query: LINKS_QUERY,\n    variables: { first: 10 },\n  });\n  const [createResult, createLink] = useMutation(CREATE_LINK_MUTATION);\n\n  const onSubmitLink = event => {\n    event.preventDefault();\n    const { target } = event;\n    createLink({ url: new FormData(target).get('link') }).then(() =>\n      target.reset()\n    );\n  };\n\n  return (\n    <div>\n      {linksResult.error && <p>Oh no... {linksResult.error.message}</p>}\n\n      {linksResult.data && (\n        <ul>\n          {linksResult.data.links.nodes.map(link => (\n            <li key={link.id}>\n              <a rel=\"noreferrer\" href={link.canonicalUrl}>\n                {link.title}\n              </a>\n            </li>\n          ))}\n        </ul>\n      )}\n\n      <form onSubmit={onSubmitLink}>\n        {createResult.fetching ? <p>Submitting...</p> : null}\n        {createResult.error ? (\n          <p>Oh no... {createResult.error.message}</p>\n        ) : null}\n\n        <fieldset disabled={createResult.fetching ? 'disabled' : null}>\n          <label>\n            {'Link to Blog Post: '}\n            <input type=\"url\" name=\"link\" placeholder=\"https://...\" />\n          </label>\n          <button type=\"submit\">Add Link</button>\n        </fieldset>\n      </form>\n    </div>\n  );\n};\n\nexport default Links;\n"
  },
  {
    "path": "examples/with-graphcache-updates/src/pages/LoginForm.jsx",
    "content": "import React from 'react';\nimport { gql, useMutation } from 'urql';\n\nconst LOGIN_MUTATION = gql`\n  mutation Login($input: LoginInput!) {\n    signin(input: $input) {\n      refreshToken\n      token\n    }\n  }\n`;\n\nconst REGISTER_MUTATION = gql`\n  mutation Register($input: LoginInput!) {\n    register(input: $input) {\n      refreshToken\n      token\n    }\n  }\n`;\n\nconst LoginForm = ({ onLoginSuccess }) => {\n  const [loginResult, login] = useMutation(LOGIN_MUTATION);\n  const [registerResult, register] = useMutation(REGISTER_MUTATION);\n\n  const onSubmitLogin = event => {\n    event.preventDefault();\n    const data = new FormData(event.target);\n    const username = data.get('username');\n    const password = data.get('password');\n\n    login({ input: { username, password } }).then(result => {\n      if (!result.error && result.data && result.data.signin) {\n        onLoginSuccess(result.data.signin);\n      }\n    });\n  };\n\n  const onSubmitRegister = event => {\n    event.preventDefault();\n    const data = new FormData(event.target);\n    const username = data.get('username');\n    const password = data.get('password');\n\n    register({ input: { username, password } }).then(result => {\n      if (!result.error && result.data && result.data.register) {\n        onLoginSuccess(result.data.register);\n      }\n    });\n  };\n\n  const disabled = loginResult.fetching || registerResult.fetching;\n\n  return (\n    <>\n      <form onSubmit={onSubmitLogin}>\n        {loginResult.fetching ? <p>Logging in...</p> : null}\n        {loginResult.error ? <p>Oh no... {loginResult.error.message}</p> : null}\n\n        <fieldset disabled={disabled ? 'disabled' : null}>\n          <h3>Login</h3>\n          <label>\n            Username:\n            <input name=\"username\" type=\"text\" />\n          </label>\n\n          <label>\n            Password:\n            <input name=\"password\" type=\"password\" />\n          </label>\n\n          <button type=\"submit\">Login</button>\n        </fieldset>\n      </form>\n\n      <form onSubmit={onSubmitRegister}>\n        {registerResult.fetching ? <p>Signing up...</p> : null}\n        {registerResult.error ? (\n          <p>Oh no... {registerResult.error.message}</p>\n        ) : null}\n\n        <fieldset disabled={disabled ? 'disabled' : null}>\n          <h3>Register</h3>\n          <label>\n            {'Username: '}\n            <input name=\"username\" type=\"text\" />\n          </label>\n\n          <label>\n            {'Password: '}\n            <input name=\"password\" type=\"password\" />\n          </label>\n\n          <button type=\"submit\">Register</button>\n        </fieldset>\n      </form>\n    </>\n  );\n};\n\nexport default LoginForm;\n"
  },
  {
    "path": "examples/with-graphcache-updates/vite.config.js",
    "content": "import { defineConfig } from 'vite';\nimport react from '@vitejs/plugin-react';\n\n// https://vitejs.dev/config/\nexport default defineConfig({\n  plugins: [react()],\n});\n"
  },
  {
    "path": "examples/with-infinite-pagination/README.md",
    "content": "# With Infinite Pagination (in React)\n\n<p>\n  <a\n  href=\"https://stackblitz.com/github/urql-graphql/urql/tree/main/examples/with-infinite-pagination\">\n    <img\n      alt=\"Open in StackBlitz\"\n      src=\"https://img.shields.io/badge/open_in_stackblitz-1269D3?logo=stackblitz&style=for-the-badge\"\n    />\n  </a>\n  <a\n  href=\"https://codesandbox.io/p/sandbox/github/urql-graphql/urql/tree/main/examples/with-infinite-pagination\">\n    <img\n      alt=\"Open in CodeSandbox\"\n      src=\"https://img.shields.io/badge/open_in_codesandbox-151515?logo=codesandbox&style=for-the-badge\"\n    />\n  </a>\n</p>\n\nThis example shows how to implement **infinite scroll** pagination with `urql`\nin your React UI code.\n\nIt's slightly different than the [`with-pagination`](../with-pagination) example\nand shows how to implement a full infinitely scrolling list with only your UI code,\nwhile fulfilling the following requirements:\n\n- Unlike with [`with-graphcache-pagination`](../with-graphcache-pagination),\n  the `urql` cache doesn't have to know about your infinite list, and this works\n  with any cache, even the document cache\n- Unlike with [`with-pagination`](../with-pagination), your list can use cursors,\n  and each page can update, while keeping the variables for the next page dynamic.\n- It uses no added state, no extra processing of lists, and you need no effects.\n\nIn other words, unless you need a flat array of items\n(e.g. unless you’re using React Native’s `FlatList`), this is the simplest way\nto implement an infinitely scrolling, paginated list.\n\nThis example is also reapplicable to other libraries, like Svelte or Vue.\n\nTo run this example install dependencies and run the `start` script:\n\n```sh\nyarn install\nyarn run start\n# or\nnpm install\nnpm run start\n```\n\nThis example contains:\n\n- The `urql` bindings and a React app with a client set up in [`src/App.js`](src/App.jsx)\n  - This also contains a search input which is used as input for the GraphQL queries\n- All pagination components are in [`src/SearchResults.jsx`](src/SearchResults.jsx)\n  - The `SearchRoot` component loads the first page of results and renders `SearchPage`\n  - The `SearchPage` displays cached results, and otherwise only starts a network request on\n    a button press\n  - The `Package` component is used for each result item\n"
  },
  {
    "path": "examples/with-infinite-pagination/index.html",
    "content": "<!doctype html>\n<html lang=\"en\">\n  <head>\n    <meta charset=\"UTF-8\" />\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\" />\n    <title>with-pagination</title>\n    <style>\n      body {\n        margin: 0;\n        font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto',\n          'Oxygen', 'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans',\n          'Helvetica Neue', sans-serif;\n        -webkit-font-smoothing: antialiased;\n        -moz-osx-font-smoothing: grayscale;\n      }\n\n      code {\n        font-family: source-code-pro, Menlo, Monaco, Consolas, 'Courier New',\n          monospace;\n      }\n    </style>\n  </head>\n  <body>\n    <div id=\"root\"></div>\n    <script type=\"module\" src=\"/src/index.jsx\"></script>\n  </body>\n</html>\n"
  },
  {
    "path": "examples/with-infinite-pagination/package.json",
    "content": "{\n  \"name\": \"with-pagination\",\n  \"version\": \"0.0.0\",\n  \"private\": true,\n  \"scripts\": {\n    \"start\": \"vite\"\n  },\n  \"dependencies\": {\n    \"@urql/core\": \"^6.0.1\",\n    \"graphql\": \"^16.6.0\",\n    \"react\": \"^18.2.0\",\n    \"react-dom\": \"^18.2.0\",\n    \"urql\": \"^5.0.1\"\n  },\n  \"devDependencies\": {\n    \"@vitejs/plugin-react\": \"^3.1.0\",\n    \"vite\": \"^4.2.0\"\n  }\n}\n"
  },
  {
    "path": "examples/with-infinite-pagination/src/App.jsx",
    "content": "import React, { useState } from 'react';\nimport { Client, Provider, cacheExchange, fetchExchange } from 'urql';\n\nimport SearchRoot from './SearchResults';\n\nconst client = new Client({\n  // The GraphQL API we use here uses the NPM registry\n  // We'll use it to display search results for packages\n  url: 'https://trygql.formidable.dev/graphql/relay-npm',\n  exchanges: [cacheExchange, fetchExchange],\n});\n\n// We will be able to enter a search term, and this term\n// will render search results\nfunction PaginatedNpmSearch() {\n  const [search, setSearch] = useState('urql');\n\n  const setSearchValue = event => {\n    event.preventDefault();\n    setSearch(event.currentTarget.value);\n  };\n\n  return (\n    <>\n      <header>\n        <h4>Type to search for npm packages</h4>\n        {/* Try changing the search input, then changing it back... */}\n        {/* If you do this, all cached pages will display immediately! */}\n        <input\n          type=\"search\"\n          value={search}\n          onChange={setSearchValue}\n          placeholder=\"npm package name\"\n        />\n      </header>\n      <main>\n        {/* The <SearchRoot> component contains all querying logic */}\n        <SearchRoot searchTerm={search} />\n      </main>\n    </>\n  );\n}\n\nfunction App() {\n  return (\n    <Provider value={client}>\n      <PaginatedNpmSearch />\n    </Provider>\n  );\n}\n\nexport default App;\n"
  },
  {
    "path": "examples/with-infinite-pagination/src/SearchResults.jsx",
    "content": "import React, { useCallback } from 'react';\nimport { gql, useQuery } from 'urql';\n\n// We define a fragment, just to define the data\n// that our item component will use in the results list\nconst packageFragment = gql`\n  fragment SearchPackage on Package {\n    id\n    name\n    latest: version(selector: \"latest\") {\n      version\n    }\n  }\n`;\n\n// The main query fetches the first page of results and gets our `PageInfo`\n// This tells us whether more pages are present which we can query.\nconst rootQuery = gql`\n  query SearchRoot($searchTerm: String!, $resultsPerPage: Int!) {\n    search(query: $searchTerm, first: $resultsPerPage) {\n      edges {\n        cursor\n        node {\n          ...SearchPackage\n        }\n      }\n      pageInfo {\n        hasNextPage\n        endCursor\n      }\n    }\n  }\n\n  ${packageFragment}\n`;\n\n// We split the next pages we load into a separate query. In this example code,\n// both queries could be the same, but we keep them separate for educational\n// purposes.\n// In a real app, your \"root query\" would often fetch more data than the search page query.\nconst pageQuery = gql`\n  query SearchPage(\n    $searchTerm: String!\n    $resultsPerPage: Int!\n    $afterCursor: String!\n  ) {\n    search(query: $searchTerm, first: $resultsPerPage, after: $afterCursor) {\n      edges {\n        cursor\n        node {\n          ...SearchPackage\n        }\n      }\n      pageInfo {\n        hasNextPage\n        endCursor\n      }\n    }\n  }\n\n  ${packageFragment}\n`;\n\n// This is the <SearchRoot> component that we render in `./App.jsx`.\n// It accepts our variables as props.\nconst SearchRoot = ({ searchTerm = 'urql', resultsPerPage = 10 }) => {\n  const [rootResult] = useQuery({\n    query: rootQuery,\n    variables: {\n      searchTerm,\n      resultsPerPage,\n    },\n  });\n\n  if (rootResult.fetching) {\n    return <em>Loading...</em>;\n  }\n\n  // Here, we render the results as a list into a fragment, and if `hasNextPage`\n  // is truthy, we immediately render <SearchPage> for the next page.\n  const connection = rootResult.data?.search;\n  return (\n    <>\n      {connection?.edges?.length === 0 ? <strong>No Results</strong> : null}\n\n      {connection?.edges.map(edge => (\n        <Package key={edge.cursor} node={edge.node} />\n      ))}\n\n      {/* The <SearchPage> component receives the same props, plus the `afterCursor` for its variables */}\n      {connection?.pageInfo.hasNextPage ? (\n        <SearchPage\n          searchTerm={searchTerm}\n          resultsPerPage={resultsPerPage}\n          afterCursor={connection.pageInfo.endCursor}\n        />\n      ) : rootResult.fetching ? (\n        <em>Loading...</em>\n      ) : null}\n    </>\n  );\n};\n\n// The <SearchPage> is rendered for each page of results, except for the root query.\n// It renders *itself* recursively, for the next page of results.\nconst SearchPage = ({ searchTerm, resultsPerPage, afterCursor }) => {\n  // Each <SearchPage> fetches its own page results!\n  const [pageResult, executeQuery] = useQuery({\n    query: pageQuery,\n    // Initially, we *only* want to display results if, they're cached\n    requestPolicy: 'cache-only',\n    // We don't want to run the query if we don't have a cursor (in this example, this will never happen)\n    pause: !afterCursor,\n    variables: {\n      searchTerm,\n      resultsPerPage,\n      afterCursor,\n    },\n  });\n\n  // We only load more results, by allowing the query to make a network request, if\n  // a button has pressed.\n  // In your app, you may want to do this automatically if the user can see the end of\n  // your list, e.g. via an IntersectionObserver.\n  const onLoadMore = useCallback(() => {\n    // This tells the query above to execute and instead of `cache-only`, which forbids\n    // network requests, we now allow them.\n    executeQuery({ requestPolicy: 'cache-first' });\n  }, [executeQuery]);\n\n  if (pageResult.fetching) {\n    return <em>Loading...</em>;\n  }\n\n  const connection = pageResult.data?.search;\n  return (\n    <>\n      {/* If our query has nodes, we render them here. The page renders its own results */}\n      {connection?.edges.map(edge => (\n        <Package key={edge.cursor} node={edge.node} />\n      ))}\n\n      {/* If we have a next page, we now render it recursively! */}\n      {/* As before, the next <SearchPage> will not fetch immediately, but only query from cache */}\n      {connection?.pageInfo.hasNextPage ? (\n        <SearchPage\n          searchTerm={searchTerm}\n          resultsPerPage={resultsPerPage}\n          afterCursor={connection.pageInfo.endCursor}\n        />\n      ) : pageResult.fetching ? (\n        <em>Loading...</em>\n      ) : null}\n\n      {!connection && !pageResult.fetching ? (\n        <button type=\"button\" onClick={onLoadMore}>\n          Load more\n        </button>\n      ) : null}\n    </>\n  );\n};\n\n// This is the component that then renders each result item\nconst Package = ({ node }) => (\n  <section>\n    <strong>{node.name}</strong>\n    <em>@{node.latest.version}</em>\n  </section>\n);\n\nexport default SearchRoot;\n"
  },
  {
    "path": "examples/with-infinite-pagination/src/index.jsx",
    "content": "import React from 'react';\nimport { createRoot } from 'react-dom/client';\n\nimport App from './App';\n\ncreateRoot(document.getElementById('root')).render(<App />);\n"
  },
  {
    "path": "examples/with-infinite-pagination/vite.config.js",
    "content": "import { defineConfig } from 'vite';\nimport react from '@vitejs/plugin-react';\n\n// https://vitejs.dev/config/\nexport default defineConfig({\n  plugins: [react()],\n});\n"
  },
  {
    "path": "examples/with-multipart/README.md",
    "content": "# With Multipart File Upload\n\n<p>\n  <a href=\"https://stackblitz.com/github/urql-graphql/urql/tree/main/examples/with-multipart\">\n    <img\n      alt=\"Open in StackBlitz\"\n      src=\"https://img.shields.io/badge/open_in_stackblitz-1269D3?logo=stackblitz&style=for-the-badge\"\n    />\n  </a>\n  <a\n  href=\"https://codesandbox.io/p/sandbox/github/urql-graphql/urql/tree/main/examples/with-multipart\">\n    <img\n      alt=\"Open in CodeSandbox\"\n      src=\"https://img.shields.io/badge/open_in_codesandbox-151515?logo=codesandbox&style=for-the-badge\"\n    />\n  </a>\n</p>\n\nThis example shows `urql` in use with `@urql/exchange-multipart-fetch`'s `multipartFetchExchange`\nto support file uploads in GraphQL. This largely follows the [\"File Uploads\" docs\npage](https://formidable.com/open-source/urql/docs/advanced/persistence-and-uploads/)\nand uses the [`trygql.formidable.dev/graphql/uploads-mock` schema](https://github.com/FormidableLabs/trygql).\n\nTo run this example install dependencies and run the `start` script:\n\n```sh\nyarn install\nyarn run start\n# or\nnpm install\nnpm run start\n```\n\nThis example contains:\n\n- The `urql` bindings and a React app with a client set up in [`src/App.jsx`](src/App.jsx)\n- A basic file upload form in [`src/FileUpload.jsx`](src/FileUpload.jsx)\n"
  },
  {
    "path": "examples/with-multipart/index.html",
    "content": "<!doctype html>\n<html lang=\"en\">\n  <head>\n    <meta charset=\"UTF-8\" />\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\" />\n    <title>with-multipart</title>\n    <style>\n      body {\n        margin: 0;\n        font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto',\n          'Oxygen', 'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans',\n          'Helvetica Neue', sans-serif;\n        -webkit-font-smoothing: antialiased;\n        -moz-osx-font-smoothing: grayscale;\n      }\n\n      code {\n        font-family: source-code-pro, Menlo, Monaco, Consolas, 'Courier New',\n          monospace;\n      }\n    </style>\n  </head>\n  <body>\n    <div id=\"root\"></div>\n    <script type=\"module\" src=\"/src/index.jsx\"></script>\n  </body>\n</html>\n"
  },
  {
    "path": "examples/with-multipart/package.json",
    "content": "{\n  \"name\": \"with-multipart\",\n  \"version\": \"0.0.0\",\n  \"private\": true,\n  \"scripts\": {\n    \"start\": \"vite\"\n  },\n  \"dependencies\": {\n    \"@urql/core\": \"^6.0.1\",\n    \"graphql\": \"^16.6.0\",\n    \"react\": \"^18.2.0\",\n    \"react-dom\": \"^18.2.0\",\n    \"urql\": \"^5.0.1\"\n  },\n  \"devDependencies\": {\n    \"@vitejs/plugin-react\": \"^3.1.0\",\n    \"vite\": \"^4.2.0\"\n  }\n}\n"
  },
  {
    "path": "examples/with-multipart/src/App.jsx",
    "content": "import React from 'react';\nimport { Client, Provider, fetchExchange } from 'urql';\n\nimport FileUpload from './FileUpload';\n\nconst client = new Client({\n  url: 'https://trygql.formidable.dev/graphql/uploads-mock',\n  exchanges: [fetchExchange],\n});\n\nfunction App() {\n  return (\n    <Provider value={client}>\n      <FileUpload />\n    </Provider>\n  );\n}\n\nexport default App;\n"
  },
  {
    "path": "examples/with-multipart/src/FileUpload.jsx",
    "content": "import React, { useState } from 'react';\nimport { gql, useMutation } from 'urql';\n\nconst UPLOAD_FILE = gql`\n  mutation UploadFile($file: Upload!) {\n    uploadFile(file: $file) {\n      filename\n    }\n  }\n`;\n\nconst FileUpload = () => {\n  const [selectedFile, setSelectedFile] = useState();\n  const [result, uploadFile] = useMutation(UPLOAD_FILE);\n\n  const { data, fetching, error } = result;\n\n  const handleFileUpload = () => {\n    uploadFile({ file: selectedFile });\n  };\n\n  const handleFileChange = event => {\n    setSelectedFile(event.target.files[0]);\n  };\n\n  return (\n    <div>\n      {fetching && <p>Loading...</p>}\n\n      {error && <p>Oh no... {error.message}</p>}\n\n      {data && data.uploadFile ? (\n        <p>File uploaded to {data.uploadFile.filename}</p>\n      ) : (\n        <div>\n          <input type=\"file\" onChange={handleFileChange} />\n\n          <button onClick={handleFileUpload}>Upload!</button>\n        </div>\n      )}\n    </div>\n  );\n};\n\nexport default FileUpload;\n"
  },
  {
    "path": "examples/with-multipart/src/index.jsx",
    "content": "import React from 'react';\nimport { createRoot } from 'react-dom/client';\n\nimport App from './App';\n\ncreateRoot(document.getElementById('root')).render(<App />);\n"
  },
  {
    "path": "examples/with-multipart/vite.config.js",
    "content": "import { defineConfig } from 'vite';\nimport react from '@vitejs/plugin-react';\n\n// https://vitejs.dev/config/\nexport default defineConfig({\n  plugins: [react()],\n});\n"
  },
  {
    "path": "examples/with-next/README.md",
    "content": "# With Next.js\n\n<p>\n  <a href=\"https://stackblitz.com/github/urql-graphql/urql/tree/main/examples/with-next\">\n    <img\n      alt=\"Open in StackBlitz\"\n      src=\"https://img.shields.io/badge/open_in_stackblitz-1269D3?logo=stackblitz&style=for-the-badge\"\n    />\n  </a>\n  <a href=\"https://codesandbox.io/p/sandbox/github/urql-graphql/urql/tree/main/examples/with-next\">\n    <img\n      alt=\"Open in CodeSandbox\"\n      src=\"https://img.shields.io/badge/open_in_codesandbox-151515?logo=codesandbox&style=for-the-badge\"\n    />\n  </a>\n</p>\n\nThis example shows `next-urql` and `urql` in use with Next.js as explained [in the \"Next.js\" section\non the \"Server-side Rendering\" docs\npage](https://formidable.com/open-source/urql/docs/advanced/server-side-rendering/#nextjs).\n\nTo run this example install dependencies and run the `start` script:\n\n```sh\nyarn install\nyarn run start\n# or\nnpm install\nnpm run start\n```\n"
  },
  {
    "path": "examples/with-next/app/layout.tsx",
    "content": "export const metadata = {\n  title: 'Create Next App',\n  description: 'Generated by create next app',\n};\n\nexport default function RootLayout({\n  children,\n}: {\n  children: React.ReactNode;\n}) {\n  return (\n    <html lang=\"en\">\n      <body>{children}</body>\n    </html>\n  );\n}\n"
  },
  {
    "path": "examples/with-next/app/non-rsc/layout.tsx",
    "content": "'use client';\n\nimport { useMemo } from 'react';\nimport {\n  UrqlProvider,\n  ssrExchange,\n  cacheExchange,\n  fetchExchange,\n  createClient,\n} from '@urql/next';\n\nexport default function Layout({ children }: React.PropsWithChildren) {\n  const [client, ssr] = useMemo(() => {\n    const ssr = ssrExchange({\n      isClient: typeof window !== 'undefined',\n    });\n    const client = createClient({\n      url: 'https://graphql-pokeapi.graphcdn.app/',\n      exchanges: [cacheExchange, ssr, fetchExchange],\n      suspense: true,\n    });\n\n    return [client, ssr];\n  }, []);\n\n  return (\n    <UrqlProvider client={client} ssr={ssr}>\n      {children}\n    </UrqlProvider>\n  );\n}\n"
  },
  {
    "path": "examples/with-next/app/non-rsc/page.tsx",
    "content": "'use client';\n\nimport Link from 'next/link';\nimport { Suspense } from 'react';\nimport { useQuery, gql } from '@urql/next';\n\nexport default function Page() {\n  return (\n    <Suspense>\n      <Pokemons />\n    </Suspense>\n  );\n}\n\nconst PokemonsQuery = gql`\n  query {\n    pokemons(limit: 10) {\n      results {\n        id\n        name\n      }\n    }\n  }\n`;\n\nfunction Pokemons() {\n  const [result] = useQuery({ query: PokemonsQuery });\n  return (\n    <main>\n      <h1>This is rendered as part of SSR</h1>\n      <ul>\n        {result.data\n          ? result.data.pokemons.results.map((x: any) => (\n              <li key={x.id}>{x.name}</li>\n            ))\n          : JSON.stringify(result.error)}\n      </ul>\n      <Suspense>\n        <Pokemon name=\"bulbasaur\" />\n      </Suspense>\n      <Link href=\"/\">RSC</Link>\n    </main>\n  );\n}\n\nconst PokemonQuery = gql`\n  query ($name: String!) {\n    pokemon(name: $name) {\n      id\n      name\n    }\n  }\n`;\n\nfunction Pokemon(props: any) {\n  const [result] = useQuery({\n    query: PokemonQuery,\n    variables: { name: props.name },\n  });\n  return (\n    <div>\n      <h1>{result.data && result.data.pokemon.name}</h1>\n    </div>\n  );\n}\n"
  },
  {
    "path": "examples/with-next/app/page.tsx",
    "content": "import Link from 'next/link';\nimport { cacheExchange, createClient, fetchExchange, gql } from '@urql/core';\nimport { registerUrql } from '@urql/next/rsc';\n\nconst makeClient = () => {\n  return createClient({\n    url: 'https://graphql-pokeapi.graphcdn.app/',\n    exchanges: [cacheExchange, fetchExchange],\n  });\n};\n\nconst { getClient } = registerUrql(makeClient);\n\nconst PokemonsQuery = gql`\n  query {\n    pokemons(limit: 10) {\n      results {\n        id\n        name\n      }\n    }\n  }\n`;\n\nexport default async function Home() {\n  const result = await getClient().query(PokemonsQuery, {});\n  return (\n    <main>\n      <h1>This is rendered as part of an RSC</h1>\n      <ul>\n        {result.data\n          ? result.data.pokemons.results.map((x: any) => (\n              <li key={x.id}>{x.name}</li>\n            ))\n          : JSON.stringify(result.error)}\n      </ul>\n      <Link href=\"/non-rsc\">Non RSC</Link>\n    </main>\n  );\n}\n"
  },
  {
    "path": "examples/with-next/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": "examples/with-next/package.json",
    "content": "{\n  \"name\": \"with-next\",\n  \"version\": \"0.0.0\",\n  \"private\": true,\n  \"dependencies\": {\n    \"@urql/core\": \"^6.0.1\",\n    \"@urql/next\": \"^2.0.0\",\n    \"graphql\": \"^16.6.0\",\n    \"next\": \"13.4.2\",\n    \"react\": \"^18.2.0\",\n    \"react-dom\": \"^18.2.0\",\n    \"urql\": \"^5.0.1\"\n  },\n  \"scripts\": {\n    \"dev\": \"next dev\",\n    \"start\": \"next\",\n    \"build\": \"next build\"\n  },\n  \"devDependencies\": {\n    \"@types/react\": \"18.2.6\"\n  }\n}\n"
  },
  {
    "path": "examples/with-next/tsconfig.json",
    "content": "{\n  \"compilerOptions\": {\n    \"lib\": [\"dom\", \"dom.iterable\", \"esnext\"],\n    \"allowJs\": true,\n    \"skipLibCheck\": true,\n    \"strict\": false,\n    \"forceConsistentCasingInFileNames\": true,\n    \"noEmit\": true,\n    \"incremental\": true,\n    \"esModuleInterop\": true,\n    \"module\": \"esnext\",\n    \"moduleResolution\": \"node\",\n    \"resolveJsonModule\": true,\n    \"isolatedModules\": true,\n    \"jsx\": \"preserve\",\n    \"plugins\": [\n      {\n        \"name\": \"next\"\n      }\n    ]\n  },\n  \"include\": [\"next-env.d.ts\", \".next/types/**/*.ts\", \"**/*.ts\", \"**/*.tsx\"],\n  \"exclude\": [\"node_modules\"]\n}\n"
  },
  {
    "path": "examples/with-pagination/README.md",
    "content": "# With Pagination (in React)\n\n<p>\n  <a href=\"https://stackblitz.com/github/urql-graphql/urql/tree/main/examples/with-pagination\">\n    <img\n      alt=\"Open in StackBlitz\"\n      src=\"https://img.shields.io/badge/open_in_stackblitz-1269D3?logo=stackblitz&style=for-the-badge\"\n    />\n  </a>\n  <a\n  href=\"https://codesandbox.io/p/sandbox/github/urql-graphql/urql/tree/main/examples/with-pagination\">\n    <img\n      alt=\"Open in CodeSandbox\"\n      src=\"https://img.shields.io/badge/open_in_codesandbox-151515?logo=codesandbox&style=for-the-badge\"\n    />\n  </a>\n</p>\n\nThis example shows how to implement pagination with `urql` in your React UI code.\n\nIt renders several pages as fragments with one component managing the variables\nfor the page queries. This example is also reapplicable to other libraries,\nlike Svelte or Vue.\n\nTo run this example install dependencies and run the `start` script:\n\n```sh\nyarn install\nyarn run start\n# or\nnpm install\nnpm run start\n```\n\nThis example contains:\n\n- The `urql` bindings and a React app with a client set up in [`src/App.js`](src/App.jsx)\n- A managing component called `PaginatedNpmSearch` set up to render all pages in [`src/PaginatedNpmSearch.jss`](src/PaginatedNpmSearch.jsx)\n- A page component called `SearchResultPage` running page queries in [`src/PaginatedNpmSearch.jsx`](src/PaginatedNpmSearch.jsx)\n"
  },
  {
    "path": "examples/with-pagination/index.html",
    "content": "<!doctype html>\n<html lang=\"en\">\n  <head>\n    <meta charset=\"UTF-8\" />\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\" />\n    <title>with-pagination</title>\n    <style>\n      body {\n        margin: 0;\n        font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto',\n          'Oxygen', 'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans',\n          'Helvetica Neue', sans-serif;\n        -webkit-font-smoothing: antialiased;\n        -moz-osx-font-smoothing: grayscale;\n      }\n\n      code {\n        font-family: source-code-pro, Menlo, Monaco, Consolas, 'Courier New',\n          monospace;\n      }\n    </style>\n  </head>\n  <body>\n    <div id=\"root\"></div>\n    <script type=\"module\" src=\"/src/index.jsx\"></script>\n  </body>\n</html>\n"
  },
  {
    "path": "examples/with-pagination/package.json",
    "content": "{\n  \"name\": \"with-pagination\",\n  \"version\": \"0.0.0\",\n  \"private\": true,\n  \"scripts\": {\n    \"start\": \"vite\"\n  },\n  \"dependencies\": {\n    \"@urql/core\": \"^6.0.1\",\n    \"graphql\": \"^16.6.0\",\n    \"react\": \"^18.2.0\",\n    \"react-dom\": \"^18.2.0\",\n    \"urql\": \"^5.0.1\"\n  },\n  \"devDependencies\": {\n    \"@vitejs/plugin-react\": \"^3.1.0\",\n    \"vite\": \"^4.2.0\"\n  }\n}\n"
  },
  {
    "path": "examples/with-pagination/src/App.jsx",
    "content": "import React from 'react';\nimport { Client, Provider, cacheExchange, fetchExchange } from 'urql';\n\nimport PaginatedNpmSearch from './PaginatedNpmSearch';\n\nconst client = new Client({\n  url: 'https://trygql.formidable.dev/graphql/relay-npm',\n  exchanges: [cacheExchange, fetchExchange],\n});\n\nfunction App() {\n  return (\n    <Provider value={client}>\n      <PaginatedNpmSearch />\n    </Provider>\n  );\n}\n\nexport default App;\n"
  },
  {
    "path": "examples/with-pagination/src/PaginatedNpmSearch.jsx",
    "content": "import React, { useState } from 'react';\nimport { gql, useQuery } from 'urql';\n\nconst limit = 5;\nconst query = 'graphql';\n\nconst NPM_SEARCH = gql`\n  query Search($query: String!, $first: Int!, $after: String) {\n    search(query: $query, first: $first, after: $after) {\n      nodes {\n        id\n        name\n      }\n      pageInfo {\n        hasNextPage\n        endCursor\n      }\n    }\n  }\n`;\n\nconst SearchResultPage = ({ variables, onLoadMore, isLastPage }) => {\n  const [result] = useQuery({ query: NPM_SEARCH, variables });\n\n  const { data, fetching, error } = result;\n\n  const searchResults = data?.search;\n\n  return (\n    <div>\n      {error && <p>Oh no... {error.message}</p>}\n\n      {fetching && <p>Loading...</p>}\n\n      {searchResults && (\n        <>\n          {searchResults.nodes.map(packageInfo => (\n            <div key={packageInfo.id}>\n              {packageInfo.id}: {packageInfo.name}\n            </div>\n          ))}\n\n          {isLastPage && searchResults.pageInfo.hasNextPage && (\n            <button\n              onClick={() => onLoadMore(searchResults.pageInfo.endCursor)}\n            >\n              load more\n            </button>\n          )}\n        </>\n      )}\n    </div>\n  );\n};\n\nconst PaginatedNpmSearch = () => {\n  const [pageVariables, setPageVariables] = useState([\n    {\n      query,\n      first: limit,\n      after: '',\n    },\n  ]);\n\n  return (\n    <div>\n      {pageVariables.map((variables, i) => (\n        <SearchResultPage\n          key={'' + variables.after}\n          variables={variables}\n          isLastPage={i === pageVariables.length - 1}\n          onLoadMore={after =>\n            setPageVariables([...pageVariables, { after, first: limit, query }])\n          }\n        />\n      ))}\n    </div>\n  );\n};\n\nexport default PaginatedNpmSearch;\n"
  },
  {
    "path": "examples/with-pagination/src/index.jsx",
    "content": "import React from 'react';\nimport { createRoot } from 'react-dom/client';\n\nimport App from './App';\n\ncreateRoot(document.getElementById('root')).render(<App />);\n"
  },
  {
    "path": "examples/with-pagination/vite.config.js",
    "content": "import { defineConfig } from 'vite';\nimport react from '@vitejs/plugin-react';\n\n// https://vitejs.dev/config/\nexport default defineConfig({\n  plugins: [react()],\n});\n"
  },
  {
    "path": "examples/with-react/README.md",
    "content": "# With React\n\n<p>\n  <a href=\"https://stackblitz.com/github/urql-graphql/urql/tree/main/examples/with-react\">\n    <img\n      alt=\"Open in StackBlitz\"\n      src=\"https://img.shields.io/badge/open_in_stackblitz-1269D3?logo=stackblitz&style=for-the-badge\"\n    />\n  </a>\n  <a href=\"https://codesandbox.io/p/sandbox/github/urql-graphql/urql/tree/main/examples/with-react\">\n    <img\n      alt=\"Open in CodeSandbox\"\n      src=\"https://img.shields.io/badge/open_in_codesandbox-151515?logo=codesandbox&style=for-the-badge\"\n    />\n  </a>\n</p>\n\nThis example shows `urql` in use with React, as explained on the [\"React/Preact\" page of the \"Basics\"\ndocumentation.](https://formidable.com/open-source/urql/docs/basics/react-preact/)\n\nTo run this example install dependencies and run the `start` script:\n\n```sh\nyarn install\nyarn run start\n# or\nnpm install\nnpm run start\n```\n\nThis example contains:\n\n- The `urql` bindings and a React app with a client set up in [`src/App.jsx`](src/App.jsx)\n- A query for pokémon in [`src/PokemonList.jsx`](src/PokemonList.jsx)\n"
  },
  {
    "path": "examples/with-react/index.html",
    "content": "<!doctype html>\n<html lang=\"en\">\n  <head>\n    <meta charset=\"UTF-8\" />\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\" />\n    <title>with-react</title>\n    <style>\n      body {\n        margin: 0;\n        font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto',\n          'Oxygen', 'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans',\n          'Helvetica Neue', sans-serif;\n        -webkit-font-smoothing: antialiased;\n        -moz-osx-font-smoothing: grayscale;\n      }\n\n      code {\n        font-family: source-code-pro, Menlo, Monaco, Consolas, 'Courier New',\n          monospace;\n      }\n    </style>\n  </head>\n  <body>\n    <div id=\"root\"></div>\n    <script type=\"module\" src=\"/src/index.jsx\"></script>\n  </body>\n</html>\n"
  },
  {
    "path": "examples/with-react/package.json",
    "content": "{\n  \"name\": \"with-react\",\n  \"version\": \"0.0.0\",\n  \"private\": true,\n  \"scripts\": {\n    \"start\": \"vite\"\n  },\n  \"dependencies\": {\n    \"@urql/core\": \"^6.0.1\",\n    \"graphql\": \"^16.6.0\",\n    \"react\": \"^18.2.0\",\n    \"react-dom\": \"^18.2.0\",\n    \"urql\": \"^5.0.1\"\n  },\n  \"devDependencies\": {\n    \"@vitejs/plugin-react\": \"^3.1.0\",\n    \"vite\": \"^4.2.0\"\n  }\n}\n"
  },
  {
    "path": "examples/with-react/src/App.jsx",
    "content": "import React from 'react';\nimport { Client, Provider, cacheExchange, fetchExchange } from 'urql';\n\nimport PokemonList from './PokemonList';\n\nconst client = new Client({\n  url: 'https://trygql.formidable.dev/graphql/basic-pokedex',\n  exchanges: [cacheExchange, fetchExchange],\n});\n\nfunction App() {\n  return (\n    <Provider value={client}>\n      <PokemonList />\n    </Provider>\n  );\n}\n\nexport default App;\n"
  },
  {
    "path": "examples/with-react/src/PokemonList.jsx",
    "content": "import React from 'react';\nimport { gql, useQuery } from 'urql';\n\nconst POKEMONS_QUERY = gql`\n  query Pokemons {\n    pokemons(limit: 10) {\n      id\n      name\n    }\n  }\n`;\n\nconst PokemonList = () => {\n  const [result] = useQuery({ query: POKEMONS_QUERY });\n\n  const { data, fetching, error } = result;\n\n  return (\n    <div>\n      {fetching && <p>Loading...</p>}\n\n      {error && <p>Oh no... {error.message}</p>}\n\n      {data && (\n        <ul>\n          {data.pokemons.map(pokemon => (\n            <li key={pokemon.id}>{pokemon.name}</li>\n          ))}\n        </ul>\n      )}\n    </div>\n  );\n};\n\nexport default PokemonList;\n"
  },
  {
    "path": "examples/with-react/src/index.jsx",
    "content": "import React from 'react';\nimport { createRoot } from 'react-dom/client';\n\nimport App from './App';\n\ncreateRoot(document.getElementById('root')).render(<App />);\n"
  },
  {
    "path": "examples/with-react/vite.config.js",
    "content": "import { defineConfig } from 'vite';\nimport react from '@vitejs/plugin-react';\n\n// https://vitejs.dev/config/\nexport default defineConfig({\n  plugins: [react()],\n});\n"
  },
  {
    "path": "examples/with-react-native/App.js",
    "content": "import React from 'react';\nimport { Client, Provider, cacheExchange, fetchExchange } from 'urql';\n\nimport PokemonList from './src/screens/PokemonList';\n\nconst client = new Client({\n  url: 'https://trygql.formidable.dev/graphql/basic-pokedex',\n  exchanges: [cacheExchange, fetchExchange],\n});\n\nconst App = () => {\n  return (\n    <Provider value={client}>\n      <PokemonList />\n    </Provider>\n  );\n};\n\nexport default App;\n"
  },
  {
    "path": "examples/with-react-native/README.md",
    "content": "# With React Native\n\n<p>\n  <a href=\"https://stackblitz.com/github/urql-graphql/urql/tree/main/examples/with-react-native\">\n    <img\n      alt=\"Open in StackBlitz\"\n      src=\"https://img.shields.io/badge/open_in_stackblitz-1269D3?logo=stackblitz&style=for-the-badge\"\n    />\n  </a>\n  <a\n  href=\"https://codesandbox.io/p/sandbox/github/urql-graphql/urql/tree/main/examples/with-react-native\">\n    <img\n      alt=\"Open in CodeSandbox\"\n      src=\"https://img.shields.io/badge/open_in_codesandbox-151515?logo=codesandbox&style=for-the-badge\"\n    />\n  </a>\n</p>\n\nThis example shows `urql` in use with React Native.\n\nTo run this example install dependencies and run the `start` script:\n\n```sh\nyarn install\nyarn run start\n# or\nnpm install\nnpm run start\n```\n\nThis example contains:\n\n- The `urql` bindings and a React Native app with a client set up in [`App.js`](./App.js)\n- A query for pokémon in [`src/screens/PokemonList.js`](src/screens/PokemonList.js)\n"
  },
  {
    "path": "examples/with-react-native/app.json",
    "content": "{\n  \"name\": \"withReactNative\",\n  \"displayName\": \"withReactNative\"\n}\n"
  },
  {
    "path": "examples/with-react-native/index.js",
    "content": "/**\n * @format\n */\n\nimport { AppRegistry } from 'react-native';\nimport App from './App';\nimport { name as appName } from './app.json';\n\nAppRegistry.registerComponent(appName, () => App);\n"
  },
  {
    "path": "examples/with-react-native/package.json",
    "content": "{\n  \"name\": \"with-react-native\",\n  \"version\": \"0.0.0\",\n  \"private\": true,\n  \"scripts\": {\n    \"android\": \"react-native run-android\",\n    \"ios\": \"react-native run-ios\",\n    \"start\": \"react-native start\"\n  },\n  \"dependencies\": {\n    \"@urql/core\": \"^6.0.1\",\n    \"graphql\": \"^16.6.0\",\n    \"react\": \"18.2.0\",\n    \"react-native\": \"0.71.4\",\n    \"urql\": \"^5.0.1\"\n  },\n  \"devDependencies\": {\n    \"@babel/core\": \"^7.12.9\",\n    \"@babel/preset-env\": \"^7.20.2\",\n    \"@babel/runtime\": \"^7.12.5\",\n    \"metro-react-native-babel-preset\": \"^0.76.0\"\n  }\n}\n"
  },
  {
    "path": "examples/with-react-native/src/screens/PokemonList.js",
    "content": "import React from 'react';\nimport { SafeAreaView, StyleSheet, Text, FlatList, View } from 'react-native';\nimport { gql, useQuery } from 'urql';\n\nconst POKEMONS_QUERY = gql`\n  query Pokemons {\n    pokemons(limit: 10) {\n      id\n      name\n    }\n  }\n`;\n\nconst Item = ({ name }) => (\n  <View style={styles.item}>\n    <Text style={styles.title}>{name}</Text>\n  </View>\n);\n\nconst PokemonList = () => {\n  const [result] = useQuery({ query: POKEMONS_QUERY });\n\n  const { data, fetching, error } = result;\n\n  const renderItem = ({ item }) => <Item name={item.name} />;\n\n  return (\n    <SafeAreaView style={styles.container}>\n      {fetching && <Text>Loading...</Text>}\n\n      {error && <Text>Oh no... {error.message}</Text>}\n\n      <FlatList\n        data={data?.pokemons}\n        renderItem={renderItem}\n        keyExtractor={item => item.id}\n      />\n    </SafeAreaView>\n  );\n};\n\nconst styles = StyleSheet.create({\n  container: {\n    flex: 1,\n  },\n  item: {\n    backgroundColor: '#dadada',\n    padding: 20,\n    marginVertical: 8,\n    marginHorizontal: 16,\n  },\n  title: {\n    fontSize: 20,\n  },\n});\n\nexport default PokemonList;\n"
  },
  {
    "path": "examples/with-refresh-auth/README.md",
    "content": "# With Refresh Authentication\n\n<p>\n  <a href=\"https://stackblitz.com/github/urql-graphql/urql/tree/main/examples/with-refresh-auth\">\n    <img\n      alt=\"Open in StackBlitz\"\n      src=\"https://img.shields.io/badge/open_in_stackblitz-1269D3?logo=stackblitz&style=for-the-badge\"\n    />\n  </a>\n  <a\n  href=\"https://codesandbox.io/p/sandbox/github/urql-graphql/urql/tree/main/examples/with-refresh-auth\">\n    <img\n      alt=\"Open in CodeSandbox\"\n      src=\"https://img.shields.io/badge/open_in_codesandbox-151515?logo=codesandbox&style=for-the-badge\"\n    />\n  </a>\n</p>\n\nThis example shows `urql` in use with `@urql/exchange-auth`'s `authExchange`\nto support authentication token and refresh token logic. This largely follows the [\"Authentication\" docs\npage](https://formidable.com/open-source/urql/docs/advanced/authentication/)\nand uses the [`trygql.formidable.dev/graphql/web-collections` schema](https://github.com/FormidableLabs/trygql).\n\nTo run this example install dependencies and run the `start` script:\n\n```sh\nyarn install\nyarn run start\n# or\nnpm install\nnpm run start\n```\n\nThis example contains:\n\n- The `urql` bindings and a React app set up in [`src/App.jsx`](src/App.jsx)\n- Some authentication glue code to store the tokens in [`src/authStore.js`](src/authStore.js)\n- The `Client` and the `authExchange` from `@urql/exchange-auth` set up in [`src/client.js`](src/client.js)\n- A basic login form in [`src/pages/LoginForm.jsx`](src/pages/LoginForm.jsx)\n- And a basic login guard on [`src/App.jsx`](src/App.jsx)\n  (Note: This isn't using a query in this particular component, since this is just an example)\n"
  },
  {
    "path": "examples/with-refresh-auth/index.html",
    "content": "<!doctype html>\n<html lang=\"en\">\n  <head>\n    <meta charset=\"UTF-8\" />\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\" />\n    <title>with-refresh-auth</title>\n    <style>\n      body {\n        margin: 0;\n        font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto',\n          'Oxygen', 'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans',\n          'Helvetica Neue', sans-serif;\n        -webkit-font-smoothing: antialiased;\n        -moz-osx-font-smoothing: grayscale;\n      }\n\n      code {\n        font-family: source-code-pro, Menlo, Monaco, Consolas, 'Courier New',\n          monospace;\n      }\n    </style>\n  </head>\n  <body>\n    <div id=\"root\"></div>\n    <script type=\"module\" src=\"/src/index.jsx\"></script>\n  </body>\n</html>\n"
  },
  {
    "path": "examples/with-refresh-auth/package.json",
    "content": "{\n  \"name\": \"with-refresh-auth\",\n  \"version\": \"0.0.0\",\n  \"private\": true,\n  \"scripts\": {\n    \"start\": \"vite\"\n  },\n  \"dependencies\": {\n    \"@urql/core\": \"^6.0.1\",\n    \"@urql/exchange-auth\": \"^3.0.0\",\n    \"graphql\": \"^16.6.0\",\n    \"react\": \"^18.2.0\",\n    \"react-dom\": \"^18.2.0\",\n    \"urql\": \"^5.0.1\"\n  },\n  \"devDependencies\": {\n    \"@vitejs/plugin-react\": \"^3.1.0\",\n    \"vite\": \"^4.2.0\"\n  }\n}\n"
  },
  {
    "path": "examples/with-refresh-auth/src/App.jsx",
    "content": "import React, { useState, useEffect } from 'react';\nimport { Provider } from 'urql';\n\nimport client from './client';\n\nimport { getToken, saveAuthData } from './authStore';\nimport Profile from './pages/Profile';\nimport LoginForm from './pages/LoginForm';\n\nconst Home = () => {\n  const [isLoggedIn, setIsLoggedIn] = useState(false);\n\n  const onLoginSuccess = auth => {\n    saveAuthData(auth);\n    setIsLoggedIn(true);\n  };\n\n  useEffect(() => {\n    if (getToken()) {\n      setIsLoggedIn(true);\n    }\n  }, []);\n\n  return isLoggedIn ? (\n    <Profile />\n  ) : (\n    <LoginForm onLoginSuccess={onLoginSuccess} />\n  );\n};\n\nfunction App() {\n  return (\n    <Provider value={client}>\n      <Home />\n    </Provider>\n  );\n}\n\nexport default App;\n"
  },
  {
    "path": "examples/with-refresh-auth/src/authStore.js",
    "content": "const TOKEN_KEY = 'token';\nconst REFRESH_TOKEN_KEY = 'refresh_token';\n\nexport const saveAuthData = ({ token, refreshToken }) => {\n  localStorage.setItem(TOKEN_KEY, token);\n  localStorage.setItem(REFRESH_TOKEN_KEY, refreshToken);\n};\n\nexport const getToken = () => {\n  return localStorage.getItem(TOKEN_KEY);\n};\n\nexport const getRefreshToken = () => {\n  return localStorage.getItem(REFRESH_TOKEN_KEY);\n};\n\nexport const clearStorage = () => {\n  localStorage.clear();\n};\n"
  },
  {
    "path": "examples/with-refresh-auth/src/client.js",
    "content": "import { Client, fetchExchange, cacheExchange, gql } from 'urql';\nimport { authExchange } from '@urql/exchange-auth';\n\nimport {\n  getRefreshToken,\n  getToken,\n  saveAuthData,\n  clearStorage,\n} from './authStore';\n\nconst REFRESH_TOKEN_MUTATION = gql`\n  mutation RefreshCredentials($refreshToken: String!) {\n    refreshCredentials(refreshToken: $refreshToken) {\n      refreshToken\n      token\n    }\n  }\n`;\n\nconst auth = authExchange(async utilities => {\n  let token = getToken();\n  let refreshToken = getRefreshToken();\n\n  return {\n    addAuthToOperation(operation) {\n      return token\n        ? utilities.appendHeaders(operation, {\n            Authorization: `Bearer ${token}`,\n          })\n        : operation;\n    },\n    didAuthError(error) {\n      return error.graphQLErrors.some(\n        e => e.extensions?.code === 'UNAUTHORIZED'\n      );\n    },\n    willAuthError(operation) {\n      // Sync tokens on every operation\n      token = getToken();\n      refreshToken = getRefreshToken();\n\n      if (!token) {\n        // Detect our login mutation and let this operation through:\n        return (\n          operation.kind !== 'mutation' ||\n          // Here we find any mutation definition with the \"signin\" field\n          !operation.query.definitions.some(definition => {\n            return (\n              definition.kind === 'OperationDefinition' &&\n              definition.selectionSet.selections.some(node => {\n                // The field name is just an example, since register may also be an exception\n                return node.kind === 'Field' && node.name.value === 'signin';\n              })\n            );\n          })\n        );\n      }\n      return false;\n    },\n    async refreshAuth() {\n      if (refreshToken) {\n        const result = await utilities.mutate(REFRESH_TOKEN_MUTATION, {\n          refreshToken,\n        });\n\n        if (result.data?.refreshCredentials) {\n          token = result.data.refreshCredentials.token;\n          refreshToken = result.data.refreshCredentials.refreshToken;\n          saveAuthData({ token, refreshToken });\n          return;\n        }\n      }\n\n      // This is where auth has gone wrong and we need to clean up and redirect to a login page\n      clearStorage();\n      window.location.reload();\n    },\n  };\n});\n\nconst client = new Client({\n  url: 'https://trygql.formidable.dev/graphql/web-collections',\n  exchanges: [cacheExchange, auth, fetchExchange],\n});\n\nexport default client;\n"
  },
  {
    "path": "examples/with-refresh-auth/src/index.jsx",
    "content": "import React from 'react';\nimport { createRoot } from 'react-dom/client';\n\nimport App from './App';\n\ncreateRoot(document.getElementById('root')).render(<App />);\n"
  },
  {
    "path": "examples/with-refresh-auth/src/pages/LoginForm.jsx",
    "content": "import React from 'react';\nimport { gql, useMutation } from 'urql';\n\nconst LOGIN_MUTATION = gql`\n  mutation Login($input: LoginInput!) {\n    signin(input: $input) {\n      refreshToken\n      token\n    }\n  }\n`;\n\nconst REGISTER_MUTATION = gql`\n  mutation Register($input: LoginInput!) {\n    register(input: $input) {\n      refreshToken\n      token\n    }\n  }\n`;\n\nconst LoginForm = ({ onLoginSuccess }) => {\n  const [loginResult, login] = useMutation(LOGIN_MUTATION);\n  const [registerResult, register] = useMutation(REGISTER_MUTATION);\n\n  const onSubmitLogin = event => {\n    event.preventDefault();\n    const data = new FormData(event.target);\n    const username = data.get('username');\n    const password = data.get('password');\n\n    login({ input: { username, password } }).then(result => {\n      if (!result.error && result.data && result.data.signin) {\n        onLoginSuccess(result.data.signin);\n      }\n    });\n  };\n\n  const onSubmitRegister = event => {\n    event.preventDefault();\n    const data = new FormData(event.target);\n    const username = data.get('username');\n    const password = data.get('password');\n\n    register({ input: { username, password } }).then(result => {\n      if (!result.error && result.data && result.data.register) {\n        onLoginSuccess(result.data.register);\n      }\n    });\n  };\n\n  const disabled = loginResult.fetching || registerResult.fetching;\n\n  return (\n    <>\n      <form onSubmit={onSubmitLogin}>\n        {loginResult.fetching ? <p>Logging in...</p> : null}\n        {loginResult.error ? <p>Oh no... {loginResult.error.message}</p> : null}\n\n        <fieldset disabled={disabled ? 'disabled' : null}>\n          <h3>Login</h3>\n          <label>\n            Username:\n            <input name=\"username\" type=\"text\" />\n          </label>\n\n          <label>\n            Password:\n            <input name=\"password\" type=\"password\" />\n          </label>\n\n          <button type=\"submit\">Login</button>\n        </fieldset>\n      </form>\n\n      <form onSubmit={onSubmitRegister}>\n        {registerResult.fetching ? <p>Signing up...</p> : null}\n        {registerResult.error ? (\n          <p>Oh no... {registerResult.error.message}</p>\n        ) : null}\n\n        <fieldset disabled={disabled ? 'disabled' : null}>\n          <h3>Register</h3>\n          <label>\n            {'Username: '}\n            <input name=\"username\" type=\"text\" />\n          </label>\n\n          <label>\n            {'Password: '}\n            <input name=\"password\" type=\"password\" />\n          </label>\n\n          <button type=\"submit\">Register</button>\n        </fieldset>\n      </form>\n    </>\n  );\n};\n\nexport default LoginForm;\n"
  },
  {
    "path": "examples/with-refresh-auth/src/pages/Profile.jsx",
    "content": "import React from 'react';\nimport { gql, useQuery } from 'urql';\n\nconst PROFILE_QUERY = gql`\n  query Profile {\n    me {\n      id\n      username\n      createdAt\n    }\n  }\n`;\n\nconst Profile = () => {\n  const [result] = useQuery({ query: PROFILE_QUERY });\n\n  const { data, fetching, error } = result;\n\n  return (\n    <div>\n      {fetching && <p>Loading...</p>}\n\n      {error && <p>Oh no... {error.message}</p>}\n\n      {data?.me && (\n        <>\n          <p>profile data</p>\n          <p>id: {data.me.id}</p>\n          <p>username: {data.me.username}</p>\n        </>\n      )}\n    </div>\n  );\n};\n\nexport default Profile;\n"
  },
  {
    "path": "examples/with-refresh-auth/vite.config.js",
    "content": "import { defineConfig } from 'vite';\nimport react from '@vitejs/plugin-react';\n\n// https://vitejs.dev/config/\nexport default defineConfig({\n  plugins: [react()],\n});\n"
  },
  {
    "path": "examples/with-retry/README.md",
    "content": "# Integrating `@urql/exchange-retry`’s retryExchange\n\n<p>\n  <a href=\"https://stackblitz.com/github/urql-graphql/urql/tree/main/examples/with-retry\">\n    <img\n      alt=\"Open in StackBlitz\"\n      src=\"https://img.shields.io/badge/open_in_stackblitz-1269D3?logo=stackblitz&style=for-the-badge\"\n    />\n  </a>\n  <a href=\"https://codesandbox.io/p/sandbox/github/urql-graphql/urql/tree/main/examples/with-retry\">\n    <img\n      alt=\"Open in CodeSandbox\"\n      src=\"https://img.shields.io/badge/open_in_codesandbox-151515?logo=codesandbox&style=for-the-badge\"\n    />\n  </a>\n</p>\n\nIntegrating urql is as simple as:\n\n1.  Install packages\n\n```sh\nyarn add urql graphql\n# or\nnpm install --save urql graphql\n```\n\n2. Add [retry exchange](https://formidable.com/open-source/urql/docs/advanced/retry-operations/)\n\n```sh\nyarn add @urql/exchange-retry\n# or\nnpm install --save @urql/exchange-retry\n```\n\n3.  Setting up the Client and adding the `retryExchange` [here](src/App.js)\n\n4.  Execute the Query [here](src/pages/Color.js)\n\n# With Retry\n\nThis example shows `urql` in use with `@urql/exchange-retry`'s `retryExchange`\nto implement retrying failed operations. This largely follows the [\"Retrying Operations\" docs\npage](https://formidable.com/open-source/urql/docs/advanced/retry-operations/)\nand uses the [`trygql.formidable.dev/graphql/intermittent-colors`\nschema](https://github.com/FormidableLabs/trygql), which emits a special `NO_SOUP` error randomly.\n\nTo run this example install dependencies and run the `start` script:\n\n```sh\nyarn install\nyarn run start\n# or\nnpm install\nnpm run start\n```\n\nThis example contains:\n\n- The `urql` bindings and a React app with a client set up in [`src/App.jsx`](src/App.jsx)\n- The `retryExchange` from `@urql/exchange-retry` in [`src/App.jsx`](src/App.jsx)\n- A random colour query in [`src/Color.jsx`](src/pages/Color.jsx)\n"
  },
  {
    "path": "examples/with-retry/index.html",
    "content": "<!doctype html>\n<html lang=\"en\">\n  <head>\n    <meta charset=\"UTF-8\" />\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\" />\n    <title>with-retry</title>\n    <style>\n      body {\n        margin: 0;\n        font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto',\n          'Oxygen', 'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans',\n          'Helvetica Neue', sans-serif;\n        -webkit-font-smoothing: antialiased;\n        -moz-osx-font-smoothing: grayscale;\n      }\n\n      code {\n        font-family: source-code-pro, Menlo, Monaco, Consolas, 'Courier New',\n          monospace;\n      }\n    </style>\n  </head>\n  <body>\n    <div id=\"root\"></div>\n    <script type=\"module\" src=\"/src/index.jsx\"></script>\n  </body>\n</html>\n"
  },
  {
    "path": "examples/with-retry/package.json",
    "content": "{\n  \"name\": \"with-retry\",\n  \"version\": \"0.0.0\",\n  \"private\": true,\n  \"scripts\": {\n    \"start\": \"vite\"\n  },\n  \"dependencies\": {\n    \"@urql/core\": \"^6.0.1\",\n    \"@urql/exchange-retry\": \"^2.0.0\",\n    \"graphql\": \"^16.6.0\",\n    \"react\": \"^18.2.0\",\n    \"react-dom\": \"^18.2.0\",\n    \"urql\": \"^5.0.1\"\n  },\n  \"devDependencies\": {\n    \"@vitejs/plugin-react\": \"^3.1.0\",\n    \"vite\": \"^4.2.0\"\n  }\n}\n"
  },
  {
    "path": "examples/with-retry/src/App.jsx",
    "content": "import React from 'react';\nimport { Client, fetchExchange, Provider } from 'urql';\nimport { retryExchange } from '@urql/exchange-retry';\n\nimport Color from './Color';\n\nconst client = new Client({\n  url: 'https://trygql.formidable.dev/graphql/intermittent-colors',\n  exchanges: [\n    retryExchange({\n      maxNumberAttempts: 10,\n      maxDelayMs: 500,\n      retryIf: error => {\n        // NOTE: With this deemo schema we have a specific random error to look out for:\n        return (\n          error.graphQLErrors.some(x => x.extensions?.code === 'NO_SOUP') ||\n          !!error.networkError\n        );\n      },\n    }),\n    fetchExchange,\n  ],\n});\n\nfunction App() {\n  return (\n    <Provider value={client}>\n      <Color />\n    </Provider>\n  );\n}\n\nexport default App;\n"
  },
  {
    "path": "examples/with-retry/src/Color.jsx",
    "content": "import React from 'react';\nimport { gql, useQuery } from 'urql';\n\nconst RANDOM_COLOR_QUERY = gql`\n  query RandomColor {\n    randomColor {\n      name\n      hex\n    }\n  }\n`;\n\nconst RandomColorDisplay = () => {\n  const [result] = useQuery({ query: RANDOM_COLOR_QUERY });\n\n  const { data, fetching, error } = result;\n\n  return (\n    <div>\n      {fetching && <p>Loading...</p>}\n\n      {error && <p>Oh no... {error.message}</p>}\n\n      {data && (\n        <div style={{ backgroundColor: data.randomColor.hex }}>\n          {data.randomColor.name}\n        </div>\n      )}\n\n      {result.operation && (\n        <p>\n          To get a result, the retry exchange retried:{' '}\n          {result.operation.context.retryCount || 0} times.\n        </p>\n      )}\n    </div>\n  );\n};\n\nexport default RandomColorDisplay;\n"
  },
  {
    "path": "examples/with-retry/src/index.jsx",
    "content": "import React from 'react';\nimport { createRoot } from 'react-dom/client';\n\nimport App from './App';\n\ncreateRoot(document.getElementById('root')).render(<App />);\n"
  },
  {
    "path": "examples/with-retry/vite.config.js",
    "content": "import { defineConfig } from 'vite';\nimport react from '@vitejs/plugin-react';\n\n// https://vitejs.dev/config/\nexport default defineConfig({\n  plugins: [react()],\n});\n"
  },
  {
    "path": "examples/with-solid/.eslintrc.js",
    "content": "module.exports = {\n  rules: {\n    'react/react-in-jsx-scope': 'off',\n  },\n};\n"
  },
  {
    "path": "examples/with-solid/README.md",
    "content": "# URQL with Solid\n\nThis example demonstrates how to use URQL with Solid.js.\n\n## Features\n\n- Basic query with `createQuery`\n- Client setup with `Provider`\n- Suspense integration\n\n## Getting Started\n\n```bash\npnpm install\npnpm start\n```\n\nThen open [http://localhost:5173](http://localhost:5173) in your browser.\n\n## What's Inside\n\n- `src/App.jsx` - Sets up the URQL client and provider\n- `src/PokemonList.jsx` - Demonstrates `createQuery` with Suspense\n\n## Learn More\n\n- [Solid Documentation](https://www.solidjs.com/)\n- [URQL Solid Documentation](https://formidable.com/open-source/urql/docs/basics/solid/)\n"
  },
  {
    "path": "examples/with-solid/index.html",
    "content": "<!DOCTYPE html>\n<html lang=\"en\">\n  <head>\n    <meta charset=\"UTF-8\" />\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\" />\n    <title>URQL with Solid</title>\n  </head>\n  <body>\n    <div id=\"root\"></div>\n    <script type=\"module\" src=\"/src/index.jsx\"></script>\n  </body>\n</html>\n"
  },
  {
    "path": "examples/with-solid/package.json",
    "content": "{\n  \"name\": \"with-solid\",\n  \"version\": \"0.0.0\",\n  \"private\": true,\n  \"scripts\": {\n    \"start\": \"vite\",\n    \"build\": \"vite build\"\n  },\n  \"dependencies\": {\n    \"@urql/core\": \"^6.0.1\",\n    \"@urql/solid\": \"^1.0.1\",\n    \"graphql\": \"^16.9.0\",\n    \"solid-js\": \"^1.9.10\"\n  },\n  \"devDependencies\": {\n    \"vite\": \"^7.3.1\",\n    \"vite-plugin-solid\": \"^2.11.10\"\n  }\n}\n"
  },
  {
    "path": "examples/with-solid/src/App.jsx",
    "content": "/** @jsxImportSource solid-js */\nimport {\n  createClient,\n  Provider,\n  cacheExchange,\n  fetchExchange,\n} from '@urql/solid';\nimport PokemonList from './PokemonList';\n\nconst client = createClient({\n  url: 'https://trygql.formidable.dev/graphql/basic-pokedex',\n  exchanges: [cacheExchange, fetchExchange],\n});\n\nfunction App() {\n  return (\n    <Provider value={client}>\n      <PokemonList />\n    </Provider>\n  );\n}\n\nexport default App;\n"
  },
  {
    "path": "examples/with-solid/src/PokemonList.jsx",
    "content": "/** @jsxImportSource solid-js */\nimport { Suspense, For } from 'solid-js';\nimport { gql } from '@urql/core';\nimport { createQuery } from '@urql/solid';\n\nconst POKEMONS_QUERY = gql`\n  query Pokemons {\n    pokemons(limit: 10) {\n      id\n      name\n    }\n  }\n`;\n\nconst PokemonList = () => {\n  const [result] = createQuery({ query: POKEMONS_QUERY });\n\n  return (\n    <div>\n      <h1>Pokemon List</h1>\n      <Suspense fallback={<p>Loading...</p>}>\n        <ul>\n          <For each={result.data?.pokemons}>\n            {pokemon => <li>{pokemon.name}</li>}\n          </For>\n        </ul>\n      </Suspense>\n    </div>\n  );\n};\n\nexport default PokemonList;\n"
  },
  {
    "path": "examples/with-solid/src/index.jsx",
    "content": "/** @jsxImportSource solid-js */\nimport { render } from 'solid-js/web';\nimport App from './App';\n\nrender(() => <App />, document.getElementById('root'));\n"
  },
  {
    "path": "examples/with-solid/vite.config.js",
    "content": "import { defineConfig } from 'vite';\nimport solid from 'vite-plugin-solid';\n\nexport default defineConfig({\n  plugins: [solid()],\n});\n"
  },
  {
    "path": "examples/with-solid-start/.gitignore",
    "content": "/.output\n/.vinxi\n\n.DS_Store\n"
  },
  {
    "path": "examples/with-solid-start/README.md",
    "content": "# URQL with SolidStart\n\nThis example demonstrates how to use URQL with SolidStart.\n\n## Features\n\n- Basic query with `createQuery`\n- Client setup with `Provider`\n- SSR with automatic hydration\n- Route-level preloading\n- Suspense integration\n\n## Getting Started\n\n```bash\npnpm install\npnpm start\n```\n\nThen open [http://localhost:3000](http://localhost:3000) in your browser.\n\n## What's Inside\n\n- `src/app.tsx` - Sets up the URQL client and router\n- `src/routes/index.tsx` - Demonstrates `createQuery` with preloading and Suspense\n\n## Key Features Demonstrated\n\n### Route Preloading\n\nThe example uses SolidStart's `preload` function to start fetching data before the route component renders:\n\n```tsx\nexport const route = {\n  preload: () => {\n    const pokemons = createQuery({ query: POKEMONS_QUERY });\n    return pokemons(); // Start fetching\n  },\n} satisfies RouteDefinition;\n```\n\n### Server-Side Rendering\n\nQueries automatically execute on the server during SSR and hydrate on the client without refetching.\n\n## Learn More\n\n- [SolidStart Documentation](https://start.solidjs.com/)\n- [URQL SolidStart Documentation](https://formidable.com/open-source/urql/docs/basics/solid-start/)\n"
  },
  {
    "path": "examples/with-solid-start/app.config.ts",
    "content": "import { defineConfig } from '@solidjs/start/config';\n\nexport default defineConfig({});\n"
  },
  {
    "path": "examples/with-solid-start/package.json",
    "content": "{\n  \"name\": \"with-solid-start\",\n  \"version\": \"0.0.0\",\n  \"private\": true,\n  \"type\": \"module\",\n  \"scripts\": {\n    \"start\": \"vinxi dev\",\n    \"build\": \"vinxi build\"\n  },\n  \"dependencies\": {\n    \"@solidjs/router\": \"^0.15.4\",\n    \"@solidjs/start\": \"^1.2.1\",\n    \"@urql/core\": \"^6.0.1\",\n    \"@urql/solid-start\": \"^0.1.0\",\n    \"graphql\": \"^16.9.0\",\n    \"solid-js\": \"^1.9.10\",\n    \"vinxi\": \"^0.5.0\"\n  },\n  \"devDependencies\": {\n    \"vite\": \"^7.3.1\",\n    \"vite-plugin-solid\": \"^2.11.10\"\n  }\n}\n"
  },
  {
    "path": "examples/with-solid-start/src/app.tsx",
    "content": "import { Router, action, query } from '@solidjs/router';\nimport { FileRoutes } from '@solidjs/start/router';\nimport { Suspense } from 'solid-js';\nimport {\n  createClient,\n  Provider,\n  cacheExchange,\n  fetchExchange,\n} from '@urql/solid-start';\n\nconst client = createClient({\n  url: 'https://trygql.formidable.dev/graphql/basic-pokedex',\n  exchanges: [cacheExchange, fetchExchange],\n});\n\nexport default function App() {\n  return (\n    <Router\n      root={props => (\n        <Provider value={{ client, query, action }}>\n          <Suspense>{props.children}</Suspense>\n        </Provider>\n      )}\n    >\n      <FileRoutes />\n    </Router>\n  );\n}\n"
  },
  {
    "path": "examples/with-solid-start/src/entry-client.tsx",
    "content": "// @refresh reload\nimport { mount, StartClient } from '@solidjs/start/client';\n\nmount(() => <StartClient />, document.getElementById('app')!);\n"
  },
  {
    "path": "examples/with-solid-start/src/entry-server.tsx",
    "content": "// @refresh reload\nimport { createHandler, StartServer } from '@solidjs/start/server';\n\nexport default createHandler(() => (\n  <StartServer\n    document={({ assets, children, scripts }) => (\n      <html lang=\"en\">\n        <head>\n          <meta charset=\"utf-8\" />\n          <meta name=\"viewport\" content=\"width=device-width, initial-scale=1\" />\n          <title>URQL with SolidStart</title>\n          {assets}\n        </head>\n        <body>\n          <div id=\"app\">{children}</div>\n          {scripts}\n        </body>\n      </html>\n    )}\n  />\n));\n"
  },
  {
    "path": "examples/with-solid-start/src/routes/index.tsx",
    "content": "import { Suspense, For, Show, createSignal } from 'solid-js';\nimport { createAsync, useAction, useSubmission } from '@solidjs/router';\nimport { gql } from '@urql/core';\nimport { createQuery, createMutation } from '@urql/solid-start';\n\nconst POKEMONS_QUERY = gql`\n  query Pokemons {\n    pokemons(limit: 10) {\n      id\n      name\n    }\n  }\n`;\n\nconst ADD_POKEMON_MUTATION = gql`\n  mutation AddPokemon($name: String!) {\n    addPokemon(name: $name) {\n      id\n      name\n    }\n  }\n`;\n\nexport default function Home() {\n  const queryPokemons = createQuery(POKEMONS_QUERY, 'list-pokemons');\n  const result = createAsync(() => queryPokemons());\n\n  // Create the mutation action inside the component where it has access to context\n  const addPokemonAction = createMutation(ADD_POKEMON_MUTATION, 'add-pokemon');\n  const addPokemon = useAction(addPokemonAction);\n  const submission = useSubmission(addPokemonAction);\n\n  const [pokemonName, setPokemonName] = createSignal('');\n\n  const handleSubmit = async (e: Event) => {\n    e.preventDefault();\n    const name = pokemonName();\n    if (!name) return;\n\n    const result = await addPokemon({ name });\n    if (result.data) {\n      setPokemonName('');\n      // Note: In a real app, you'd want to refetch or update the cache\n    }\n  };\n\n  return (\n    <main style={{ padding: '20px', 'font-family': 'system-ui' }}>\n      <h1>Pokemon List (SolidStart + URQL)</h1>\n\n      <section style={{ 'margin-bottom': '20px' }}>\n        <h2>Add Pokemon</h2>\n        <form\n          onSubmit={handleSubmit}\n          style={{ display: 'flex', gap: '10px', 'align-items': 'center' }}\n        >\n          <input\n            type=\"text\"\n            value={pokemonName()}\n            onInput={e => setPokemonName(e.currentTarget.value)}\n            placeholder=\"Pokemon name\"\n            style={{ padding: '8px', 'font-size': '14px' }}\n          />\n          <button\n            type=\"submit\"\n            disabled={submission.pending}\n            style={{\n              padding: '8px 16px',\n              'font-size': '14px',\n              cursor: submission.pending ? 'not-allowed' : 'pointer',\n            }}\n          >\n            {submission.pending ? 'Adding...' : 'Add Pokemon'}\n          </button>\n        </form>\n        <Show when={submission.result && submission.result.error}>\n          <p style={{ color: 'red' }}>\n            Error: {submission.result.error.message}\n          </p>\n        </Show>\n        <Show when={submission.result && submission.result.data}>\n          <p style={{ color: 'green' }}>\n            Added: {submission.result.data.addPokemon.name}\n          </p>\n        </Show>\n      </section>\n\n      <section>\n        <h2>Pokemon List</h2>\n        <Suspense fallback={<p>Loading...</p>}>\n          <Show when={result() && result()!.data}>\n            <ul>\n              <For each={result()!.data!.pokemons}>\n                {pokemon => <li>{pokemon.name}</li>}\n              </For>\n            </ul>\n          </Show>\n        </Suspense>\n      </section>\n    </main>\n  );\n}\n"
  },
  {
    "path": "examples/with-solid-start/tsconfig.json",
    "content": "{\n  \"compilerOptions\": {\n    \"jsx\": \"preserve\",\n    \"jsxImportSource\": \"solid-js\",\n    \"module\": \"ESNext\",\n    \"moduleResolution\": \"bundler\",\n    \"target\": \"ESNext\",\n    \"types\": [\"vite/client\"],\n    \"isolatedModules\": true,\n    \"resolveJsonModule\": true,\n    \"esModuleInterop\": true,\n    \"skipLibCheck\": true,\n    \"strict\": true,\n    \"noEmit\": true\n  }\n}\n"
  },
  {
    "path": "examples/with-subscriptions-via-fetch/README.md",
    "content": "# With Subscriptions via Fetch\n\n<p>\n  <a\n  href=\"https://stackblitz.com/github/urql-graphql/urql/tree/main/examples/with-subscriptions-via-fetch\">\n    <img\n      alt=\"Open in StackBlitz\"\n      src=\"https://img.shields.io/badge/open_in_stackblitz-1269D3?logo=stackblitz&style=for-the-badge\"\n    />\n  </a>\n  <a\n  href=\"https://codesandbox.io/p/sandbox/github/urql-graphql/urql/tree/main/examples/with-subscriptions-via-fetch\">\n    <img\n      alt=\"Open in CodeSandbox\"\n      src=\"https://img.shields.io/badge/open_in_codesandbox-151515?logo=codesandbox&style=for-the-badge\"\n    />\n  </a>\n</p>\n\nThis example shows `urql` in use with subscriptions running via a plain `fetch`\nHTTP request to GraphQL Yoga. This uses the [GraphQL Server-Sent\nEvents](https://the-guild.dev/blog/graphql-over-sse) protocol, which means that\nthe request streams in more results via a single HTTP response.\n\nThis example also includes Graphcache [\"Cache\nUpdates\"](https://formidable.com/open-source/urql/docs/graphcache/cache-updates/)\nto update a list with incoming items from the subscriptions.\n\nTo run this example install dependencies and run the `start` script:\n\n```sh\nyarn install\nyarn run start\n# or\nnpm install\nnpm run start\n```\n\nThis example contains:\n\n- The `urql` bindings and a React app with a client set up in [`src/App.jsx`](src/App.jsx)\n- A local `graphql-yoga` server set up to test subscriptions in [`server/`](server/).\n"
  },
  {
    "path": "examples/with-subscriptions-via-fetch/index.html",
    "content": "<!doctype html>\n<html lang=\"en\">\n  <head>\n    <meta charset=\"UTF-8\" />\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\" />\n    <title>with-defer-stream-directives</title>\n    <style>\n      body {\n        margin: 0;\n        font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto',\n          'Oxygen', 'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans',\n          'Helvetica Neue', sans-serif;\n        -webkit-font-smoothing: antialiased;\n        -moz-osx-font-smoothing: grayscale;\n      }\n\n      code {\n        font-family: source-code-pro, Menlo, Monaco, Consolas, 'Courier New',\n          monospace;\n      }\n    </style>\n  </head>\n  <body>\n    <div id=\"root\"></div>\n    <script type=\"module\" src=\"/src/index.jsx\"></script>\n  </body>\n</html>\n"
  },
  {
    "path": "examples/with-subscriptions-via-fetch/package.json",
    "content": "{\n  \"name\": \"with-subscriptions-via-fetch\",\n  \"version\": \"0.0.0\",\n  \"private\": true,\n  \"scripts\": {\n    \"server\": \"node server/graphql-yoga.js\",\n    \"client\": \"vite\",\n    \"start\": \"run-p client server\"\n  },\n  \"dependencies\": {\n    \"@urql/core\": \"^6.0.1\",\n    \"@urql/exchange-graphcache\": \"^9.0.0\",\n    \"graphql\": \"^16.6.0\",\n    \"react\": \"^18.2.0\",\n    \"react-dom\": \"^18.2.0\",\n    \"urql\": \"^5.0.1\"\n  },\n  \"devDependencies\": {\n    \"@vitejs/plugin-react\": \"^3.1.0\",\n    \"graphql-yoga\": \"^3.7.1\",\n    \"npm-run-all\": \"^4.1.5\",\n    \"vite\": \"^4.2.0\"\n  }\n}\n"
  },
  {
    "path": "examples/with-subscriptions-via-fetch/server/graphql-yoga.js",
    "content": "const { createYoga } = require('graphql-yoga');\nconst { createServer } = require('http');\nconst { schema } = require('./schema');\n\nconst yoga = createYoga({ schema });\nconst server = createServer(yoga);\nserver.listen(3004);\n"
  },
  {
    "path": "examples/with-subscriptions-via-fetch/server/schema.js",
    "content": "const {\n  GraphQLList,\n  GraphQLObjectType,\n  GraphQLSchema,\n  GraphQLString,\n} = require('graphql');\n\nconst Alphabet = new GraphQLObjectType({\n  name: 'Alphabet',\n  fields: {\n    char: {\n      type: GraphQLString,\n    },\n  },\n});\n\nconst schema = new GraphQLSchema({\n  query: new GraphQLObjectType({\n    name: 'Query',\n    fields: () => ({\n      list: {\n        type: new GraphQLList(Alphabet),\n        resolve() {\n          return [{ char: 'Where are my letters?' }];\n        },\n      },\n    }),\n  }),\n  subscription: new GraphQLObjectType({\n    name: 'Subscription',\n    fields: () => ({\n      alphabet: {\n        type: Alphabet,\n        resolve(root) {\n          return root;\n        },\n        subscribe: async function* () {\n          for (let letter = 65; letter <= 90; letter++) {\n            await new Promise(resolve => setTimeout(resolve, 500));\n            yield { char: String.fromCharCode(letter) };\n          }\n        },\n      },\n    }),\n  }),\n});\n\nmodule.exports = { schema };\n"
  },
  {
    "path": "examples/with-subscriptions-via-fetch/src/App.jsx",
    "content": "import React from 'react';\nimport { Client, Provider, fetchExchange } from 'urql';\n\nimport { cacheExchange } from '@urql/exchange-graphcache';\n\nimport Songs from './Songs';\n\nconst cache = cacheExchange({\n  keys: {\n    Alphabet: data => data.char,\n  },\n  updates: {\n    Subscription: {\n      alphabet(parent, _args, cache) {\n        const list = cache.resolve('Query', 'list') || [];\n        list.push(parent.alphabet);\n        cache.link('Query', 'list', list);\n      },\n    },\n  },\n});\n\nconst client = new Client({\n  url: 'http://localhost:3004/graphql',\n  fetchSubscriptions: true,\n  exchanges: [cache, fetchExchange],\n});\n\nfunction App() {\n  return (\n    <Provider value={client}>\n      <Songs />\n    </Provider>\n  );\n}\n\nexport default App;\n"
  },
  {
    "path": "examples/with-subscriptions-via-fetch/src/Songs.jsx",
    "content": "import React from 'react';\nimport { gql, useQuery, useSubscription } from 'urql';\n\nconst LIST_QUERY = gql`\n  query List_Query {\n    list {\n      char\n    }\n  }\n`;\n\nconst SONG_SUBSCRIPTION = gql`\n  subscription App_Subscription {\n    alphabet {\n      char\n    }\n  }\n`;\n\nconst ListQuery = () => {\n  const [listResult] = useQuery({\n    query: LIST_QUERY,\n  });\n  return (\n    <div>\n      <h3>List</h3>\n      {listResult?.data?.list.map(i => (\n        <div key={i.char}>{i.char}</div>\n      ))}\n    </div>\n  );\n};\n\nconst SongSubscription = () => {\n  const [songsResult] = useSubscription(\n    { query: SONG_SUBSCRIPTION },\n    (prev = [], data) => [...prev, data.alphabet]\n  );\n\n  return (\n    <div>\n      <h3>Song</h3>\n      {songsResult?.data?.map(i => (\n        <div key={i.char}>{i.char}</div>\n      ))}\n    </div>\n  );\n};\n\nconst LocationsList = () => {\n  return (\n    <>\n      <ListQuery />\n      <SongSubscription />\n    </>\n  );\n};\n\nexport default LocationsList;\n"
  },
  {
    "path": "examples/with-subscriptions-via-fetch/src/index.jsx",
    "content": "import React from 'react';\nimport { createRoot } from 'react-dom/client';\n\nimport App from './App';\n\ncreateRoot(document.getElementById('root')).render(<App />);\n"
  },
  {
    "path": "examples/with-subscriptions-via-fetch/vite.config.js",
    "content": "import { defineConfig } from 'vite';\nimport react from '@vitejs/plugin-react';\n\n// https://vitejs.dev/config/\nexport default defineConfig({\n  plugins: [react()],\n});\n"
  },
  {
    "path": "examples/with-svelte/.gitignore",
    "content": "/node_modules/\n/public/build/\n\n.DS_Store\n"
  },
  {
    "path": "examples/with-svelte/README.md",
    "content": "# With Svelte\n\n<p>\n  <a href=\"https://stackblitz.com/github/urql-graphql/urql/tree/main/examples/with-svelte\">\n    <img\n      alt=\"Open in StackBlitz\"\n      src=\"https://img.shields.io/badge/open_in_stackblitz-1269D3?logo=stackblitz&style=for-the-badge\"\n    />\n  </a>\n  <a href=\"https://codesandbox.io/p/sandbox/github/urql-graphql/urql/tree/main/examples/with-svelte\">\n    <img\n      alt=\"Open in CodeSandbox\"\n      src=\"https://img.shields.io/badge/open_in_codesandbox-151515?logo=codesandbox&style=for-the-badge\"\n    />\n  </a>\n</p>\n\nThis example shows `@urql/svelte` in use with Svelte, as explained on the [\"Svelte\" page of the \"Basics\"\ndocumentation.](https://formidable.com/open-source/urql/docs/basics/svelte/)\n\nTo run this example install dependencies and run the `start` script:\n\n```sh\nyarn install\nyarn run start\n# or\nnpm install\nnpm run start\n```\n\nThis example contains:\n\n- The `@urql/svelte` bindings with a client set up in [`src/App.svelte`](src/App.svelte)\n- A query for pokémon in [`src/PokemonList.svelte`](src/pages/PokemonList.svelte)\n"
  },
  {
    "path": "examples/with-svelte/index.html",
    "content": "<!doctype html>\n<html lang=\"en\">\n  <head>\n    <meta charset=\"UTF-8\" />\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\" />\n    <title>with-svelte</title>\n  </head>\n  <body>\n    <div id=\"app\"></div>\n    <script type=\"module\" src=\"/src/main.js\"></script>\n  </body>\n</html>\n"
  },
  {
    "path": "examples/with-svelte/package.json",
    "content": "{\n  \"name\": \"with-svelte\",\n  \"private\": true,\n  \"version\": \"0.0.0\",\n  \"scripts\": {\n    \"start\": \"vite\",\n    \"build\": \"vite build\",\n    \"serve\": \"vite preview\"\n  },\n  \"dependencies\": {\n    \"@urql/core\": \"^6.0.1\",\n    \"@urql/svelte\": \"^5.0.0\",\n    \"graphql\": \"^16.6.0\",\n    \"svelte\": \"^4.0.5\"\n  },\n  \"devDependencies\": {\n    \"@sveltejs/vite-plugin-svelte\": \"^2.4.2\",\n    \"vite\": \"^4.2.0\"\n  }\n}\n"
  },
  {
    "path": "examples/with-svelte/src/App.svelte",
    "content": "<script>\n  import { setContextClient, Client, cacheExchange, fetchExchange } from \"@urql/svelte\";\n  import PokemonList from \"./PokemonList.svelte\";\n\n  setContextClient(new Client({\n    url: \"https://trygql.formidable.dev/graphql/basic-pokedex\",\n    exchanges: [cacheExchange, fetchExchange],\n  }));\n</script>\n\n<PokemonList />\n"
  },
  {
    "path": "examples/with-svelte/src/PokemonList.svelte",
    "content": "<script>\n  import { getContextClient, gql, queryStore } from \"@urql/svelte\";\n\n  let skip = 0;\n  $: pokemons = queryStore({\n    client: getContextClient(),\n    query: gql`\n      query ($skip: Int!) {\n        pokemons(limit: 10, skip: $skip) {\n          id\n          name\n        }\n      }\n    `,\n    variables: { skip },\n    requestPolicy: 'cache-and-network'\n  });\n\n  function nextPage() {\n    skip = skip + 10;\n  }\n\n  function reexcute() {\n    pokemons.reexecute({ requestPolicy: 'network-only' })\n  }\n</script>\n\n<div>\n  {#if $pokemons.fetching}\n    Loading...\n  {:else if $pokemons.error}\n    Oh no... {$pokemons.error.message}\n  {:else}\n    <ul>\n      {#each $pokemons.data.pokemons as pokemon}\n        <li>{pokemon.name}</li>\n      {/each}\n    </ul>\n  {/if}\n  <button on:click={nextPage}>Next Page</button>\n  <button on:click={reexcute}>Reexec</button>\n</div>\n"
  },
  {
    "path": "examples/with-svelte/src/main.js",
    "content": "import App from './App.svelte';\n\nvar app = new App({\n  target: document.body,\n});\n\nexport default app;\n"
  },
  {
    "path": "examples/with-svelte/vite.config.mjs",
    "content": "import { defineConfig } from 'vite';\nimport { svelte } from '@sveltejs/vite-plugin-svelte';\n\n// https://vitejs.dev/config/\nexport default defineConfig({\n  plugins: [svelte()],\n});\n"
  },
  {
    "path": "examples/with-vue3/.gitignore",
    "content": "node_modules\n.DS_Store\ndist\n*.local"
  },
  {
    "path": "examples/with-vue3/README.md",
    "content": "# With Vue 3\n\n<p>\n  <a href=\"https://stackblitz.com/github/urql-graphql/urql/tree/main/examples/with-vue3\">\n    <img\n      alt=\"Open in StackBlitz\"\n      src=\"https://img.shields.io/badge/open_in_stackblitz-1269D3?logo=stackblitz&style=for-the-badge\"\n    />\n  </a>\n  <a href=\"https://codesandbox.io/p/sandbox/github/urql-graphql/urql/tree/main/examples/with-vue3\">\n    <img\n      alt=\"Open in CodeSandbox\"\n      src=\"https://img.shields.io/badge/open_in_codesandbox-151515?logo=codesandbox&style=for-the-badge\"\n    />\n  </a>\n</p>\n\nThis example shows `@urql/vue` in use with Vue 3, as explained on the [\"Vue\" page of the \"Basics\"\ndocumentation.](https://formidable.com/open-source/urql/docs/basics/vue/)\n\nTo run this example install dependencies and run the `start` script:\n\n```sh\nyarn install\nyarn run start\n# or\nnpm install\nnpm run start\n```\n\nThis example contains:\n\n- The `@urql/vue` bindings with a client set up in [`src/App.vue`](src/App.vue)\n- A suspense loading boundary in the `App` component in [`src/App.vue`](src/App.vue)\n- A query for pokémon in [`src/PokemonList.vue`](src/pages/PokemonList.vue)\n"
  },
  {
    "path": "examples/with-vue3/index.html",
    "content": "<!doctype html>\n<html lang=\"en\">\n  <head>\n    <meta charset=\"UTF-8\" />\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\" />\n    <title>Vite App</title>\n  </head>\n  <body>\n    <div id=\"app\"></div>\n    <script type=\"module\" src=\"/src/main.js\"></script>\n  </body>\n</html>\n"
  },
  {
    "path": "examples/with-vue3/package.json",
    "content": "{\n  \"name\": \"with-vue3\",\n  \"version\": \"0.0.0\",\n  \"private\": true,\n  \"scripts\": {\n    \"start\": \"vite\",\n    \"build\": \"vite build\",\n    \"serve\": \"vite preview\"\n  },\n  \"dependencies\": {\n    \"@urql/core\": \"^6.0.1\",\n    \"@urql/vue\": \"^2.0.0\",\n    \"graphql\": \"^16.6.0\",\n    \"vue\": \"^3.2.47\"\n  },\n  \"devDependencies\": {\n    \"@vitejs/plugin-vue\": \"^4.1.0\",\n    \"vite\": \"^4.2.0\"\n  }\n}\n"
  },
  {
    "path": "examples/with-vue3/src/App.vue",
    "content": "<template>\n  <Suspense>\n    <template #default>\n      <PokemonList />\n    </template>\n    <template #fallback>\n      <div>Loading...</div>\n    </template>\n  </Suspense>\n</template>\n\n<script>\nimport { provideClient, cacheExchange, fetchExchange } from '@urql/vue';\nimport PokemonList from './PokemonList.vue';\n\nexport default {\n  name: 'App',\n  setup() {\n    provideClient({\n      url: 'https://trygql.formidable.dev/graphql/basic-pokedex',\n      exchanges: [cacheExchange, fetchExchange],\n    });\n  },\n  components: {\n    PokemonList,\n  },\n};\n</script>\n"
  },
  {
    "path": "examples/with-vue3/src/PokemonList.vue",
    "content": "<template>\n  <div>\n    <ul v-if=\"pokemons\">\n      <li v-for=\"pokemon in pokemons.pokemons\" :key=\"pokemon.id\">\n        {{ pokemon.name }}\n      </li>\n    </ul>\n    <button @click=\"nextPage\">Next Page</button>\n  </div>\n</template>\n\n<script>\nimport { ref, computed } from 'vue';\nimport { gql, useQuery } from '@urql/vue';\n\nexport default {\n  async setup() {\n    const skip = ref(0);\n\n    const pokemons = await useQuery({\n      query: gql`\n        query ($skip: Int!) {\n          pokemons(limit: 10, skip: $skip) {\n            id\n            name\n          }\n        }\n      `,\n      variables: { skip },\n    });\n\n    return {\n      pokemons: pokemons.data,\n      nextPage() {\n        skip.value += 10;\n      },\n    };\n  },\n  name: 'PokemonList',\n};\n</script>\n"
  },
  {
    "path": "examples/with-vue3/src/main.js",
    "content": "import { createApp } from 'vue';\nimport App from './App.vue';\n\ncreateApp(App).mount('#app');\n"
  },
  {
    "path": "examples/with-vue3/vite.config.js",
    "content": "import { defineConfig } from 'vite';\nimport vue from '@vitejs/plugin-vue';\n\n// https://vitejs.dev/config/\nexport default defineConfig({\n  plugins: [vue()],\n});\n"
  },
  {
    "path": "exchanges/auth/CHANGELOG.md",
    "content": "# Changelog\n\n## 3.0.0\n\n### Patch Changes\n\n- Updated dependencies (See [#3789](https://github.com/urql-graphql/urql/pull/3789) and [#3807](https://github.com/urql-graphql/urql/pull/3807))\n  - @urql/core@6.0.0\n\n## 2.2.1\n\n### Patch Changes\n\n- Omit minified files and sourcemaps' `sourcesContent` in published packages\n  Submitted by [@kitten](https://github.com/kitten) (See [#3755](https://github.com/urql-graphql/urql/pull/3755))\n- Updated dependencies (See [#3755](https://github.com/urql-graphql/urql/pull/3755))\n  - @urql/core@5.1.1\n\n## 2.2.0\n\n### Minor Changes\n\n- Mark `@urql/core` as a peer dependency as well as a regular dependency\n  Submitted by [@kitten](https://github.com/kitten) (See [#3579](https://github.com/urql-graphql/urql/pull/3579))\n\n## 2.1.6\n\n### Patch Changes\n\n- `authExchange()` will now block and pass on errors if the initialization function passed to it fails, and will retry indefinitely. It’ll also output a warning for these cases, as the initialization function (i.e. `authExchange(async (utils) => { /*...*/ })`) is not expected to reject/throw\n  Submitted by [@kitten](https://github.com/kitten) (See [#3343](https://github.com/urql-graphql/urql/pull/3343))\n\n## 2.1.5\n\n### Patch Changes\n\n- Handle `refreshAuth` rejections and pass the resulting error on to `OperationResult`s on the authentication queue\n  Submitted by [@kitten](https://github.com/kitten) (See [#3307](https://github.com/urql-graphql/urql/pull/3307))\n\n## 2.1.4\n\n### Patch Changes\n\n- ⚠️ Fix regression that caused teardowns to be ignored by an `authExchange`’s retry queue\n  Submitted by [@kitten](https://github.com/kitten) (See [#3235](https://github.com/urql-graphql/urql/pull/3235))\n\n## 2.1.3\n\n### Patch Changes\n\n- Update build process to generate correct source maps\n  Submitted by [@kitten](https://github.com/kitten) (See [#3201](https://github.com/urql-graphql/urql/pull/3201))\n\n## 2.1.2\n\n### Patch Changes\n\n- Publish with npm provenance\n  Submitted by [@kitten](https://github.com/kitten) (See [#3180](https://github.com/urql-graphql/urql/pull/3180))\n\n## 2.1.1\n\n### Patch Changes\n\n- ⚠️ Fix operations created by `utilities.mutate()` erroneously being retried and sent again like a regular operation\n  Submitted by [@JoviDeCroock](https://github.com/JoviDeCroock) (See [#3164](https://github.com/urql-graphql/urql/pull/3164))\n\n## 2.1.0\n\n### Minor Changes\n\n- Update exchanges to drop redundant `share` calls, since `@urql/core`’s `composeExchanges` utility now automatically does so for us\n  Submitted by [@kitten](https://github.com/kitten) (See [#3082](https://github.com/urql-graphql/urql/pull/3082))\n\n### Patch Changes\n\n- ⚠️ Fix source maps included with recently published packages, which lost their `sourcesContent`, including additional source files, and had incorrect paths in some of them\n  Submitted by [@kitten](https://github.com/kitten) (See [#3053](https://github.com/urql-graphql/urql/pull/3053))\n- Upgrade to `wonka@^6.3.0`\n  Submitted by [@kitten](https://github.com/kitten) (See [#3104](https://github.com/urql-graphql/urql/pull/3104))\n- Avoid infinite loop when `didAuthError` keeps returning true\n  Submitted by [@JoviDeCroock](https://github.com/JoviDeCroock) (See [#3112](https://github.com/urql-graphql/urql/pull/3112))\n- Updated dependencies (See [#3101](https://github.com/urql-graphql/urql/pull/3101), [#3033](https://github.com/urql-graphql/urql/pull/3033), [#3054](https://github.com/urql-graphql/urql/pull/3054), [#3053](https://github.com/urql-graphql/urql/pull/3053), [#3060](https://github.com/urql-graphql/urql/pull/3060), [#3081](https://github.com/urql-graphql/urql/pull/3081), [#3039](https://github.com/urql-graphql/urql/pull/3039), [#3104](https://github.com/urql-graphql/urql/pull/3104), [#3082](https://github.com/urql-graphql/urql/pull/3082), [#3097](https://github.com/urql-graphql/urql/pull/3097), [#3061](https://github.com/urql-graphql/urql/pull/3061), [#3055](https://github.com/urql-graphql/urql/pull/3055), [#3085](https://github.com/urql-graphql/urql/pull/3085), [#3079](https://github.com/urql-graphql/urql/pull/3079), [#3087](https://github.com/urql-graphql/urql/pull/3087), [#3059](https://github.com/urql-graphql/urql/pull/3059), [#3055](https://github.com/urql-graphql/urql/pull/3055), [#3057](https://github.com/urql-graphql/urql/pull/3057), [#3050](https://github.com/urql-graphql/urql/pull/3050), [#3062](https://github.com/urql-graphql/urql/pull/3062), [#3051](https://github.com/urql-graphql/urql/pull/3051), [#3043](https://github.com/urql-graphql/urql/pull/3043), [#3063](https://github.com/urql-graphql/urql/pull/3063), [#3054](https://github.com/urql-graphql/urql/pull/3054), [#3102](https://github.com/urql-graphql/urql/pull/3102), [#3097](https://github.com/urql-graphql/urql/pull/3097), [#3106](https://github.com/urql-graphql/urql/pull/3106), [#3058](https://github.com/urql-graphql/urql/pull/3058), and [#3062](https://github.com/urql-graphql/urql/pull/3062))\n  - @urql/core@4.0.0\n\n## 2.0.0\n\n### Major Changes\n\n- Implement new `authExchange` API, which removes the need for an `authState` (i.e. an internal authentication state) and removes `getAuth`, replacing it with a separate `refreshAuth` flow.\n  The new API requires you to now pass an initializer function. This function receives a `utils`\n  object with `utils.mutate` and `utils.appendHeaders` utility methods.\n  It must return the configuration object, wrapped in a promise, and this configuration is similar to\n  what we had before, if you're migrating to this. Its `refreshAuth` method is now only called after\n  authentication errors occur and not on initialization. Instead, it's now recommended that you write\n  your initialization logic in-line.\n  ```js\n  authExchange(async utils => {\n    let token = localStorage.getItem('token');\n    let refreshToken = localStorage.getItem('refreshToken');\n    return {\n      addAuthToOperation(operation) {\n        return utils.appendHeaders(operation, {\n          Authorization: `Bearer ${token}`,\n        });\n      },\n      didAuthError(error) {\n        return error.graphQLErrors.some(\n          e => e.extensions?.code === 'FORBIDDEN'\n        );\n      },\n      async refreshAuth() {\n        const result = await utils.mutate(REFRESH, { token });\n        if (result.data?.refreshLogin) {\n          token = result.data.refreshLogin.token;\n          refreshToken = result.data.refreshLogin.refreshToken;\n          localStorage.setItem('token', token);\n          localStorage.setItem('refreshToken', refreshToken);\n        }\n      },\n    };\n  });\n  ```\n  Submitted by [@kitten](https://github.com/kitten) (See [#3012](https://github.com/urql-graphql/urql/pull/3012))\n\n### Patch Changes\n\n- ⚠️ Fix `willAuthError` not being called for operations that are waiting on the authentication state to update. This can actually lead to a common issue where operations that came in during the authentication initialization (on startup) will never have `willAuthError` called on them. This can cause an easy mistake where the initial authentication state is never checked to be valid\n  Submitted by [@kitten](https://github.com/kitten) (See [#3017](https://github.com/urql-graphql/urql/pull/3017))\n- Updated dependencies (See [#3007](https://github.com/urql-graphql/urql/pull/3007), [#2962](https://github.com/urql-graphql/urql/pull/2962), [#3007](https://github.com/urql-graphql/urql/pull/3007), [#3015](https://github.com/urql-graphql/urql/pull/3015), and [#3022](https://github.com/urql-graphql/urql/pull/3022))\n  - @urql/core@3.2.0\n\n## 1.0.0\n\n### Major Changes\n\n- **Goodbye IE11!** 👋 This major release removes support for IE11. All code that is shipped will be transpiled much less and will _not_ be ES5-compatible anymore, by [@kitten](https://github.com/kitten) (See [#2504](https://github.com/FormidableLabs/urql/pull/2504))\n- Upgrade to [Wonka v6](https://github.com/0no-co/wonka) (`wonka@^6.0.0`), which has no breaking changes but is built to target ES2015 and comes with other minor improvements.\n  The library has fully been migrated to TypeScript which will hopefully help with making contributions easier!, by [@kitten](https://github.com/kitten) (See [#2504](https://github.com/FormidableLabs/urql/pull/2504))\n\n### Minor Changes\n\n- Remove the `babel-plugin-modular-graphql` helper, this because the graphql package hasn't converted to ESM yet which gives issues in node environments, by [@JoviDeCroock](https://github.com/JoviDeCroock) (See [#2551](https://github.com/FormidableLabs/urql/pull/2551))\n\n### Patch Changes\n\n- Updated dependencies (See [#2551](https://github.com/FormidableLabs/urql/pull/2551), [#2504](https://github.com/FormidableLabs/urql/pull/2504), [#2619](https://github.com/FormidableLabs/urql/pull/2619), [#2607](https://github.com/FormidableLabs/urql/pull/2607), and [#2504](https://github.com/FormidableLabs/urql/pull/2504))\n  - @urql/core@3.0.0\n\n## 0.1.7\n\n### Patch Changes\n\n- Extend peer dependency range of `graphql` to include `^16.0.0`.\n  As always when upgrading across many packages of `urql`, especially including `@urql/core` we recommend you to deduplicate dependencies after upgrading, using `npm dedupe` or `npx yarn-deduplicate`, by [@kitten](https://github.com/kitten) (See [#2133](https://github.com/FormidableLabs/urql/pull/2133))\n- Updated dependencies (See [#2133](https://github.com/FormidableLabs/urql/pull/2133))\n  - @urql/core@2.3.6\n\n## 0.1.6\n\n### Patch Changes\n\n- ⚠️ Fix willAuthError causing duplicate operations, by [@yankovalera](https://github.com/yankovalera) (See [#1849](https://github.com/FormidableLabs/urql/pull/1849))\n- Updated dependencies (See [#1851](https://github.com/FormidableLabs/urql/pull/1851), [#1850](https://github.com/FormidableLabs/urql/pull/1850), and [#1852](https://github.com/FormidableLabs/urql/pull/1852))\n  - @urql/core@2.2.0\n\n## 0.1.5\n\n### Patch Changes\n\n- Expose `AuthContext` type, by [@arempe93](https://github.com/arempe93) (See [#1828](https://github.com/FormidableLabs/urql/pull/1828))\n- Updated dependencies (See [#1829](https://github.com/FormidableLabs/urql/pull/1829))\n  - @urql/core@2.1.6\n\n## 0.1.4\n\n### Patch Changes\n\n- Allow `mutate` to infer the result's type when a `TypedDocumentNode` is passed via the usual generics, like `client.mutation` for instance, by [@younesmln](https://github.com/younesmln) (See [#1796](https://github.com/FormidableLabs/urql/pull/1796))\n\n## 0.1.3\n\n### Patch Changes\n\n- Remove closure-compiler from the build step (See [#1570](https://github.com/FormidableLabs/urql/pull/1570))\n- Updated dependencies (See [#1570](https://github.com/FormidableLabs/urql/pull/1570), [#1509](https://github.com/FormidableLabs/urql/pull/1509), [#1600](https://github.com/FormidableLabs/urql/pull/1600), and [#1515](https://github.com/FormidableLabs/urql/pull/1515))\n  - @urql/core@2.1.0\n\n## 0.1.2\n\n### Patch Changes\n\n- Deprecate the `Operation.operationName` property in favor of `Operation.kind`. This name was\n  previously confusing as `operationName` was effectively referring to two different things. You can\n  safely upgrade to this new version, however to mute all deprecation warnings you will have to\n  **upgrade** all `urql` packages you use. If you have custom exchanges that spread operations, please\n  use [the new `makeOperation` helper\n  function](https://formidable.com/open-source/urql/docs/api/core/#makeoperation) instead, by [@bkonkle](https://github.com/bkonkle) (See [#1045](https://github.com/FormidableLabs/urql/pull/1045))\n- Updated dependencies (See [#1094](https://github.com/FormidableLabs/urql/pull/1094) and [#1045](https://github.com/FormidableLabs/urql/pull/1045))\n  - @urql/core@1.14.0\n\n## 0.1.1\n\n### Patch Changes\n\n- ⚠️ Fix an operation that triggers `willAuthError` with a truthy return value being sent off twice, by [@kitten](https://github.com/kitten) (See [#1075](https://github.com/FormidableLabs/urql/pull/1075))\n\n## v0.1.0\n\n**Initial Release**\n"
  },
  {
    "path": "exchanges/auth/README.md",
    "content": "<h2 align=\"center\">@urql/exchange-auth</h2>\n\n<p align=\"center\"><strong>An exchange for managing authentication in <code>urql</code></strong></p>\n\n`@urql/exchange-auth` is an exchange for the [`urql`](https://github.com/urql-graphql/urql) GraphQL client which helps handle auth headers and token refresh\n\n## Quick Start Guide\n\nFirst install `@urql/exchange-auth` alongside `urql`:\n\n```sh\nyarn add @urql/exchange-auth\n# or\nnpm install --save @urql/exchange-auth\n```\n\nYou'll then need to add the `authExchange`, that this package exposes to your `urql` Client\n\n```js\nimport { createClient, cacheExchange, fetchExchange } from 'urql';\nimport { makeOperation } from '@urql/core';\nimport { authExchange } from '@urql/exchange-auth';\n\nconst client = createClient({\n  url: 'http://localhost:1234/graphql',\n  exchanges: [\n    cacheExchange,\n    authExchange(async utils => {\n      // called on initial launch,\n      // fetch the auth state from storage (local storage, async storage etc)\n      let token = localStorage.getItem('token');\n      let refreshToken = localStorage.getItem('refreshToken');\n\n      return {\n        addAuthToOperation(operation) {\n          if (token) {\n            return utils.appendHeaders(operation, {\n              Authorization: `Bearer ${token}`,\n            });\n          }\n          return operation;\n        },\n        willAuthError(_operation) {\n          // e.g. check for expiration, existence of auth etc\n          return !token;\n        },\n        didAuthError(error, _operation) {\n          // check if the error was an auth error\n          // this can be implemented in various ways, e.g. 401 or a special error code\n          return error.graphQLErrors.some(e => e.extensions?.code === 'FORBIDDEN');\n        },\n        async refreshAuth() {\n          // called when auth error has occurred\n          // we should refresh the token with a GraphQL mutation or a fetch call,\n          // depending on what the API supports\n          const result = await mutate(refreshMutation, {\n            token: authState?.refreshToken,\n          });\n\n          if (result.data?.refreshLogin) {\n            // save the new tokens in storage for next restart\n            token = result.data.refreshLogin.token;\n            refreshToken = result.data.refreshLogin.refreshToken;\n            localStorage.setItem('token', token);\n            localStorage.setItem('refreshToken', refreshToken);\n          } else {\n            // otherwise, if refresh fails, log clear storage and log out\n            localStorage.clear();\n            logout();\n          }\n        },\n      };\n    }),\n    fetchExchange,\n  ],\n});\n```\n\n## Handling Errors via the errorExchange\n\nHandling the logout logic in `refreshAuth` is the easiest way to get started,\nbut it means the errors will always get swallowed by the `authExchange`.\nIf you want to handle errors globally, this can be done using the `mapExchange`:\n\n```js\nimport { mapExchange } from 'urql';\n\n// this needs to be placed ABOVE the authExchange in the exchanges array, otherwise the auth error\n// will show up hear before the auth exchange has had the chance to handle it\nmapExchange({\n  onError(error) {\n    // we only get an auth error here when the auth exchange had attempted to refresh auth and\n    // getting an auth error again for the second time\n    const isAuthError = error.graphQLErrors.some(\n      e => e.extensions?.code === 'FORBIDDEN',\n    );\n    if (isAuthError) {\n      // clear storage, log the user out etc\n    }\n  }\n}),\n```\n"
  },
  {
    "path": "exchanges/auth/jsr.json",
    "content": "{\n  \"name\": \"@urql/exchange-auth\",\n  \"version\": \"3.0.0\",\n  \"exports\": {\n    \".\": \"./src/index.ts\"\n  },\n  \"exclude\": [\n    \"node_modules\",\n    \"cypress\",\n    \"**/*.test.*\",\n    \"**/*.spec.*\",\n    \"**/*.test.*.snap\",\n    \"**/*.spec.*.snap\"\n  ]\n}"
  },
  {
    "path": "exchanges/auth/package.json",
    "content": "{\n  \"name\": \"@urql/exchange-auth\",\n  \"version\": \"3.0.0\",\n  \"description\": \"An exchange for managing authentication and token refresh in urql\",\n  \"sideEffects\": false,\n  \"homepage\": \"https://formidable.com/open-source/urql/docs/\",\n  \"bugs\": \"https://github.com/urql-graphql/urql/issues\",\n  \"license\": \"MIT\",\n  \"author\": \"urql GraphQL Contributors\",\n  \"repository\": {\n    \"type\": \"git\",\n    \"url\": \"https://github.com/urql-graphql/urql.git\",\n    \"directory\": \"exchanges/auth\"\n  },\n  \"keywords\": [\n    \"urql\",\n    \"exchange\",\n    \"auth\",\n    \"authentication\",\n    \"graphql\",\n    \"exchanges\"\n  ],\n  \"main\": \"dist/urql-exchange-auth\",\n  \"module\": \"dist/urql-exchange-auth.mjs\",\n  \"types\": \"dist/urql-exchange-auth.d.ts\",\n  \"source\": \"src/index.ts\",\n  \"exports\": {\n    \".\": {\n      \"types\": \"./dist/urql-exchange-auth.d.ts\",\n      \"import\": \"./dist/urql-exchange-auth.mjs\",\n      \"require\": \"./dist/urql-exchange-auth.js\",\n      \"source\": \"./src/index.ts\"\n    },\n    \"./package.json\": \"./package.json\"\n  },\n  \"files\": [\n    \"LICENSE\",\n    \"CHANGELOG.md\",\n    \"README.md\",\n    \"dist/\"\n  ],\n  \"scripts\": {\n    \"test\": \"vitest\",\n    \"clean\": \"rimraf dist extras\",\n    \"check\": \"tsc --noEmit\",\n    \"lint\": \"eslint --ext=js,jsx,ts,tsx .\",\n    \"build\": \"rollup -c ../../scripts/rollup/config.mjs\",\n    \"prepare\": \"node ../../scripts/prepare/index.js\",\n    \"prepublishOnly\": \"run-s clean build\"\n  },\n  \"peerDependencies\": {\n    \"@urql/core\": \"^6.0.0\"\n  },\n  \"dependencies\": {\n    \"@urql/core\": \"workspace:^6.0.1\",\n    \"wonka\": \"^6.3.2\"\n  },\n  \"devDependencies\": {\n    \"@urql/core\": \"workspace:*\",\n    \"graphql\": \"^16.0.0\"\n  },\n  \"publishConfig\": {\n    \"access\": \"public\",\n    \"provenance\": true\n  }\n}\n"
  },
  {
    "path": "exchanges/auth/src/authExchange.test.ts",
    "content": "import {\n  Source,\n  pipe,\n  fromValue,\n  toPromise,\n  take,\n  makeSubject,\n  share,\n  publish,\n  scan,\n  tap,\n  map,\n} from 'wonka';\n\nimport {\n  makeOperation,\n  CombinedError,\n  Client,\n  Operation,\n  OperationResult,\n} from '@urql/core';\n\nimport { vi, expect, it } from 'vitest';\nimport { print } from 'graphql';\nimport {\n  queryResponse,\n  queryOperation,\n} from '../../../packages/core/src/test-utils';\nimport { authExchange } from './authExchange';\n\nconst makeExchangeArgs = () => {\n  const operations: Operation[] = [];\n  const result = vi.fn(\n    (operation: Operation): OperationResult => ({ ...queryResponse, operation })\n  );\n\n  return {\n    operations,\n    result,\n    exchangeArgs: {\n      forward: (op$: Source<Operation>) =>\n        pipe(\n          op$,\n          tap(op => operations.push(op)),\n          map(result),\n          share\n        ),\n      client: new Client({\n        url: '/api',\n        exchanges: [],\n      }),\n    } as any,\n  };\n};\n\nit('adds the auth header correctly', async () => {\n  const { exchangeArgs } = makeExchangeArgs();\n\n  const res = await pipe(\n    fromValue(queryOperation),\n    authExchange(async utils => {\n      const token = 'my-token';\n      return {\n        addAuthToOperation(operation) {\n          return utils.appendHeaders(operation, {\n            Authorization: token,\n          });\n        },\n        didAuthError: () => false,\n        async refreshAuth() {\n          /*noop*/\n        },\n      };\n    })(exchangeArgs),\n    take(1),\n    toPromise\n  );\n\n  expect(res.operation.context.authAttempt).toBe(false);\n  expect(res.operation.context.fetchOptions).toEqual({\n    ...(queryOperation.context.fetchOptions || {}),\n    headers: {\n      Authorization: 'my-token',\n    },\n  });\n});\n\nit('adds the auth header correctly when intialized asynchronously', async () => {\n  const { exchangeArgs } = makeExchangeArgs();\n\n  const res = await pipe(\n    fromValue(queryOperation),\n    authExchange(async utils => {\n      // delayed initial auth\n      await Promise.resolve();\n      const token = 'async-token';\n\n      return {\n        addAuthToOperation(operation) {\n          return utils.appendHeaders(operation, {\n            Authorization: token,\n          });\n        },\n        didAuthError: () => false,\n        async refreshAuth() {\n          /*noop*/\n        },\n      };\n    })(exchangeArgs),\n    take(1),\n    toPromise\n  );\n\n  expect(res.operation.context.authAttempt).toBe(false);\n  expect(res.operation.context.fetchOptions).toEqual({\n    ...(queryOperation.context.fetchOptions || {}),\n    headers: {\n      Authorization: 'async-token',\n    },\n  });\n});\n\nit('supports calls to the mutate() method in refreshAuth()', async () => {\n  const { exchangeArgs } = makeExchangeArgs();\n\n  const willAuthError = vi\n    .fn()\n    .mockReturnValueOnce(true)\n    .mockReturnValue(false);\n\n  const [mutateRes, res] = await pipe(\n    fromValue(queryOperation),\n    authExchange(async utils => {\n      const token = 'async-token';\n\n      return {\n        addAuthToOperation(operation) {\n          return utils.appendHeaders(operation, {\n            Authorization: token,\n          });\n        },\n        willAuthError,\n        didAuthError: () => false,\n        async refreshAuth() {\n          const result = await utils.mutate('mutation { auth }', undefined);\n          expect(print(result.operation.query)).toBe('mutation {\\n  auth\\n}');\n        },\n      };\n    })(exchangeArgs),\n    take(2),\n    scan((acc, res) => [...acc, res], [] as OperationResult[]),\n    toPromise\n  );\n\n  expect(mutateRes.operation.context.fetchOptions).toEqual({\n    headers: {\n      Authorization: 'async-token',\n    },\n  });\n\n  expect(res.operation.context.authAttempt).toBe(true);\n  expect(res.operation.context.fetchOptions).toEqual({\n    method: 'POST',\n    headers: {\n      Authorization: 'async-token',\n    },\n  });\n});\n\nit('adds the same token to subsequent operations', async () => {\n  const { exchangeArgs } = makeExchangeArgs();\n  const { source, next } = makeSubject<any>();\n\n  const result = vi.fn();\n  const auth$ = pipe(\n    source,\n    authExchange(async utils => {\n      const token = 'my-token';\n      return {\n        addAuthToOperation(operation) {\n          return utils.appendHeaders(operation, {\n            Authorization: token,\n          });\n        },\n        didAuthError: () => false,\n        async refreshAuth() {\n          /*noop*/\n        },\n      };\n    })(exchangeArgs),\n    tap(result),\n    take(2),\n    toPromise\n  );\n\n  await new Promise(resolve => setTimeout(resolve));\n\n  next(queryOperation);\n\n  next(\n    makeOperation('query', queryOperation, {\n      ...queryOperation.context,\n      foo: 'bar',\n    })\n  );\n\n  await auth$;\n  expect(result).toHaveBeenCalledTimes(2);\n\n  expect(result.mock.calls[0][0].operation.context.authAttempt).toBe(false);\n  expect(result.mock.calls[0][0].operation.context.fetchOptions).toEqual({\n    ...(queryOperation.context.fetchOptions || {}),\n    headers: {\n      Authorization: 'my-token',\n    },\n  });\n\n  expect(result.mock.calls[1][0].operation.context.authAttempt).toBe(false);\n  expect(result.mock.calls[1][0].operation.context.fetchOptions).toEqual({\n    ...(queryOperation.context.fetchOptions || {}),\n    headers: {\n      Authorization: 'my-token',\n    },\n  });\n});\n\nit('triggers authentication when an operation did error', async () => {\n  const { exchangeArgs, result, operations } = makeExchangeArgs();\n  const { source, next } = makeSubject<any>();\n\n  const didAuthError = vi.fn().mockReturnValueOnce(true);\n\n  pipe(\n    source,\n    authExchange(async utils => {\n      let token = 'initial-token';\n      return {\n        addAuthToOperation(operation) {\n          return utils.appendHeaders(operation, {\n            Authorization: token,\n          });\n        },\n        didAuthError,\n        async refreshAuth() {\n          token = 'final-token';\n        },\n      };\n    })(exchangeArgs),\n    publish\n  );\n\n  await new Promise(resolve => setTimeout(resolve));\n\n  result.mockReturnValueOnce({\n    ...queryResponse,\n    operation: queryOperation,\n    data: undefined,\n    error: new CombinedError({\n      graphQLErrors: [{ message: 'Oops' }],\n    }),\n  });\n\n  next(queryOperation);\n  expect(result).toHaveBeenCalledTimes(1);\n  expect(didAuthError).toHaveBeenCalledTimes(1);\n\n  await new Promise(resolve => setTimeout(resolve));\n\n  expect(result).toHaveBeenCalledTimes(2);\n  expect(operations.length).toBe(2);\n  expect(operations[0]).toHaveProperty(\n    'context.fetchOptions.headers.Authorization',\n    'initial-token'\n  );\n  expect(operations[1]).toHaveProperty(\n    'context.fetchOptions.headers.Authorization',\n    'final-token'\n  );\n});\n\nit('triggers authentication when an operation will error', async () => {\n  const { exchangeArgs, result, operations } = makeExchangeArgs();\n  const { source, next } = makeSubject<any>();\n\n  const willAuthError = vi\n    .fn()\n    .mockReturnValueOnce(true)\n    .mockReturnValue(false);\n\n  pipe(\n    source,\n    authExchange(async utils => {\n      let token = 'initial-token';\n      return {\n        addAuthToOperation(operation) {\n          return utils.appendHeaders(operation, {\n            Authorization: token,\n          });\n        },\n        willAuthError,\n        didAuthError: () => false,\n        async refreshAuth() {\n          token = 'final-token';\n        },\n      };\n    })(exchangeArgs),\n    publish\n  );\n\n  await new Promise(resolve => setTimeout(resolve));\n\n  next(queryOperation);\n  expect(result).toHaveBeenCalledTimes(0);\n  expect(willAuthError).toHaveBeenCalledTimes(1);\n\n  await new Promise(resolve => setTimeout(resolve));\n\n  expect(result).toHaveBeenCalledTimes(1);\n  expect(operations.length).toBe(1);\n  expect(operations[0]).toHaveProperty(\n    'context.fetchOptions.headers.Authorization',\n    'final-token'\n  );\n});\n\nit('calls willAuthError on queued operations', async () => {\n  const { exchangeArgs, result, operations } = makeExchangeArgs();\n  const { source, next } = makeSubject<any>();\n\n  let initialAuthResolve: ((_?: any) => void) | undefined;\n\n  const willAuthError = vi\n    .fn()\n    .mockReturnValueOnce(true)\n    .mockReturnValue(false);\n\n  pipe(\n    source,\n    authExchange(async utils => {\n      await new Promise(resolve => {\n        initialAuthResolve = resolve;\n      });\n\n      let token = 'token';\n      return {\n        willAuthError,\n        didAuthError: () => false,\n        addAuthToOperation(operation) {\n          return utils.appendHeaders(operation, {\n            Authorization: token,\n          });\n        },\n        async refreshAuth() {\n          token = 'final-token';\n        },\n      };\n    })(exchangeArgs),\n    publish\n  );\n\n  await Promise.resolve();\n\n  next({ ...queryOperation, key: 1 });\n  next({ ...queryOperation, key: 2 });\n\n  expect(result).toHaveBeenCalledTimes(0);\n  expect(willAuthError).toHaveBeenCalledTimes(0);\n\n  expect(initialAuthResolve).toBeDefined();\n  initialAuthResolve!();\n\n  await new Promise(resolve => setTimeout(resolve));\n\n  expect(willAuthError).toHaveBeenCalledTimes(2);\n  expect(result).toHaveBeenCalledTimes(2);\n\n  expect(operations.length).toBe(2);\n  expect(operations[0]).toHaveProperty(\n    'context.fetchOptions.headers.Authorization',\n    'final-token'\n  );\n\n  expect(operations[1]).toHaveProperty(\n    'context.fetchOptions.headers.Authorization',\n    'final-token'\n  );\n});\n\nit('does not infinitely retry authentication when an operation did error', async () => {\n  const { exchangeArgs, result, operations } = makeExchangeArgs();\n  const { source, next } = makeSubject<any>();\n\n  const didAuthError = vi.fn().mockReturnValue(true);\n\n  pipe(\n    source,\n    authExchange(async utils => {\n      let token = 'initial-token';\n      return {\n        addAuthToOperation(operation) {\n          return utils.appendHeaders(operation, {\n            Authorization: token,\n          });\n        },\n        didAuthError,\n        async refreshAuth() {\n          token = 'final-token';\n        },\n      };\n    })(exchangeArgs),\n    publish\n  );\n\n  await new Promise(resolve => setTimeout(resolve));\n\n  result.mockImplementation(x => ({\n    ...queryResponse,\n    operation: {\n      ...queryResponse.operation,\n      ...x,\n    },\n    data: undefined,\n    error: new CombinedError({\n      graphQLErrors: [{ message: 'Oops' }],\n    }),\n  }));\n\n  next(queryOperation);\n  expect(result).toHaveBeenCalledTimes(1);\n  expect(didAuthError).toHaveBeenCalledTimes(1);\n\n  await new Promise(resolve => setTimeout(resolve));\n\n  expect(result).toHaveBeenCalledTimes(2);\n  expect(operations.length).toBe(2);\n  expect(operations[0]).toHaveProperty(\n    'context.fetchOptions.headers.Authorization',\n    'initial-token'\n  );\n  expect(operations[1]).toHaveProperty(\n    'context.fetchOptions.headers.Authorization',\n    'final-token'\n  );\n});\n\nit('passes on failing refreshAuth() errors to results', async () => {\n  const { exchangeArgs, result } = makeExchangeArgs();\n\n  const didAuthError = vi.fn().mockReturnValue(true);\n  const willAuthError = vi.fn().mockReturnValue(true);\n\n  const res = await pipe(\n    fromValue(queryOperation),\n    authExchange(async utils => {\n      const token = 'initial-token';\n      return {\n        addAuthToOperation(operation) {\n          return utils.appendHeaders(operation, {\n            Authorization: token,\n          });\n        },\n        didAuthError,\n        willAuthError,\n        async refreshAuth() {\n          throw new Error('test');\n        },\n      };\n    })(exchangeArgs),\n    take(1),\n    toPromise\n  );\n\n  expect(result).toHaveBeenCalledTimes(0);\n  expect(didAuthError).toHaveBeenCalledTimes(0);\n  expect(willAuthError).toHaveBeenCalledTimes(1);\n\n  expect(res.error).toMatchInlineSnapshot('[CombinedError: [Network] test]');\n});\n\nit('passes on errors during initialization', async () => {\n  const { source, next } = makeSubject<any>();\n  const { exchangeArgs, result } = makeExchangeArgs();\n  const init = vi.fn().mockRejectedValue(new Error('oops!'));\n  const output = vi.fn();\n\n  pipe(source, authExchange(init)(exchangeArgs), tap(output), publish);\n\n  expect(result).toHaveBeenCalledTimes(0);\n  expect(output).toHaveBeenCalledTimes(0);\n\n  next(queryOperation);\n  await new Promise(resolve => setTimeout(resolve));\n  expect(result).toHaveBeenCalledTimes(0);\n  expect(output).toHaveBeenCalledTimes(1);\n  expect(init).toHaveBeenCalledTimes(1);\n  expect(output.mock.calls[0][0].error).toMatchInlineSnapshot(\n    '[CombinedError: [Network] oops!]'\n  );\n\n  next(queryOperation);\n  await new Promise(resolve => setTimeout(resolve));\n  expect(result).toHaveBeenCalledTimes(0);\n  expect(output).toHaveBeenCalledTimes(2);\n  expect(init).toHaveBeenCalledTimes(2);\n  expect(output.mock.calls[1][0].error).toMatchInlineSnapshot(\n    '[CombinedError: [Network] oops!]'\n  );\n});\n"
  },
  {
    "path": "exchanges/auth/src/authExchange.ts",
    "content": "import type { Source } from 'wonka';\nimport {\n  pipe,\n  map,\n  filter,\n  onStart,\n  take,\n  makeSubject,\n  toPromise,\n  merge,\n} from 'wonka';\n\nimport type {\n  Operation,\n  OperationContext,\n  OperationResult,\n  CombinedError,\n  Exchange,\n  DocumentInput,\n  AnyVariables,\n  OperationInstance,\n} from '@urql/core';\nimport { createRequest, makeOperation, makeErrorResult } from '@urql/core';\n\n/** Utilities to use while refreshing authentication tokens. */\nexport interface AuthUtilities {\n  /** Sends a mutation to your GraphQL API, bypassing earlier exchanges and authentication.\n   *\n   * @param query - a GraphQL document containing the mutation operation that will be executed.\n   * @param variables - the variables used to execute the operation.\n   * @param context - {@link OperationContext} options that'll be used in future exchanges.\n   * @returns A `Promise` of an {@link OperationResult} for the GraphQL mutation.\n   *\n   * @remarks\n   * The `mutation()` utility method is useful when your authentication requires you to make a GraphQL mutation\n   * request to update your authentication tokens. In these cases, you likely wish to bypass prior exchanges and\n   * the authentication in the `authExchange` itself.\n   *\n   * This method bypasses the usual mutation flow of the `Client` and instead issues the mutation as directly\n   * as possible. This also means that it doesn’t carry your `Client`'s default {@link OperationContext}\n   * options, so you may have to pass them again, if needed.\n   */\n  mutate<Data = any, Variables extends AnyVariables = AnyVariables>(\n    query: DocumentInput<Data, Variables>,\n    variables: Variables,\n    context?: Partial<OperationContext>\n  ): Promise<OperationResult<Data>>;\n\n  /** Adds additional HTTP headers to an `Operation`.\n   *\n   * @param operation - An {@link Operation} to add headers to.\n   * @param headers - The HTTP headers to add to the `Operation`.\n   * @returns The passed {@link Operation} with the headers added to it.\n   *\n   * @remarks\n   * The `appendHeaders()` utility method is useful to add additional HTTP headers\n   * to an {@link Operation}. It’s a simple convenience function that takes\n   * `operation.context.fetchOptions` into account, since adding headers for\n   * authentication is common.\n   */\n  appendHeaders(\n    operation: Operation,\n    headers: Record<string, string>\n  ): Operation;\n}\n\n/** Configuration for the `authExchange` returned by the initializer function you write. */\nexport interface AuthConfig {\n  /** Called for every operation to add authentication data to your operation.\n   *\n   * @param operation - An {@link Operation} that needs authentication tokens added.\n   * @returns a new {@link Operation} with added authentication tokens.\n   *\n   * @remarks\n   * The {@link authExchange} will call this function you provide and expects that you\n   * add your authentication tokens to your operation here, on the {@link Operation}\n   * that is returned.\n   *\n   * Hint: You likely want to modify your `fetchOptions.headers` here, for instance to\n   * add an `Authorization` header.\n   */\n  addAuthToOperation(operation: Operation): Operation;\n\n  /** Called before an operation is forwaded onwards to make a request.\n   *\n   * @param operation - An {@link Operation} that needs authentication tokens added.\n   * @returns a boolean, if true, authentication must be refreshed.\n   *\n   * @remarks\n   * The {@link authExchange} will call this function before an {@link Operation} is\n   * forwarded onwards to your following exchanges.\n   *\n   * When this function returns `true`, the `authExchange` will call\n   * {@link AuthConfig.refreshAuth} before forwarding more operations\n   * to prompt you to update your authentication tokens.\n   *\n   * Hint: If you define this function, you can use it to check whether your authentication\n   * tokens have expired.\n   */\n  willAuthError?(operation: Operation): boolean;\n\n  /** Called after receiving an operation result to check whether it has failed with an authentication error.\n   *\n   * @param error - A {@link CombinedError} that a result has come back with.\n   * @param operation - The {@link Operation} of that has failed.\n   * @returns a boolean, if true, authentication must be refreshed.\n   *\n   * @remarks\n   * The {@link authExchange} will call this function if it sees an {@link OperationResult}\n   * with a {@link CombinedError} on it, implying that it may have failed due to an authentication\n   * error.\n   *\n   * When this function returns `true`, the `authExchange` will call\n   * {@link AuthConfig.refreshAuth} before forwarding more operations\n   * to prompt you to update your authentication tokens.\n   * Afterwards, this operation will be retried once.\n   *\n   * Hint: You should define a function that detects your API’s authentication\n   * errors, e.g. using `result.extensions`.\n   */\n  didAuthError(error: CombinedError, operation: Operation): boolean;\n\n  /** Called to refresh the authentication state.\n   *\n   * @remarks\n   * The {@link authExchange} will call this function if either {@link AuthConfig.willAuthError}\n   * or {@link AuthConfig.didAuthError} have returned `true` prior, which indicates that the\n   * authentication state you hold has expired or is out-of-date.\n   *\n   * When this function is called, you should refresh your authentication state.\n   * For instance, if you have a refresh token and an access token, you should rotate\n   * these tokens with your API by sending the refresh token.\n   *\n   * Hint: You can use the {@link fetch} API here, or use {@link AuthUtilities.mutate}\n   * if your API requires a GraphQL mutation to refresh your authentication state.\n   */\n  refreshAuth(): Promise<void>;\n}\n\nconst addAuthAttemptToOperation = (\n  operation: Operation,\n  authAttempt: boolean\n) =>\n  makeOperation(operation.kind, operation, {\n    ...operation.context,\n    authAttempt,\n  });\n\n/** Creates an `Exchange` handling control flow for authentication.\n *\n * @param init - An initializer function that returns an {@link AuthConfig} wrapped in a `Promise`.\n * @returns the created authentication {@link Exchange}.\n *\n * @remarks\n * The `authExchange` is used to create an exchange handling authentication and\n * the control flow of refresh authentication.\n *\n * You must pass an initializer function, which receives {@link AuthUtilities} and\n * must return an {@link AuthConfig} wrapped in a `Promise`.\n * When this exchange is used in your `Client`, it will first call your initializer\n * function, which gives you an opportunity to get your authentication state, e.g.\n * from local storage.\n *\n * You may then choose to validate this authentication state and update it, and must\n * then return an {@link AuthConfig}.\n *\n * This configuration defines how you add authentication state to {@link Operation | Operations},\n * when your authentication state expires, when an {@link OperationResult} has errored\n * with an authentication error, and how to refresh your authentication state.\n *\n * @example\n * ```ts\n * authExchange(async (utils) => {\n *   let token = localStorage.getItem('token');\n *   let refreshToken = localStorage.getItem('refreshToken');\n *   return {\n *     addAuthToOperation(operation) {\n *       return utils.appendHeaders(operation, {\n *         Authorization: `Bearer ${token}`,\n *       });\n *     },\n *     didAuthError(error) {\n *       return error.graphQLErrors.some(e => e.extensions?.code === 'FORBIDDEN');\n *     },\n *     async refreshAuth() {\n *       const result = await utils.mutate(REFRESH, { token });\n *       if (result.data?.refreshLogin) {\n *         token = result.data.refreshLogin.token;\n *         refreshToken = result.data.refreshLogin.refreshToken;\n *         localStorage.setItem('token', token);\n *         localStorage.setItem('refreshToken', refreshToken);\n *       }\n *     },\n *   };\n * });\n * ```\n */\nexport function authExchange(\n  init: (utilities: AuthUtilities) => Promise<AuthConfig>\n): Exchange {\n  return ({ client, forward }) => {\n    const bypassQueue = new Set<OperationInstance | undefined>();\n    const retries = makeSubject<Operation>();\n    const errors = makeSubject<OperationResult>();\n\n    let retryQueue = new Map<number, Operation>();\n\n    function flushQueue() {\n      authPromise = undefined;\n      const queue = retryQueue;\n      retryQueue = new Map();\n      queue.forEach(retries.next);\n    }\n\n    function errorQueue(error: Error) {\n      authPromise = undefined;\n      const queue = retryQueue;\n      retryQueue = new Map();\n      queue.forEach(operation => {\n        errors.next(makeErrorResult(operation, error));\n      });\n    }\n\n    let authPromise: Promise<void> | void;\n    let config: AuthConfig | null = null;\n\n    return operations$ => {\n      function initAuth() {\n        authPromise = Promise.resolve()\n          .then(() =>\n            init({\n              mutate<Data = any, Variables extends AnyVariables = AnyVariables>(\n                query: DocumentInput<Data, Variables>,\n                variables: Variables,\n                context?: Partial<OperationContext>\n              ): Promise<OperationResult<Data>> {\n                const baseOperation = client.createRequestOperation(\n                  'mutation',\n                  createRequest(query, variables),\n                  context\n                );\n                return pipe(\n                  result$,\n                  onStart(() => {\n                    const operation = addAuthToOperation(baseOperation);\n                    bypassQueue.add(\n                      operation.context._instance as OperationInstance\n                    );\n                    retries.next(operation);\n                  }),\n                  filter(\n                    result =>\n                      result.operation.key === baseOperation.key &&\n                      baseOperation.context._instance ===\n                        result.operation.context._instance\n                  ),\n                  take(1),\n                  toPromise\n                );\n              },\n              appendHeaders(\n                operation: Operation,\n                headers: Record<string, string>\n              ) {\n                const fetchOptions =\n                  typeof operation.context.fetchOptions === 'function'\n                    ? operation.context.fetchOptions()\n                    : operation.context.fetchOptions || {};\n                return makeOperation(operation.kind, operation, {\n                  ...operation.context,\n                  fetchOptions: {\n                    ...fetchOptions,\n                    headers: {\n                      ...fetchOptions.headers,\n                      ...headers,\n                    },\n                  },\n                });\n              },\n            })\n          )\n          .then((_config: AuthConfig) => {\n            if (_config) config = _config;\n            flushQueue();\n          })\n          .catch((error: Error) => {\n            if (process.env.NODE_ENV !== 'production') {\n              console.warn(\n                'authExchange()’s initialization function has failed, which is unexpected.\\n' +\n                  'If your initialization function is expected to throw/reject, catch this error and handle it explicitly.\\n' +\n                  'Unless this error is handled it’ll be passed onto any `OperationResult` instantly and authExchange() will block further operations and retry.',\n                error\n              );\n            }\n\n            errorQueue(error);\n          });\n      }\n\n      initAuth();\n\n      function refreshAuth(operation: Operation) {\n        // add to retry queue to try again later\n        retryQueue.set(\n          operation.key,\n          addAuthAttemptToOperation(operation, true)\n        );\n\n        // check that another operation isn't already doing refresh\n        if (config && !authPromise) {\n          authPromise = config.refreshAuth().then(flushQueue).catch(errorQueue);\n        }\n      }\n\n      function willAuthError(operation: Operation) {\n        return (\n          !operation.context.authAttempt &&\n          config &&\n          config.willAuthError &&\n          config.willAuthError(operation)\n        );\n      }\n\n      function didAuthError(result: OperationResult) {\n        return (\n          config &&\n          config.didAuthError &&\n          config.didAuthError(result.error!, result.operation)\n        );\n      }\n\n      function addAuthToOperation(operation: Operation) {\n        return config ? config.addAuthToOperation(operation) : operation;\n      }\n\n      const opsWithAuth$ = pipe(\n        merge([retries.source, operations$]),\n        map(operation => {\n          if (operation.kind === 'teardown') {\n            retryQueue.delete(operation.key);\n            return operation;\n          } else if (\n            operation.context._instance &&\n            bypassQueue.has(operation.context._instance)\n          ) {\n            return operation;\n          } else if (operation.context.authAttempt) {\n            return addAuthToOperation(operation);\n          } else if (authPromise || !config) {\n            if (!authPromise) initAuth();\n\n            if (!retryQueue.has(operation.key))\n              retryQueue.set(\n                operation.key,\n                addAuthAttemptToOperation(operation, false)\n              );\n\n            return null;\n          } else if (willAuthError(operation)) {\n            refreshAuth(operation);\n            return null;\n          }\n\n          return addAuthToOperation(\n            addAuthAttemptToOperation(operation, false)\n          );\n        }),\n        filter(Boolean)\n      ) as Source<Operation>;\n\n      const result$ = pipe(opsWithAuth$, forward);\n\n      return merge([\n        errors.source,\n        pipe(\n          result$,\n          filter(result => {\n            if (\n              !bypassQueue.has(result.operation.context._instance) &&\n              result.error &&\n              didAuthError(result) &&\n              !result.operation.context.authAttempt\n            ) {\n              refreshAuth(result.operation);\n              return false;\n            }\n\n            if (bypassQueue.has(result.operation.context._instance)) {\n              bypassQueue.delete(result.operation.context._instance);\n            }\n\n            return true;\n          })\n        ),\n      ]);\n    };\n  };\n}\n"
  },
  {
    "path": "exchanges/auth/src/index.ts",
    "content": "export { authExchange } from './authExchange';\nexport type { AuthUtilities, AuthConfig } from './authExchange';\n"
  },
  {
    "path": "exchanges/auth/tsconfig.json",
    "content": "{\n  \"extends\": \"../../tsconfig.json\",\n  \"include\": [\"src\"]\n}\n"
  },
  {
    "path": "exchanges/auth/vitest.config.ts",
    "content": "import { mergeConfig } from 'vitest/config';\nimport baseConfig from '../../vitest.config';\n\nexport default mergeConfig(baseConfig, {});\n"
  },
  {
    "path": "exchanges/context/CHANGELOG.md",
    "content": "# Changelog\n\n## 1.0.0\n\n### Patch Changes\n\n- Updated dependencies (See [#3789](https://github.com/urql-graphql/urql/pull/3789) and [#3807](https://github.com/urql-graphql/urql/pull/3807))\n  - @urql/core@6.0.0\n\n## 0.3.1\n\n### Patch Changes\n\n- Omit minified files and sourcemaps' `sourcesContent` in published packages\n  Submitted by [@kitten](https://github.com/kitten) (See [#3755](https://github.com/urql-graphql/urql/pull/3755))\n- Updated dependencies (See [#3755](https://github.com/urql-graphql/urql/pull/3755))\n  - @urql/core@5.1.1\n\n## 0.3.0\n\n### Minor Changes\n\n- Mark `@urql/core` as a peer dependency as well as a regular dependency\n  Submitted by [@kitten](https://github.com/kitten) (See [#3579](https://github.com/urql-graphql/urql/pull/3579))\n\n## 0.2.1\n\n### Patch Changes\n\n- Publish with npm provenance\n  Submitted by [@kitten](https://github.com/kitten) (See [#3180](https://github.com/urql-graphql/urql/pull/3180))\n\n## 0.2.0\n\n### Minor Changes\n\n- Update exchanges to drop redundant `share` calls, since `@urql/core`’s `composeExchanges` utility now automatically does so for us\n  Submitted by [@kitten](https://github.com/kitten) (See [#3082](https://github.com/urql-graphql/urql/pull/3082))\n\n### Patch Changes\n\n- Upgrade to `wonka@^6.3.0`\n  Submitted by [@kitten](https://github.com/kitten) (See [#3104](https://github.com/urql-graphql/urql/pull/3104))\n- Add TSDocs for all exchanges, documenting API internals\n  Submitted by [@kitten](https://github.com/kitten) (See [#3072](https://github.com/urql-graphql/urql/pull/3072))\n- Updated dependencies (See [#3101](https://github.com/urql-graphql/urql/pull/3101), [#3033](https://github.com/urql-graphql/urql/pull/3033), [#3054](https://github.com/urql-graphql/urql/pull/3054), [#3053](https://github.com/urql-graphql/urql/pull/3053), [#3060](https://github.com/urql-graphql/urql/pull/3060), [#3081](https://github.com/urql-graphql/urql/pull/3081), [#3039](https://github.com/urql-graphql/urql/pull/3039), [#3104](https://github.com/urql-graphql/urql/pull/3104), [#3082](https://github.com/urql-graphql/urql/pull/3082), [#3097](https://github.com/urql-graphql/urql/pull/3097), [#3061](https://github.com/urql-graphql/urql/pull/3061), [#3055](https://github.com/urql-graphql/urql/pull/3055), [#3085](https://github.com/urql-graphql/urql/pull/3085), [#3079](https://github.com/urql-graphql/urql/pull/3079), [#3087](https://github.com/urql-graphql/urql/pull/3087), [#3059](https://github.com/urql-graphql/urql/pull/3059), [#3055](https://github.com/urql-graphql/urql/pull/3055), [#3057](https://github.com/urql-graphql/urql/pull/3057), [#3050](https://github.com/urql-graphql/urql/pull/3050), [#3062](https://github.com/urql-graphql/urql/pull/3062), [#3051](https://github.com/urql-graphql/urql/pull/3051), [#3043](https://github.com/urql-graphql/urql/pull/3043), [#3063](https://github.com/urql-graphql/urql/pull/3063), [#3054](https://github.com/urql-graphql/urql/pull/3054), [#3102](https://github.com/urql-graphql/urql/pull/3102), [#3097](https://github.com/urql-graphql/urql/pull/3097), [#3106](https://github.com/urql-graphql/urql/pull/3106), [#3058](https://github.com/urql-graphql/urql/pull/3058), and [#3062](https://github.com/urql-graphql/urql/pull/3062))\n  - @urql/core@4.0.0\n\n## v0.1.0\n\n**Initial Release**\n"
  },
  {
    "path": "exchanges/context/README.md",
    "content": "<h2 align=\"center\">@urql/exchange-context</h2>\n\n<p align=\"center\"><strong>An exchange for setting operation context in <code>urql</code></strong></p>\n\n`@urql/exchange-context` is an exchange for the [`urql`](https://github.com/urql-graphql/urql) GraphQL client which can set the operation context both synchronously as well as asynchronously\n\n## Quick Start Guide\n\nFirst install `@urql/exchange-context` alongside `urql`:\n\n```sh\nyarn add @urql/exchange-context\n# or\nnpm install --save @urql/exchange-context\n```\n\nYou'll then need to add the `contextExchange`, that this package exposes, to your `urql` Client, the positioning of this exchange depends on whether you set an async setter or not. If you set an async context-setter it's best placed after all the synchronous exchanges (in front of the fetchExchange).\n\n```js\nimport { createClient, cacheExchange, fetchExchange } from 'urql';\nimport { contextExchange } from '@urql/exchange-context';\n\nconst client = createClient({\n  url: 'http://localhost:1234/graphql',\n  exchanges: [\n    cacheExchange,\n    contextExchange({\n      getContext: async operation => {\n        const token = await getToken();\n        return { ...operation.context, headers: { authorization: token } };\n      },\n    }),\n    fetchExchange,\n  ],\n});\n```\n"
  },
  {
    "path": "exchanges/context/jsr.json",
    "content": "{\n  \"name\": \"@urql/exchange-context\",\n  \"version\": \"1.0.0\",\n  \"exports\": {\n    \".\": \"./src/index.ts\"\n  },\n  \"exclude\": [\n    \"node_modules\",\n    \"cypress\",\n    \"**/*.test.*\",\n    \"**/*.spec.*\",\n    \"**/*.test.*.snap\",\n    \"**/*.spec.*.snap\"\n  ]\n}"
  },
  {
    "path": "exchanges/context/package.json",
    "content": "{\n  \"name\": \"@urql/exchange-context\",\n  \"version\": \"1.0.0\",\n  \"description\": \"An exchange for setting (a)synchronous operation-context in urql\",\n  \"sideEffects\": false,\n  \"homepage\": \"https://formidable.com/open-source/urql/docs/\",\n  \"bugs\": \"https://github.com/urql-graphql/urql/issues\",\n  \"license\": \"MIT\",\n  \"author\": \"urql GraphQL Contributors\",\n  \"repository\": {\n    \"type\": \"git\",\n    \"url\": \"https://github.com/urql-graphql/urql.git\",\n    \"directory\": \"exchanges/context\"\n  },\n  \"keywords\": [\n    \"urql\",\n    \"exchange\",\n    \"context\",\n    \"graphql\",\n    \"exchanges\"\n  ],\n  \"main\": \"dist/urql-exchange-context\",\n  \"module\": \"dist/urql-exchange-context.mjs\",\n  \"types\": \"dist/urql-exchange-context.d.ts\",\n  \"source\": \"src/index.ts\",\n  \"exports\": {\n    \".\": {\n      \"types\": \"./dist/urql-exchange-context.d.ts\",\n      \"import\": \"./dist/urql-exchange-context.mjs\",\n      \"require\": \"./dist/urql-exchange-context.js\",\n      \"source\": \"./src/index.ts\"\n    },\n    \"./package.json\": \"./package.json\"\n  },\n  \"files\": [\n    \"LICENSE\",\n    \"CHANGELOG.md\",\n    \"README.md\",\n    \"dist/\"\n  ],\n  \"scripts\": {\n    \"test\": \"vitest\",\n    \"clean\": \"rimraf dist extras\",\n    \"check\": \"tsc --noEmit\",\n    \"lint\": \"eslint --ext=js,jsx,ts,tsx .\",\n    \"build\": \"rollup -c ../../scripts/rollup/config.mjs\",\n    \"prepare\": \"node ../../scripts/prepare/index.js\",\n    \"prepublishOnly\": \"run-s clean build\"\n  },\n  \"peerDependencies\": {\n    \"@urql/core\": \"^6.0.0\"\n  },\n  \"dependencies\": {\n    \"@urql/core\": \"workspace:^6.0.1\",\n    \"wonka\": \"^6.3.2\"\n  },\n  \"devDependencies\": {\n    \"@urql/core\": \"workspace:*\",\n    \"graphql\": \"^16.0.0\"\n  },\n  \"publishConfig\": {\n    \"access\": \"public\",\n    \"provenance\": true\n  }\n}\n"
  },
  {
    "path": "exchanges/context/src/context.test.ts",
    "content": "import { pipe, map, makeSubject, publish, tap } from 'wonka';\nimport { vi, expect, it, beforeEach } from 'vitest';\n\nimport {\n  gql,\n  createClient,\n  Operation,\n  OperationResult,\n  ExchangeIO,\n} from '@urql/core';\n\nimport { queryResponse } from '../../../packages/core/src/test-utils';\nimport { contextExchange } from './context';\n\nconst queryOne = gql`\n  {\n    author {\n      id\n      name\n    }\n  }\n`;\n\nconst queryOneData = {\n  __typename: 'Query',\n  author: {\n    __typename: 'Author',\n    id: '123',\n    name: 'Author',\n  },\n};\n\nconst dispatchDebug = vi.fn();\nlet client, op, ops$, next;\nbeforeEach(() => {\n  client = createClient({\n    url: 'http://0.0.0.0',\n    exchanges: [],\n  });\n  op = client.createRequestOperation('query', {\n    key: 1,\n    query: queryOne,\n  });\n\n  ({ source: ops$, next } = makeSubject<Operation>());\n});\n\nit(`calls getContext`, () => {\n  const response = vi.fn((forwardOp: Operation): OperationResult => {\n    return {\n      ...queryResponse,\n      operation: forwardOp,\n      data: queryOneData,\n    };\n  });\n\n  const result = vi.fn();\n  const forward: ExchangeIO = ops$ => {\n    return pipe(ops$, map(response));\n  };\n\n  const headers = { hello: 'world' };\n  pipe(\n    contextExchange({\n      getContext: op => ({ ...op.context, headers }),\n    })({\n      forward,\n      client,\n      dispatchDebug,\n    })(ops$),\n    tap(result),\n    publish\n  );\n\n  next(op);\n\n  expect(response).toHaveBeenCalledTimes(1);\n  expect(response.mock.calls[0][0].context.headers).toEqual(headers);\n  expect(result).toHaveBeenCalledTimes(1);\n});\n\nit(`calls getContext async`, async () => {\n  const response = vi.fn((forwardOp: Operation): OperationResult => {\n    return {\n      ...queryResponse,\n      operation: forwardOp,\n      data: queryOneData,\n    };\n  });\n\n  const result = vi.fn();\n  const forward: ExchangeIO = ops$ => {\n    return pipe(ops$, map(response));\n  };\n\n  const headers = { hello: 'world' };\n  pipe(\n    contextExchange({\n      getContext: async op => {\n        await Promise.resolve();\n        return { ...op.context, headers };\n      },\n    })({\n      forward,\n      client,\n      dispatchDebug,\n    })(ops$),\n    tap(result),\n    publish\n  );\n\n  next(op);\n\n  await new Promise(res => {\n    setTimeout(() => {\n      expect(response).toHaveBeenCalledTimes(1);\n      expect(response.mock.calls[0][0].context.headers).toEqual(headers);\n      expect(result).toHaveBeenCalledTimes(1);\n      res(null);\n    }, 10);\n  });\n});\n"
  },
  {
    "path": "exchanges/context/src/context.ts",
    "content": "import type { Exchange, Operation, OperationContext } from '@urql/core';\nimport { makeOperation } from '@urql/core';\n\nimport { fromPromise, fromValue, mergeMap, pipe } from 'wonka';\n\n/** Input parameters for the {@link contextExchange}. */\nexport interface ContextExchangeArgs {\n  /** Returns a new {@link OperationContext}, optionally wrapped in a `Promise`.\n   *\n   * @remarks\n   * `getContext` is called for every {@link Operation} the `contextExchange`\n   * receives and must return a new {@link OperationContext} or a `Promise`\n   * of it.\n   *\n   * The new `OperationContext` will be used to update the `Operation`'s\n   * context before it's forwarded to the next exchange.\n   */\n  getContext(\n    operation: Operation\n  ): OperationContext | Promise<OperationContext>;\n}\n\n/** Exchange factory modifying the {@link OperationContext} per incoming `Operation`.\n *\n * @param options - A {@link ContextExchangeArgs} configuration object.\n * @returns the created context {@link Exchange}.\n *\n * @remarks\n * The `contextExchange` allows the {@link OperationContext` to be easily\n * modified per `Operation`. This may be useful to dynamically change the\n * `Operation`’s parameters, even when we need to do so asynchronously.\n *\n * You must define a {@link ContextExchangeArgs.getContext} function,\n * which may return a `Promise<OperationContext>` or `OperationContext`.\n *\n * Hint: If the `getContext` function passed to this exchange returns a\n * `Promise` it must be placed _after_ all synchronous exchanges, such as\n * a `cacheExchange`.\n *\n * @example\n * ```ts\n * import { Client, cacheExchange, fetchExchange } from '@urql/core';\n * import { contextExchange } from '@urql/exchange-context';\n *\n * const client = new Client({\n *   url: '',\n *   exchanges: [\n *     cacheExchange,\n *     contextExchange({\n *       async getContext(operation) {\n *         const url = await loadDynamicUrl();\n *         return {\n *           ...operation.context,\n *           url,\n *         };\n *       },\n *     }),\n *     fetchExchange,\n *   ],\n * });\n * ```\n */\n\nexport const contextExchange =\n  ({ getContext }: ContextExchangeArgs): Exchange =>\n  ({ forward }) => {\n    return ops$ => {\n      return pipe(\n        ops$,\n        mergeMap(operation => {\n          const result = getContext(operation);\n          const isPromise = 'then' in result;\n          if (isPromise) {\n            return fromPromise(\n              result.then((ctx: OperationContext) =>\n                makeOperation(operation.kind, operation, ctx)\n              )\n            );\n          } else {\n            return fromValue(\n              makeOperation(\n                operation.kind,\n                operation,\n                result as OperationContext\n              )\n            );\n          }\n        }),\n        forward\n      );\n    };\n  };\n"
  },
  {
    "path": "exchanges/context/src/index.ts",
    "content": "export { contextExchange } from './context';\nexport type { ContextExchangeArgs } from './context';\n"
  },
  {
    "path": "exchanges/context/tsconfig.json",
    "content": "{\n  \"extends\": \"../../tsconfig.json\",\n  \"include\": [\"src\"]\n}\n"
  },
  {
    "path": "exchanges/context/vitest.config.ts",
    "content": "import { mergeConfig } from 'vitest/config';\nimport baseConfig from '../../vitest.config';\n\nexport default mergeConfig(baseConfig, {});\n"
  },
  {
    "path": "exchanges/execute/CHANGELOG.md",
    "content": "# Changelog\n\n## 3.0.0\n\n### Patch Changes\n\n- Updated dependencies (See [#3789](https://github.com/urql-graphql/urql/pull/3789) and [#3807](https://github.com/urql-graphql/urql/pull/3807))\n  - @urql/core@6.0.0\n\n## 2.3.1\n\n### Patch Changes\n\n- Omit minified files and sourcemaps' `sourcesContent` in published packages\n  Submitted by [@kitten](https://github.com/kitten) (See [#3755](https://github.com/urql-graphql/urql/pull/3755))\n- Updated dependencies (See [#3755](https://github.com/urql-graphql/urql/pull/3755))\n  - @urql/core@5.1.1\n\n## 2.3.0\n\n### Minor Changes\n\n- Mark `@urql/core` as a peer dependency as well as a regular dependency\n  Submitted by [@kitten](https://github.com/kitten) (See [#3579](https://github.com/urql-graphql/urql/pull/3579))\n\n## 2.2.2\n\n### Patch Changes\n\n- Update build process to generate correct source maps\n  Submitted by [@kitten](https://github.com/kitten) (See [#3201](https://github.com/urql-graphql/urql/pull/3201))\n\n## 2.2.1\n\n### Patch Changes\n\n- Publish with npm provenance\n  Submitted by [@kitten](https://github.com/kitten) (See [#3180](https://github.com/urql-graphql/urql/pull/3180))\n\n## 2.2.0\n\n### Minor Changes\n\n- Update exchanges to drop redundant `share` calls, since `@urql/core`’s `composeExchanges` utility now automatically does so for us\n  Submitted by [@kitten](https://github.com/kitten) (See [#3082](https://github.com/urql-graphql/urql/pull/3082))\n- Remove `getOperationName` export from `@urql/core`\n  Submitted by [@kitten](https://github.com/kitten) (See [#3062](https://github.com/urql-graphql/urql/pull/3062))\n\n### Patch Changes\n\n- Upgrade to `wonka@^6.3.0`\n  Submitted by [@kitten](https://github.com/kitten) (See [#3104](https://github.com/urql-graphql/urql/pull/3104))\n- Add TSDocs for all exchanges, documenting API internals\n  Submitted by [@kitten](https://github.com/kitten) (See [#3072](https://github.com/urql-graphql/urql/pull/3072))\n- Updated dependencies (See [#3101](https://github.com/urql-graphql/urql/pull/3101), [#3033](https://github.com/urql-graphql/urql/pull/3033), [#3054](https://github.com/urql-graphql/urql/pull/3054), [#3053](https://github.com/urql-graphql/urql/pull/3053), [#3060](https://github.com/urql-graphql/urql/pull/3060), [#3081](https://github.com/urql-graphql/urql/pull/3081), [#3039](https://github.com/urql-graphql/urql/pull/3039), [#3104](https://github.com/urql-graphql/urql/pull/3104), [#3082](https://github.com/urql-graphql/urql/pull/3082), [#3097](https://github.com/urql-graphql/urql/pull/3097), [#3061](https://github.com/urql-graphql/urql/pull/3061), [#3055](https://github.com/urql-graphql/urql/pull/3055), [#3085](https://github.com/urql-graphql/urql/pull/3085), [#3079](https://github.com/urql-graphql/urql/pull/3079), [#3087](https://github.com/urql-graphql/urql/pull/3087), [#3059](https://github.com/urql-graphql/urql/pull/3059), [#3055](https://github.com/urql-graphql/urql/pull/3055), [#3057](https://github.com/urql-graphql/urql/pull/3057), [#3050](https://github.com/urql-graphql/urql/pull/3050), [#3062](https://github.com/urql-graphql/urql/pull/3062), [#3051](https://github.com/urql-graphql/urql/pull/3051), [#3043](https://github.com/urql-graphql/urql/pull/3043), [#3063](https://github.com/urql-graphql/urql/pull/3063), [#3054](https://github.com/urql-graphql/urql/pull/3054), [#3102](https://github.com/urql-graphql/urql/pull/3102), [#3097](https://github.com/urql-graphql/urql/pull/3097), [#3106](https://github.com/urql-graphql/urql/pull/3106), [#3058](https://github.com/urql-graphql/urql/pull/3058), and [#3062](https://github.com/urql-graphql/urql/pull/3062))\n  - @urql/core@4.0.0\n\n## 2.1.1\n\n### Patch Changes\n\n- ⚠️ Fix type-generation, with a change in TS/Rollup the type generation took the paths as src and resolved them into the types dir, by [@JoviDeCroock](https://github.com/JoviDeCroock) (See [#2870](https://github.com/urql-graphql/urql/pull/2870))\n- Updated dependencies (See [#2872](https://github.com/urql-graphql/urql/pull/2872), [#2870](https://github.com/urql-graphql/urql/pull/2870), and [#2871](https://github.com/urql-graphql/urql/pull/2871))\n  - @urql/core@3.1.1\n\n## 2.1.0\n\n### Minor Changes\n\n- The `context` option, which may be set to a context value or a function returning a context, can now return a `Promise` and will be correctly resolved and awaited, by [@YutaUra](https://github.com/YutaUra) (See [#2806](https://github.com/urql-graphql/urql/pull/2806))\n\n### Patch Changes\n\n- End iterator when teardown functions runs, previously it waited for one extra call to next, then ended the iterator, by [@danielkaxis](https://github.com/danielkaxis) (See [#2803](https://github.com/urql-graphql/urql/pull/2803))\n- Updated dependencies (See [#2843](https://github.com/urql-graphql/urql/pull/2843), [#2847](https://github.com/urql-graphql/urql/pull/2847), [#2850](https://github.com/urql-graphql/urql/pull/2850), and [#2846](https://github.com/urql-graphql/urql/pull/2846))\n  - @urql/core@3.1.0\n\n## 2.0.0\n\n### Major Changes\n\n- **Goodbye IE11!** 👋 This major release removes support for IE11. All code that is shipped will be transpiled much less and will _not_ be ES5-compatible anymore, by [@kitten](https://github.com/kitten) (See [#2504](https://github.com/FormidableLabs/urql/pull/2504))\n- Upgrade to [Wonka v6](https://github.com/0no-co/wonka) (`wonka@^6.0.0`), which has no breaking changes but is built to target ES2015 and comes with other minor improvements.\n  The library has fully been migrated to TypeScript which will hopefully help with making contributions easier!, by [@kitten](https://github.com/kitten) (See [#2504](https://github.com/FormidableLabs/urql/pull/2504))\n\n### Minor Changes\n\n- Remove the `babel-plugin-modular-graphql` helper, this because the graphql package hasn't converted to ESM yet which gives issues in node environments, by [@JoviDeCroock](https://github.com/JoviDeCroock) (See [#2551](https://github.com/FormidableLabs/urql/pull/2551))\n\n### Patch Changes\n\n- ⚠️ fix return for context function argument, by [@JoviDeCroock](https://github.com/JoviDeCroock) (See [#2583](https://github.com/FormidableLabs/urql/pull/2583))\n- Updated dependencies (See [#2551](https://github.com/FormidableLabs/urql/pull/2551), [#2504](https://github.com/FormidableLabs/urql/pull/2504), [#2619](https://github.com/FormidableLabs/urql/pull/2619), [#2607](https://github.com/FormidableLabs/urql/pull/2607), and [#2504](https://github.com/FormidableLabs/urql/pull/2504))\n  - @urql/core@3.0.0\n\n## 1.2.3\n\n### Patch Changes\n\n- Support using default values with directives. Previously, using a variables with a default value within a directive would fail the validation if it is empty, by [@fathyb](https://github.com/fathyb) (See [#2435](https://github.com/FormidableLabs/urql/pull/2435))\n\n## 1.2.2\n\n### Patch Changes\n\n- Upgrade modular imports for graphql package, which fixes an issue in `@urql/exchange-execute`, where `graphql@16` files wouldn't resolve the old `subscribe` import from the correct file, by [@kitten](https://github.com/kitten) (See [#2149](https://github.com/FormidableLabs/urql/pull/2149))\n\n## 1.2.1\n\n### Patch Changes\n\n- Extend peer dependency range of `graphql` to include `^16.0.0`.\n  As always when upgrading across many packages of `urql`, especially including `@urql/core` we recommend you to deduplicate dependencies after upgrading, using `npm dedupe` or `npx yarn-deduplicate`, by [@kitten](https://github.com/kitten) (See [#2133](https://github.com/FormidableLabs/urql/pull/2133))\n- Updated dependencies (See [#2133](https://github.com/FormidableLabs/urql/pull/2133))\n  - @urql/core@2.3.6\n\n## 1.2.0\n\n### Minor Changes\n\n- Add subscription support, by [@Tigge](https://github.com/Tigge) (See [#2061](https://github.com/FormidableLabs/urql/pull/2061))\n\n### Patch Changes\n\n- Updated dependencies (See [#2074](https://github.com/FormidableLabs/urql/pull/2074))\n  - @urql/core@2.3.5\n\n## 1.1.0\n\n### Minor Changes\n\n- Support async iterated results, including subscriptions via `AsyncIterator` support and `@defer` / `@stream` if the appropriate version of `graphql` is used, e.g. `15.4.0-experimental-stream-defer.1`, by [@kitten](https://github.com/kitten) (See [#1854](https://github.com/FormidableLabs/urql/pull/1854))\n\n### Patch Changes\n\n- Updated dependencies (See [#1854](https://github.com/FormidableLabs/urql/pull/1854))\n  - @urql/core@2.3.0\n\n## 1.0.5\n\n### Patch Changes\n\n- Expose `ExecuteExchangeArgs` interface, by [@taneba](https://github.com/taneba) (See [#1837](https://github.com/FormidableLabs/urql/pull/1837))\n- Updated dependencies (See [#1829](https://github.com/FormidableLabs/urql/pull/1829))\n  - @urql/core@2.1.6\n\n## 1.0.4\n\n### Patch Changes\n\n- Remove closure-compiler from the build step (See [#1570](https://github.com/FormidableLabs/urql/pull/1570))\n- Updated dependencies (See [#1570](https://github.com/FormidableLabs/urql/pull/1570), [#1509](https://github.com/FormidableLabs/urql/pull/1509), [#1600](https://github.com/FormidableLabs/urql/pull/1600), and [#1515](https://github.com/FormidableLabs/urql/pull/1515))\n  - @urql/core@2.1.0\n\n## 1.0.3\n\n### Patch Changes\n\n- Export `getOperationName` from `@urql/core` and use it in `@urql/exchange-execute`, fixing several imports, by [@JoviDeCroock](https://github.com/JoviDeCroock) (See [#1135](https://github.com/FormidableLabs/urql/pull/1135))\n- Updated dependencies (See [#1135](https://github.com/FormidableLabs/urql/pull/1135))\n  - @urql/core@1.15.1\n\n## 1.0.2\n\n### Patch Changes\n\n- Add missing `.mjs` extension to all imports from `graphql` to fix Webpack 5 builds, which require extension-specific import paths for ESM bundles and packages. **This change allows you to safely upgrade to Webpack 5.**, by [@kitten](https://github.com/kitten) (See [#1094](https://github.com/FormidableLabs/urql/pull/1094))\n- Deprecate the `Operation.operationName` property in favor of `Operation.kind`. This name was\n  previously confusing as `operationName` was effectively referring to two different things. You can\n  safely upgrade to this new version, however to mute all deprecation warnings you will have to\n  **upgrade** all `urql` packages you use. If you have custom exchanges that spread operations, please\n  use [the new `makeOperation` helper\n  function](https://formidable.com/open-source/urql/docs/api/core/#makeoperation) instead, by [@bkonkle](https://github.com/bkonkle) (See [#1045](https://github.com/FormidableLabs/urql/pull/1045))\n- Updated dependencies (See [#1094](https://github.com/FormidableLabs/urql/pull/1094) and [#1045](https://github.com/FormidableLabs/urql/pull/1045))\n  - @urql/core@1.14.0\n\n## 1.0.1\n\n### Patch Changes\n\n- Upgrade to a minimum version of wonka@^4.0.14 to work around issues with React Native's minification builds, which use uglify-es and could lead to broken bundles, by [@kitten](https://github.com/kitten) (See [#842](https://github.com/FormidableLabs/urql/pull/842))\n- Updated dependencies (See [#838](https://github.com/FormidableLabs/urql/pull/838) and [#842](https://github.com/FormidableLabs/urql/pull/842))\n  - @urql/core@1.12.0\n\n## v1.0.0\n\n**Initial Release**\n"
  },
  {
    "path": "exchanges/execute/README.md",
    "content": "<h2 align=\"center\">@urql/exchange-execute</h2>\n\n<p align=\"center\"><strong>An exchange for executing queries against a local schema in <code>urql</code></strong></p>\n\n`@urql/exchange-execute` is an exchange for the [`urql`](https://github.com/urql-graphql/urql) GraphQL client which executes queries against a local schema.\nThis is a replacement for the default _fetchExchange_ which sends queries over HTTP/S to be executed remotely.\n\n## Quick Start Guide\n\nFirst install `@urql/exchange-execute` alongside `urql`:\n\n```sh\nyarn add @urql/exchange-execute\n# or\nnpm install --save @urql/exchange-execute\n```\n\nYou'll then need to add the `executeExchange`, that this package exposes, to your `urql` Client,\nby replacing the default fetch exchange with it:\n\n```js\nimport { createClient, cacheExchange } from 'urql';\nimport { executeExchange } from '@urql/exchange-execute';\n\nconst client = createClient({\n  url: 'http://localhost:1234/graphql',\n  exchanges: [\n    cacheExchange,\n    // Replace the default fetchExchange with the new one.\n    executeExchange({\n      /* config */\n    }),\n  ],\n});\n```\n\n## Usage\n\nThe exchange takes the same arguments as the [_execute_ function](https://graphql.org/graphql-js/execution/#execute) provided by graphql-js.\n\nHere's a brief example of how it might be used:\n\n```js\nimport { buildSchema } from 'graphql';\n\n// Create local schema\nconst schema = buildSchema(`\n  type Todo {\n    id: ID!\n    text: String!\n  }\n\n  type Query {\n    todos: [Todo]!\n  }\n\n  type Mutation {\n    addTodo(text: String!): Todo!\n  }\n`);\n\n// Create local state\nlet todos = [];\n\n// Create root value with resolvers\nconst rootValue = {\n  todos: () => todos,\n  addTodo: (_, args) => {\n    const todo = { id: todos.length.toString(), ...args };\n    todos = [...todos, todo];\n    return todo;\n  }\n}\n\n// ...\n\n// Pass schema and root value to executeExchange\nexecuteExchange({\n  schema,\n  rootValue,\n}),\n// ...\n```\n"
  },
  {
    "path": "exchanges/execute/jsr.json",
    "content": "{\n  \"name\": \"@urql/exchange-execute\",\n  \"version\": \"3.0.0\",\n  \"exports\": {\n    \".\": \"./src/index.ts\"\n  },\n  \"exclude\": [\n    \"node_modules\",\n    \"cypress\",\n    \"**/*.test.*\",\n    \"**/*.spec.*\",\n    \"**/*.test.*.snap\",\n    \"**/*.spec.*.snap\"\n  ]\n}"
  },
  {
    "path": "exchanges/execute/package.json",
    "content": "{\n  \"name\": \"@urql/exchange-execute\",\n  \"version\": \"3.0.0\",\n  \"description\": \"An exchange for executing queries against a local schema in urql\",\n  \"sideEffects\": false,\n  \"homepage\": \"https://formidable.com/open-source/urql/docs/\",\n  \"bugs\": \"https://github.com/urql-graphql/urql/issues\",\n  \"license\": \"MIT\",\n  \"author\": \"urql GraphQL Contributors\",\n  \"repository\": {\n    \"type\": \"git\",\n    \"url\": \"https://github.com/urql-graphql/urql.git\",\n    \"directory\": \"exchanges/execute\"\n  },\n  \"keywords\": [\n    \"urql\",\n    \"exchange\",\n    \"execute\",\n    \"executable schema\",\n    \"graphql\",\n    \"exchanges\"\n  ],\n  \"main\": \"dist/urql-exchange-execute\",\n  \"module\": \"dist/urql-exchange-execute.mjs\",\n  \"types\": \"dist/urql-exchange-execute.d.ts\",\n  \"source\": \"src/index.ts\",\n  \"exports\": {\n    \".\": {\n      \"types\": \"./dist/urql-exchange-execute.d.ts\",\n      \"import\": \"./dist/urql-exchange-execute.mjs\",\n      \"require\": \"./dist/urql-exchange-execute.js\",\n      \"source\": \"./src/index.ts\"\n    },\n    \"./package.json\": \"./package.json\"\n  },\n  \"files\": [\n    \"LICENSE\",\n    \"CHANGELOG.md\",\n    \"README.md\",\n    \"dist/\"\n  ],\n  \"scripts\": {\n    \"test\": \"vitest\",\n    \"clean\": \"rimraf dist extras\",\n    \"check\": \"tsc --noEmit\",\n    \"lint\": \"eslint --ext=js,jsx,ts,tsx .\",\n    \"build\": \"rollup -c ../../scripts/rollup/config.mjs\",\n    \"prepare\": \"node ../../scripts/prepare/index.js\",\n    \"prepublishOnly\": \"run-s clean build\"\n  },\n  \"dependencies\": {\n    \"@urql/core\": \"workspace:^6.0.1\",\n    \"wonka\": \"^6.3.2\"\n  },\n  \"peerDependencies\": {\n    \"@urql/core\": \"^6.0.0\",\n    \"graphql\": \"^14.0.0 || ^15.0.0 || ^16.0.0 || ^17.0.0\"\n  },\n  \"devDependencies\": {\n    \"@urql/core\": \"workspace:*\",\n    \"graphql\": \"^16.0.0\"\n  },\n  \"publishConfig\": {\n    \"access\": \"public\",\n    \"provenance\": true\n  }\n}\n"
  },
  {
    "path": "exchanges/execute/src/execute.test.ts",
    "content": "import { vi, expect, it, beforeEach, afterEach, describe, Mock } from 'vitest';\n\nvi.mock('graphql', async () => {\n  const graphql = await vi.importActual<typeof import('graphql')>('graphql');\n\n  return {\n    __esModule: true,\n    ...(graphql as object),\n    print: vi.fn(() => '{ placeholder }'),\n    execute: vi.fn(() => ({ key: 'value' })),\n    subscribe: vi.fn(),\n  };\n});\n\nimport { fetchExchange } from '@urql/core';\nimport { executeExchange } from './execute';\nimport { execute, print, subscribe } from 'graphql';\nimport {\n  pipe,\n  fromValue,\n  toPromise,\n  take,\n  makeSubject,\n  empty,\n  Source,\n} from 'wonka';\nimport {\n  context,\n  queryOperation,\n  subscriptionOperation,\n} from '../../../packages/core/src/test-utils';\nimport {\n  makeErrorResult,\n  makeOperation,\n  Client,\n  OperationResult,\n} from '@urql/core';\n\nconst mocked = (x: any): any => x;\n\nconst schema = 'STUB_SCHEMA' as any;\nconst exchangeArgs = {\n  forward: a => a,\n  client: {},\n} as any;\n\nconst expectedQueryOperationName = 'getUser';\nconst expectedSubscribeOperationName = 'subscribeToUser';\n\nconst fetchMock = (globalThis as any).fetch as Mock;\nconst mockHttpResponseData = { key: 'value' };\n\nbeforeEach(() => {\n  vi.clearAllMocks();\n  mocked(print).mockImplementation(a => a as any);\n  mocked(execute).mockResolvedValue({ data: mockHttpResponseData });\n  mocked(subscribe).mockImplementation(async function* x(this: any) {\n    yield { data: { key: 'value1' } };\n    yield { data: { key: 'value2' } };\n    yield { data: { key: 'value3' } };\n  });\n});\n\nafterEach(() => {\n  fetchMock.mockClear();\n});\n\ndescribe('on operation', () => {\n  it('calls execute with args', async () => {\n    const context = 'USER_ID=123';\n\n    await pipe(\n      fromValue(queryOperation),\n      executeExchange({ schema, context })(exchangeArgs),\n      take(1),\n      toPromise\n    );\n\n    expect(mocked(execute)).toBeCalledTimes(1);\n    expect(mocked(execute)).toBeCalledWith({\n      schema,\n      document: queryOperation.query,\n      rootValue: undefined,\n      contextValue: context,\n      variableValues: queryOperation.variables,\n      operationName: expectedQueryOperationName,\n      fieldResolver: undefined,\n      typeResolver: undefined,\n      subscribeFieldResolver: undefined,\n    });\n  });\n\n  it('calls subscribe with args', async () => {\n    const context = 'USER_ID=123';\n\n    await pipe(\n      fromValue(subscriptionOperation),\n      executeExchange({ schema, context })(exchangeArgs),\n      take(3),\n      toPromise\n    );\n\n    expect(mocked(subscribe)).toBeCalledTimes(1);\n    expect(mocked(subscribe)).toBeCalledWith({\n      schema,\n      document: subscriptionOperation.query,\n      rootValue: undefined,\n      contextValue: context,\n      variableValues: subscriptionOperation.variables,\n      operationName: expectedSubscribeOperationName,\n      fieldResolver: undefined,\n      typeResolver: undefined,\n      subscribeFieldResolver: undefined,\n    });\n  });\n\n  it('calls execute after executing context as a function', async () => {\n    const context = operation => {\n      expect(operation).toBe(queryOperation);\n      return 'CALCULATED_USER_ID=' + 8 * 10;\n    };\n\n    await pipe(\n      fromValue(queryOperation),\n      executeExchange({ schema, context })(exchangeArgs),\n      take(1),\n      toPromise\n    );\n\n    expect(mocked(execute)).toBeCalledTimes(1);\n    expect(mocked(execute)).toBeCalledWith({\n      schema,\n      document: queryOperation.query,\n      rootValue: undefined,\n      contextValue: 'CALCULATED_USER_ID=80',\n      variableValues: queryOperation.variables,\n      operationName: expectedQueryOperationName,\n      fieldResolver: undefined,\n      typeResolver: undefined,\n      subscribeFieldResolver: undefined,\n    });\n  });\n\n  it('calls execute after executing context as a function returning a Promise', async () => {\n    const context = async operation => {\n      expect(operation).toBe(queryOperation);\n      return 'CALCULATED_USER_ID=' + 8 * 10;\n    };\n\n    await pipe(\n      fromValue(queryOperation),\n      executeExchange({ schema, context })(exchangeArgs),\n      take(1),\n      toPromise\n    );\n\n    expect(mocked(execute)).toBeCalledTimes(1);\n    expect(mocked(execute)).toBeCalledWith({\n      schema,\n      document: queryOperation.query,\n      rootValue: undefined,\n      contextValue: 'CALCULATED_USER_ID=80',\n      variableValues: queryOperation.variables,\n      operationName: expectedQueryOperationName,\n      fieldResolver: undefined,\n      typeResolver: undefined,\n      subscribeFieldResolver: undefined,\n    });\n  });\n\n  it('should return data from subscribe', async () => {\n    const context = 'USER_ID=123';\n\n    const responseFromExecuteExchange = await pipe(\n      fromValue(subscriptionOperation),\n      executeExchange({ schema, context })(exchangeArgs),\n      take(3),\n      toPromise\n    );\n\n    expect(responseFromExecuteExchange.data).toEqual({ key: 'value3' });\n  });\n\n  it('should return the same data as the fetch exchange', async () => {\n    const context = 'USER_ID=123';\n\n    const responseFromExecuteExchange = await pipe(\n      fromValue(queryOperation),\n      executeExchange({ schema, context })(exchangeArgs),\n      take(1),\n      toPromise\n    );\n\n    fetchMock.mockResolvedValue({\n      status: 200,\n      headers: { get: () => 'application/json' },\n      text: vi\n        .fn()\n        .mockResolvedValue(JSON.stringify({ data: mockHttpResponseData })),\n    });\n\n    const responseFromFetchExchange = await pipe(\n      fromValue(queryOperation),\n      fetchExchange({\n        dispatchDebug: vi.fn(),\n        forward: () => empty as Source<OperationResult>,\n        client: {} as Client,\n      }),\n      toPromise\n    );\n\n    expect(responseFromExecuteExchange.data).toEqual(\n      responseFromFetchExchange.data\n    );\n    expect(mocked(execute)).toBeCalledTimes(1);\n    expect(fetchMock).toBeCalledTimes(1);\n  });\n\n  it('should trim undefined values before calling execute()', async () => {\n    const contextValue = 'USER_ID=123';\n\n    const operation = makeOperation(\n      'query',\n      {\n        ...queryOperation,\n        variables: { ...queryOperation.variables, withLastName: undefined },\n      },\n      context\n    );\n\n    await pipe(\n      fromValue(operation),\n      executeExchange({ schema, context: contextValue })(exchangeArgs),\n      take(1),\n      toPromise\n    );\n\n    expect(mocked(execute)).toBeCalledTimes(1);\n    expect(mocked(execute)).toBeCalledWith({\n      schema,\n      document: queryOperation.query,\n      rootValue: undefined,\n      contextValue: contextValue,\n      variableValues: queryOperation.variables,\n      operationName: expectedQueryOperationName,\n      fieldResolver: undefined,\n      typeResolver: undefined,\n      subscribeFieldResolver: undefined,\n    });\n\n    const variables = mocked(execute).mock.calls[0][0].variableValues;\n\n    for (const key in variables) {\n      expect(variables[key]).not.toBeUndefined();\n    }\n  });\n});\n\ndescribe('on success response', () => {\n  it('returns operation result', async () => {\n    const response = await pipe(\n      fromValue(queryOperation),\n      executeExchange({ schema })(exchangeArgs),\n      take(1),\n      toPromise\n    );\n\n    expect(response).toEqual({\n      operation: queryOperation,\n      data: mockHttpResponseData,\n      hasNext: false,\n      stale: false,\n    });\n  });\n});\n\ndescribe('on error response', () => {\n  const errors = ['error'] as any;\n\n  beforeEach(() => {\n    mocked(execute).mockResolvedValue({ errors });\n  });\n\n  it('returns operation result', async () => {\n    const response = await pipe(\n      fromValue(queryOperation),\n      executeExchange({ schema })(exchangeArgs),\n      take(1),\n      toPromise\n    );\n\n    expect(response).toHaveProperty('operation', queryOperation);\n    expect(response).toHaveProperty('error');\n  });\n});\n\ndescribe('on thrown error', () => {\n  const errors = ['error'] as any;\n\n  beforeEach(() => {\n    mocked(execute).mockRejectedValue({ errors });\n  });\n\n  it('returns operation result', async () => {\n    const response = await pipe(\n      fromValue(queryOperation),\n      executeExchange({ schema })(exchangeArgs),\n      take(1),\n      toPromise\n    );\n\n    const expected = makeErrorResult(queryOperation, errors);\n\n    expect(response.operation).toBe(expected.operation);\n    expect(response.data).toEqual(expected.data);\n    expect(response.error).toEqual(expected.error);\n  });\n});\n\ndescribe('on unsupported operation', () => {\n  const operation = makeOperation(\n    'teardown',\n    queryOperation,\n    queryOperation.context\n  );\n\n  it('returns operation result', async () => {\n    const { source, next } = makeSubject<any>();\n\n    const response = pipe(\n      source,\n      executeExchange({ schema })(exchangeArgs),\n      take(1),\n      toPromise\n    );\n\n    next(operation);\n    expect(await response).toEqual(operation);\n  });\n});\n"
  },
  {
    "path": "exchanges/execute/src/execute.ts",
    "content": "import type { Source } from 'wonka';\nimport { pipe, filter, takeUntil, mergeMap, merge, make } from 'wonka';\n\nimport type {\n  GraphQLSchema,\n  GraphQLFieldResolver,\n  GraphQLTypeResolver,\n  ExecutionArgs,\n  SubscriptionArgs,\n} from 'graphql';\nimport { execute, subscribe, Kind } from 'graphql';\n\nimport type {\n  Exchange,\n  ExecutionResult,\n  Operation,\n  OperationResult,\n} from '@urql/core';\nimport { makeResult, makeErrorResult, mergeResultPatch } from '@urql/core';\n\n/** Input parameters for the {@link executeExchange}.\n * @see {@link ExecutionArgs} which this interface mirrors. */\nexport interface ExecuteExchangeArgs {\n  /** GraphQL Schema definition that `Operation`s are execute against. */\n  schema: GraphQLSchema;\n  /** Context object or a factory function creating a `context` object.\n   *\n   * @remarks\n   * The `context` that is passed to the `schema` may either be passed\n   * or created from an incoming `Operation`, which also allows it to\n   * be recreated per `Operation`.\n   */\n  context?: ((operation: Operation) => any) | any;\n  rootValue?: any;\n  fieldResolver?: GraphQLFieldResolver<any, any>;\n  typeResolver?: GraphQLTypeResolver<any, any>;\n  subscribeFieldResolver?: GraphQLFieldResolver<any, any>;\n}\n\ntype ExecuteParams = ExecutionArgs | SubscriptionArgs;\n\nconst asyncIterator =\n  typeof Symbol !== 'undefined' ? Symbol.asyncIterator : null;\n\nconst makeExecuteSource = (\n  operation: Operation,\n  _args: ExecuteParams\n): Source<OperationResult> => {\n  return make<OperationResult>(observer => {\n    let iterator: AsyncIterator<ExecutionResult>;\n    let ended = false;\n\n    Promise.resolve()\n      .then(async () => ({ ..._args, contextValue: await _args.contextValue }))\n      .then(args => {\n        if (ended) return;\n        if (operation.kind === 'subscription') {\n          return subscribe(args) as any;\n        }\n        return execute(args) as any;\n      })\n      .then((result: ExecutionResult | AsyncIterable<ExecutionResult>) => {\n        if (ended || !result) {\n          return;\n        } else if (!asyncIterator || !result[asyncIterator]) {\n          observer.next(makeResult(operation, result as ExecutionResult));\n          return;\n        }\n        iterator = result[asyncIterator!]();\n        let prevResult: OperationResult | null = null;\n\n        function next({\n          done,\n          value,\n        }: {\n          done?: boolean;\n          value: ExecutionResult;\n        }) {\n          if (value) {\n            observer.next(\n              (prevResult = prevResult\n                ? mergeResultPatch(prevResult, value)\n                : makeResult(operation, value))\n            );\n          }\n\n          if (!done && !ended) {\n            return iterator.next().then(next);\n          }\n        }\n\n        return iterator.next().then(next);\n      })\n      .then(() => {\n        observer.complete();\n      })\n      .catch(error => {\n        observer.next(makeErrorResult(operation, error));\n        observer.complete();\n      });\n\n    return () => {\n      if (iterator && iterator.return) iterator.return();\n      ended = true;\n    };\n  });\n};\n\n/** Exchange factory that executes operations against a GraphQL schema.\n *\n * @param options - A {@link ExecuteExchangeArgs} configuration object.\n * @returns the created execute {@link Exchange}.\n *\n * @remarks\n * The `executeExchange` executes GraphQL operations against the `schema`\n * that it’s passed. As such, its options mirror the options that GraphQL.js’\n * {@link execute} function accepts.\n */\nexport const executeExchange =\n  (options: ExecuteExchangeArgs): Exchange =>\n  ({ forward }) => {\n    return operations$ => {\n      const executedOps$ = pipe(\n        operations$,\n        filter((operation: Operation) => {\n          return (\n            operation.kind === 'query' ||\n            operation.kind === 'mutation' ||\n            operation.kind === 'subscription'\n          );\n        }),\n        mergeMap((operation: Operation) => {\n          const { key } = operation;\n          const teardown$ = pipe(\n            operations$,\n            filter(op => op.kind === 'teardown' && op.key === key)\n          );\n\n          const contextValue =\n            typeof options.context === 'function'\n              ? options.context(operation)\n              : options.context;\n\n          // Filter undefined values from variables before calling execute()\n          // to support default values within directives.\n          const variableValues = Object.create(null);\n          if (operation.variables) {\n            for (const key in operation.variables) {\n              if (operation.variables[key] !== undefined) {\n                variableValues[key] = operation.variables[key];\n              }\n            }\n          }\n\n          let operationName: string | undefined;\n          for (const node of operation.query.definitions) {\n            if (node.kind === Kind.OPERATION_DEFINITION) {\n              operationName = node.name ? node.name.value : undefined;\n              break;\n            }\n          }\n\n          return pipe(\n            makeExecuteSource(operation, {\n              schema: options.schema,\n              document: operation.query,\n              rootValue: options.rootValue,\n              contextValue,\n              variableValues,\n              operationName,\n              fieldResolver: options.fieldResolver,\n              typeResolver: options.typeResolver,\n              subscribeFieldResolver: options.subscribeFieldResolver,\n            }),\n            takeUntil(teardown$)\n          );\n        })\n      );\n\n      const forwardedOps$ = pipe(\n        operations$,\n        filter(operation => operation.kind === 'teardown'),\n        forward\n      );\n\n      return merge([executedOps$, forwardedOps$]);\n    };\n  };\n"
  },
  {
    "path": "exchanges/execute/src/index.ts",
    "content": "export { executeExchange } from './execute';\nexport type { ExecuteExchangeArgs } from './execute';\n"
  },
  {
    "path": "exchanges/execute/tsconfig.json",
    "content": "{\n  \"extends\": \"../../tsconfig.json\",\n  \"include\": [\"src\"]\n}\n"
  },
  {
    "path": "exchanges/execute/vitest.config.ts",
    "content": "import { mergeConfig } from 'vitest/config';\nimport baseConfig from '../../vitest.config';\n\nexport default mergeConfig(baseConfig, {});\n"
  },
  {
    "path": "exchanges/graphcache/.gitignore",
    "content": "/extras\n/default-storage\n"
  },
  {
    "path": "exchanges/graphcache/CHANGELOG.md",
    "content": "# @urql/exchange-graphcache\n\n## 9.0.0\n\n### Major Changes\n\n- Don't serialize data to IDB. This invalidates all existing data, but greatly improves performance of read/write operations\n  Submitted by [@ThaUnknown](https://github.com/ThaUnknown) (See [#3824](https://github.com/urql-graphql/urql/pull/3824))\n\n## 8.1.0\n\n### Minor Changes\n\n- Add possibleTypes config for deterministic fragment matching\n  Submitted by [@xuanduc987](https://github.com/xuanduc987) (See [#3805](https://github.com/urql-graphql/urql/pull/3805))\n\n## 8.0.0\n\n### Patch Changes\n\n- Updated dependencies (See [#3789](https://github.com/urql-graphql/urql/pull/3789) and [#3807](https://github.com/urql-graphql/urql/pull/3807))\n  - @urql/core@6.0.0\n\n## 7.2.4\n\n### Patch Changes\n\n- ⚠️ Fix compatibility with Typescript >5.5 (See: https://github.com/0no-co/graphql.web/pull/49)\n  Submitted by [@andreisergiu98](https://github.com/andreisergiu98) (See [#3730](https://github.com/urql-graphql/urql/pull/3730))\n- Updated dependencies (See [#3773](https://github.com/urql-graphql/urql/pull/3773), [#3767](https://github.com/urql-graphql/urql/pull/3767), [#3730](https://github.com/urql-graphql/urql/pull/3730), and [#3770](https://github.com/urql-graphql/urql/pull/3770))\n  - @urql/core@5.1.2\n\n## 7.2.3\n\n### Patch Changes\n\n- Omit minified files and sourcemaps' `sourcesContent` in published packages\n  Submitted by [@kitten](https://github.com/kitten) (See [#3755](https://github.com/urql-graphql/urql/pull/3755))\n- Updated dependencies (See [#3755](https://github.com/urql-graphql/urql/pull/3755))\n  - @urql/core@5.1.1\n\n## 7.2.2\n\n### Patch Changes\n\n- Remove addMetadata transform where we'd strip out metadata for production environments, this particularly affects OperationResult.context.metadata.cacheOutcome\n  Submitted by [@JoviDeCroock](https://github.com/JoviDeCroock) (See [#3744](https://github.com/urql-graphql/urql/pull/3744))\n\n## 7.2.1\n\n### Patch Changes\n\n- Update selection iterator implementation for JSC memory reduction\n  Submitted by [@kitten](https://github.com/kitten) (See [#3693](https://github.com/urql-graphql/urql/pull/3693))\n\n## 7.2.0\n\n### Minor Changes\n\n- Allow @\\_required directive to be used in combination with configured schemas\n  Submitted by [@AndrewIngram](https://github.com/AndrewIngram) (See [#3685](https://github.com/urql-graphql/urql/pull/3685))\n\n## 7.1.3\n\n### Patch Changes\n\n- ⚠️ fix bug that mutation would cause dependent operations and reexecuting operations to become the same set\n  Submitted by [@xuanduc987](https://github.com/xuanduc987) (See [#3665](https://github.com/urql-graphql/urql/pull/3665))\n\n## 7.1.2\n\n### Patch Changes\n\n- Disregard write-only operation when fragment-matching with schema awareness\n  Submitted by [@JoviDeCroock](https://github.com/JoviDeCroock) (See [#3621](https://github.com/urql-graphql/urql/pull/3621))\n\n## 7.1.1\n\n### Patch Changes\n\n- ⚠️ Fix where we would incorrectly match all fragment concrete types because they belong to the abstract type\n  Submitted by [@JoviDeCroock](https://github.com/JoviDeCroock) (See [#3603](https://github.com/urql-graphql/urql/pull/3603))\n\n## 7.1.0\n\n### Minor Changes\n\n- Mark `@urql/core` as a peer dependency as well as a regular dependency\n  Submitted by [@kitten](https://github.com/kitten) (See [#3579](https://github.com/urql-graphql/urql/pull/3579))\n\n## 7.0.2\n\n### Patch Changes\n\n- Only record dependencies that are changing data, this will reduce the amount of operations we re-invoke due to network-only/cache-and-network queries and mutations\n  Submitted by [@JoviDeCroock](https://github.com/JoviDeCroock) (See [#3564](https://github.com/urql-graphql/urql/pull/3564))\n\n## 7.0.1\n\n### Patch Changes\n\n- When invoking the automatic creation updater ignore the entity we are currently on in the mutation\n  Submitted by [@JoviDeCroock](https://github.com/JoviDeCroock) (See [#3560](https://github.com/urql-graphql/urql/pull/3560))\n\n## 7.0.0\n\n### Major Changes\n\n- Add a default updater for mutation fields who are lacking an updater and where the returned entity is not present in the cache\n  Submitted by [@JoviDeCroock](https://github.com/JoviDeCroock) (See [#3518](https://github.com/urql-graphql/urql/pull/3518))\n- Remove deprecated `resolveFieldByKey`, use `cache.resolve` instead\n  Submitted by [@JoviDeCroock](https://github.com/JoviDeCroock) (See [#3520](https://github.com/urql-graphql/urql/pull/3520))\n\n### Minor Changes\n\n- Track abstract types being written so that we have a more reliable way of matching abstract fragments\n  Submitted by [@JoviDeCroock](https://github.com/JoviDeCroock) (See [#3548](https://github.com/urql-graphql/urql/pull/3548))\n\n### Patch Changes\n\n- ⚠️ Fix `invalidate` not applying when using a string to invalidate an entity\n  Submitted by [@JoviDeCroock](https://github.com/JoviDeCroock) (See [#3545](https://github.com/urql-graphql/urql/pull/3545))\n- Upgrade `@0no-co/graphql.web` to `1.0.5`\n  Submitted by [@kitten](https://github.com/kitten) (See [#3553](https://github.com/urql-graphql/urql/pull/3553))\n- Updated dependencies (See [#3520](https://github.com/urql-graphql/urql/pull/3520), [#3553](https://github.com/urql-graphql/urql/pull/3553), and [#3520](https://github.com/urql-graphql/urql/pull/3520))\n  - @urql/core@5.0.0\n\n## 6.5.0\n\n### Minor Changes\n\n- Allow `@_optional` and `@_required` to be placed on fragment definitions and inline fragments\n  Submitted by [@JoviDeCroock](https://github.com/JoviDeCroock) (See [#3502](https://github.com/urql-graphql/urql/pull/3502))\n- Track list of entity keys for a given type name. This enables enumerating and invalidating all entities of a given type within the normalized cache\n  Submitted by [@JoviDeCroock](https://github.com/JoviDeCroock) (See [#3501](https://github.com/urql-graphql/urql/pull/3501))\n\n### Patch Changes\n\n- Prevent `@defer` from being applied in child field selections. Previously, a child field (i.e. a nested field) under a `@defer`-ed fragment would also become optional, which was based on a prior version of the DeferStream spec which didn't require deferred fields to be delivered as a group\n  Submitted by [@kitten](https://github.com/kitten) (See [#3517](https://github.com/urql-graphql/urql/pull/3517))\n- ⚠️ Fix `store.resolve()` returning the exact link array that’s used by the cache. This can lead to subtle bugs when a user mutates the result returned by `cache.resolve()`, since this directly mutates what’s in the cache at that layer\n  Submitted by [@kitten](https://github.com/kitten) (See [#3516](https://github.com/urql-graphql/urql/pull/3516))\n- Updated dependencies (See [#3514](https://github.com/urql-graphql/urql/pull/3514), [#3505](https://github.com/urql-graphql/urql/pull/3505), [#3499](https://github.com/urql-graphql/urql/pull/3499), and [#3515](https://github.com/urql-graphql/urql/pull/3515))\n  - @urql/core@4.3.0\n\n## 6.4.1\n\n### Patch Changes\n\n- Set `stale: true` on cache results, even if a reexecution has been blocked by the loop protection, if the operation is already pending and in-flight\n  Submitted by [@kitten](https://github.com/kitten) (See [#3493](https://github.com/urql-graphql/urql/pull/3493))\n- ⚠️ Fix `@defer` state leaking into following operations\n  Submitted by [@kitten](https://github.com/kitten) (See [#3497](https://github.com/urql-graphql/urql/pull/3497))\n\n## 6.4.0\n\n### Minor Changes\n\n- Allow the user to debug cache-misses by means of the new `logger` interface on the `cacheExchange`. A field miss will dispatch a `debug` log when it's not marked with `@_optional` or when it's non-nullable in the `schema`\n  Submitted by [@JoviDeCroock](https://github.com/JoviDeCroock) (See [#3446](https://github.com/urql-graphql/urql/pull/3446))\n- Add `onCacheHydrated` as an option for the `StorageAdapter`\n  Submitted by [@JoviDeCroock](https://github.com/JoviDeCroock) (See [#3428](https://github.com/urql-graphql/urql/pull/3428))\n- Add optional `logger` to the options, this allows you to filter out warnings or disable them all together\n  Submitted by [@JoviDeCroock](https://github.com/JoviDeCroock) (See [#3444](https://github.com/urql-graphql/urql/pull/3444))\n\n## 6.3.3\n\n### Patch Changes\n\n- ⚠️ Fix a typo that caused an inverted condition, for checking owned data, to cause incorrect results when handling `null` values and encountering them first\n  Submitted by [@kitten](https://github.com/kitten) (See [#3371](https://github.com/urql-graphql/urql/pull/3371))\n\n## 6.3.2\n\n### Patch Changes\n\n- ⚠️ Fix extra variables in mutation results regressing by a change made in [#3317](https://github.com/urql-graphql/urql/pull/3317). The original operation wasn't being preserved anymore\n  Submitted by [@kitten](https://github.com/kitten) (See [#3356](https://github.com/urql-graphql/urql/pull/3356))\n\n## 6.3.1\n\n### Patch Changes\n\n- Reset `partial` result marker when reading from selections when a child value sees a cache miss. This only affects resolvers on child values enabling `info.partial` while a parent may abort early instead\n  Submitted by [@kitten](https://github.com/kitten) (See [#3340](https://github.com/urql-graphql/urql/pull/3340))\n- ⚠️ Fix `@_optional` directive not setting `info.partial = true` on cache miss and fix usage of `info.parentKey` and `info.parentFieldKey` usage in default directives\n  Submitted by [@kitten](https://github.com/kitten) (See [#3338](https://github.com/urql-graphql/urql/pull/3338))\n- Replace implementation for `@_optional` and `@_required` with built-in handling inside cache reads to allow `@_optional` to work for nested selection sets\n  Submitted by [@kitten](https://github.com/kitten) (See [#3341](https://github.com/urql-graphql/urql/pull/3341))\n\n## 6.3.0\n\n### Minor Changes\n\n- Allow scalar values on the parent to be accessed from `parent[info.fieldName]` consistently. Prior to this change `parent[fieldAlias]` would get populated, which wouldn’t always result in a field that’s consistently accessible\n  Submitted by [@kitten](https://github.com/kitten) (See [#3336](https://github.com/urql-graphql/urql/pull/3336))\n- Allow `cache.resolve` to return `undefined` when a value is not cached to make it easier to cause a cache miss in resolvers. **Reminder:** Returning `undefined` from a resolver means a field is uncached, while returning `null` means that a field’s value is `null` without causing a cache miss\n  Submitted by [@kitten](https://github.com/kitten) (See [#3333](https://github.com/urql-graphql/urql/pull/3333))\n\n### Patch Changes\n\n- Record a dependency when `__typename` field is read. This removes a prior, outdated exception to avoid confusion when using `cache.resolve(entity, '__typename')` which doesn't cause the cache to record a dependency\n  Submitted by [@kitten](https://github.com/kitten) (See [#3335](https://github.com/urql-graphql/urql/pull/3335))\n- ⚠️ Fix cases where `ResolveInfo`’s `parentFieldKey` was incorrectly populated with a key that isn’t a field key (allowing for `cache.resolve(info.parentKey, info.parentFieldKey)` to be possible) but was instead set to `info.parentKey` combined with the field key\n  Submitted by [@kitten](https://github.com/kitten) (See [#3336](https://github.com/urql-graphql/urql/pull/3336))\n\n## 6.2.0\n\n### Minor Changes\n\n- Implement **local directives**. It’s now possible to add client-only directives to queries by adding them to the `cacheExchange`’s new `directives` option.\n  Directives accept an object of their arguments and return a resolver. When a field is annotated with\n  a resolver, e.g. `@_optional` or `@_required`, their resolvers from the `directives` config are\n  executed. This means it’s now possible to use `@_relayPagination` for example, by passing adding\n  the `relayPagination` helper to the config.\n  Due to the change in [#3317](https://github.com/urql-graphql/urql/pull/3317), any directive in\n  queries that’s prefixed with an underscore (`_`) is only visible to Graphcache and not the API.\n  Submitted by undefined (See https://github.com/urql-graphql/urql/pull/3306)\n\n### Patch Changes\n\n- Use new `FormattedNode` / `formatDocument` functionality added to `@urql/core` to slightly speed up directive processing by using the client-side `_directives` dictionary that `formatDocument` adds\n  Submitted by [@kitten](https://github.com/kitten) (See [#3317](https://github.com/urql-graphql/urql/pull/3317))\n- Allow `offlineExchange` to once again issue all request policies, instead of mapping them to `cache-first`. When replaying operations after rehydrating it will now prioritise network policies, and before rehydrating receiving a network result will prevent a network request from being issued again\n  Submitted by [@kitten](https://github.com/kitten) (See [#3308](https://github.com/urql-graphql/urql/pull/3308))\n- Add `OperationContext.optimistic` flag as an internal indication on whether a mutation triggered an optimistic update in `@urql/exchange-graphcache`'s `cacheExchange`\n  Submitted by [@kitten](https://github.com/kitten) (See [#3308](https://github.com/urql-graphql/urql/pull/3308))\n- Updated dependencies (See [#3317](https://github.com/urql-graphql/urql/pull/3317) and [#3308](https://github.com/urql-graphql/urql/pull/3308))\n  - @urql/core@4.1.0\n\n## 6.1.4\n\n### Patch Changes\n\n- ⚠️ Fix untranspiled class property initializer syntax being leftover in build output. (Regression in #3053)\n  Submitted by [@kitten](https://github.com/kitten) (See [#3275](https://github.com/urql-graphql/urql/pull/3275))\n\n## 6.1.3\n\n### Patch Changes\n\n- ⚠️ Fix `info.parentKey` not being correctly set for updaters or optimistic updaters\n  Submitted by [@kitten](https://github.com/kitten) (See [#3267](https://github.com/urql-graphql/urql/pull/3267))\n\n## 6.1.2\n\n### Patch Changes\n\n- Make \"Invalid undefined\" warning heuristic smarter and allow for partial optimistic results. Previously, when a partial optimistic result would be passed, a warning would be issued, and in production, fields would be deleted from the cache. Instead, we now only issue a warning if these fields aren't cached already\n  Submitted by [@kitten](https://github.com/kitten) (See [#3264](https://github.com/urql-graphql/urql/pull/3264))\n- Optimistic mutation results should never result in dependent operations being blocked\n  Submitted by [@kitten](https://github.com/kitten) (See [#3265](https://github.com/urql-graphql/urql/pull/3265))\n\n## 6.1.1\n\n### Patch Changes\n\n- ⚠️ Fix torn down queries not being removed from `offlineExchange`’s failed queue on rehydration\n  Submitted by [@kitten](https://github.com/kitten) (See [#3236](https://github.com/urql-graphql/urql/pull/3236))\n\n## 6.1.0\n\n### Minor Changes\n\n- Add `globalIDs` configuration option to omit typenames in cache keys\n  Submitted by [@kitten](https://github.com/kitten) (See [#3224](https://github.com/urql-graphql/urql/pull/3224))\n\n### Patch Changes\n\n- Update build process to generate correct source maps\n  Submitted by [@kitten](https://github.com/kitten) (See [#3201](https://github.com/urql-graphql/urql/pull/3201))\n- Prevent `offlineExchange` from issuing duplicate operations\n  Submitted by [@kitten](https://github.com/kitten) (See [#3200](https://github.com/urql-graphql/urql/pull/3200))\n- ⚠️ Fix reference equality not being preserved. This is a fix on top of [#3165](https://github.com/urql-graphql/urql/pull/3165), and was previously not addressed to avoid having to test for corner cases that are hard to cover. If you experience issues with this fix, please let us know\n  Submitted by [@kitten](https://github.com/kitten) (See [#3228](https://github.com/urql-graphql/urql/pull/3228))\n- Retry operations against offline cache and stabilize timing of flushing failed operations queue after rehydrating the storage data\n  Submitted by [@kitten](https://github.com/kitten) (See [#3196](https://github.com/urql-graphql/urql/pull/3196))\n\n## 6.0.4\n\n### Patch Changes\n\n- ⚠️ Fix missing cache updates, when a query that was previously torn down restarts and retrieves results from the cache. In this case a regression caused cache updates to not be correctly applied to the queried results, since the operation wouldn’t be recognised properly\n  Submitted by [@kitten](https://github.com/kitten) (See [#3193](https://github.com/urql-graphql/urql/pull/3193))\n\n## 6.0.3\n\n### Patch Changes\n\n- Publish with npm provenance\n  Submitted by [@kitten](https://github.com/kitten) (See [#3180](https://github.com/urql-graphql/urql/pull/3180))\n\n## 6.0.2\n\n### Patch Changes\n\n- Prevent reusal of incoming API data in Graphcache’s produced (“owned”) data. This prevents us from copying the `__typename` and other superfluous fields\n  Submitted by [@kitten](https://github.com/kitten) (See [#3165](https://github.com/urql-graphql/urql/pull/3165))\n- ⚠️ Fix regression which caused `@defer` directives from becoming “sticky” and causing every subsequent cache read to be treated as if the field was deferred\n  Submitted by [@kitten](https://github.com/kitten) (See [#3167](https://github.com/urql-graphql/urql/pull/3167))\n- Apply `hasNext: true` and fallthrough logic to cached queries that contain deferred, uncached fields. Deferred query results will now be fetched against the API correctly, even if prior requests have been incomplete\n  Submitted by [@kitten](https://github.com/kitten) (See [#3163](https://github.com/urql-graphql/urql/pull/3163))\n- ⚠️ Fix `offlineExchange` duplicating offline mutations in failed queue\n  Submitted by [@kitten](https://github.com/kitten) (See [#3158](https://github.com/urql-graphql/urql/pull/3158))\n\n## 6.0.1\n\n### Patch Changes\n\n- Remove inclusion and usage of optional chaining operator\n  Submitted by [@kitten](https://github.com/kitten) (See [#3116](https://github.com/urql-graphql/urql/pull/3116))\n\n## 6.0.0\n\n### Major Changes\n\n- Remove dependence on `graphql` package and replace it with `@0no-co/graphql.web`, which reduces the default bundlesize impact of `urql` packages to a minimum. All types should remain compatible, even if you use `graphql` elsewhere in your app, and if other dependencies are using `graphql` you may alias it to `graphql-web-lite`\n  Submitted by [@kitten](https://github.com/kitten) (See [#3097](https://github.com/urql-graphql/urql/pull/3097))\n- Update `OperationResult.hasNext` and `OperationResult.stale` to be required fields. If you have a custom exchange creating results, you'll have to add these fields or use the `makeResult`, `mergeResultPatch`, or `makeErrorResult` helpers\n  Submitted by [@kitten](https://github.com/kitten) (See [#3061](https://github.com/urql-graphql/urql/pull/3061))\n\n### Minor Changes\n\n- Update exchanges to drop redundant `share` calls, since `@urql/core`’s `composeExchanges` utility now automatically does so for us\n  Submitted by [@kitten](https://github.com/kitten) (See [#3082](https://github.com/urql-graphql/urql/pull/3082))\n\n### Patch Changes\n\n- ⚠️ Fix source maps included with recently published packages, which lost their `sourcesContent`, including additional source files, and had incorrect paths in some of them\n  Submitted by [@kitten](https://github.com/kitten) (See [#3053](https://github.com/urql-graphql/urql/pull/3053))\n- Upgrade to `wonka@^6.3.0`\n  Submitted by [@kitten](https://github.com/kitten) (See [#3104](https://github.com/urql-graphql/urql/pull/3104))\n- Restore variables correctly on mutations\n  Submitted by [@JoviDeCroock](https://github.com/JoviDeCroock) (See [#3046](https://github.com/urql-graphql/urql/pull/3046))\n- Use `stringifyDocument` in `offlineExchange` rather than `print` and serialize `operation.extensions` as needed\n  Submitted by [@kitten](https://github.com/kitten) (See [#3094](https://github.com/urql-graphql/urql/pull/3094))\n- Add missing `hasNext` and `stale` passthroughs on caching exchanges\n  Submitted by [@kitten](https://github.com/kitten) (See [#3059](https://github.com/urql-graphql/urql/pull/3059))\n- Add TSDocs for all exchanges, documenting API internals\n  Submitted by [@kitten](https://github.com/kitten) (See [#3072](https://github.com/urql-graphql/urql/pull/3072))\n- Updated dependencies (See [#3101](https://github.com/urql-graphql/urql/pull/3101), [#3033](https://github.com/urql-graphql/urql/pull/3033), [#3054](https://github.com/urql-graphql/urql/pull/3054), [#3053](https://github.com/urql-graphql/urql/pull/3053), [#3060](https://github.com/urql-graphql/urql/pull/3060), [#3081](https://github.com/urql-graphql/urql/pull/3081), [#3039](https://github.com/urql-graphql/urql/pull/3039), [#3104](https://github.com/urql-graphql/urql/pull/3104), [#3082](https://github.com/urql-graphql/urql/pull/3082), [#3097](https://github.com/urql-graphql/urql/pull/3097), [#3061](https://github.com/urql-graphql/urql/pull/3061), [#3055](https://github.com/urql-graphql/urql/pull/3055), [#3085](https://github.com/urql-graphql/urql/pull/3085), [#3079](https://github.com/urql-graphql/urql/pull/3079), [#3087](https://github.com/urql-graphql/urql/pull/3087), [#3059](https://github.com/urql-graphql/urql/pull/3059), [#3055](https://github.com/urql-graphql/urql/pull/3055), [#3057](https://github.com/urql-graphql/urql/pull/3057), [#3050](https://github.com/urql-graphql/urql/pull/3050), [#3062](https://github.com/urql-graphql/urql/pull/3062), [#3051](https://github.com/urql-graphql/urql/pull/3051), [#3043](https://github.com/urql-graphql/urql/pull/3043), [#3063](https://github.com/urql-graphql/urql/pull/3063), [#3054](https://github.com/urql-graphql/urql/pull/3054), [#3102](https://github.com/urql-graphql/urql/pull/3102), [#3097](https://github.com/urql-graphql/urql/pull/3097), [#3106](https://github.com/urql-graphql/urql/pull/3106), [#3058](https://github.com/urql-graphql/urql/pull/3058), and [#3062](https://github.com/urql-graphql/urql/pull/3062))\n  - @urql/core@4.0.0\n\n## 5.2.0\n\n### Minor Changes\n\n- Add `isOfflineError` option to the `offlineExchange` to allow it to be customized to different conditions to determine whether an operation has failed because of a network error\n  Submitted by [@robertherber](https://github.com/robertherber) (See [#3020](https://github.com/urql-graphql/urql/pull/3020))\n- Allow `updates` config to react to arbitrary type updates other than just `Mutation` and `Subscription` fields.\n  You’ll now be able to write updaters that react to any entity field being written to the cache,\n  which allows for more granular invalidations. **Note:** If you’ve previously used `updates.Mutation`\n  and `updated.Subscription` with a custom schema with custom root names, you‘ll get a warning since\n  you’ll have to update your `updates` config to reflect this. This was a prior implementation\n  mistake!\n  Submitted by [@kitten](https://github.com/kitten) (See [#2979](https://github.com/urql-graphql/urql/pull/2979))\n\n### Patch Changes\n\n- ⚠️ Fix regression which caused partial results, whose refetches were blocked by the looping protection, to not have a `stale: true` flag added to them. This is a regression from https://github.com/urql-graphql/urql/pull/2831 and only applies to `cacheExchange`s that had the `schema` option set\n  Submitted by [@kitten](https://github.com/kitten) (See [#2999](https://github.com/urql-graphql/urql/pull/2999))\n- Add `invariant` to data layer that prevents cache writes during cache query operations. This prevents `cache.writeFragment`, `cache.updateQuery`, and `cache.link` from being called in `resolvers` for instance\n  Submitted by [@kitten](https://github.com/kitten) (See [#2978](https://github.com/urql-graphql/urql/pull/2978))\n- Updated dependencies (See [#3007](https://github.com/urql-graphql/urql/pull/3007), [#2962](https://github.com/urql-graphql/urql/pull/2962), [#3007](https://github.com/urql-graphql/urql/pull/3007), [#3015](https://github.com/urql-graphql/urql/pull/3015), and [#3022](https://github.com/urql-graphql/urql/pull/3022))\n  - @urql/core@3.2.0\n\n## 5.0.9\n\n### Patch Changes\n\n- ⚠️ Fix potential data loss in `offlineExchange` that's caused when `onOnline` triggers and flushes mutation queue before the mutation queue is used, by [@trcoffman](https://github.com/trcoffman) (See [#2945](https://github.com/urql-graphql/urql/pull/2945))\n- Patch message for `(16) Heuristic Fragment Matching`, by [@inokawa](https://github.com/inokawa) (See [#2923](https://github.com/urql-graphql/urql/pull/2923))\n- Patch message for (19) Can't generate a key for invalidate(...) error, by [@inokawa](https://github.com/inokawa) (See [#2918](https://github.com/urql-graphql/urql/pull/2918))\n\n## 5.0.8\n\n### Patch Changes\n\n- ⚠️ Fix operation being blocked for looping due to it not cancelling the looping protection when a `teardown` is received. This bug could be triggered when a shared query operation triggers again and causes a cache miss (e.g. due to an error). The re-execution of the operation would then be blocked as Graphcache considered it a \"reexecution loop\" rather than a legitimate execution triggered by the UI. (See https://github.com/urql-graphql/urql/pull/2737 for more information), by [@kitten](https://github.com/kitten) (See [#2876](https://github.com/urql-graphql/urql/pull/2876))\n\n## 5.0.7\n\n### Patch Changes\n\n- ⚠️ Fix type-generation, with a change in TS/Rollup the type generation took the paths as src and resolved them into the types dir, by [@JoviDeCroock](https://github.com/JoviDeCroock) (See [#2870](https://github.com/urql-graphql/urql/pull/2870))\n- Updated dependencies (See [#2872](https://github.com/urql-graphql/urql/pull/2872), [#2870](https://github.com/urql-graphql/urql/pull/2870), and [#2871](https://github.com/urql-graphql/urql/pull/2871))\n  - @urql/core@3.1.1\n\n## 5.0.6\n\n### Patch Changes\n\n- Solve issue where partial data could cause loops between related queries, by [@JoviDeCroock](https://github.com/JoviDeCroock) (See [#2831](https://github.com/urql-graphql/urql/pull/2831))\n- Add skipping of garbage collection runs when the cache is waiting for optimistic, deferred or other results in layers. This means that we only take an opportunity to run garbage collection after results have settled and are hence decreasing the chance of hogging the event loop when a run isn't needed, by [@kitten](https://github.com/kitten) (See [#2862](https://github.com/urql-graphql/urql/pull/2862))\n- ⚠️ Fix a deadlock condition in Graphcache's layers, which is caused by subscriptions (or other deferred layers) starting before one-off mutation layers. This causes the mutation to not be completed, which keeps its data preferred above the deferred layer. That in turn means that layers stop squashing, which causes new results to be missing indefinitely, when they overlap, by [@kitten](https://github.com/kitten) (See [#2861](https://github.com/urql-graphql/urql/pull/2861))\n- Updated dependencies (See [#2843](https://github.com/urql-graphql/urql/pull/2843), [#2847](https://github.com/urql-graphql/urql/pull/2847), [#2850](https://github.com/urql-graphql/urql/pull/2850), and [#2846](https://github.com/urql-graphql/urql/pull/2846))\n  - @urql/core@3.1.0\n\n## 5.0.5\n\n### Patch Changes\n\n- Set operations when updating the cache with a result, by [@JoviDeCroock](https://github.com/JoviDeCroock) (See [#2782](https://github.com/FormidableLabs/urql/pull/2782))\n\n## 5.0.4\n\n### Patch Changes\n\n- Ensure we aren't eagerly removing layers that are caused by subscriptions, by [@JoviDeCroock](https://github.com/JoviDeCroock) (See [#2771](https://github.com/FormidableLabs/urql/pull/2771))\n\n## 5.0.3\n\n### Patch Changes\n\n- ⚠️ Fix case where a mutation would also be counted in the loop-protection, this prevented partial queries from initiating refetches, by [@JoviDeCroock](https://github.com/JoviDeCroock) (See [#2761](https://github.com/FormidableLabs/urql/pull/2761))\n- Updated dependencies (See [#2758](https://github.com/FormidableLabs/urql/pull/2758) and [#2762](https://github.com/FormidableLabs/urql/pull/2762))\n  - @urql/core@3.0.5\n\n## 5.0.2\n\n### Patch Changes\n\n- Preserve the original `DocumentNode` AST when updating the cache, to prevent results after a network request from differing and breaking referential equality due to added `__typename` fields, by [@kitten](https://github.com/kitten) (See [#2736](https://github.com/FormidableLabs/urql/pull/2736))\n- ⚠️ Fix optimistic mutations containing partial results (`undefined` fields), which previously actually caused a hidden cache miss, which may then affect a subsequent non-optimistic mutation result, by [@kitten](https://github.com/kitten) (See [#2740](https://github.com/FormidableLabs/urql/pull/2740))\n- Prevent cache misses from causing infinite network requests from being issued, when two operations manipulate each other while experiencing cache misses or are partially uncacheable, by [@kitten](https://github.com/kitten) (See [#2737](https://github.com/FormidableLabs/urql/pull/2737))\n- ⚠️ Fix operation identities preventing users from deeply cloning operation contexts. Instead, we now use a client-wide counter (rolling over as needed).\n  While this changes an internal data structure in `@urql/core` only, this change also affects the `offlineExchange` in `@urql/exchange-graphcache` due to it relying on the identity being previously an object rather than an integer, by [@kitten](https://github.com/kitten) (See [#2732](https://github.com/FormidableLabs/urql/pull/2732))\n- ⚠️ Fix referential equality preservation in Graphcache failing after API results, due to a typo writing the API result rather than the updated cache result, by [@kitten](https://github.com/kitten) (See [#2741](https://github.com/FormidableLabs/urql/pull/2741))\n- Updated dependencies (See [#2691](https://github.com/FormidableLabs/urql/pull/2691), [#2692](https://github.com/FormidableLabs/urql/pull/2692), and [#2732](https://github.com/FormidableLabs/urql/pull/2732))\n  - @urql/core@3.0.4\n\n## 5.0.1\n\n### Patch Changes\n\n- Adjust timing of when an introspected schema will be processed into field maps, interface maps, and union type maps. By making this lazy we can avoid excessive work when these maps aren't actually ever used, by [@kitten](https://github.com/kitten) (See [#2640](https://github.com/FormidableLabs/urql/pull/2640))\n\n## 5.0.0\n\n### Major Changes\n\n- **Goodbye IE11!** 👋 This major release removes support for IE11. All code that is shipped will be transpiled much less and will _not_ be ES5-compatible anymore, by [@kitten](https://github.com/kitten) (See [#2504](https://github.com/FormidableLabs/urql/pull/2504))\n- Prevent cache-hydration from buffering operations, by [@JoviDeCroock](https://github.com/JoviDeCroock) (See [#2612](https://github.com/FormidableLabs/urql/pull/2612))\n- Implement stricter variables types, which require variables to always be passed and match TypeScript types when the generic is set or inferred. This is a breaking change for TypeScript users potentially, unless all types are adhered to, by [@kitten](https://github.com/kitten) (See [#2607](https://github.com/FormidableLabs/urql/pull/2607))\n- Upgrade to [Wonka v6](https://github.com/0no-co/wonka) (`wonka@^6.0.0`), which has no breaking changes but is built to target ES2015 and comes with other minor improvements.\n  The library has fully been migrated to TypeScript which will hopefully help with making contributions easier!, by [@kitten](https://github.com/kitten) (See [#2504](https://github.com/FormidableLabs/urql/pull/2504))\n\n### Minor Changes\n\n- Remove the `babel-plugin-modular-graphql` helper, this because the graphql package hasn't converted to ESM yet which gives issues in node environments, by [@JoviDeCroock](https://github.com/JoviDeCroock) (See [#2551](https://github.com/FormidableLabs/urql/pull/2551))\n- Allow passing in `fragmentName` for `write` and `read` operations, by [@JoviDeCroock](https://github.com/JoviDeCroock) (See [#2609](https://github.com/FormidableLabs/urql/pull/2609))\n\n### Patch Changes\n\n- Graphcache's `optimistic` option now accepts optimistic mutation resolvers that return fields by\n  name rather than alias. Previously, depending on which mutation was run, the optimistic resolvers\n  would read your optimistic data by field alias (i.e. \"alias\" for `alias: id` rather than \"id\").\n  Instead, optimistic updates now correctly use field names and allow you to also pass resolvers as\n  values on your optimistic config, by [@JoviDeCroock](https://github.com/JoviDeCroock) (See [#2616](https://github.com/FormidableLabs/urql/pull/2616))\n- Updated dependencies (See [#2551](https://github.com/FormidableLabs/urql/pull/2551), [#2504](https://github.com/FormidableLabs/urql/pull/2504), [#2619](https://github.com/FormidableLabs/urql/pull/2619), [#2607](https://github.com/FormidableLabs/urql/pull/2607), and [#2504](https://github.com/FormidableLabs/urql/pull/2504))\n  - @urql/core@3.0.0\n\n## 4.4.3\n\n### Patch Changes\n\n- Correctly reorder optimistic layers when we see repeated keys coming in, by [@JoviDeCroock](https://github.com/JoviDeCroock) (See [#2489](https://github.com/FormidableLabs/urql/pull/2489))\n\n## 4.4.2\n\n### Patch Changes\n\n- Keep track of mutations in the offline exchange so we can accurately recreate the original variables, there could be more variables for use in updater functions which we strip away in graphCache before sending to the API, by [@JoviDeCroock](https://github.com/JoviDeCroock) (See [#2472](https://github.com/FormidableLabs/urql/pull/2472))\n\n## 4.4.1\n\n### Patch Changes\n\n- Switch `isFragmentHeuristicallyMatching()` to always return `true` for writes, so that we give every fragment a chance to be applied and to write to the cache, by [@kitten](https://github.com/kitten) (See [#2455](https://github.com/FormidableLabs/urql/pull/2455))\n- ⚠️ Fix default storage persisting data after `clear()` was called on it, by [@JoviDeCroock](https://github.com/JoviDeCroock) (See [#2458](https://github.com/FormidableLabs/urql/pull/2458))\n- Updated dependencies (See [#2446](https://github.com/FormidableLabs/urql/pull/2446), [#2456](https://github.com/FormidableLabs/urql/pull/2456), and [#2457](https://github.com/FormidableLabs/urql/pull/2457))\n  - @urql/core@2.5.0\n\n## 4.4.0\n\n### Minor Changes\n\n- Fix issues with continuously updating operations (i.e. subscriptions and `hasNext: true` queries) by shifting their layers in Graphcache behind those that are still awaiting a result. This causes continuous updates to not overwrite one-off query results while still keeping continuously updating operations at the highest possible layer, by [@kitten](https://github.com/kitten) (See [#2419](https://github.com/FormidableLabs/urql/pull/2419))\n\n### Patch Changes\n\n- ⚠️ Fix ignore empty relay edges when using the `relayPagination` resolver, by [@tgriesser](https://github.com/tgriesser) (See [#2431](https://github.com/FormidableLabs/urql/pull/2431))\n- Prevent creating unnecessary layers, which should improve performance slightly, by [@kitten](https://github.com/kitten) (See [#2419](https://github.com/FormidableLabs/urql/pull/2419))\n\n## 4.3.6\n\n### Patch Changes\n\n- Extend peer dependency range of `graphql` to include `^16.0.0`.\n  As always when upgrading across many packages of `urql`, especially including `@urql/core` we recommend you to deduplicate dependencies after upgrading, using `npm dedupe` or `npx yarn-deduplicate`, by [@kitten](https://github.com/kitten) (See [#2133](https://github.com/FormidableLabs/urql/pull/2133))\n- Updated dependencies (See [#2133](https://github.com/FormidableLabs/urql/pull/2133))\n  - @urql/core@2.3.6\n\n## 4.3.5\n\n### Patch Changes\n\n- ⚠️ Fix regression from [#1869](https://github.com/FormidableLabs/urql/pull/1869) that caused nullable lists to always cause a cache miss, if schema awareness is enabled, by [@kitten](https://github.com/kitten) (See [#1983](https://github.com/FormidableLabs/urql/pull/1983))\n- Updated dependencies (See [#1985](https://github.com/FormidableLabs/urql/pull/1985))\n  - @urql/core@2.3.3\n\n## 4.3.4\n\n### Patch Changes\n\n- Improve perf by using String.indexOf in getField, by [@JoviDeCroock](https://github.com/JoviDeCroock) (See [#1957](https://github.com/FormidableLabs/urql/pull/1957))\n- Updated dependencies (See [#1944](https://github.com/FormidableLabs/urql/pull/1944))\n  - @urql/core@2.3.2\n\n## 4.3.3\n\n### Patch Changes\n\n- Remove `hasNext: true` flag from stale responses. This was erroneously added in debugging, but leads to stale responses being marked with `hasNext`, which means the `dedupExchange` will keep waiting for further network responses, by [@kitten](https://github.com/kitten) (See [#1911](https://github.com/FormidableLabs/urql/pull/1911))\n\n## 4.3.2\n\n### Patch Changes\n\n- Cleanup the previous `onOnline` event-listener when called again, by [@JoviDeCroock](https://github.com/JoviDeCroock) (See [#1896](https://github.com/FormidableLabs/urql/pull/1896))\n\n## 4.3.1\n\n### Patch Changes\n\n- ⚠️ Fix previous results' `null` values spilling into the next result that Graphcache issues, which may prevent updates from being issued until the query is reexecuted. This was affecting any `null` links on data, and any queries that were issued before non-optimistic mutations, by [@kitten](https://github.com/kitten) (See [#1885](https://github.com/FormidableLabs/urql/pull/1885))\n- Updated dependencies (See [#1870](https://github.com/FormidableLabs/urql/pull/1870) and [#1880](https://github.com/FormidableLabs/urql/pull/1880))\n  - @urql/core@2.3.1\n\n## 4.3.0\n\n### Minor Changes\n\n- Improve referential equality of deeply queried objects from the normalised cache for queries. Each query operation will now reuse the last known result and only incrementally change references as necessary, scanning over the previous result to identify whether anything has changed.\n  This should help improve the performance of processing updates in UI frameworks (e.g. in React with `useMemo` or `React.memo`). (See [#1859](https://github.com/FormidableLabs/urql/pull/1859))\n- Add **experimental** support for `@defer` and `@stream` responses for GraphQL. This implements the [\"GraphQL Defer and Stream Directives\"](https://github.com/graphql/graphql-spec/blob/4fd39e0/rfcs/DeferStream.md) and [\"Incremental Delivery over HTTP\"](https://github.com/graphql/graphql-over-http/blob/290b0e2/rfcs/IncrementalDelivery.md) specifications. If a GraphQL API supports `multipart/mixed` responses for deferred and streamed delivery of GraphQL results, `@urql/core` (and all its derived fetch implementations) will attempt to stream results. This is _only supported_ on browsers [supporting streamed fetch responses](https://developer.mozilla.org/en-US/docs/Web/API/Response/body), which excludes IE11.\n  The implementation of streamed multipart responses is derived from [`meros` by `@maraisr`](https://github.com/maraisr/meros), and is subject to change if the RFCs end up changing, by [@kitten](https://github.com/kitten) (See [#1854](https://github.com/FormidableLabs/urql/pull/1854))\n\n### Patch Changes\n\n- ⚠️ Fix missing values cascading into lists causing a `null` item without the query being marked as stale and fetched from the API. This would happen in schema awareness when a required field, which isn't cached, cascades into a nullable list, by [@kitten](https://github.com/kitten) (See [#1869](https://github.com/FormidableLabs/urql/pull/1869))\n- Updated dependencies (See [#1854](https://github.com/FormidableLabs/urql/pull/1854))\n  - @urql/core@2.3.0\n\n## 4.2.1\n\n### Patch Changes\n\n- ⚠️ Fix issue where operations that get dispatched synchronously after the cache restoration completes get forgotten, by [@JoviDeCroock](https://github.com/JoviDeCroock) (See [#1789](https://github.com/FormidableLabs/urql/pull/1789))\n\n## 4.2.0\n\n### Minor Changes\n\n- Fixed typing of OptimisticMutationResolver, by [@taneba](https://github.com/taneba) (See [#1765](https://github.com/FormidableLabs/urql/pull/1765))\n\n### Patch Changes\n\n- Type the `relayPagination` and `simplePagination` helpers return value as `Resolver<any, any, any>` as there's no way to match them consistently to either generated or non-generated resolver types anymore, by [@kitten](https://github.com/kitten) (See [#1778](https://github.com/FormidableLabs/urql/pull/1778))\n- Updated dependencies (See [#1776](https://github.com/FormidableLabs/urql/pull/1776) and [#1755](https://github.com/FormidableLabs/urql/pull/1755))\n  - @urql/core@2.1.5\n\n## 4.1.4\n\n### Patch Changes\n\n- Apply [`bivarianceHack`](https://stackoverflow.com/questions/52667959/what-is-the-purpose-of-bivariancehack-in-typescript-types) in the `graphcache` types to better support code-generated configs, by [@JoviDeCroock](https://github.com/JoviDeCroock) (See [#1687](https://github.com/FormidableLabs/urql/pull/1687))\n- Updated dependencies (See [#1709](https://github.com/FormidableLabs/urql/pull/1709))\n  - @urql/core@2.1.4\n\n## 4.1.3\n\n### Patch Changes\n\n- ⚠️ Fix: add the `ENTRIES_STORE_NAME` to the clear transaction, by [@JoviDeCroock](https://github.com/JoviDeCroock) (See [#1685](https://github.com/FormidableLabs/urql/pull/1685))\n- Updated dependencies (See [#1695](https://github.com/FormidableLabs/urql/pull/1695))\n  - @urql/core@2.1.3\n\n## 4.1.2\n\n### Patch Changes\n\n- Loosen type constraint on `ScalarObject` to account for custom scalar deserialization like `Date` for `DateTime`s, by [@kitten](https://github.com/kitten) (See [#1648](https://github.com/FormidableLabs/urql/pull/1648))\n- Loosen the typing constraint on the cacheExchange generic, by [@JoviDeCroock](https://github.com/JoviDeCroock) (See [#1675](https://github.com/FormidableLabs/urql/pull/1675))\n\n## 4.1.1\n\n### Patch Changes\n\n- ⚠️ Fix an edge-case for which an introspection query during runtime could fail when schema-awareness was enabled in Graphcache, since built-in types weren't recognised as existent, by [@kitten](https://github.com/kitten) (See [#1631](https://github.com/FormidableLabs/urql/pull/1631))\n\n## 4.1.0\n\n### Minor Changes\n\n- Add `cache.link(...)` method to Graphcache. This method may be used in updaters to update links in the cache. It is hence the writing-equivalent of `cache.resolve()`, which previously didn't have any equivalent as such, which meant that only `cache.updateQuery` or `cache.writeFragment` could be used, even to update simple relations, by [@JoviDeCroock](https://github.com/JoviDeCroock) (See [#1551](https://github.com/FormidableLabs/urql/pull/1551))\n- Add on a generic to `cacheExchange` and `offlineExchange` for future, experimental type-generation support, by [@JoviDeCroock](https://github.com/JoviDeCroock) (See [#1562](https://github.com/FormidableLabs/urql/pull/1562))\n\n### Patch Changes\n\n- ⚠️ Fix up internal types in Graphcache to improve their accuracy for catching more edge cases in its implementation. This only affects you if you previously imported any type related to `ScalarObject` from Graphcache which now is a more opaque type. We've also adjusted the `NullArray` types to be potentially nested, since lists in GraphQL can be nested arbitarily, which we were covering but didn't reflect in our types, by [@kitten](https://github.com/kitten) (See [#1591](https://github.com/FormidableLabs/urql/pull/1591))\n- Remove closure-compiler from the build step (See [#1570](https://github.com/FormidableLabs/urql/pull/1570))\n- ⚠️ Fix list items being returned as `null` even for non-nullable lists, when the entities are missing in the cache. This could happen when a resolver was added returning entities or their keys. This behaviour is now (correctly) only applied to partial results with schema awareness, by [@JoviDeCroock](https://github.com/JoviDeCroock) (See [#1566](https://github.com/FormidableLabs/urql/pull/1566))\n- Allow for the schema subscription and mutationType to be null, by [@JoviDeCroock](https://github.com/JoviDeCroock) (See [#1530](https://github.com/FormidableLabs/urql/pull/1530))\n- Updated dependencies (See [#1570](https://github.com/FormidableLabs/urql/pull/1570), [#1509](https://github.com/FormidableLabs/urql/pull/1509), [#1600](https://github.com/FormidableLabs/urql/pull/1600), and [#1515](https://github.com/FormidableLabs/urql/pull/1515))\n  - @urql/core@2.1.0\n\n## 4.0.0\n\n### Major Changes\n\n- Add improved error awareness to Graphcache. When Graphcache now receives a `GraphQLError` (via a `CombinedError`) it checks whether the `GraphQLError`'s `path` matches up with `null` values in the `data`. Any `null` values that the write operation now sees in the data will be replaced with a \"cache miss\" value (i.e. `undefined`) when it has an associated error. This means that errored fields from your GraphQL API will be marked as uncached and won't be cached. Instead the client will now attempt a refetch of the data so that errors aren't preventing future refetches or with schema awareness it will attempt a refetch automatically. Additionally, the `updates` functions will now be able to check whether the current field has any errors associated with it with `info.error`, by [@kitten](https://github.com/kitten) (See [#1356](https://github.com/FormidableLabs/urql/pull/1356))\n\n### Minor Changes\n\n- Allow `schema` option to be passed with a partial introspection result that only contains `queryType`, `mutationType`, and `subscriptionType` with their respective names. This allows you to pass `{ __schema: { queryType: { name: 'Query' } } }` and the likes to Graphcache's `cacheExchange` to alter the default root names without enabling full schema awareness, by [@kitten](https://github.com/kitten) (See [#1379](https://github.com/FormidableLabs/urql/pull/1379))\n\n### Patch Changes\n\n- Updated dependencies (See [#1374](https://github.com/FormidableLabs/urql/pull/1374), [#1357](https://github.com/FormidableLabs/urql/pull/1357), and [#1375](https://github.com/FormidableLabs/urql/pull/1375))\n  - @urql/core@2.0.0\n\n## 3.4.0\n\n### Minor Changes\n\n- Warn when using an interface or union field in the graphCache resolvers config, by [@JoviDeCroock](https://github.com/JoviDeCroock) (See [#1304](https://github.com/FormidableLabs/urql/pull/1304))\n\n### Patch Changes\n\n- ⚠️ Fix edge-case where query results would pick up invalidated fields from mutation results as they're written to the cache. This would cause invalid cache misses although the result was expected to just be passed through from the API result, by [@kitten](https://github.com/kitten) (See [#1300](https://github.com/FormidableLabs/urql/pull/1300))\n- ⚠️ Fix a Relay Pagination edge case where overlapping ends of pages queried using the `last` argument would be in reverse order, by [@JoviDeCroock](https://github.com/JoviDeCroock) (See [#1311](https://github.com/FormidableLabs/urql/pull/1311))\n\n## 3.3.4\n\n### Patch Changes\n\n- ⚠️ Fix, add null as a possible type for the variables argument in `cache.invalidate`, by [@JoviDeCroock](https://github.com/JoviDeCroock) (See [#1269](https://github.com/FormidableLabs/urql/pull/1269))\n\n## 3.3.3\n\n### Patch Changes\n\n- Update `cache.resolve(parent, ...)` case to enable _even more_ cases, for instance where `parent.__typename` isn't set yet. This was intended to be enabled in the previous patch but has been forgotten, by [@kitten](https://github.com/kitten) (See [#1219](https://github.com/FormidableLabs/urql/pull/1219))\n- Deprecate `cache.resolveFieldByKey` in favour of `cache.resolve`, which functionally was already able to do the same, by [@kitten](https://github.com/kitten) (See [#1219](https://github.com/FormidableLabs/urql/pull/1219))\n- Updated dependencies (See [#1225](https://github.com/FormidableLabs/urql/pull/1225))\n  - @urql/core@1.16.1\n\n## 3.3.2\n\n### Patch Changes\n\n- Update `cache` methods, for instance `cache.resolve`, to consistently accept the `parent` argument from `resolvers` and `updates` and alias it to the parent's key (which is usually found on `info.parentKey`). This usage of `cache.resolve(parent, ...)` was intuitive and is now supported as expected, by [@kitten](https://github.com/kitten) (See [#1208](https://github.com/FormidableLabs/urql/pull/1208))\n\n## 3.3.1\n\n### Patch Changes\n\n- ⚠️ Fix reusing original query data from APIs accidentally, which can lead to subtle mismatches in results when the API's incoming `query` results are being updated by the `cacheExchange`, to apply resolvers. Specifically this may lead to relations from being set back to `null` when the resolver returns a different list of links than the result, since some `null` relations may unintentionally exist but aren't related. If you're using `relayPagination` then this fix is critical, by [@kitten](https://github.com/kitten) (See [#1196](https://github.com/FormidableLabs/urql/pull/1196))\n\n## 3.3.0\n\n### Minor Changes\n\n- Increase the consistency of when and how the `__typename` field is added to results. Instead of\n  adding it by default and automatically first, the `__typename` field will now be added along with\n  the usual selection set. The `write` operation now automatically issues a warning if `__typename`\n  isn't present where it's expected more often, which helps in debugging. Also the `__typename` field\n  may now not proactively be added to root results, e.g. `\"Query\"`, by [@kitten](https://github.com/kitten) (See [#1185](https://github.com/FormidableLabs/urql/pull/1185))\n\n### Patch Changes\n\n- Replace `graphql/utilities/buildClientSchema.mjs` with a custom-tailored, lighter implementation\n  built into `@urql/exchange-graphcache`. This will appear to increase its size by about `0.2kB gzip`\n  but will actually save around `8.5kB gzip` to `9.4kB gzip` in any production bundle by using less of\n  `graphql`'s code, by [@kitten](https://github.com/kitten) (See [#1189](https://github.com/FormidableLabs/urql/pull/1189))\n- Updated dependencies (See [#1187](https://github.com/FormidableLabs/urql/pull/1187), [#1186](https://github.com/FormidableLabs/urql/pull/1186), and [#1186](https://github.com/FormidableLabs/urql/pull/1186))\n  - @urql/core@1.16.0\n\n## 3.2.0\n\n### Minor Changes\n\n- Add a `mergeMode: 'before' | 'after'` option to the `simplePagination` helper to define whether pages are merged before or after preceding ones when pagination, similar to `relayPagination`'s option, by [@hoangvvo](https://github.com/hoangvvo) (See [#1174](https://github.com/FormidableLabs/urql/pull/1174))\n\n### Patch Changes\n\n- Updated dependencies (See [#1168](https://github.com/FormidableLabs/urql/pull/1168))\n  - @urql/core@1.15.2\n\n## 3.1.11\n\n### Patch Changes\n\n- Add support for `TypedDocumentNode` to infer the type of the `OperationResult` and `Operation` for all methods, functions, and hooks that either directly or indirectly accept a `DocumentNode`. See [`graphql-typed-document-node` and the corresponding blog post for more information.](https://github.com/dotansimha/graphql-typed-document-node), by [@kitten](https://github.com/kitten) (See [#1113](https://github.com/FormidableLabs/urql/pull/1113))\n- Updated dependencies (See [#1119](https://github.com/FormidableLabs/urql/pull/1119), [#1113](https://github.com/FormidableLabs/urql/pull/1113), [#1104](https://github.com/FormidableLabs/urql/pull/1104), and [#1123](https://github.com/FormidableLabs/urql/pull/1123))\n  - @urql/core@1.15.0\n\n## 3.1.10\n\n### Patch Changes\n\n- ⚠️ Fix a stray `operationName` deprecation warning in `@urql/exchange-graphcache`'s exchange logic, which adds the `meta.cacheOutcome` field to the operation's context, by [@kitten](https://github.com/kitten) (See [#1103](https://github.com/FormidableLabs/urql/pull/1103))\n\n## 3.1.9\n\n### Patch Changes\n\n- ⚠️ Fix the production build overwriting the development build. Specifically in the previous release we mistakenly replaced all development bundles with production bundles. This doesn't have any direct influence on how these packages work, but prevented development warnings from being logged or full errors from being thrown, by [@kitten](https://github.com/kitten) (See [#1097](https://github.com/FormidableLabs/urql/pull/1097))\n- Updated dependencies (See [#1097](https://github.com/FormidableLabs/urql/pull/1097))\n  - @urql/core@1.14.1\n\n## 3.1.8\n\n### Patch Changes\n\n- Add missing `.mjs` extension to all imports from `graphql` to fix Webpack 5 builds, which require extension-specific import paths for ESM bundles and packages. **This change allows you to safely upgrade to Webpack 5.**, by [@kitten](https://github.com/kitten) (See [#1094](https://github.com/FormidableLabs/urql/pull/1094))\n- Deprecate the `Operation.operationName` property in favor of `Operation.kind`. This name was\n  previously confusing as `operationName` was effectively referring to two different things. You can\n  safely upgrade to this new version, however to mute all deprecation warnings you will have to\n  **upgrade** all `urql` packages you use. If you have custom exchanges that spread operations, please\n  use [the new `makeOperation` helper\n  function](https://formidable.com/open-source/urql/docs/api/core/#makeoperation) instead, by [@bkonkle](https://github.com/bkonkle) (See [#1045](https://github.com/FormidableLabs/urql/pull/1045))\n- Updated dependencies (See [#1094](https://github.com/FormidableLabs/urql/pull/1094) and [#1045](https://github.com/FormidableLabs/urql/pull/1045))\n  - @urql/core@1.14.0\n\n## 3.1.7\n\n### Patch Changes\n\n- Enforce atomic optimistic updates so that optimistic layers are cleared before they're reapplied. This is important for instance when an optimistic update is performed while offline and then reapplied while online, which would previously repeat the optimistic update on top of its past data changes, by [@kitten](https://github.com/kitten) (See [#1080](https://github.com/FormidableLabs/urql/pull/1080))\n\n## 3.1.6\n\n### Patch Changes\n\n- ⚠️ Fix optimistic updates not being allowed to be cumulative and apply on top of each other. Previously in [#866](https://github.com/FormidableLabs/urql/pull/866) we explicitly deemed this as unsafe which isn't correct anymore given that concrete, non-optimistic updates are now never applied on top of optimistic layers, by [@kitten](https://github.com/kitten) (See [#1074](https://github.com/FormidableLabs/urql/pull/1074))\n\n## 3.1.5\n\n### Patch Changes\n\n- Changes some internals of how selections are iterated over and remove some private exports. This will have no effect or fixes on how Graphcache functions, but may improve some minor performance characteristics of large queries, by [@kitten](https://github.com/kitten) (See [#1060](https://github.com/FormidableLabs/urql/pull/1060))\n\n## 3.1.4\n\n### Patch Changes\n\n- ⚠️ Fix inline fragments being skipped when they were missing a full type condition as per the GraphQL spec (e.g `{ ... { field } }`), by [@kitten](https://github.com/kitten) (See [#1040](https://github.com/FormidableLabs/urql/pull/1040))\n\n## 3.1.3\n\n### Patch Changes\n\n- ⚠️ Fix a case where the `offlineExchange` would not start processing operations after hydrating persisted data when no operations arrived in time by the time the persisted data was restored. This would be more evident in Preact and Svelte due to their internal short timings, by [@kitten](https://github.com/kitten) (See [#1019](https://github.com/FormidableLabs/urql/pull/1019))\n\n## 3.1.2\n\n### Patch Changes\n\n- ⚠️ Fix small pieces of code where polyfill-less ES5 usage was compromised. This was unlikely to have affected anyone in production as `Array.prototype.find` (the only usage of an ES6 method) is commonly used and polyfilled, by [@kitten](https://github.com/kitten) (See [#991](https://github.com/FormidableLabs/urql/pull/991))\n- ⚠️ Fix queries that have erroed with a `NetworkError` (`isOfflineError`) not flowing back completely through the `cacheExchange`.\n  These queries should also now be reexecuted when the client comes back online, by [@kitten](https://github.com/kitten) (See [#1011](https://github.com/FormidableLabs/urql/pull/1011))\n- Updated dependencies (See [#1011](https://github.com/FormidableLabs/urql/pull/1011))\n  - @urql/core@1.13.1\n\n## 3.1.1\n\n### Patch Changes\n\n- ⚠️ Fix updaters config not working when Mutation/Subscription root names were altered.\n  For instance, a Mutation named `mutation_root` could cause `store.updates` to be misread and cause a\n  runtime error, by [@kitten](https://github.com/kitten) (See [#984](https://github.com/FormidableLabs/urql/pull/984))\n- ⚠️ Fix operation results being obstructed by the `offlineExchange` when the network request has failed due to being offline and no cache result has been issued. Instead the `offlineExchange` will now retry with `cache-only` policy, by [@kitten](https://github.com/kitten) (See [#985](https://github.com/FormidableLabs/urql/pull/985))\n\n## 3.1.0\n\n### Minor Changes\n\n- Add support for `nodes` fields to the `relayPagination` helper, instead of only supporting the standard `edges`. (See [#897](https://github.com/FormidableLabs/urql/pull/897))\n\n### Patch Changes\n\n- Updated dependencies (See [#947](https://github.com/FormidableLabs/urql/pull/947), [#962](https://github.com/FormidableLabs/urql/pull/962), and [#957](https://github.com/FormidableLabs/urql/pull/957))\n  - @urql/core@1.13.0\n\n## 3.0.2\n\n### Patch Changes\n\n- Add special-case for fetching an introspection result in our schema-checking, this avoids an error when urql-devtools fetches the backend graphql schema, by [@JoviDeCroock](https://github.com/JoviDeCroock) (See [#893](https://github.com/FormidableLabs/urql/pull/893))\n- Mute warning when using built-in GraphQL fields, like `__type`, by [@kitten](https://github.com/kitten) (See [#919](https://github.com/FormidableLabs/urql/pull/919))\n- ⚠️ Fix return type for resolvers to allow data objects to be returned with `__typename` as expected, by [@JoviDeCroock](https://github.com/JoviDeCroock) (See [#927](https://github.com/FormidableLabs/urql/pull/927))\n- Updated dependencies (See [#911](https://github.com/FormidableLabs/urql/pull/911) and [#908](https://github.com/FormidableLabs/urql/pull/908))\n  - @urql/core@1.12.3\n\n## 3.0.1\n\n### Patch Changes\n\n- Add warning for queries that traverse an Operation Root Type (Mutation / Subscription types occuring in a query result), by [@kitten](https://github.com/kitten) (See [#859](https://github.com/FormidableLabs/urql/pull/859))\n- ⚠️ Fix storage implementation not preserving deleted values correctly or erroneously checking optimistically written entries for changes. This is fixed by adding a new default serializer to the `@urql/exchange-graphcache/default-storage` implementation, which will be incompatible with the old one, by [@kitten](https://github.com/kitten) (See [#866](https://github.com/FormidableLabs/urql/pull/866))\n- Replace unnecessary `scheduleTask` polyfill with inline `Promise.resolve().then(fn)` calls, by [@kitten](https://github.com/kitten) (See [#861](https://github.com/FormidableLabs/urql/pull/861))\n- Updated dependencies (See [#860](https://github.com/FormidableLabs/urql/pull/860) and [#861](https://github.com/FormidableLabs/urql/pull/861))\n  - @urql/core@1.12.1\n\n## 3.0.0\n\nThis major release comes with a couple of fixes and new **experimental offline support**, which\nwe're very excited for! Please give it a try if your application is targeting Offline First!\n\nTo migrate to this new major version, check the major breaking changes below. Mainly you will have\nto watch out for `cache.invalidateQuery` which has been removed. Instead you should now invalidate\nindividual entities and fields using `cache.invalidate`. [Learn more about this method on our\ndocs.](https://formidable.com/open-source/urql/docs/graphcache/custom-updates/#cacheinvalidate)\n\n### Major Changes\n\n- Remove the deprecated `populateExchange` export from `@urql/exchange-graphcache`.\n  If you're using the `populateExchange`, please install the separate `@urql/exchange-populate` package and import it from there, by [@kitten](https://github.com/kitten) (See [#840](https://github.com/FormidableLabs/urql/pull/840))\n- The deprecated `cache.invalidateQuery()` method has been removed. Please migrate over to `cache.invalidate()` instead, which operates on individual fields instead of queries, by [@kitten](https://github.com/kitten) (See [#840](https://github.com/FormidableLabs/urql/pull/840))\n\n### Minor Changes\n\n- Implement experimental Offline Support in Graphcache.\n  [Read more about how to use the Offline Support in our docs.](https://formidable.com/open-source/urql/docs/graphcache/offline/), by [@kitten](https://github.com/kitten) (See [#793](https://github.com/FormidableLabs/urql/pull/793))\n- Issue warnings when an unknown type or field has been included in Graphcache's `opts` configuration to help spot typos.\n  Checks `opts.keys`, `opts.updates`, `opts.resolvers` and `opts.optimistic`. (See [#820](https://github.com/FormidableLabs/urql/pull/820) and [#826](https://github.com/FormidableLabs/urql/pull/826))\n\n### Patch Changes\n\n- ⚠️ Fix resolvers being executed for data even when data is currently written. This behaviour could lead to interference with custom updaters that update fragments or queries, e.g. an updater that was receiving paginated data due to a pagination resolver. We've determined that generally it is undesirable to have any resolvers run during the cache update (writing) process, since it may lead to resolver data being accidentally written to the cache or for resolvers to interfere with custom user updates, by [@olistic](https://github.com/olistic) (See [#812](https://github.com/FormidableLabs/urql/pull/812))\n- Upgrade to a minimum version of wonka@^4.0.14 to work around issues with React Native's minification builds, which use uglify-es and could lead to broken bundles, by [@kitten](https://github.com/kitten) (See [#842](https://github.com/FormidableLabs/urql/pull/842))\n- Updated dependencies (See [#838](https://github.com/FormidableLabs/urql/pull/838) and [#842](https://github.com/FormidableLabs/urql/pull/842))\n  - @urql/core@1.12.0\n\n## 2.4.2\n\n### Patch Changes\n\n- Add `source` debug name to all `dispatchDebug` calls during build time to identify events by which exchange dispatched them, by [@JoviDeCroock](https://github.com/JoviDeCroock) (See [#780](https://github.com/FormidableLabs/urql/pull/780))\n- ⚠️ Fix Introspection Queries (or internal types in general) triggering lots of warnings for unkeyed entities, by [@kitten](https://github.com/kitten) (See [#779](https://github.com/FormidableLabs/urql/pull/779))\n- Updated dependencies (See [#780](https://github.com/FormidableLabs/urql/pull/780))\n  - @urql/core@1.11.7\n\n## 2.4.1\n\n### Patch Changes\n\n- Add a `\"./package.json\"` entry to the `package.json`'s `\"exports\"` field for Node 14. This seems to be required by packages like `rollup-plugin-svelte` to function properly, by [@JoviDeCroock](https://github.com/JoviDeCroock) (See [#771](https://github.com/FormidableLabs/urql/pull/771))\n- ⚠️ Fix traversal issue, where when a prior selection set has set a nested result field to `null`, a subsequent traversal of this field attempts to access `prevData` on `null`, by [@kitten](https://github.com/kitten) (See [#772](https://github.com/FormidableLabs/urql/pull/772))\n- Updated dependencies (See [#771](https://github.com/FormidableLabs/urql/pull/771) and [#771](https://github.com/FormidableLabs/urql/pull/771))\n  - @urql/exchange-populate@0.1.7\n  - @urql/core@1.11.6\n\n## 2.4.0\n\nThis release heavily improves on the intuitiveness of how Optimistic Updates work. It ensures that\noptimistic updates aren't accidentally discarded, by temporarily blocking some refetches when\nnecessary. It also prevents optimistic mutation updates from becoming permanent, which could\npreviously happen if an updater read optimistic data and rewrote it again. This isn't possible\nanymore as mutation results are applied as a batch.\n\n### Minor Changes\n\n- Implement refetch blocking for queries that are affected by optimistic update. When a query would normally be refetched, either because it was partial or a cache-and-network operation, we now wait if it touched optimistic data for that optimistic mutation to complete. This prevents optimistic update data from unexpectedly disappearing, by [@kitten](https://github.com/kitten) (See [#750](https://github.com/FormidableLabs/urql/pull/750))\n- Implement optimistic mutation result flushing. Mutation results for mutation that have had optimistic updates will now wait for all optimistic mutations to complete at the same time before being applied to the cache. This sometimes does delay cache updates to until after multiple mutations have completed, but it does prevent optimistic data from being accidentally committed permanently, which is more intuitive, by [@kitten](https://github.com/kitten) (See [#750](https://github.com/FormidableLabs/urql/pull/750))\n\n### Patch Changes\n\n- Adjust mutation results priority to always override query results as they arrive, similarly to subscriptions. This will prevent race conditions when mutations are slow to execute at the cost of some consistency, by [@kitten](https://github.com/kitten) (See [#745](https://github.com/FormidableLabs/urql/pull/745))\n- Improve warning and error console output in development by cleaning up the GraphQL trace stack, by [@JoviDeCroock](https://github.com/JoviDeCroock) (See [#751](https://github.com/FormidableLabs/urql/pull/751))\n\n## 2.3.8\n\n### Patch Changes\n\nSorry for the many updates; Please only upgrade to `>=2.3.8` and don't use the deprecated `2.3.7`\nand `2.3.6` release.\n\n- ⚠️ Fix nested package path for @urql/core/internal and @urql/exchange-graphcache/extras, by [@kitten](https://github.com/kitten) (See [#734](https://github.com/FormidableLabs/urql/pull/734))\n- Updated dependencies (See [#734](https://github.com/FormidableLabs/urql/pull/734))\n  - @urql/core@1.11.4\n\n## 2.3.7\n\n### Patch Changes\n\n- Make the extension of the main export unknown, which fixes a Webpack issue where the resolver won't pick `module` fields in `package.json` files once it's importing from another `.mjs` file, by [@JoviDeCroock](https://github.com/JoviDeCroock) (See [#733](https://github.com/FormidableLabs/urql/pull/733))\n- Updated dependencies (See [#733](https://github.com/FormidableLabs/urql/pull/733))\n  - @urql/core@1.11.2\n\n## 2.3.5\n\n### Patch Changes\n\n- ⚠️ Fix data persistence for embedded fields, by [@kitten](https://github.com/kitten) (See [#727](https://github.com/FormidableLabs/urql/pull/727))\n\n## 2.3.4\n\n### Patch Changes\n\n- Add debugging events to exchanges that add more detailed information on what is happening\n  internally, which will be displayed by devtools like the urql [Chrome / Firefox extension](https://github.com/FormidableLabs/urql-devtools), by [@andyrichardson](https://github.com/andyrichardson) (See [#608](https://github.com/FormidableLabs/urql/pull/608))\n- ⚠️ Fix persistence using special tab character in serialized keys and add sanitization to persistence key serializer, by [@kitten](https://github.com/kitten) (See [#715](https://github.com/FormidableLabs/urql/pull/715))\n- Updated dependencies (See [#608](https://github.com/FormidableLabs/urql/pull/608), [#718](https://github.com/FormidableLabs/urql/pull/718), and [#722](https://github.com/FormidableLabs/urql/pull/722))\n  - @urql/core@1.11.0\n\n## 2.3.3\n\n### Patch Changes\n\n- ⚠️ Fix @urql/exchange-populate visitWithTypeInfo import by bumping babel-plugin-modular-graphql, by [@kitten](https://github.com/kitten) (See [#709](https://github.com/FormidableLabs/urql/pull/709))\n- Updated dependencies (See [#709](https://github.com/FormidableLabs/urql/pull/709))\n  - @urql/exchange-populate@0.1.6\n\n## 2.3.2\n\n### Patch Changes\n\n- Pick modules from graphql package, instead of importing from graphql/index.mjs, by [@kitten](https://github.com/kitten) (See [#700](https://github.com/FormidableLabs/urql/pull/700))\n- Change invalidation to check for undefined links since null is a valid value in graphql, by [@JoviDeCroock](https://github.com/JoviDeCroock) (See [#694](https://github.com/FormidableLabs/urql/pull/694))\n- Updated dependencies (See [#700](https://github.com/FormidableLabs/urql/pull/700))\n  - @urql/exchange-populate@0.1.5\n  - @urql/core@1.10.9\n\n## 2.3.1\n\n### Patch Changes\n\n- Add graphql@^15.0.0 to peer dependency range, by [@kitten](https://github.com/kitten) (See [#688](https://github.com/FormidableLabs/urql/pull/688))\n- Forcefully bump @urql/core package in all bindings and in @urql/exchange-graphcache.\n  We're aware that in some cases users may not have upgraded to @urql/core, even though that's within\n  the typical patch range. Since the latest @urql/core version contains a patch that is required for\n  `cache-and-network` to work, we're pushing another patch that now forcefully bumps everyone to the\n  new version that includes this fix, by [@kitten](https://github.com/kitten) (See [#684](https://github.com/FormidableLabs/urql/pull/684))\n- Reimplement persistence support to take commutative layers into account, by [@kitten](https://github.com/kitten) (See [#674](https://github.com/FormidableLabs/urql/pull/674))\n- Updated dependencies (See [#688](https://github.com/FormidableLabs/urql/pull/688) and [#678](https://github.com/FormidableLabs/urql/pull/678))\n  - @urql/exchange-populate@0.1.4\n  - @urql/core@1.10.8\n\n## 2.3.0\n\n### Minor Changes\n\n- Support optimistic values for mutations without a selectionset, by [@JoviDeCroock](https://github.com/JoviDeCroock) (See [#657](https://github.com/FormidableLabs/urql/pull/657))\n\n### Patch Changes\n\n- Refactor to replace dictionary-based (`Object.create(null)`) results with regular objects, by [@kitten](https://github.com/kitten) (See [#651](https://github.com/FormidableLabs/urql/pull/651))\n- ⚠️ Fix case where a mutation-rootfield would cause an empty call to the cache.updates[mutationRootField], by [@JoviDeCroock](https://github.com/JoviDeCroock) (See [#654](https://github.com/FormidableLabs/urql/pull/654))\n- Updated dependencies (See [#658](https://github.com/FormidableLabs/urql/pull/658) and [#650](https://github.com/FormidableLabs/urql/pull/650))\n  - @urql/core@1.10.5\n\n## 2.2.8\n\n### Patch Changes\n\n- ⚠️ Fix node resolution when using Webpack, which experiences a bug where it only resolves\n  `package.json:main` instead of `module` when an `.mjs` file imports a package, by [@JoviDeCroock](https://github.com/JoviDeCroock) (See [#642](https://github.com/FormidableLabs/urql/pull/642))\n- Updated dependencies (See [#642](https://github.com/FormidableLabs/urql/pull/642))\n  - @urql/exchange-populate@0.1.3\n  - @urql/core@1.10.4\n\n## 2.2.7\n\n### Patch Changes\n\n- ⚠️ Fix critical ordering bug in commutative queries and mutations. Subscriptions and queries would ad-hoc be receiving an empty optimistic layer accidentally. This leads to subscription results potentially being cleared, queries from being erased on a second write, and layers from sticking around on every second write or indefinitely. This affects versions `> 2.2.2` so please upgrade!, by [@kitten](https://github.com/kitten) (See [#638](https://github.com/FormidableLabs/urql/pull/638))\n- ⚠️ Fix multipart conversion, in the `extract-files` dependency (used by multipart-fetch) there is an explicit check for the constructor property of an object. This made the files unretrievable, by [@JoviDeCroock](https://github.com/JoviDeCroock) (See [#639](https://github.com/FormidableLabs/urql/pull/639))\n- ⚠️ Fix Node.js Module support for v13 (experimental-modules) and v14. If your bundler doesn't support\n  `.mjs` files and fails to resolve the new version, please double check your configuration for\n  Webpack, or similar tools, by [@JoviDeCroock](https://github.com/JoviDeCroock) (See [#637](https://github.com/FormidableLabs/urql/pull/637))\n- Updated dependencies (See [#637](https://github.com/FormidableLabs/urql/pull/637))\n  - @urql/exchange-populate@0.1.2\n  - @urql/core@1.10.3\n\n## 2.2.6\n\n### Patch Changes\n\n- ⚠️ Fix cache.inspectFields causing an undefined error for uninitialised or cleared commutative layers, by [@kitten](https://github.com/kitten) (See [#626](https://github.com/FormidableLabs/urql/pull/626))\n- Improve Store constructor to accept an options object instead of separate arguments, identical to the cacheExchange options. (This is a patch, not a minor, since we consider Store part of the private API), by [@kitten](https://github.com/kitten) (See [#622](https://github.com/FormidableLabs/urql/pull/622))\n- Allow a single field to be invalidated using cache.invalidate using two additional arguments, similar to store.resolve; This is a very small addition, so it's marked as a patch, by [@kitten](https://github.com/kitten) (See [#627](https://github.com/FormidableLabs/urql/pull/627))\n- Prevent variables from being filtered and queries from being altered before they're forwarded, which prevented additional untyped variables from being used inside updater functions, by [@kitten](https://github.com/kitten) (See [#629](https://github.com/FormidableLabs/urql/pull/629))\n- Expose generated result data on writeOptimistic and passthrough data on write operations, by [@kitten](https://github.com/kitten) (See [#613](https://github.com/FormidableLabs/urql/pull/613))\n- Updated dependencies (See [#621](https://github.com/FormidableLabs/urql/pull/621))\n  - @urql/core@1.10.2\n\n## 2.2.5\n\n### Patch Changes\n\n- Refactor parts of Graphcache for a minor performance boost and bundlesize reductions, by [@kitten](https://github.com/kitten) (See [#611](https://github.com/FormidableLabs/urql/pull/611))\n\n## 2.2.4\n\n### Patch Changes\n\n- ⚠️ Fix Rollup bundle output being written to .es.js instead of .esm.js, by [@kitten](https://github.com/kitten) (See [#609](https://github.com/FormidableLabs/urql/pull/609))\n- Updated dependencies (See [#609](https://github.com/FormidableLabs/urql/pull/609))\n  - @urql/core@1.10.1\n\n## 2.2.3\n\n### Patch Changes\n\n- Apply commutative layers to all operations, so now including mutations and subscriptions, to ensure that unordered data is written in the correct order, by [@kitten](https://github.com/kitten) (See [#593](https://github.com/FormidableLabs/urql/pull/593))\n- Updated dependencies (See [#607](https://github.com/FormidableLabs/urql/pull/607) and [#601](https://github.com/FormidableLabs/urql/pull/601))\n  - @urql/core@1.10.0\n\n## 2.2.2\n\n### Patch Changes\n\n- ⚠️ Fix commutative layer edge case when lowest-priority layer comes back earlier than others, by [@kitten](https://github.com/kitten) (See [#587](https://github.com/FormidableLabs/urql/pull/587))\n- Externalise @urql/exchange-populate from bundle, by [@kitten](https://github.com/kitten) (See [#590](https://github.com/FormidableLabs/urql/pull/590))\n- ⚠️ Fix teardown events leading to broken commutativity, by [@kitten](https://github.com/kitten) (See [#588](https://github.com/FormidableLabs/urql/pull/588))\n\n## 2.2.1\n\n### Patch Changes\n\n- Remove the shared package, this will fix the types file generation for graphcache, by [@JoviDeCroock](https://github.com/JoviDeCroock) (See [#579](https://github.com/FormidableLabs/urql/pull/579))\n- Updated dependencies (See [#577](https://github.com/FormidableLabs/urql/pull/577))\n  - @urql/core@1.9.2\n\n## 2.2.0\n\n### Minor Changes\n\n- Add `cache.invalidate` to invalidate an entity directly to remove it from the cache and all subsequent cache results, e.g. `cache.invalidate({ __typename: 'Todo', id: 1 })`, by [@JoviDeCroock](https://github.com/JoviDeCroock) (See [#566](https://github.com/FormidableLabs/urql/pull/566))\n\n### Patch Changes\n\n- ⚠️ Fix `cache-only` operations being forwarded and triggering fetch requests, by [@JoviDeCroock](https://github.com/JoviDeCroock) (See [#551](https://github.com/FormidableLabs/urql/pull/551))\n- Apply Query results in-order and commutatively even when results arrive out-of-order, by [@kitten](https://github.com/kitten) (See [#565](https://github.com/FormidableLabs/urql/pull/565))\n- Updated dependencies (See [#551](https://github.com/FormidableLabs/urql/pull/551), [#542](https://github.com/FormidableLabs/urql/pull/542), and [#544](https://github.com/FormidableLabs/urql/pull/544))\n  - @urql/core@1.9.1\n\n## 2.1.1\n\n### Patch Changes\n\n- Update the `updater` function type of `cache.updateQuery` to have a return type of `DataFields` so that `__typename` does not need to be defined, by [@JoviDeCroock](https://github.com/JoviDeCroock) (See [#538](https://github.com/FormidableLabs/urql/pull/538))\n- ⚠️ Fix updates not being triggered when optimistic updates diverge from the actual result. (See [#160](https://github.com/FormidableLabs/urql-exchange-graphcache/pull/160))\n- Refactor away SchemaPredicates helper to reduce bundlesize. (See [#161](https://github.com/FormidableLabs/urql-exchange-graphcache/pull/161))\n- Ensure that pagination helpers don't confuse pages that have less params with a\n  query that has more params. (See [#156](https://github.com/FormidableLabs/urql-exchange-graphcache/pull/156))\n- Updated dependencies (See [#533](https://github.com/FormidableLabs/urql/pull/533), [#519](https://github.com/FormidableLabs/urql/pull/519), [#515](https://github.com/FormidableLabs/urql/pull/515), [#512](https://github.com/FormidableLabs/urql/pull/512), and [#518](https://github.com/FormidableLabs/urql/pull/518))\n  - @urql/core@1.9.0\n\n## 2.1.0\n\nThis release adds support for cache persistence which is bringing us one step closer to\nfull offline-support, which we hope to bring you soon.\n\nIt also allows `wonka@^4.0.0` as a dependency to be compatible with [`urql@1.8.0`](https://github.com/FormidableLabs/urql/blob/master/CHANGELOG.md#v180). It also fixes a couple of issues in our\nnew `populateExchange`.\n\n- Refactor internal store code and simplify `Store` (see [#134](https://github.com/FormidableLabs/urql-exchange-graphcache/pull/134))\n- ✨ Implement store persistence support (see [#137](https://github.com/FormidableLabs/urql-exchange-graphcache/pull/137))\n- ✨ Apply GC to store persistence (see [#138](https://github.com/FormidableLabs/urql-exchange-graphcache/pull/138))\n- Remove unused case where scalars are written from an API when links are expected (see [#142](https://github.com/FormidableLabs/urql-exchange-graphcache/pull/142))\n- ⚠️ Add support for resolvers causing cache misses (see [#143](https://github.com/FormidableLabs/urql-exchange-graphcache/pull/143))\n- ⚠️ Fix nested types (e.g. `[Item!]!`) in `populateExchange` (see [#150](https://github.com/FormidableLabs/urql-exchange-graphcache/pull/150))\n- Fix duplicate fragments in `populateExchange` output (see [#151](https://github.com/FormidableLabs/urql-exchange-graphcache/pull/151))\n- Allow `wonka@^3.2.1||^4.0.0` to be used (see [#153](https://github.com/FormidableLabs/urql-exchange-graphcache/pull/153))\n\n## 2.0.0\n\n> **Note:** The minimum required version of `urql` for this release is now `1.7.0`!\n\n**Christmas came early!** This version improves performance again by about 25% over `1.2.2`. It also\nnow ships with two new features: The `populateExchange` and automatic garbage collection.\n\nIncluding the `populateExchange` is optional. It records all fragments in any active queries, and\npopulates mutation selection sets when the `@populate` directive is used based on typenames. If your\nschema includes `viewer` fields on mutations, which resolve back to your `Query` type, you can use\nthis to automatically update your app's data when a mutation is made. _(More documentation on this\nis coming soon!)_\n\nThe garbage collection works by utilising an automatic reference counting algorithm rather than\na mark & sweep algorithm. We feel this is the best tradeoff to maintain good performance during\nruntime while minimising the data that is unnecessarily retained in-memory. You don't have to do\n_anything_! Graphcache will do its newly added magic in the background.\n\nThere are some breaking changes, if you're using `cache.resolveConnections` or `resolveValueOrLink`\nthen you now need to use `inspectFields` and `resolveFieldByKey` instead. You may also now make\nuse of `cache.keyOfField`. (More info on [#128](https://github.com/FormidableLabs/urql-exchange-graphcache/pull/128))\n\n- ✨ Implement `populateExchange` (see [#120](https://github.com/FormidableLabs/urql-exchange-graphcache/pull/120))\n- Improve type safety of `invariant` and `warning` (see [#121](https://github.com/FormidableLabs/urql-exchange-graphcache/pull/121))\n- Reduce size of `populateExchange` (see [#122](https://github.com/FormidableLabs/urql-exchange-graphcache/pull/122))\n- Move more code to KVMap (see [#125](https://github.com/FormidableLabs/urql-exchange-graphcache/pull/125))\n- Move deletion to setting `undefined` instead (see [#126](https://github.com/FormidableLabs/urql-exchange-graphcache/pull/126))\n- Fix multiple edge cases in the `relayPagination` helper, by [@rafeca](https://github.com/rafeca) (see [#127](https://github.com/FormidableLabs/urql-exchange-graphcache/pull/127))\n- ✨⚠️ Reimplement data structure and add garbage collection (see [#128](https://github.com/FormidableLabs/urql-exchange-graphcache/pull/128))\n- Use Closure Compiler (see [#131](https://github.com/FormidableLabs/urql-exchange-graphcache/pull/131))\n- Switch to using `urql/core` on `1.7.0` (see [#132](https://github.com/FormidableLabs/urql-exchange-graphcache/pull/132))\n\n## 1.2.2\n\nThis patch replaces `pessimism` (our former underlying data structure) with a smaller implementation\nthat just uses `Map`s, since we weren't relying on any immutability internally. This cuts down\non bundlesize and massively on GC-pressure, which provides a large speedup on low-end devices.\n\n- Replace Pessimism with mutable store to prevent excessive GC work (see [#117](https://github.com/FormidableLabs/urql-exchange-graphcache/pull/117))\n\n## 1.2.1\n\n- Fix viewer fields (which return `Query` types) not being written or read correctly (see [#116](https://github.com/FormidableLabs/urql-exchange-graphcache/pull/116))\n\n## 1.2.0\n\n- ⚠️ Fix unions not being checked supported by schema predicates, by [@StevenLangbroek](https://github.com/StevenLangbroek) (see [#113](https://github.com/FormidableLabs/urql-exchange-graphcache/pull/113))\n- ✨ Add `simplePagination` helper for resolving simple, paginated lists (see [#115](https://github.com/FormidableLabs/urql-exchange-graphcache/pull/115))\n\n## 1.1.2\n\n- Fix `relayPagination` helper causing cache-misses for empty lists, by [@rafeca](https://github.com/rafeca) (see [#111](https://github.com/FormidableLabs/urql-exchange-graphcache/pull/111))\n\n## 1.1.1\n\nThis is a minor release since it increases the peer dependency of `urql` to `>= 1.6.0`, due to the addition\nof the `stale` flag to partial responses and `cache-and-network` responses. This flag is useful to check\nwhether more requests are being made in the background by `@urql/exchange-graphcache`.\n\nAdditionally, this release adds a small stack to every error and warning that indicates where an\nerror has occured. It lists out the query and all subsequent fragments it has been traversing\nso that errors and warnings can be traced more easily.\n\n- Add a query/fragment stack to all errors and warnings (see [#107](https://github.com/FormidableLabs/urql-exchange-graphcache/pull/107))\n- Add `stale: true` to all `cache-and-network` and partial responses (see [#108](https://github.com/FormidableLabs/urql-exchange-graphcache/pull/108))\n\n## 1.0.3\n\n- Fix `relayPagination` helper merging pages with different field arguments (see [#104](https://github.com/FormidableLabs/urql-exchange-graphcache/pull/104))\n\n## 1.0.2\n\n- Deduplicate connections in `Store.writeConnection` when possible (see [#103](https://github.com/FormidableLabs/urql-exchange-graphcache/pull/103))\n- Fix early bail-out in `relayPagination` helper (see [#103](https://github.com/FormidableLabs/urql-exchange-graphcache/pull/103))\n\n## 1.0.1\n\n- Trims down the size by 100 bytes (see [#96](https://github.com/FormidableLabs/urql-exchange-graphcache/pull/96))\n- Include the `/extras` build in the published version (see [#97](https://github.com/FormidableLabs/urql-exchange-graphcache/pull/97))\n- Invariant and warnings will now have an error code associated with a more elaborate explanation (see [#99](https://github.com/FormidableLabs/urql-exchange-graphcache/pull/99))\n- Invariant errors will now be included in your production bundle (see [#100](https://github.com/FormidableLabs/urql-exchange-graphcache/pull/100))\n- Fixes the relayPagination helper to correctly return partial results (see [#101](https://github.com/FormidableLabs/urql-exchange-graphcache/pull/101))\n- Add special case to relayPagination for first and last during inwards merge (see [#102](https://github.com/FormidableLabs/urql-exchange-graphcache/pull/102))\n\n## 1.0.0\n\n> **Note:** The minimum required version of `urql` for this release is now `1.5.1`!\n\n**Hooray it's `v1.0.0` time!** This doesn't mean that we won't be changing little things anymore, but we're so far happy with our API and trust Graphcache to work correctly. We will further iterate on this version with some **planned features**, like \"fragment invalidation\", garbage collection, and more.\n\nThis version refactors the **cache resolvers** and adds some new special powers to them! You can now return almost anything from cache resolvers and trust that it'll do the right thing:\n\n- You can return entity keys, which will resolve the cached entities\n- You can return keyable entities, which will also be resolved from cache\n- You may also return unkeyable entities, which will be partially resolved from cache, with your resolved values taking precedence\n\nThis can also be nested, so that unkeyable entities can eventually lead back to normal, cached entities!\n\nThis has enabled us to expose the `relayPagination()` helper! This is a resolver that you can just drop into the `cacheExchange`'s `resolvers` config. It automatically does Relay-style pagination, which is now possible due to our more powerful resolvers! You can import it from `@urql/exchange-graphcache/extras`.\n\n- ✨ Add full cache resolver traversal (see [#91](https://github.com/FormidableLabs/urql-exchange-graphcache/pull/91))\n- ✨ Add a new `relayPagination` helper (see [#91](https://github.com/FormidableLabs/urql-exchange-graphcache/pull/91))\n- Add a `Cache` interface with all methods (that are safe for userland) having documentation (see [#91](https://github.com/FormidableLabs/urql-exchange-graphcache/pull/91))\n- ⚠ Fix non-default root keys (that aren't just `Query`) not being respected (see [#87](https://github.com/FormidableLabs/urql-exchange-graphcache/pull/87))\n\n## 1.0.0-rc.11\n\n- Fix `updates` not being called for `optimistic` results (see [#83](https://github.com/FormidableLabs/urql-exchange-graphcache/pull/83))\n- Add optional `variables` argument to `readFragment` and `writeFragment` (see [#84](https://github.com/FormidableLabs/urql-exchange-graphcache/pull/84))\n- ⚠ Fix field arguments not normalising optional `null` values (see [#85](https://github.com/FormidableLabs/urql-exchange-graphcache/pull/85))\n\n## 1.0.0-rc.10\n\n- ⚠ Fix removing cache entries by upgrading to Pessimism `1.1.4` (see [ae72d3](https://github.com/FormidableLabs/urql-exchange-graphcache/commit/ae72d3b1c8b3e5965e122d5509eb561f68579474))\n\n## 1.0.0-rc.9\n\n- ⚠ Fix optimistic updates by upgrading to Pessimism `1.1.3` (see [#81](https://github.com/FormidableLabs/urql-exchange-graphcache/pull/81))\n\n## 1.0.0-rc.8\n\n- Fix warnings being shown for Relay `Connection` and `Edge` embedded types (see [#79](https://github.com/FormidableLabs/urql-exchange-graphcache/pull/79))\n- Implement `readFragment` method on `Store` (see [#73](https://github.com/FormidableLabs/urql-exchange-graphcache/pull/73))\n- Implement `readQuery` method on `Store` (see [#73](https://github.com/FormidableLabs/urql-exchange-graphcache/pull/73))\n- Improve `writeFragment` method on `Store` (see [#73](https://github.com/FormidableLabs/urql-exchange-graphcache/pull/73))\n\n## 1.0.0-rc.7\n\n- ⚠ Fix reexecuted operations due to dependencies not using `cache-first` (see [0bd58f6](https://github.com/FormidableLabs/urql-exchange-graphcache/commit/0bd58f6))\n\n## 1.0.0-rc.6\n\n- ⚠ Fix concurrency issue where a single operation is reexecuted multiple times (see [#70](https://github.com/FormidableLabs/urql-exchange-graphcache/pull/70))\n- Skip writing `undefined` to the cache and log a warning in development (see [#71](https://github.com/FormidableLabs/urql-exchange-graphcache/pull/71))\n- Allow `query` to be passed as a string to `store.updateQuery` (see [#72](https://github.com/FormidableLabs/urql-exchange-graphcache/pull/72))\n\n## 1.0.0-rc.5\n\n- ⚠ Fix user-provided `keys` config not being able to return `null` (see [#68](https://github.com/FormidableLabs/urql-exchange-graphcache/pull/68))\n\n## 1.0.0-rc.4\n\n- ⚠ Fix development warnings throwing an error for root fields (see [#65](https://github.com/FormidableLabs/urql-exchange-graphcache/pull/65))\n\n## 1.0.0-rc.3\n\n_Note: This is release contains a bug that `v1.0.0-rc.4` fixes_\n\n- Fix warning condition for missing entity keys (see [98287ae](https://github.com/FormidableLabs/urql-exchange-graphcache/commit/98287ae))\n\n## 1.0.0-rc.2\n\n_Note: This is release contains a bug that `v1.0.0-rc.3` fixes_\n\n- Add warnings for unknown fields based on the schema and deduplicate warnings (see [#63](https://github.com/FormidableLabs/urql-exchange-graphcache/pull/63))\n\n## 1.0.0-rc.1\n\nThis is the first release that adds _schema awareness_. Passing a schema to Graphcache allows it to make deterministic\nassumptions about the cached results it generates from its data. It can deterministically match fragments to interfaces,\ninstead of resorting to a heuristic, and it can provide _partial results_ for queries. With a `schema` passed to Graphcache,\nas long as only nullable fields are uncached and missing, it will still provide an initial cached result.\n\n- ✨ Add schema awareness using the `schema` option (see [#58](https://github.com/FormidableLabs/urql-exchange-graphcache/pull/58))\n- ✨ Allow for partial results to cascade missing values upwards (see [#59](https://github.com/FormidableLabs/urql-exchange-graphcache/pull/59))\n- Fix `store.keyOfEntity` not using root names from the schema (see [#62](https://github.com/FormidableLabs/urql-exchange-graphcache/pull/62))\n\n## 1.0.0-rc.0\n\nThis is where this CHANGELOG starts.\nFor a log on what happened in `beta` and `alpha` releases, please read the commit history.\n"
  },
  {
    "path": "exchanges/graphcache/README.md",
    "content": "<h2 align=\"center\">@urql/exchange-graphcache</h2>\n\n<p align=\"center\"><strong>An exchange for normalized caching support in <code>urql</code></strong></p>\n\n`@urql/exchange-graphcache` is a normalized cache exchange for the [`urql`](https://github.com/urql-graphql/urql) GraphQL client.\nThis is a drop-in replacement for the default `cacheExchange` that, instead of document\ncaching, caches normalized data by keys and connections between data.\n\nYou can also pass your introspected GraphQL schema to the `cacheExchange`, which enables\nit to deliver partial results and match fragments deterministically!\n\n`urql` is already quite a comprehensive GraphQL client. However in several cases it may be\ndesirable to have data update across the entirety of an app when a response updates some\nknown pieces of data.\n\n[Learn more about Graphcache and normalized caching on our docs!](https://formidable.com/open-source/urql/docs/graphcache/)\n\n## Quick Start Guide\n\nFirst install `@urql/exchange-graphcache` alongside `urql`:\n\n```sh\nyarn add @urql/exchange-graphcache\n# or\nnpm install --save @urql/exchange-graphcache\n```\n\nYou'll then need to add the `cacheExchange`, that this package exposes, to your `urql` Client,\nby replacing the default cache exchange with it:\n\n```js\nimport { createClient, fetchExchange } from 'urql';\nimport { cacheExchange } from '@urql/exchange-graphcache';\n\nconst client = createClient({\n  url: 'http://localhost:1234/graphql',\n  exchanges: [\n    // Replace the default cacheExchange with the new one\n    cacheExchange({\n      /* optional config */\n    }),\n    fetchExchange,\n  ],\n});\n```\n"
  },
  {
    "path": "exchanges/graphcache/benchmarks/10000Reads.html",
    "content": "<!doctype html>\n<html lang=\"en\">\n  <head>\n    <meta charset=\"UTF-8\" />\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\" />\n    <title>10000 Reads</title>\n    <script>\n      window.process = { env: { NODE_ENV: 'development' } };\n    </script>\n  </head>\n\n  <body>\n    <div id=\"root\"></div>\n    <script type=\"module\">\n      import urqlClient from './urqlClient.js';\n      import * as bench from '/bench.js';\n      import { makeEntries } from './makeEntries.js';\n      import { makeTodo } from './entities.js';\n      import { getAllTodos, addTodos } from './benchmarks.js';\n\n      // create todos to be added/written\n      const tenThousandTodos = makeEntries(10000, makeTodo);\n\n      const benchmark = async () => {\n        await addTodos(tenThousandTodos);\n        bench.start();\n        await getAllTodos();\n        bench.stop();\n      };\n\n      benchmark();\n    </script>\n  </body>\n</html>\n"
  },
  {
    "path": "exchanges/graphcache/benchmarks/10000ReadsComplex.html",
    "content": "<!doctype html>\n<html lang=\"en\">\n  <head>\n    <meta charset=\"UTF-8\" />\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\" />\n    <title>10000 Reads Complex</title>\n    <script>\n      window.process = { env: { NODE_ENV: 'development' } };\n    </script>\n  </head>\n\n  <body>\n    <div id=\"root\"></div>\n    <script type=\"module\">\n      import urqlClient from './urqlClient.js';\n      import * as bench from '/bench.js';\n      import { makeEntries } from './makeEntries.js';\n      import { makeAuthor } from './entities.js';\n      import { getAllAuthors, addAuthors } from './benchmarks.js';\n\n      // create authors to be added/written\n      const tenThousandAuthors = makeEntries(10000, makeAuthor);\n\n      const benchmark = async () => {\n        await addAuthors(tenThousandAuthors);\n        // measure how long read takes\n        bench.start();\n        await getAllAuthors();\n        bench.stop();\n      };\n\n      benchmark();\n    </script>\n  </body>\n</html>\n"
  },
  {
    "path": "exchanges/graphcache/benchmarks/10000Writes.html",
    "content": "<!doctype html>\n<html lang=\"en\">\n  <head>\n    <meta charset=\"UTF-8\" />\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\" />\n    <title>10000 Writes</title>\n    <script>\n      window.process = { env: { NODE_ENV: 'development' } };\n    </script>\n  </head>\n\n  <body>\n    <div id=\"root\"></div>\n    <script type=\"module\">\n      import urqlClient from './urqlClient.js';\n      import * as bench from '/bench.js';\n      import { makeEntries } from './makeEntries.js';\n      import { makeTodo } from './entities.js';\n      import { getAllTodos, addTodos } from './benchmarks.js';\n\n      // create todos to be added/written\n      const tenThousandTodos = makeEntries(10000, makeTodo);\n\n      const benchmark = async () => {\n        bench.start();\n        await addTodos(tenThousandTodos);\n        bench.stop();\n      };\n\n      benchmark();\n    </script>\n  </body>\n</html>\n"
  },
  {
    "path": "exchanges/graphcache/benchmarks/10000WritesComplex.html",
    "content": "<!doctype html>\n<html lang=\"en\">\n  <head>\n    <meta charset=\"UTF-8\" />\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\" />\n    <title>10000 Writes Complex</title>\n    <script>\n      window.process = { env: { NODE_ENV: 'development' } };\n    </script>\n  </head>\n\n  <body>\n    <div id=\"root\"></div>\n    <script type=\"module\">\n      import urqlClient from './urqlClient.js';\n      import * as bench from '/bench.js';\n      import { makeEntries } from './makeEntries.js';\n      import { makeAuthor } from './entities.js';\n      import { getAllAuthors, addAuthors } from './benchmarks.js';\n\n      // create authors to be added/written\n      const hundredAuthors = makeEntries(10000, makeAuthor);\n\n      const benchmark = async () => {\n        // measure how long write takes\n        bench.start();\n        await addAuthors(hundredAuthors);\n        bench.stop();\n      };\n\n      benchmark();\n    </script>\n  </body>\n</html>\n"
  },
  {
    "path": "exchanges/graphcache/benchmarks/1000Reads.html",
    "content": "<!doctype html>\n<html lang=\"en\">\n  <head>\n    <meta charset=\"UTF-8\" />\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\" />\n    <title>1000 Reads</title>\n    <script>\n      window.process = { env: { NODE_ENV: 'development' } };\n    </script>\n  </head>\n\n  <body>\n    <div id=\"root\"></div>\n    <script type=\"module\">\n      import urqlClient from './urqlClient.js';\n      import * as bench from '/bench.js';\n      import { makeEntries } from './makeEntries.js';\n      import { makeTodo } from './entities.js';\n      import { getAllTodos, addTodos } from './benchmarks.js';\n\n      // create todos to be added/written\n      const thousandTodos = makeEntries(1000, makeTodo);\n\n      const benchmark = async () => {\n        await addTodos(thousandTodos);\n        bench.start();\n        await getAllTodos();\n        bench.stop();\n      };\n\n      benchmark();\n    </script>\n  </body>\n</html>\n"
  },
  {
    "path": "exchanges/graphcache/benchmarks/1000ReadsComplex.html",
    "content": "<!doctype html>\n<html lang=\"en\">\n  <head>\n    <meta charset=\"UTF-8\" />\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\" />\n    <title>1000 Reads Complex</title>\n    <script>\n      window.process = { env: { NODE_ENV: 'development' } };\n    </script>\n  </head>\n\n  <body>\n    <div id=\"root\"></div>\n    <script type=\"module\">\n      import urqlClient from './urqlClient.js';\n      import * as bench from '/bench.js';\n      import { makeEntries } from './makeEntries.js';\n      import { makeAuthor } from './entities.js';\n      import { getAllAuthors, addAuthors } from './benchmarks.js';\n\n      // create authors to be added/written\n      const thousandAuthors = makeEntries(1000, makeAuthor);\n\n      const benchmark = async () => {\n        await addAuthors(thousandAuthors);\n        // measure how long read takes\n        bench.start();\n        await getAllAuthors();\n        bench.stop();\n      };\n\n      benchmark();\n    </script>\n  </body>\n</html>\n"
  },
  {
    "path": "exchanges/graphcache/benchmarks/1000Writes.html",
    "content": "<!doctype html>\n<html lang=\"en\">\n  <head>\n    <meta charset=\"UTF-8\" />\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\" />\n    <title>1000 Writes</title>\n    <script>\n      window.process = { env: { NODE_ENV: 'development' } };\n    </script>\n  </head>\n\n  <body>\n    <div id=\"root\"></div>\n    <script type=\"module\">\n      import urqlClient from './urqlClient.js';\n      import * as bench from '/bench.js';\n      import { makeEntries } from './makeEntries.js';\n      import { makeTodo } from './entities.js';\n      import { getAllTodos, addTodos } from './benchmarks.js';\n\n      // create todos to be added/written\n      const thousandTodos = makeEntries(1000, makeTodo);\n\n      const benchmark = async () => {\n        bench.start();\n        await addTodos(thousandTodos);\n        bench.stop();\n      };\n\n      benchmark();\n    </script>\n  </body>\n</html>\n"
  },
  {
    "path": "exchanges/graphcache/benchmarks/1000WritesComplex.html",
    "content": "<!doctype html>\n<html lang=\"en\">\n  <head>\n    <meta charset=\"UTF-8\" />\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\" />\n    <title>1000 Writes Complex</title>\n    <script>\n      window.process = { env: { NODE_ENV: 'development' } };\n    </script>\n  </head>\n\n  <body>\n    <div id=\"root\"></div>\n    <script type=\"module\">\n      import urqlClient from './urqlClient.js';\n      import * as bench from '/bench.js';\n      import { makeEntries } from './makeEntries.js';\n      import { makeAuthor } from './entities.js';\n      import { getAllAuthors, addAuthors } from './benchmarks.js';\n\n      // create authors to be added/written\n      const hundredAuthors = makeEntries(1000, makeAuthor);\n\n      const benchmark = async () => {\n        // measure how long write takes\n        bench.start();\n        await addAuthors(hundredAuthors);\n        bench.stop();\n      };\n\n      benchmark();\n    </script>\n  </body>\n</html>\n"
  },
  {
    "path": "exchanges/graphcache/benchmarks/100Reads.html",
    "content": "<!doctype html>\n<html lang=\"en\">\n  <head>\n    <meta charset=\"UTF-8\" />\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\" />\n    <title>100 Reads</title>\n    <script>\n      window.process = { env: { NODE_ENV: 'development' } };\n    </script>\n  </head>\n\n  <body>\n    <div id=\"root\"></div>\n    <script type=\"module\">\n      import urqlClient from './urqlClient.js';\n      import * as bench from '/bench.js';\n      import { makeEntries } from './makeEntries.js';\n      import { makeTodo } from './entities.js';\n      import { getAllTodos, addTodos } from './benchmarks.js';\n\n      // create todos to be added/written\n      const hundredTodos = makeEntries(100, makeTodo);\n\n      // benchmark to be performed to assess urql client performance\n      const benchmark = async () => {\n        await addTodos(hundredTodos);\n        bench.start();\n        await getAllTodos();\n        bench.stop();\n      };\n\n      benchmark();\n    </script>\n  </body>\n</html>\n"
  },
  {
    "path": "exchanges/graphcache/benchmarks/100ReadsComplex.html",
    "content": "<!doctype html>\n<html lang=\"en\">\n  <head>\n    <meta charset=\"UTF-8\" />\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\" />\n    <title>100 Reads Complex</title>\n    <script>\n      window.process = { env: { NODE_ENV: 'development' } };\n    </script>\n  </head>\n\n  <body>\n    <div id=\"root\"></div>\n    <script type=\"module\">\n      import urqlClient from './urqlClient.js';\n      import * as bench from '/bench.js';\n      import { makeEntries } from './makeEntries.js';\n      import { makeAuthor } from './entities.js';\n      import { getAllAuthors, addAuthors } from './benchmarks.js';\n\n      // create authors to be added/written\n      const hundredAuthors = makeEntries(100, makeAuthor);\n\n      // benchmark to be performed to assess urql client performance\n      const benchmark = async () => {\n        await addAuthors(hundredAuthors);\n        bench.start();\n        await getAllAuthors();\n        bench.stop();\n      };\n\n      benchmark();\n    </script>\n  </body>\n</html>\n"
  },
  {
    "path": "exchanges/graphcache/benchmarks/100Writes.html",
    "content": "<!doctype html>\n<html lang=\"en\">\n  <head>\n    <meta charset=\"UTF-8\" />\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\" />\n    <title>100 Writes</title>\n    <script>\n      window.process = { env: { NODE_ENV: 'development' } };\n    </script>\n  </head>\n\n  <body>\n    <div id=\"root\"></div>\n    <script type=\"module\">\n      import urqlClient from './urqlClient.js';\n      import * as bench from '/bench.js';\n      import { makeEntries } from './makeEntries.js';\n      import { makeTodo } from './entities.js';\n      import { getAllTodos, addTodos } from './benchmarks.js';\n\n      // create todos to be added/written\n      const hundredTodos = makeEntries(100, makeTodo);\n\n      // benchmark to be performed to assess urql client performance\n      const benchmark = async () => {\n        bench.start();\n        await addTodos(hundredTodos);\n        bench.stop();\n      };\n\n      benchmark();\n    </script>\n  </body>\n</html>\n"
  },
  {
    "path": "exchanges/graphcache/benchmarks/100WritesComplex.html",
    "content": "<!doctype html>\n<html lang=\"en\">\n  <head>\n    <meta charset=\"UTF-8\" />\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\" />\n    <title>100 Writes Complex</title>\n    <script>\n      window.process = { env: { NODE_ENV: 'development' } };\n    </script>\n  </head>\n\n  <body>\n    <div id=\"root\"></div>\n    <script type=\"module\">\n      import urqlClient from './urqlClient.js';\n      import * as bench from '/bench.js';\n      import { makeEntries } from './makeEntries.js';\n      import { makeAuthor } from './entities.js';\n      import { getAllAuthors, addAuthors } from './benchmarks.js';\n\n      // create authors to be added/written\n      const hundredAuthors = makeEntries(100, makeAuthor);\n\n      // benchmark to be performed to assess urql client performance\n      const benchmark = async () => {\n        bench.start();\n        await addAuthors(hundredAuthors);\n        bench.stop();\n      };\n\n      benchmark();\n    </script>\n  </body>\n</html>\n"
  },
  {
    "path": "exchanges/graphcache/benchmarks/50000Reads.html",
    "content": "<!doctype html>\n<html lang=\"en\">\n  <head>\n    <meta charset=\"UTF-8\" />\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\" />\n    <title>50000 Reads</title>\n    <script>\n      window.process = { env: { NODE_ENV: 'development' } };\n    </script>\n  </head>\n\n  <body>\n    <div id=\"root\"></div>\n    <script type=\"module\">\n      import urqlClient from './urqlClient.js';\n      import * as bench from '/bench.js';\n      import { makeEntries } from './makeEntries.js';\n      import {\n        makeTodo,\n        makeWriter,\n        makeBook,\n        makeStore,\n        makeEmployee,\n      } from './entities.js';\n      import {\n        getAllTodos,\n        getAllWriters,\n        getAllBooks,\n        getAllStores,\n        getAllEmployees,\n        addTodos,\n        addWriters,\n        addBooks,\n        addStores,\n        addEmployees,\n      } from './benchmarks.js';\n\n      // create entities to be written\n      const hundredTodos = makeEntries(10000, makeTodo);\n      const hundredWriters = makeEntries(10000, makeWriter);\n      const hundredBooks = makeEntries(10000, makeBook);\n      const hundredStores = makeEntries(10000, makeStore);\n      const hundredEmployees = makeEntries(10000, makeEmployee);\n\n      const benchmark = async () => {\n        await addTodos(hundredTodos);\n        await addWriters(hundredWriters);\n        await addBooks(hundredBooks);\n        await addStores(hundredStores);\n        await addEmployees(hundredEmployees);\n\n        bench.start();\n        await getAllTodos();\n        await getAllWriters();\n        await getAllBooks();\n        await getAllStores();\n        await getAllEmployees();\n        bench.stop();\n      };\n\n      benchmark();\n    </script>\n  </body>\n</html>\n"
  },
  {
    "path": "exchanges/graphcache/benchmarks/50000Writes.html",
    "content": "<!doctype html>\n<html lang=\"en\">\n  <head>\n    <meta charset=\"UTF-8\" />\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\" />\n    <title>50000 Writes</title>\n    <script>\n      window.process = { env: { NODE_ENV: 'development' } };\n    </script>\n  </head>\n\n  <body>\n    <div id=\"root\"></div>\n    <script type=\"module\">\n      import urqlClient from './urqlClient.js';\n      import * as bench from '/bench.js';\n      import { makeEntries } from './makeEntries.js';\n      import {\n        makeTodo,\n        makeWriter,\n        makeBook,\n        makeStore,\n        makeEmployee,\n      } from './entities.js';\n      import {\n        getAllTodos,\n        addTodos,\n        addWriters,\n        addBooks,\n        addStores,\n        addEmployees,\n      } from './benchmarks.js';\n\n      // create entities to be written\n      const tenThousandTodos = makeEntries(10000, makeTodo);\n      const tenThousandWriters = makeEntries(10000, makeWriter);\n      const tenThousandBooks = makeEntries(10000, makeBook);\n      const tenThousandStores = makeEntries(10000, makeStore);\n      const tenThousandEmployees = makeEntries(10000, makeEmployee);\n\n      const benchmark = async () => {\n        bench.start();\n        await addTodos(tenThousandTodos);\n        await addWriters(tenThousandWriters);\n        await addBooks(tenThousandBooks);\n        await addStores(tenThousandStores);\n        await addEmployees(tenThousandEmployees);\n        bench.stop();\n      };\n\n      benchmark();\n    </script>\n  </body>\n</html>\n"
  },
  {
    "path": "exchanges/graphcache/benchmarks/5000Reads.html",
    "content": "<!doctype html>\n<html lang=\"en\">\n  <head>\n    <meta charset=\"UTF-8\" />\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\" />\n    <title>5000 Writes</title>\n    <script>\n      window.process = { env: { NODE_ENV: 'development' } };\n    </script>\n  </head>\n\n  <body>\n    <div id=\"root\"></div>\n    <script type=\"module\">\n      import urqlClient from './urqlClient.js';\n      import * as bench from '/bench.js';\n      import { makeEntries } from './makeEntries.js';\n      import {\n        makeTodo,\n        makeWriter,\n        makeBook,\n        makeStore,\n        makeEmployee,\n      } from './entities.js';\n      import {\n        getAllTodos,\n        getAllWriters,\n        getAllBooks,\n        getAllStores,\n        getAllEmployees,\n        addTodos,\n        addWriters,\n        addBooks,\n        addStores,\n        addEmployees,\n      } from './benchmarks.js';\n\n      // create entities to be written\n      const hundredTodos = makeEntries(1000, makeTodo);\n      const hundredWriters = makeEntries(1000, makeWriter);\n      const hundredBooks = makeEntries(1000, makeBook);\n      const hundredStores = makeEntries(1000, makeStore);\n      const hundredEmployees = makeEntries(1000, makeEmployee);\n\n      const benchmark = async () => {\n        await addTodos(hundredTodos);\n        await addWriters(hundredWriters);\n        await addBooks(hundredBooks);\n        await addStores(hundredStores);\n        await addEmployees(hundredEmployees);\n\n        bench.start();\n        await getAllTodos();\n        await getAllWriters();\n        await getAllBooks();\n        await getAllStores();\n        await getAllEmployees();\n        bench.stop();\n      };\n\n      benchmark();\n    </script>\n  </body>\n</html>\n"
  },
  {
    "path": "exchanges/graphcache/benchmarks/5000Writes.html",
    "content": "<!doctype html>\n<html lang=\"en\">\n  <head>\n    <meta charset=\"UTF-8\" />\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\" />\n    <title>5000 Writes</title>\n    <script>\n      window.process = { env: { NODE_ENV: 'development' } };\n    </script>\n  </head>\n\n  <body>\n    <div id=\"root\"></div>\n    <script type=\"module\">\n      import urqlClient from './urqlClient.js';\n      import * as bench from '/bench.js';\n      import { makeEntries } from './makeEntries.js';\n      import {\n        makeTodo,\n        makeWriter,\n        makeBook,\n        makeStore,\n        makeEmployee,\n      } from './entities.js';\n      import {\n        getAllTodos,\n        addTodos,\n        addWriters,\n        addBooks,\n        addStores,\n        addEmployees,\n      } from './benchmarks.js';\n\n      // create entities to be written\n      const thousandTodos = makeEntries(1000, makeTodo);\n      const thousandWriters = makeEntries(1000, makeWriter);\n      const thousandBooks = makeEntries(1000, makeBook);\n      const thousandStores = makeEntries(1000, makeStore);\n      const thousandEmployees = makeEntries(1000, makeEmployee);\n\n      const benchmark = async () => {\n        bench.start();\n        await addTodos(thousandTodos);\n        await addWriters(thousandWriters);\n        await addBooks(thousandBooks);\n        await addStores(thousandStores);\n        await addEmployees(thousandEmployees);\n        bench.stop();\n      };\n\n      benchmark();\n    </script>\n  </body>\n</html>\n"
  },
  {
    "path": "exchanges/graphcache/benchmarks/500Reads.html",
    "content": "<!doctype html>\n<html lang=\"en\">\n  <head>\n    <meta charset=\"UTF-8\" />\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\" />\n    <title>500 Writes</title>\n    <script>\n      window.process = { env: { NODE_ENV: 'development' } };\n    </script>\n  </head>\n\n  <body>\n    <div id=\"root\"></div>\n    <script type=\"module\">\n      import urqlClient from './urqlClient.js';\n      import * as bench from '/bench.js';\n      import { makeEntries } from './makeEntries.js';\n      import {\n        makeTodo,\n        makeWriter,\n        makeBook,\n        makeStore,\n        makeEmployee,\n      } from './entities.js';\n      import {\n        getAllTodos,\n        getAllWriters,\n        getAllBooks,\n        getAllStores,\n        getAllEmployees,\n        addTodos,\n        addWriters,\n        addBooks,\n        addStores,\n        addEmployees,\n      } from './benchmarks.js';\n\n      // create entities to be written\n      const hundredTodos = makeEntries(100, makeTodo);\n      const hundredWriters = makeEntries(100, makeWriter);\n      const hundredBooks = makeEntries(100, makeBook);\n      const hundredStores = makeEntries(100, makeStore);\n      const hundredEmployees = makeEntries(100, makeEmployee);\n\n      const benchmark = async () => {\n        await addTodos(hundredTodos);\n        await addWriters(hundredWriters);\n        await addBooks(hundredBooks);\n        await addStores(hundredStores);\n        await addEmployees(hundredEmployees);\n\n        bench.start();\n        await getAllTodos();\n        await getAllWriters();\n        await getAllBooks();\n        await getAllStores();\n        await getAllEmployees();\n        bench.stop();\n      };\n\n      benchmark();\n    </script>\n  </body>\n</html>\n"
  },
  {
    "path": "exchanges/graphcache/benchmarks/500Writes.html",
    "content": "<!doctype html>\n<html lang=\"en\">\n  <head>\n    <meta charset=\"UTF-8\" />\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\" />\n    <title>500 Writes</title>\n    <script>\n      window.process = { env: { NODE_ENV: 'development' } };\n    </script>\n  </head>\n\n  <body>\n    <div id=\"root\"></div>\n    <script type=\"module\">\n      import urqlClient from './urqlClient.js';\n      import * as bench from '/bench.js';\n      import { makeEntries } from './makeEntries.js';\n      import {\n        makeTodo,\n        makeWriter,\n        makeBook,\n        makeStore,\n        makeEmployee,\n      } from './entities.js';\n      import {\n        getAllTodos,\n        addTodos,\n        addWriters,\n        addBooks,\n        addStores,\n        addEmployees,\n      } from './benchmarks.js';\n\n      // create entities to be written\n      const hundredTodos = makeEntries(100, makeTodo);\n      const hundredWriters = makeEntries(100, makeWriter);\n      const hundredBooks = makeEntries(100, makeBook);\n      const hundredStores = makeEntries(100, makeStore);\n      const hundredEmployees = makeEntries(100, makeEmployee);\n\n      const benchmark = async () => {\n        bench.start();\n        await addTodos(hundredTodos);\n        await addWriters(hundredWriters);\n        await addBooks(hundredBooks);\n        await addStores(hundredStores);\n        await addEmployees(hundredEmployees);\n        bench.stop();\n      };\n\n      benchmark();\n    </script>\n  </body>\n</html>\n"
  },
  {
    "path": "exchanges/graphcache/benchmarks/addTodo.html",
    "content": "<!doctype html>\n<html lang=\"en\">\n  <head>\n    <meta charset=\"UTF-8\" />\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\" />\n    <title>Add Todo</title>\n    <script>\n      window.process = { env: { NODE_ENV: 'development' } };\n    </script>\n  </head>\n\n  <body>\n    <div id=\"root\"></div>\n    <script type=\"module\">\n      import urqlClient from './urqlClient.js';\n      import * as bench from '/bench.js';\n      import { makeEntries } from './makeEntries.js';\n      import { makeTodo } from './entities.js';\n      import { getAllTodos, addTodo, addTodos } from './benchmarks.js';\n\n      const todosToBeAdded = makeEntries(100, makeTodo);\n\n      const benchmark = async () => {\n        await addTodos(todosToBeAdded);\n        await getAllTodos();\n        bench.start();\n        await addTodo();\n        bench.stop();\n      };\n\n      benchmark();\n    </script>\n  </body>\n</html>\n"
  },
  {
    "path": "exchanges/graphcache/benchmarks/benchmarks.js",
    "content": "import urqlClient from './urqlClient.js';\nimport {\n  ALL_TODOS_QUERY,\n  ALL_WRITERS_QUERY,\n  ALL_BOOKS_QUERY,\n  ALL_STORES_QUERY,\n  ALL_EMPLOYEES_QUERY,\n  ALL_AUTHORS_QUERY,\n  ADD_TODO_MUTATION,\n  UPDATE_TODO_MUTATION,\n  ADD_TODOS_MUTATION,\n  ADD_WRITERS_MUTATION,\n  ADD_BOOKS_MUTATION,\n  ADD_STORES_MUTATION,\n  ADD_EMPLOYEES_MUTATION,\n  ADD_AUTHORS_MUTATION,\n} from './operations.js';\n\n// create functions that execute operations/queries/mutaitons to be benchmarked\nexport const getAllTodos = async () => {\n  const queryResult = await urqlClient.query(ALL_TODOS_QUERY).toPromise();\n  return queryResult.data.todos;\n};\nexport const getAllWriters = async () => {\n  const queryResult = await urqlClient.query(ALL_WRITERS_QUERY).toPromise();\n  return queryResult.data.writers;\n};\nexport const getAllBooks = async () => {\n  const queryResult = await urqlClient.query(ALL_BOOKS_QUERY).toPromise();\n  return queryResult.data.books;\n};\nexport const getAllStores = async () => {\n  const queryResult = await urqlClient.query(ALL_STORES_QUERY).toPromise();\n  return queryResult.data.stores;\n};\nexport const getAllEmployees = async () => {\n  const queryResult = await urqlClient.query(ALL_EMPLOYEES_QUERY).toPromise();\n  return queryResult.data.employees;\n};\nexport const getAllAuthors = async () => {\n  const queryResult = await urqlClient.query(ALL_AUTHORS_QUERY).toPromise();\n  return queryResult.data.authors;\n};\nexport const addTodo = async () => {\n  const newTodo = { text: 'New todo', complete: true };\n  const mutationResult = await urqlClient\n    .mutation(ADD_TODO_MUTATION, newTodo)\n    .toPromise();\n  return mutationResult.data.addTodo;\n};\nexport const updateTodo = async ({ id, complete }) => {\n  const updatedTodo = { id, complete };\n  const mutationResult = await urqlClient\n    .mutation(UPDATE_TODO_MUTATION, updatedTodo)\n    .toPromise();\n  return mutationResult.data.updateTodo;\n};\nexport const addTodos = async todosToBeAdded => {\n  const newTodos = { newTodos: { todos: todosToBeAdded } };\n  const mutationResult = await urqlClient\n    .mutation(ADD_TODOS_MUTATION, newTodos)\n    .toPromise();\n  return mutationResult.data.addTodos;\n};\nexport const addWriters = async writersToBeAdded => {\n  const newWriters = { newWriters: { writers: writersToBeAdded } };\n  const mutationResult = await urqlClient\n    .mutation(ADD_WRITERS_MUTATION, newWriters)\n    .toPromise();\n  return mutationResult.data.addWriters;\n};\nexport const addBooks = async booksToBeAdded => {\n  const newBooks = { newBooks: { books: booksToBeAdded } };\n  const mutationResult = await urqlClient\n    .mutation(ADD_BOOKS_MUTATION, newBooks)\n    .toPromise();\n  return mutationResult.data.addBooks;\n};\nexport const addStores = async storesToBeAdded => {\n  const newStores = { newStores: { stores: storesToBeAdded } };\n  const mutationResult = await urqlClient\n    .mutation(ADD_STORES_MUTATION, newStores)\n    .toPromise();\n  return mutationResult.data.addStores;\n};\nexport const addEmployees = async employeesToBeAdded => {\n  const newEmployees = { newEmployees: { employees: employeesToBeAdded } };\n  const mutationResult = await urqlClient\n    .mutation(ADD_EMPLOYEES_MUTATION, newEmployees)\n    .toPromise();\n  return mutationResult.data.addEmployees;\n};\nexport const addAuthors = async authorsToBeAdded => {\n  const newAuthors = { newAuthors: { authors: authorsToBeAdded } };\n  const mutationResult = await urqlClient\n    .mutation(ADD_AUTHORS_MUTATION, newAuthors)\n    .toPromise();\n  return mutationResult.data.addAuthors;\n};\n"
  },
  {
    "path": "exchanges/graphcache/benchmarks/entities.js",
    "content": "// functions to produce objects representing entities => todos, writers, books, stores, employees\nexport const makeTodo = i => ({\n  id: `${i}`,\n  text: `Todo ${i}`,\n  complete: false,\n});\nexport const makeWriter = i => ({\n  id: `${i}`,\n  name: `Writer ${i}`,\n  amountOfBooks: Math.random() * 100,\n  recognized: Boolean(i % 2),\n  number: i,\n  interests: 'Dragonball-Z',\n});\nexport const makeBook = i => ({\n  id: `${i}`,\n  title: `Book ${i}`,\n  published: Boolean(i % 2),\n  genre: 'Fantasy',\n  rating: (i / Math.random()) * 100,\n});\nexport const makeStore = i => ({\n  id: `${i}`,\n  name: `Store ${i}`,\n  country: 'USA',\n});\nexport const makeEmployee = i => ({\n  id: `${i}`,\n  name: `Employee ${i}`,\n  origin: 'USA',\n});\nexport const makeAuthor = i => ({\n  id: `${i}`,\n  name: `Author ${i}`,\n  recognized: Boolean(i % 2),\n  book: {\n    id: `${i}`,\n    title: `Book ${i}`,\n    published: Boolean(i % 2),\n    genre: `Non-Fiction`,\n    rating: (i / Math.random()) * 100,\n    review: {\n      id: `${i}`,\n      score: i,\n      name: `Review ${i}`,\n      reviewer: {\n        id: `${i}`,\n        name: `Person ${i}`,\n        verified: Boolean(i % 2),\n      },\n    },\n  },\n});\n"
  },
  {
    "path": "exchanges/graphcache/benchmarks/makeEntries.js",
    "content": "// create a function that will take in a number of times to be run and a function that will produce an entry/entity\nexport const makeEntries = (amount, makeEntry) => {\n  // create array of entries to be outputted\n  const entries = [];\n  // iterate from 0 up to the amount inputted\n  for (let i = 0; i < amount; i += 1) {\n    // each iteration, create an entry and pass it the current index & push it into output array\n    const entry = makeEntry(i);\n    entries.push(entry);\n  }\n  // return array of entries\n  return entries;\n};\n"
  },
  {
    "path": "exchanges/graphcache/benchmarks/operations.js",
    "content": "// create operations, i.e., queries & mutations, to be performed\nexport const ALL_TODOS_QUERY = `\n    query ALL_TODOS_QUERY {\n        todos {\n            id,\n            text,\n            complete\n        }\n    }\n`;\nexport const ALL_WRITERS_QUERY = `\n    query ALL_WRITERS_QUERY {\n        writers {\n            id,\n            name,\n            amountOfBooks,\n            recognized,\n            number,\n            interests\n        }\n    }\n`;\nexport const ALL_BOOKS_QUERY = `\n    query ALL_BOOKS_QUERY {\n        books {\n            id,\n            title,\n            published,\n            genre,\n            rating\n        }\n    }\n`;\nexport const ALL_STORES_QUERY = `\n    query ALL_STORES_QUERY {\n        stores {\n            id,\n            name,\n            country\n        }\n    }\n`;\nexport const ALL_EMPLOYEES_QUERY = `\n    query ALL_EMPLOYEES_QUERY {\n        employees {\n            id,\n            name,\n            origin\n        }\n    }\n`;\nexport const ALL_AUTHORS_QUERY = `\n    query ALL_AUTHORS_QUERY {\n        authors {\n            id,\n            name,\n            recognized,\n            book\n        }\n    }\n`;\nexport const ADD_TODO_MUTATION = `\n    mutation ADD_TODO_MUTATION($text: String!, $complete: Boolean!){\n        addTodo(text: $text, complete: $complete){\n            id,\n            text,\n            complete\n        }\n    }\n`;\nexport const UPDATE_TODO_MUTATION = `\n    mutation UPDATE_TODO_MUTATION($id: ID!, $complete: Boolean!){\n        updateTodo(id: $id, complete: $complete){\n            id,\n            text,\n            complete\n        }\n    }\n`;\nexport const ADD_TODOS_MUTATION = `\n    mutation ADD_TODOS_MUTATION($newTodos: NewTodosInput!){\n        addTodos(newTodos: $newTodos){\n            id,\n            text,\n            complete\n        }\n    }\n`;\nexport const ADD_WRITERS_MUTATION = `\n    mutation ADD_WRITERS_MUTATION($newWriters: NewWritersInput!){\n        addWriters(newWriters: $newWriters){\n            id,\n            name,\n            amountOfBooks,\n            recognized,\n            number,\n            interests\n        }\n    }\n`;\nexport const ADD_BOOKS_MUTATION = `\n    mutation ADD_BOOKS_MUTATION($newBooks: NewBooksInput!){\n        addBooks(newBooks: $newBooks){\n            id,\n            title,\n            published,\n            genre,\n            rating\n        }\n    }\n`;\nexport const ADD_STORES_MUTATION = `\n    mutation ADD_STORES_MUTATION($newStores: NewStoresInput!){\n        addStores(newStores: $newStores){\n            id,\n            name,\n            country\n        }\n    }\n`;\nexport const ADD_EMPLOYEES_MUTATION = `\n    mutation ADD_EMPLOYEES_MUTATION($newEmployees: NewEmployeesInput!){\n        addEmployees(newEmployees: $newEmployees){\n            id,\n            name,\n            origin\n        }\n    }\n`;\nexport const ADD_AUTHORS_MUTATION = `\n    mutation ADD_AUTHORS_MUTATION($newAuthors: NewAuthorsInput!){\n        addAuthors(newAuthors: $newAuthors){\n            id\n            name\n            recognized\n            book\n        }\n    }\n`;\n"
  },
  {
    "path": "exchanges/graphcache/benchmarks/package.json",
    "content": "{\n  \"name\": \"@urql/exchange-graphcache-tachometer-benchmark\",\n  \"version\": \"1.0.0\",\n  \"description\": \"Comprehensive Tachometer benchmarks for urql/graphcache\",\n  \"main\": \"index.js\",\n  \"scripts\": {\n    \"bench\": \"npm-run-all bench:*\",\n    \"bench:addTodo\": \"tachometer addTodo.html\",\n    \"bench:update\": \"tachometer updateTodo.html\",\n    \"bench:write100\": \"tachometer 100Writes.html\",\n    \"bench:write100c\": \"tachometer 100WritesComplex.html\",\n    \"bench:write500\": \"tachometer 500Writes.html\",\n    \"bench:write1000\": \"tachometer 1000Writes.html\",\n    \"bench:write1000c\": \"tachometer 1000WritesComplex.html\",\n    \"bench:write5000\": \"tachometer 5000Writes.html\",\n    \"bench:write10000\": \"tachometer 10000Writes.html\",\n    \"bench:write10000c\": \"tachometer 10000WritesComplex.html\",\n    \"bench:write50000\": \"tachometer 50000Writes.html\",\n    \"bench:read100\": \"tachometer 100Reads.html\",\n    \"bench:read100c\": \"tachometer 100ReadsComplex.html\",\n    \"bench:read500\": \"tachometer 500Reads.html\",\n    \"bench:read1000\": \"tachometer 1000Reads.html\",\n    \"bench:read1000c\": \"tachometer 1000ReadsComplex.html\",\n    \"bench:read5000\": \"tachometer 5000Reads.html\",\n    \"bench:read10000\": \"tachometer 10000Reads.html\",\n    \"bench:read10000c\": \"tachometer 10000ReadsComplex.html\",\n    \"bench:read50000\": \"tachometer 50000Reads.html\"\n  },\n  \"license\": \"MIT\",\n  \"dependencies\": {\n    \"@urql/exchange-execute\": \"file:../../execute\",\n    \"@urql/exchange-graphcache\": \"file:../\",\n    \"graphql\": \"^16.9.0\",\n    \"npm-run-all\": \"^4.1.5\",\n    \"tachometer\": \"^0.7.1\",\n    \"urql\": \"file:../../../packages/react-urql\"\n  }\n}\n"
  },
  {
    "path": "exchanges/graphcache/benchmarks/readMe.md",
    "content": "## About\n\nThis is a set of benchmarks assessing the performance of various graphCache operations. The operations are of varying sizes, complexitites, and are accomplished via a singular `urql` client instance. Client has a stubbed out GQL API (fetchExchange) to perform GQL operations against.\n\n## Usage\n\n#### 1. Install dependencies in repo root.\n\nTo get started, make sure to install necessary dependencies in the root directory of your clone.\n\n```bash\n# In root directory\nyarn or npm i\n```\n\n#### 2. Run benchmark(s).\n\nThe commands to run benchmarks follows a certain syntax:\nnpm run `ActionQuantityComplexity` => i.e., npm run read500c\nread === Action\n5000 === Quantity\nc === Complex\n\nAction & Quantity are required, but c is optional, as not all operations involve a more complex data structure.\n\nThere are two exceptions that don't follow the beformentioned conventions for the commands to run benchmarks. They are `addTodo` & `updateTodo`.\nThey are simply run as follows:\n\n```\nnpm run addTodo\n\nnpm run updateTodo\n```\n\n#### 3. Benchmark Expections\n\nUpon executing a command, `Tachometer` will automatically execute the benchmarks via your default browser. Done 50 times prior to returning benchmark result in the console where the command was launched.\n"
  },
  {
    "path": "exchanges/graphcache/benchmarks/updateTodo.html",
    "content": "<!doctype html>\n<html lang=\"en\">\n  <head>\n    <meta charset=\"UTF-8\" />\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\" />\n    <title>Update Todo</title>\n    <script>\n      window.process = { env: { NODE_ENV: 'development' } };\n    </script>\n  </head>\n\n  <body>\n    <div id=\"root\"></div>\n    <script type=\"module\">\n      import urqlClient from './urqlClient.js';\n      import * as bench from '/bench.js';\n      import { makeEntries } from './makeEntries.js';\n      import { makeTodo } from './entities.js';\n      import { getAllTodos, addTodos, updateTodo } from './benchmarks.js';\n\n      // create todos to be added/written\n      const hundredTodos = makeEntries(100, makeTodo);\n\n      const benchmark = async () => {\n        await addTodos(hundredTodos);\n        // measure how long update of last Todo entity takes on faux server-side (executeExchange) & cache\n        bench.start();\n        await updateTodo({ id: '99', complete: true });\n        bench.stop();\n      };\n\n      benchmark();\n    </script>\n  </body>\n</html>\n"
  },
  {
    "path": "exchanges/graphcache/benchmarks/urqlClient.js",
    "content": "import { createClient } from '@urql/core';\nimport { cacheExchange } from '@urql/exchange-graphcache';\nimport { executeExchange } from '@urql/exchange-execute';\nimport { buildSchema } from 'graphql';\nimport { ALL_TODOS_QUERY } from './operations';\n\nexport const cache = cacheExchange({\n  updates: {\n    Mutation: {\n      addTodo: (result, args, cache) => {\n        cache.updateQuery({ query: ALL_TODOS_QUERY }, data => {\n          data.todos.push(result.addTodo);\n          return data;\n        });\n        return result;\n      },\n    },\n  },\n});\n\n// local schema to be used with Execute Exchange\nconst schema = buildSchema(`\n    type Todo {\n        id: ID!\n        text: String!\n        complete: Boolean!\n    }\n\n    type Writer {\n        id: ID!\n        name: String\n        amountOfBooks: Float!\n        recognized: Boolean!\n        number: Int!\n        interests: String!\n    }\n\n    type Book {\n        id: ID!\n        title: String!\n        published: Boolean!\n        genre: String!\n        rating: Float!\n        review: Review\n    }\n\n    type Store {\n        id: ID!\n        name: String!\n        country: String!\n    }\n\n    type Employee {\n        id: ID!\n        name: String!\n        origin: String!\n    }\n\n    type Author {\n        id: ID!\n        name: String!\n        recognized: Boolean!\n        book: Book!\n    }\n\n    type Review {\n        id: ID!\n        score: Int!\n        name: String!\n        reviewer: Person!\n    }\n\n    type Person {\n        id: ID!\n        name: String!\n        verfied: Boolean!\n    }\n\n    input NewTodo {\n        id: ID!\n        text: String!\n        complete: Boolean!\n    }\n\n    input NewTodosInput {\n        todos: [NewTodo]!\n    }\n\n    input NewWriter {\n        id: ID!\n        name: String\n        amountOfBooks: Float!\n        recognized: Boolean!\n        number: Int!\n        interests: String!\n    }\n\n    input NewWritersInput {\n        writers: [NewWriter]!\n    }\n\n    input NewBook {\n        id: ID!\n        title: String!\n        published: Boolean!\n        genre: String!\n        rating: Float!\n        review: NewReview\n    }\n\n    input NewBooksInput {\n        books: [NewBook]!\n    }\n\n    input NewStore {\n        id: ID!\n        name: String!\n        country: String!\n    }\n\n    input NewStoresInput {\n        stores: [NewStore]!\n    }\n\n    input NewEmployee {\n        id: ID!\n        name: String!\n        origin: String!\n    }\n\n    input NewEmployeesInput {\n        employees: [NewEmployee]!\n    }\n\n    input NewAuthor {\n        id: ID!\n        name: String!\n        recognized: Boolean!\n        book: NewBook!\n    }\n\n\n    input NewAuthorsInput {\n        authors: [NewAuthor]!\n    }\n\n    input NewReview {\n        id: ID!\n        score: Int!\n        name: String!\n        reviewer: NewPerson!\n    }\n\n    input NewPerson {\n        id: ID!\n        name: String!\n        verified: Boolean!\n    }\n\n    type Query {\n        todos: [Todo]!\n        writers: [Writer]!\n        books: [Book]!\n        stores: [Store]!\n        employees: [Employee]!\n        authors: [Author]!\n    }\n\n    type Mutation {\n        addTodo( text: String!, complete: Boolean! ): Todo!\n        updateTodo( id: ID!, complete: Boolean! ): Todo!\n        addTodos( newTodos: NewTodosInput! ): [Todo]!\n        addWriters( newWriters: NewWritersInput! ): [Writer]!\n        addBooks( newBooks: NewBooksInput! ): [Book]!\n        addStores( newStores: NewStoresInput! ): [Store]!\n        addEmployees( newEmployees: NewEmployeesInput! ): [Employee]!\n        addAuthors( newAuthors: NewAuthorsInput! ): [Author]!\n    }\n`);\n\n// local state to be used with Execute Exchange\nconst todos = [];\nconst writers = [];\nconst books = [];\nconst stores = [];\nconst employees = [];\nconst authors = [];\n\n// root value with resolvers to be used with Execute Exchange\nconst rootValue = {\n  todos: () => {\n    return todos;\n  },\n  writers: () => {\n    return writers;\n  },\n  books: () => {\n    return books;\n  },\n  stores: () => {\n    return stores;\n  },\n  employees: () => {\n    return employees;\n  },\n  authors: () => {\n    return authors;\n  },\n  addTodo: args => {\n    const todo = { id: todos.length.toString(), ...args };\n    todos.push(todo);\n    return todo;\n  },\n  updateTodo: ({ id, complete }) => {\n    const [todoToBeUpdated] = todos.filter(todo => todo.id === id);\n    todoToBeUpdated.complete = complete;\n    return todoToBeUpdated;\n  },\n  addTodos: ({ newTodos }) => {\n    const todosToBeAdded = newTodos.todos;\n    todos.push(...todosToBeAdded);\n    return todos;\n  },\n  addWriters: ({ newWriters }) => {\n    const writersToBeAdded = newWriters.writers;\n    writers.push(...writersToBeAdded);\n    return writers;\n  },\n  addBooks: ({ newBooks }) => {\n    const booksToBeAdded = newBooks.books;\n    books.push(...booksToBeAdded);\n    return books;\n  },\n  addStores: ({ newStores }) => {\n    const storesToBeAdded = newStores.stores;\n    stores.push(...storesToBeAdded);\n    return stores;\n  },\n  addEmployees: ({ newEmployees }) => {\n    const employeesToBeAdded = newEmployees.employees;\n    employees.push(...employeesToBeAdded);\n    return employees;\n  },\n  addAuthors: ({ newAuthors }) => {\n    const authorsToBeAdded = newAuthors.authors;\n    authors.push(...authorsToBeAdded);\n    return authors;\n  },\n};\n\nconst client = createClient({\n  url: 'http://localhost:3000/graphql',\n  exchanges: [\n    cache,\n    // cacheExchange({}),\n    executeExchange({ schema, rootValue }),\n  ],\n});\n\nexport default client;\n"
  },
  {
    "path": "exchanges/graphcache/cypress/fixtures/example.json",
    "content": "{\n  \"name\": \"Using fixtures to represent data\",\n  \"email\": \"hello@cypress.io\",\n  \"body\": \"Fixtures are a great way to mock data for responses to routes\"\n}\n"
  },
  {
    "path": "exchanges/graphcache/cypress/plugins/index.js",
    "content": "// eslint-disable-next-line\nconst { startDevServer } = require('@cypress/vite-dev-server');\n// eslint-disable-next-line\nconst path = require('path');\n\n/**\n * @type {Cypress.PluginConfig}\n */\nmodule.exports = (on, _config) => {\n  on('dev-server:start', options =>\n    startDevServer({\n      options,\n    })\n  );\n};\n"
  },
  {
    "path": "exchanges/graphcache/cypress/support/component-index.html",
    "content": "<!doctype html>\n<html>\n  <head>\n    <meta charset=\"utf-8\" />\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\" />\n    <meta name=\"viewport\" content=\"width=device-width,initial-scale=1.0\" />\n    <title>Components App</title>\n  </head>\n  <body>\n    <div data-cy-root></div>\n  </body>\n</html>\n"
  },
  {
    "path": "exchanges/graphcache/cypress/support/component.js",
    "content": "// ***********************************************************\n// This example support/component.js is processed and\n// loaded automatically before your test files.\n//\n// This is a great place to put global configuration and\n// behavior that modifies Cypress.\n//\n// You can change the location of this file or turn off\n// automatically serving support files with the\n// 'supportFile' configuration option.\n//\n// You can read more here:\n// https://on.cypress.io/configuration\n// ***********************************************************\n\nimport { mount } from 'cypress/react';\n\nCypress.Commands.add('mount', mount);\n\n// Example use:\n// cy.mount(<MyComponent />)\n"
  },
  {
    "path": "exchanges/graphcache/cypress.config.js",
    "content": "// eslint-disable-next-line\nconst { defineConfig } = require('cypress');\n// eslint-disable-next-line\nconst tsconfigPaths = require('vite-tsconfig-paths').default;\n\nmodule.exports = defineConfig({\n  video: false,\n\n  e2e: {\n    setupNodeEvents(_on, _config) {\n      /*noop*/\n    },\n    supportFile: false,\n  },\n  component: {\n    specPattern: './**/e2e-tests/*spec.tsx',\n    devServer: {\n      framework: 'react',\n      bundler: 'vite',\n      viteConfig: {\n        plugins: [tsconfigPaths()],\n        server: {\n          fs: {\n            allow: ['../..'],\n          },\n        },\n      },\n    },\n  },\n});\n"
  },
  {
    "path": "exchanges/graphcache/e2e-tests/query.spec.tsx",
    "content": "/// <reference types=\"cypress\" />\n\nimport * as React from 'react';\nimport { mount } from '@cypress/react';\nimport { Provider, createClient, useQuery, debugExchange } from 'urql';\nimport { executeExchange } from '@urql/exchange-execute';\nimport { buildSchema, introspectionFromSchema } from 'graphql';\n\nimport { cacheExchange } from '../src';\n\nconst schema = buildSchema(`\n  type Query {\n    movie: Movie\n  }\n\n  type Movie {\n    id: String\n    title: String\n    metadata: Metadata\n  }\n\n  type Metadata {\n    uri: String\n  }\n`);\n\nconst rootValue = {\n  movie: async () => {\n    await new Promise(resolve => setTimeout(resolve, 50));\n    return {\n      id: 'foo',\n      title: 'title',\n      metadata: () => {\n        throw new Error('Test');\n      },\n    };\n  },\n};\n\ndescribe('Graphcache Queries', () => {\n  it('should not loop with no schema present', () => {\n    const client = createClient({\n      url: 'https://trygql.formidable.dev/graphql/basic-pokedex',\n      exchanges: [\n        cacheExchange({}),\n        debugExchange,\n        executeExchange({ schema, rootValue }),\n      ],\n    });\n\n    const FirstComponent = () => {\n      const [{ fetching, error }] = useQuery({\n        query: `{\n          movie {\n            id\n            title\n            metadata {\n              uri\n            }\n          }\n        }`,\n      });\n\n      return (\n        <div>\n          {fetching === true ? (\n            'loading'\n          ) : (\n            <div>\n              <div>First Component</div>\n              <div id=\"first-error\">{`Error: ${error?.message}`}</div>\n            </div>\n          )}\n        </div>\n      );\n    };\n\n    const SecondComponent = () => {\n      const [{ error, fetching }] = useQuery({\n        query: `{\n          movie {\n            id\n            metadata {\n              uri\n            }\n          }\n        }`,\n      });\n\n      if (fetching) {\n        return <div>Loading...</div>;\n      }\n\n      return (\n        <div>\n          <div>Second Component</div>\n          <div id=\"second-error\">{`Error: ${error?.message}`}</div>\n        </div>\n      );\n    };\n\n    mount(\n      <Provider value={client}>\n        <FirstComponent />\n        <SecondComponent />\n      </Provider>\n    );\n\n    cy.get('#first-error').should('have.text', 'Error: [GraphQL] Test');\n    cy.get('#second-error').should('have.text', 'Error: [GraphQL] Test');\n  });\n\n  it('should not loop with schema present', () => {\n    const client = createClient({\n      url: 'https://trygql.formidable.dev/graphql/basic-pokedex',\n      exchanges: [\n        cacheExchange({ schema: introspectionFromSchema(schema) }),\n        debugExchange,\n        executeExchange({ schema, rootValue }),\n      ],\n    });\n\n    const FirstComponent = () => {\n      const [{ fetching, data, error, stale }] = useQuery({\n        query: `{\n          movie {\n            id\n            title\n            metadata {\n              uri\n            }\n          }\n        }`,\n      });\n\n      return (\n        <div>\n          {fetching === true ? (\n            'loading'\n          ) : (\n            <div>\n              <div>First Component</div>\n              <div id=\"first-data\">{`Data: ${data.movie?.title}`}</div>\n              <div id=\"first-error\">{`Error: ${error?.message}`}</div>\n              <div id=\"first-stale\">{`Stale: ${!!stale}`}</div>\n            </div>\n          )}\n        </div>\n      );\n    };\n\n    const SecondComponent = () => {\n      const [{ error, data, fetching, stale }] = useQuery({\n        query: `{\n          movie {\n            id\n            metadata {\n              uri\n            }\n          }\n        }`,\n      });\n\n      if (fetching) {\n        return <div>Loading...</div>;\n      }\n\n      return (\n        <div>\n          <div>Second Component</div>\n          <div id=\"second-data\">{`Data: ${data.movie.id}`}</div>\n          <div id=\"second-error\">{`Error: ${error?.message}`}</div>\n          <div id=\"second-stale\">{`Stale: ${!!stale}`}</div>\n        </div>\n      );\n    };\n\n    mount(\n      <Provider value={client}>\n        <FirstComponent />\n        <SecondComponent />\n      </Provider>\n    );\n\n    cy.get('#first-data').should('have.text', 'Data: title');\n    cy.get('#second-data').should('have.text', 'Data: foo');\n    cy.get('#second-stale').should('have.text', 'Stale: false');\n    // TODO: ideally we would be able to keep the error here but...\n    // cy.get('#first-error').should('have.text', 'Error: [GraphQL] Test');\n    // cy.get('#second-error').should('have.text', 'Error: [GraphQL] Test');\n  });\n});\n"
  },
  {
    "path": "exchanges/graphcache/e2e-tests/updates.spec.tsx",
    "content": "import * as React from 'react';\nimport { executeExchange } from '@urql/exchange-execute';\nimport { buildSchema } from 'graphql';\nimport { mount } from '@cypress/react';\n\nimport {\n  Provider,\n  createClient,\n  gql,\n  useQuery,\n  useMutation,\n  debugExchange,\n} from 'urql';\n\nimport { cacheExchange } from '../src';\n\nconst schema = buildSchema(`\n  type Todo {\n    id: ID!\n    text: String!\n  }\n\n  type Query {\n    todos: [Todo]!\n  }\n\n  type Mutation {\n    updateTodo(id: ID! text: String!): Todo!\n  }\n`);\n\nconst todos: Array<{ id: string; text: string }> = [\n  { id: '1', text: 'testing urql' },\n];\n\nconst rootValue = {\n  todos: () => {\n    return todos;\n  },\n  updateTodo: args => {\n    const todo = todos.find(x => x.id === args.id);\n    if (!todo) throw new Error(\"Can't find todo!\");\n    todo.text = args.text;\n    return todo;\n  },\n};\n\ndescribe('Graphcache updates', () => {\n  let client;\n  beforeEach(() => {\n    client = createClient({\n      url: 'https://trygql.formidable.dev/graphql/basic-pokedex',\n      exchanges: [\n        cacheExchange({}),\n        debugExchange,\n        executeExchange({ schema, rootValue }),\n      ],\n    });\n  });\n\n  const TodosQuery = gql`\n    query {\n      todos {\n        id\n        text\n      }\n    }\n  `;\n\n  const UpdateMutation = gql`\n    mutation ($id: ID!, $text: String!) {\n      updateTodo(id: $id, text: $text) {\n        id\n        text\n      }\n    }\n  `;\n\n  it('Can automatically update entities who have been queried', () => {\n    const Todos = () => {\n      const [result] = useQuery({ query: TodosQuery });\n      const [, update] = useMutation(UpdateMutation);\n\n      if (result.fetching) return <p>Loading...</p>;\n\n      return (\n        <main>\n          <ul id=\"todos-list\">\n            {result.data.todos.map(todo => (\n              <li key={todo.id}>\n                {todo.text}\n                <button\n                  id={`update-${todo.id}`}\n                  onClick={() => {\n                    update({ id: todo.id, text: todo.text + '_foo' });\n                  }}\n                >\n                  Update {todo.id}\n                </button>\n              </li>\n            ))}\n          </ul>\n        </main>\n      );\n    };\n\n    mount(\n      <Provider value={client}>\n        <Todos />\n      </Provider>\n    );\n\n    const target = { ...todos[0] };\n    cy.get('#todos-list > li').then(items => {\n      expect(items.length).to.equal(todos.length);\n    });\n    cy.get('#update-' + target.id).click();\n\n    cy.wait(500);\n    cy.get('#todos-list > li').then(items => {\n      expect(items.length).to.equal(todos.length);\n      expect(items[0].innerText).to.contain(target.text + '_foo');\n    });\n  });\n});\n"
  },
  {
    "path": "exchanges/graphcache/help.md",
    "content": "This file (`exchanges/graphcache/help.md`) has been moved to `docs/graphcache/errors.md`\n\nIf you are looking at this in a browser\n\n- ...and your URL looks like this: `github.com/urql-graphql/urql/blob/main/exchanges/graphcache/help.md#15`\n- ...in the URL, replace `exchanges/graphcache/help.md` with `docs/graphcache/errors.md`\n- ...and keep the `#15`\n- ...and then you will get help with your error!\n"
  },
  {
    "path": "exchanges/graphcache/jsr.json",
    "content": "{\n  \"name\": \"@urql/exchange-graphcache\",\n  \"version\": \"9.0.0\",\n  \"exports\": {\n    \".\": \"./src/index.ts\",\n    \"./extras\": \"./src/extras/index.ts\",\n    \"./default-storage\": \"./src/default-storage/index.ts\"\n  },\n  \"exclude\": [\n    \"node_modules\",\n    \"cypress\",\n    \"**/*.test.*\",\n    \"**/*.spec.*\",\n    \"**/*.test.*.snap\",\n    \"**/*.spec.*.snap\"\n  ]\n}"
  },
  {
    "path": "exchanges/graphcache/package.json",
    "content": "{\n  \"name\": \"@urql/exchange-graphcache\",\n  \"version\": \"9.0.0\",\n  \"description\": \"A normalized and configurable cache exchange for urql\",\n  \"sideEffects\": false,\n  \"homepage\": \"https://formidable.com/open-source/urql/docs/graphcache\",\n  \"bugs\": \"https://github.com/urql-graphql/urql/issues\",\n  \"license\": \"MIT\",\n  \"author\": \"urql GraphQL Contributors\",\n  \"repository\": {\n    \"type\": \"git\",\n    \"url\": \"https://github.com/urql-graphql/urql.git\",\n    \"directory\": \"exchanges/graphcache\"\n  },\n  \"keywords\": [\n    \"urql\",\n    \"state management\",\n    \"normalized cache\",\n    \"cache\",\n    \"formidablelabs\",\n    \"exchanges\"\n  ],\n  \"main\": \"dist/urql-exchange-graphcache\",\n  \"module\": \"dist/urql-exchange-graphcache.mjs\",\n  \"types\": \"dist/urql-exchange-graphcache.d.ts\",\n  \"source\": \"src/index.ts\",\n  \"exports\": {\n    \".\": {\n      \"types\": \"./dist/urql-exchange-graphcache.d.ts\",\n      \"import\": \"./dist/urql-exchange-graphcache.mjs\",\n      \"require\": \"./dist/urql-exchange-graphcache.js\",\n      \"source\": \"./src/index.ts\"\n    },\n    \"./package.json\": \"./package.json\",\n    \"./extras\": {\n      \"types\": \"./dist/urql-exchange-graphcache-extras.d.ts\",\n      \"import\": \"./dist/urql-exchange-graphcache-extras.mjs\",\n      \"require\": \"./dist/urql-exchange-graphcache-extras.js\",\n      \"source\": \"./src/extras/index.ts\"\n    },\n    \"./default-storage\": {\n      \"types\": \"./dist/urql-exchange-graphcache-default-storage.d.ts\",\n      \"import\": \"./dist/urql-exchange-graphcache-default-storage.mjs\",\n      \"require\": \"./dist/urql-exchange-graphcache-default-storage.js\",\n      \"source\": \"./src/default-storage/index.ts\"\n    }\n  },\n  \"files\": [\n    \"LICENSE\",\n    \"CHANGELOG.md\",\n    \"README.md\",\n    \"dist/\",\n    \"extras/\",\n    \"default-storage/\"\n  ],\n  \"scripts\": {\n    \"test\": \"vitest\",\n    \"clean\": \"rimraf dist extras\",\n    \"check\": \"tsc --noEmit\",\n    \"lint\": \"eslint --ext=js,jsx,ts,tsx .\",\n    \"build\": \"rollup -c ../../scripts/rollup/config.mjs\",\n    \"prepare\": \"node ../../scripts/prepare/index.js\",\n    \"prepublishOnly\": \"run-s clean build\"\n  },\n  \"peerDependencies\": {\n    \"@urql/core\": \"^6.0.0\"\n  },\n  \"dependencies\": {\n    \"@0no-co/graphql.web\": \"^1.0.13\",\n    \"@urql/core\": \"workspace:^6.0.1\",\n    \"wonka\": \"^6.3.2\"\n  },\n  \"devDependencies\": {\n    \"@cypress/react\": \"^8.0.2\",\n    \"@urql/core\": \"workspace:*\",\n    \"@urql/exchange-execute\": \"workspace:*\",\n    \"@urql/introspection\": \"workspace:*\",\n    \"cypress\": \"^13.14.0\",\n    \"graphql\": \"^16.6.0\",\n    \"react\": \"^17.0.1\",\n    \"react-dom\": \"^17.0.1\",\n    \"urql\": \"workspace:*\"\n  },\n  \"publishConfig\": {\n    \"access\": \"public\",\n    \"provenance\": true\n  }\n}\n"
  },
  {
    "path": "exchanges/graphcache/src/ast/graphql.ts",
    "content": "import type * as GraphQL from 'graphql';\n\ntype OrNever<T> = void extends T ? never : T;\n\nexport type IntrospectionQuery =\n  | {\n      readonly __schema: {\n        queryType: { name: string; kind?: any };\n        mutationType?: { name: string; kind?: any } | null;\n        subscriptionType?: { name: string; kind?: any } | null;\n        types?: readonly IntrospectionType[];\n      };\n    }\n  | OrNever<GraphQL.IntrospectionQuery>;\n\nexport type IntrospectionTypeRef =\n  | {\n      readonly kind:\n        | 'SCALAR'\n        | 'OBJECT'\n        | 'INTERFACE'\n        | 'ENUM'\n        | 'UNION'\n        | 'INPUT_OBJECT';\n      readonly name?: string;\n      readonly ofType?: IntrospectionTypeRef;\n    }\n  | OrNever<GraphQL.IntrospectionTypeRef>;\n\nexport type IntrospectionInputTypeRef =\n  | {\n      readonly kind: 'SCALAR' | 'ENUM' | 'INPUT_OBJECT';\n      readonly name?: string;\n      readonly ofType?: IntrospectionInputTypeRef;\n    }\n  | OrNever<GraphQL.IntrospectionInputTypeRef>;\n\nexport type IntrospectionInputValue =\n  | {\n      readonly name: string;\n      readonly description?: string | null;\n      readonly defaultValue?: string | null;\n      readonly type: IntrospectionInputTypeRef;\n    }\n  | OrNever<GraphQL.IntrospectionInputValue>;\n\nexport type IntrospectionType =\n  | {\n      readonly kind: string;\n      readonly name: string;\n      readonly fields?: readonly any[];\n      readonly interfaces?: readonly any[];\n      readonly possibleTypes?: readonly any[];\n    }\n  | OrNever<GraphQL.IntrospectionType>;\n"
  },
  {
    "path": "exchanges/graphcache/src/ast/index.ts",
    "content": "export * from './variables';\nexport * from './traversal';\nexport * from './schema';\nexport * from './schemaPredicates';\nexport * from './node';\n"
  },
  {
    "path": "exchanges/graphcache/src/ast/node.ts",
    "content": "import type {\n  NamedTypeNode,\n  NameNode,\n  DirectiveNode,\n  SelectionNode,\n  SelectionSetNode,\n  FieldNode,\n  FragmentDefinitionNode,\n} from '@0no-co/graphql.web';\n\nimport type { FormattedNode } from '@urql/core';\n\nexport type SelectionSet = readonly FormattedNode<SelectionNode>[];\n\nconst EMPTY_DIRECTIVES: Record<string, DirectiveNode | undefined> = {};\n\n/** Returns the directives dictionary of a given node */\nexport const getDirectives = (node: {\n  _directives?: Record<string, DirectiveNode | undefined>;\n}) => node._directives || EMPTY_DIRECTIVES;\n\n/** Returns the name of a given node */\nexport const getName = (node: { name: NameNode }): string => node.name.value;\n\nexport const getFragmentTypeName = (node: FragmentDefinitionNode): string =>\n  node.typeCondition.name.value;\n\n/** Returns either the field's name or the field's alias */\nexport const getFieldAlias = (node: FieldNode): string =>\n  node.alias ? node.alias.value : node.name.value;\n\nconst emptySelectionSet: SelectionSet = [];\n\n/** Returns the SelectionSet for a given inline or defined fragment node */\nexport const getSelectionSet = (node: {\n  selectionSet?: FormattedNode<SelectionSetNode>;\n}): FormattedNode<SelectionSet> =>\n  (node.selectionSet\n    ? node.selectionSet.selections\n    : emptySelectionSet) as FormattedNode<SelectionSet>;\n\nexport const getTypeCondition = (node: {\n  typeCondition?: NamedTypeNode;\n}): string | null =>\n  node.typeCondition ? node.typeCondition.name.value : null;\n"
  },
  {
    "path": "exchanges/graphcache/src/ast/schema.ts",
    "content": "import type {\n  IntrospectionQuery,\n  IntrospectionTypeRef,\n  IntrospectionInputValue,\n  IntrospectionType,\n} from './graphql';\n\nexport interface SchemaField {\n  name: string;\n  type: IntrospectionTypeRef;\n  args(): Record<string, IntrospectionInputValue | void>;\n}\n\nexport interface SchemaObject {\n  name: string;\n  kind: 'INTERFACE' | 'OBJECT';\n  interfaces(): Record<string, unknown>;\n  fields(): Record<string, SchemaField | void>;\n}\n\nexport interface SchemaUnion {\n  name: string;\n  kind: 'UNION';\n  types(): Record<string, unknown>;\n}\n\nexport interface SchemaIntrospector {\n  query: string | null;\n  mutation: string | null;\n  subscription: string | null;\n  types?: Map<string, SchemaObject | SchemaUnion>;\n  isSubType(abstract: string, possible: string): boolean;\n}\n\nexport interface PartialIntrospectionSchema {\n  queryType: { name: string; kind?: any };\n  mutationType?: { name: string; kind?: any } | null;\n  subscriptionType?: { name: string; kind?: any } | null;\n  types?: readonly any[];\n}\n\nexport type IntrospectionData =\n  | IntrospectionQuery\n  | { __schema: PartialIntrospectionSchema };\n\nexport const buildClientSchema = ({\n  __schema,\n}: IntrospectionData): SchemaIntrospector => {\n  const typemap: Map<string, SchemaObject | SchemaUnion> = new Map();\n\n  const buildNameMap = <T extends { name: string }>(\n    arr: ReadonlyArray<T>\n  ): (() => { [name: string]: T }) => {\n    let map: Record<string, T> | void;\n    return () => {\n      if (!map) {\n        map = {};\n        for (let i = 0; i < arr.length; i++) map[arr[i].name] = arr[i];\n      }\n      return map;\n    };\n  };\n\n  const buildType = (\n    type: IntrospectionType\n  ): SchemaObject | SchemaUnion | void => {\n    switch (type.kind) {\n      case 'OBJECT':\n      case 'INTERFACE':\n        return {\n          name: type.name,\n          kind: type.kind as 'OBJECT' | 'INTERFACE',\n          interfaces: buildNameMap(type.interfaces || []),\n          fields: buildNameMap(\n            type.fields!.map((field: any) => ({\n              name: field.name,\n              type: field.type,\n              args: buildNameMap(field.args),\n            }))\n          ),\n        } as SchemaObject;\n      case 'UNION':\n        return {\n          name: type.name,\n          kind: type.kind as 'UNION',\n          types: buildNameMap(type.possibleTypes || []),\n        } as SchemaUnion;\n    }\n  };\n\n  const schema: SchemaIntrospector = {\n    query: __schema.queryType ? __schema.queryType.name : null,\n    mutation: __schema.mutationType ? __schema.mutationType.name : null,\n    subscription: __schema.subscriptionType\n      ? __schema.subscriptionType.name\n      : null,\n    types: undefined,\n    isSubType(abstract: string, possible: string) {\n      const abstractType = typemap.get(abstract);\n      const possibleType = typemap.get(possible);\n      if (!abstractType || !possibleType) {\n        return false;\n      } else if (abstractType.kind === 'UNION') {\n        return !!abstractType.types()[possible];\n      } else if (\n        abstractType.kind !== 'OBJECT' &&\n        possibleType.kind === 'OBJECT'\n      ) {\n        return !!possibleType.interfaces()[abstract];\n      } else {\n        return abstract === possible;\n      }\n    },\n  };\n\n  if (__schema.types) {\n    schema.types = typemap;\n    for (let i = 0; i < __schema.types.length; i++) {\n      const type = __schema.types[i];\n      if (type && type.name) {\n        const out = buildType(type);\n        if (out) typemap.set(type.name, out);\n      }\n    }\n  }\n\n  return schema;\n};\n"
  },
  {
    "path": "exchanges/graphcache/src/ast/schemaPredicates.test.ts",
    "content": "import { Kind, InlineFragmentNode } from 'graphql';\nimport { describe, it, expect } from 'vitest';\n\nimport { buildClientSchema } from './schema';\nimport * as SchemaPredicates from './schemaPredicates';\nimport { minifyIntrospectionQuery } from '@urql/introspection';\n\nconst mocked = (x: any): any => x;\n\ndescribe('SchemaPredicates', () => {\n  const schema = buildClientSchema(\n    // eslint-disable-next-line\n    minifyIntrospectionQuery(require('../test-utils/simple_schema.json'))\n  );\n\n  const frag = (value: string): InlineFragmentNode => ({\n    kind: Kind.INLINE_FRAGMENT,\n    typeCondition: {\n      kind: Kind.NAMED_TYPE,\n      name: {\n        kind: Kind.NAME,\n        value,\n      },\n    },\n    selectionSet: {\n      kind: Kind.SELECTION_SET,\n      selections: [],\n    },\n  });\n\n  it('should match fragments by interface/union', () => {\n    expect(\n      SchemaPredicates.isInterfaceOfType(schema, frag('ITodo'), 'BigTodo')\n    ).toBeTruthy();\n    expect(\n      SchemaPredicates.isInterfaceOfType(schema, frag('ITodo'), 'SmallTodo')\n    ).toBeTruthy();\n    expect(\n      SchemaPredicates.isInterfaceOfType(schema, frag('Search'), 'BigTodo')\n    ).toBeTruthy();\n    expect(\n      SchemaPredicates.isInterfaceOfType(schema, frag('Search'), 'SmallTodo')\n    ).toBeTruthy();\n    expect(\n      SchemaPredicates.isInterfaceOfType(schema, frag('ITodo'), 'Todo')\n    ).toBeFalsy();\n    expect(\n      SchemaPredicates.isInterfaceOfType(schema, frag('Search'), 'Todo')\n    ).toBeFalsy();\n\n    const typeConditionLess = frag('Type');\n    (typeConditionLess as any).typeCondition = undefined;\n    expect(\n      SchemaPredicates.isInterfaceOfType(schema, typeConditionLess, 'Todo')\n    ).toBeTruthy();\n  });\n\n  it('should indicate nullability', () => {\n    expect(\n      SchemaPredicates.isFieldNullable(schema, 'Todo', 'text', undefined)\n    ).toBeFalsy();\n    expect(\n      SchemaPredicates.isFieldNullable(schema, 'Todo', 'complete', undefined)\n    ).toBeTruthy();\n    expect(\n      SchemaPredicates.isFieldNullable(schema, 'Todo', 'author', undefined)\n    ).toBeTruthy();\n  });\n\n  it('should handle unions of objects', () => {\n    expect(\n      SchemaPredicates.isInterfaceOfType(\n        schema,\n        frag('LatestTodoResult'),\n        'Todo'\n      )\n    ).toBeTruthy();\n    expect(\n      SchemaPredicates.isInterfaceOfType(\n        schema,\n        frag('LatestTodoResult'),\n        'NoTodosError'\n      )\n    ).toBeTruthy();\n    expect(\n      SchemaPredicates.isInterfaceOfType(schema, frag('Todo'), 'NoTodosError')\n    ).toBeFalsy();\n  });\n\n  it('should throw if a requested type does not exist', () => {\n    expect(() =>\n      SchemaPredicates.isFieldNullable(\n        schema,\n        'SomeInvalidType',\n        'complete',\n        undefined\n      )\n    ).toThrow(\n      'The type `SomeInvalidType` is not an object in the defined schema, but the GraphQL document is traversing it.\\nhttps://bit.ly/2XbVrpR#3'\n    );\n  });\n\n  it('should warn in console if a requested field does not exist', () => {\n    expect(\n      SchemaPredicates.isFieldNullable(schema, 'Todo', 'goof', undefined)\n    ).toBeFalsy();\n\n    expect(console.warn).toBeCalledTimes(1);\n    const warnMessage = mocked(console.warn).mock.calls[0][0];\n    expect(warnMessage).toContain('The field `goof` does not exist on `Todo`');\n    expect(warnMessage).toContain('https://bit.ly/2XbVrpR#4');\n  });\n});\n"
  },
  {
    "path": "exchanges/graphcache/src/ast/schemaPredicates.ts",
    "content": "import type {\n  InlineFragmentNode,\n  FragmentDefinitionNode,\n} from '@0no-co/graphql.web';\n\nimport { warn, invariant } from '../helpers/help';\nimport { getTypeCondition } from './node';\nimport type { SchemaIntrospector, SchemaObject } from './schema';\n\nimport type {\n  KeyingConfig,\n  UpdatesConfig,\n  ResolverConfig,\n  OptimisticMutationConfig,\n  Logger,\n} from '../types';\n\nconst BUILTIN_NAME = '__';\n\nexport const isFieldNullable = (\n  schema: SchemaIntrospector,\n  typename: string,\n  fieldName: string,\n  logger: Logger | undefined\n): boolean => {\n  const field = getField(schema, typename, fieldName, logger);\n  return !!field && field.type.kind !== 'NON_NULL';\n};\n\nexport const isListNullable = (\n  schema: SchemaIntrospector,\n  typename: string,\n  fieldName: string,\n  logger: Logger | undefined\n): boolean => {\n  const field = getField(schema, typename, fieldName, logger);\n  if (!field) return false;\n  const ofType =\n    field.type.kind === 'NON_NULL' ? field.type.ofType : field.type;\n  return ofType.kind === 'LIST' && ofType.ofType.kind !== 'NON_NULL';\n};\n\nexport const isFieldAvailableOnType = (\n  schema: SchemaIntrospector,\n  typename: string,\n  fieldName: string,\n  logger: Logger | undefined\n): boolean =>\n  fieldName.indexOf(BUILTIN_NAME) === 0 ||\n  typename.indexOf(BUILTIN_NAME) === 0 ||\n  !!getField(schema, typename, fieldName, logger);\n\nexport const isInterfaceOfType = (\n  schema: SchemaIntrospector,\n  node: InlineFragmentNode | FragmentDefinitionNode,\n  typename: string | void\n): boolean => {\n  if (!typename) return false;\n  const typeCondition = getTypeCondition(node);\n  if (!typeCondition || typename === typeCondition) {\n    return true;\n  } else if (\n    schema.types!.has(typeCondition) &&\n    schema.types!.get(typeCondition)!.kind === 'OBJECT'\n  ) {\n    return typeCondition === typename;\n  }\n\n  expectAbstractType(schema, typeCondition!);\n  expectObjectType(schema, typename!);\n  return schema.isSubType(typeCondition, typename);\n};\n\nconst getField = (\n  schema: SchemaIntrospector,\n  typename: string,\n  fieldName: string,\n  logger: Logger | undefined\n) => {\n  if (\n    fieldName.indexOf(BUILTIN_NAME) === 0 ||\n    typename.indexOf(BUILTIN_NAME) === 0\n  )\n    return;\n\n  expectObjectType(schema, typename);\n  const object = schema.types!.get(typename) as SchemaObject;\n  const field = object.fields()[fieldName];\n  if (!field) {\n    warn(\n      'Invalid field: The field `' +\n        fieldName +\n        '` does not exist on `' +\n        typename +\n        '`, ' +\n        'but the GraphQL document expects it to exist.\\n' +\n        'Traversal will continue, however this may lead to undefined behavior!',\n      4,\n      logger\n    );\n  }\n\n  return field;\n};\n\nfunction expectObjectType(schema: SchemaIntrospector, typename: string) {\n  invariant(\n    schema.types!.has(typename) &&\n      schema.types!.get(typename)!.kind === 'OBJECT',\n    'Invalid Object type: The type `' +\n      typename +\n      '` is not an object in the defined schema, ' +\n      'but the GraphQL document is traversing it.',\n    3\n  );\n}\n\nfunction expectAbstractType(schema: SchemaIntrospector, typename: string) {\n  invariant(\n    schema.types!.has(typename) &&\n      (schema.types!.get(typename)!.kind === 'INTERFACE' ||\n        schema.types!.get(typename)!.kind === 'UNION'),\n    'Invalid Abstract type: The type `' +\n      typename +\n      '` is not an Interface or Union type in the defined schema, ' +\n      'but a fragment in the GraphQL document is using it as a type condition.',\n    5\n  );\n}\n\nexport function expectValidKeyingConfig(\n  schema: SchemaIntrospector,\n  keys: KeyingConfig,\n  logger: Logger | undefined\n): void {\n  if (process.env.NODE_ENV !== 'production') {\n    for (const key in keys) {\n      if (!schema.types!.has(key)) {\n        warn(\n          'Invalid Object type: The type `' +\n            key +\n            '` is not an object in the defined schema, but the `keys` option is referencing it.',\n          20,\n          logger\n        );\n      }\n    }\n  }\n}\n\nexport function expectValidUpdatesConfig(\n  schema: SchemaIntrospector,\n  updates: UpdatesConfig,\n  logger: Logger | undefined\n): void {\n  if (process.env.NODE_ENV === 'production') {\n    return;\n  }\n\n  for (const typename in updates) {\n    if (!updates[typename]) {\n      continue;\n    } else if (!schema.types!.has(typename)) {\n      let addition = '';\n\n      if (\n        typename === 'Mutation' &&\n        schema.mutation &&\n        schema.mutation !== 'Mutation'\n      ) {\n        addition +=\n          '\\nMaybe your config should reference `' + schema.mutation + '`?';\n      } else if (\n        typename === 'Subscription' &&\n        schema.subscription &&\n        schema.subscription !== 'Subscription'\n      ) {\n        addition +=\n          '\\nMaybe your config should reference `' + schema.subscription + '`?';\n      }\n\n      return warn(\n        'Invalid updates type: The type `' +\n          typename +\n          '` is not an object in the defined schema, but the `updates` config is referencing it.' +\n          addition,\n        21,\n        logger\n      );\n    }\n\n    const fields = (schema.types!.get(typename)! as SchemaObject).fields();\n    for (const fieldName in updates[typename]!) {\n      if (!fields[fieldName]) {\n        warn(\n          'Invalid updates field: `' +\n            fieldName +\n            '` on `' +\n            typename +\n            '` is not in the defined schema, but the `updates` config is referencing it.',\n          22,\n          logger\n        );\n      }\n    }\n  }\n}\n\nfunction warnAboutResolver(name: string, logger: Logger | undefined): void {\n  warn(\n    `Invalid resolver: \\`${name}\\` is not in the defined schema, but the \\`resolvers\\` option is referencing it.`,\n    23,\n    logger\n  );\n}\n\nfunction warnAboutAbstractResolver(\n  name: string,\n  kind: 'UNION' | 'INTERFACE',\n  logger: Logger | undefined\n): void {\n  warn(\n    `Invalid resolver: \\`${name}\\` does not match to a concrete type in the schema, but the \\`resolvers\\` option is referencing it. Implement the resolver for the types that ${\n      kind === 'UNION' ? 'make up the union' : 'implement the interface'\n    } instead.`,\n    26,\n    logger\n  );\n}\n\nexport function expectValidResolversConfig(\n  schema: SchemaIntrospector,\n  resolvers: ResolverConfig,\n  logger: Logger | undefined\n): void {\n  if (process.env.NODE_ENV === 'production') {\n    return;\n  }\n\n  for (const key in resolvers) {\n    if (key === 'Query') {\n      if (schema.query) {\n        const validQueries = (\n          schema.types!.get(schema.query) as SchemaObject\n        ).fields();\n        for (const resolverQuery in resolvers.Query || {}) {\n          if (!validQueries[resolverQuery]) {\n            warnAboutResolver('Query.' + resolverQuery, logger);\n          }\n        }\n      } else {\n        warnAboutResolver('Query', logger);\n      }\n    } else {\n      if (!schema.types!.has(key)) {\n        warnAboutResolver(key, logger);\n      } else if (\n        schema.types!.get(key)!.kind === 'INTERFACE' ||\n        schema.types!.get(key)!.kind === 'UNION'\n      ) {\n        warnAboutAbstractResolver(\n          key,\n          schema.types!.get(key)!.kind as 'INTERFACE' | 'UNION',\n          logger\n        );\n      } else {\n        const validTypeProperties = (\n          schema.types!.get(key) as SchemaObject\n        ).fields();\n        for (const resolverProperty in resolvers[key] || {}) {\n          if (!validTypeProperties[resolverProperty]) {\n            warnAboutResolver(key + '.' + resolverProperty, logger);\n          }\n        }\n      }\n    }\n  }\n}\n\nexport function expectValidOptimisticMutationsConfig(\n  schema: SchemaIntrospector,\n  optimisticMutations: OptimisticMutationConfig,\n  logger: Logger | undefined\n): void {\n  if (process.env.NODE_ENV === 'production') {\n    return;\n  }\n\n  if (schema.mutation) {\n    const validMutations = (\n      schema.types!.get(schema.mutation) as SchemaObject\n    ).fields();\n    for (const mutation in optimisticMutations) {\n      if (!validMutations[mutation]) {\n        warn(\n          `Invalid optimistic mutation field: \\`${mutation}\\` is not a mutation field in the defined schema, but the \\`optimistic\\` option is referencing it.`,\n          24,\n          logger\n        );\n      }\n    }\n  }\n}\n"
  },
  {
    "path": "exchanges/graphcache/src/ast/traversal.test.ts",
    "content": "import { formatDocument, gql } from '@urql/core';\nimport { describe, it, expect } from 'vitest';\n\nimport { getSelectionSet } from './node';\nimport { getMainOperation, shouldInclude } from './traversal';\n\ndescribe('getMainOperation', () => {\n  it('retrieves the first operation', () => {\n    const doc = formatDocument(gql`\n      query Query {\n        field\n      }\n    `);\n\n    const operation = getMainOperation(doc);\n    expect(operation).toBe(doc.definitions[0]);\n  });\n\n  it('throws when no operation is found', () => {\n    const doc = formatDocument(gql`\n      fragment _ on Query {\n        field\n      }\n    `);\n\n    expect(() => getMainOperation(doc)).toThrow();\n  });\n});\n\ndescribe('shouldInclude', () => {\n  it('should include fields with truthy @include or falsy @skip directives', () => {\n    const doc = formatDocument(gql`\n      {\n        fieldA @include(if: true)\n        fieldB @skip(if: false)\n      }\n    `);\n\n    const fieldA = getSelectionSet(getMainOperation(doc))[0];\n    const fieldB = getSelectionSet(getMainOperation(doc))[1];\n    expect(shouldInclude(fieldA, {})).toBe(true);\n    expect(shouldInclude(fieldB, {})).toBe(true);\n  });\n\n  it('should exclude fields with falsy @include or truthy @skip directives', () => {\n    const doc = formatDocument(gql`\n      {\n        fieldA @include(if: false)\n        fieldB @skip(if: true)\n      }\n    `);\n\n    const fieldA = getSelectionSet(getMainOperation(doc))[0];\n    const fieldB = getSelectionSet(getMainOperation(doc))[1];\n    expect(shouldInclude(fieldA, {})).toBe(false);\n    expect(shouldInclude(fieldB, {})).toBe(false);\n  });\n\n  it('ignore other directives', () => {\n    const doc = formatDocument(gql`\n      {\n        field @test(if: false)\n      }\n    `);\n\n    const field = getSelectionSet(getMainOperation(doc))[0];\n    expect(shouldInclude(field, {})).toBe(true);\n  });\n\n  it('ignore unknown arguments on directives', () => {\n    const doc = formatDocument(gql`\n      {\n        field @skip(if: true, other: false)\n      }\n    `);\n\n    const field = getSelectionSet(getMainOperation(doc))[0];\n    expect(shouldInclude(field, {})).toBe(false);\n  });\n\n  it('ignore directives with invalid first arguments', () => {\n    const doc = formatDocument(gql`\n      {\n        field @skip(other: true)\n      }\n    `);\n\n    const field = getSelectionSet(getMainOperation(doc))[0];\n    expect(shouldInclude(field, {})).toBe(true);\n  });\n});\n"
  },
  {
    "path": "exchanges/graphcache/src/ast/traversal.ts",
    "content": "import type {\n  SelectionNode,\n  DocumentNode,\n  OperationDefinitionNode,\n  FragmentSpreadNode,\n  InlineFragmentNode,\n} from '@0no-co/graphql.web';\nimport { valueFromASTUntyped, Kind } from '@0no-co/graphql.web';\n\nimport type { FormattedNode } from '@urql/core';\nimport { getName, getDirectives } from './node';\nimport { invariant } from '../helpers/help';\nimport type { Fragments, Variables } from '../types';\n\nfunction getMainOperation(\n  doc: FormattedNode<DocumentNode>\n): FormattedNode<OperationDefinitionNode>;\nfunction getMainOperation(doc: DocumentNode): OperationDefinitionNode;\n\n/** Returns the main operation's definition */\nfunction getMainOperation(doc: DocumentNode): OperationDefinitionNode {\n  for (let i = 0; i < doc.definitions.length; i++) {\n    if (doc.definitions[i].kind === Kind.OPERATION_DEFINITION) {\n      return doc.definitions[i] as FormattedNode<OperationDefinitionNode>;\n    }\n  }\n\n  invariant(\n    false,\n    'Invalid GraphQL document: All GraphQL documents must contain an OperationDefinition' +\n      'node for a query, subscription, or mutation.',\n    1\n  );\n}\n\nexport { getMainOperation };\n\n/** Returns a mapping from fragment names to their selections */\nexport const getFragments = (doc: FormattedNode<DocumentNode>): Fragments => {\n  const fragments: Fragments = {};\n  for (let i = 0; i < doc.definitions.length; i++) {\n    const node = doc.definitions[i];\n    if (node.kind === Kind.FRAGMENT_DEFINITION) {\n      fragments[getName(node)] = node;\n    }\n  }\n\n  return fragments;\n};\n\n/** Resolves @include and @skip directives to determine whether field is included. */\nexport const shouldInclude = (\n  node: FormattedNode<SelectionNode>,\n  vars: Variables\n): boolean => {\n  const directives = getDirectives(node);\n  if (directives.include || directives.skip) {\n    // Finds any @include or @skip directive that forces the node to be skipped\n    for (const name in directives) {\n      const directive = directives[name];\n      if (\n        directive &&\n        (name === 'include' || name === 'skip') &&\n        directive.arguments &&\n        directive.arguments[0] &&\n        getName(directive.arguments[0]) === 'if'\n      ) {\n        // Return whether this directive forces us to skip\n        // `@include(if: false)` or `@skip(if: true)`\n        const value = valueFromASTUntyped(directive.arguments[0].value, vars);\n        return name === 'include' ? !!value : !value;\n      }\n    }\n  }\n  return true;\n};\n\n/** Resolves @defer directive to determine whether a fragment is potentially skipped. */\nexport const isDeferred = (\n  node: FormattedNode<FragmentSpreadNode | InlineFragmentNode>,\n  vars: Variables\n): boolean => {\n  const { defer } = getDirectives(node);\n  if (defer) {\n    for (const argument of defer.arguments || []) {\n      if (getName(argument) === 'if') {\n        // Return whether `@defer(if: )` is enabled\n        return !!valueFromASTUntyped(argument.value, vars);\n      }\n    }\n    return true;\n  }\n\n  return false;\n};\n\n/** Resolves @_optional and @_required directive to determine whether the fields in a fragment are conaidered optional. */\nexport const isOptional = (\n  node: FormattedNode<FragmentSpreadNode | InlineFragmentNode>\n): boolean | undefined => {\n  const { optional, required } = getDirectives(node);\n  if (required) {\n    return false;\n  }\n\n  if (optional) {\n    return true;\n  }\n\n  return undefined;\n};\n"
  },
  {
    "path": "exchanges/graphcache/src/ast/variables.test.ts",
    "content": "import { formatDocument, gql } from '@urql/core';\nimport { describe, it, expect } from 'vitest';\nimport { getMainOperation } from './traversal';\nimport { normalizeVariables, filterVariables } from './variables';\n\ndescribe('normalizeVariables', () => {\n  it('normalizes variables', () => {\n    const input = { x: 42 };\n    const operation = getMainOperation(\n      formatDocument(gql`\n        query ($x: Int!) {\n          field\n        }\n      `)\n    );\n    const normalized = normalizeVariables(operation, input);\n    expect(normalized).toEqual({ x: 42 });\n  });\n\n  it('normalizes variables with defaults', () => {\n    const input = { x: undefined };\n    const operation = getMainOperation(\n      formatDocument(gql`\n        query ($x: Int! = 42) {\n          field\n        }\n      `)\n    );\n    const normalized = normalizeVariables(operation, input);\n    expect(normalized).toEqual({ x: 42 });\n  });\n\n  it('normalizes variables even with missing fields', () => {\n    const input = { x: undefined };\n    const operation = getMainOperation(\n      formatDocument(gql`\n        query ($x: Int!) {\n          field\n        }\n      `)\n    );\n    const normalized = normalizeVariables(operation, input);\n    expect(normalized).toEqual({});\n  });\n\n  it('skips normalizing for queries without variables', () => {\n    const operation = getMainOperation(\n      formatDocument(gql`\n        query {\n          field\n        }\n      `)\n    );\n    (operation as any).variableDefinitions = undefined;\n    const normalized = normalizeVariables(operation, {});\n    expect(normalized).toEqual({});\n  });\n\n  it('preserves missing variables', () => {\n    const operation = getMainOperation(\n      formatDocument(gql`\n        query {\n          field\n        }\n      `)\n    );\n    (operation as any).variableDefinitions = undefined;\n    const normalized = normalizeVariables(operation, { test: true });\n    expect(normalized).toEqual({ test: true });\n  });\n});\n\ndescribe('filterVariables', () => {\n  it('returns undefined when no variables are defined', () => {\n    const operation = getMainOperation(\n      formatDocument(gql`\n        query {\n          field\n        }\n      `)\n    );\n    const vars = filterVariables(operation, { test: true });\n    expect(vars).toBe(undefined);\n  });\n\n  it('filters out missing vars', () => {\n    const input = { x: true, y: false };\n    const operation = getMainOperation(\n      formatDocument(gql`\n        query ($x: Int!) {\n          field\n        }\n      `)\n    );\n    const vars = filterVariables(operation, input);\n    expect(vars).toEqual({ x: true });\n  });\n\n  it('ignores defaults', () => {\n    const input = { x: undefined };\n    const operation = getMainOperation(\n      formatDocument(gql`\n        query ($x: Int! = 42) {\n          field\n        }\n      `)\n    );\n    const vars = filterVariables(operation, input);\n    expect(vars).toEqual({ x: undefined });\n  });\n});\n"
  },
  {
    "path": "exchanges/graphcache/src/ast/variables.ts",
    "content": "import type {\n  FieldNode,\n  DirectiveNode,\n  OperationDefinitionNode,\n} from '@0no-co/graphql.web';\nimport { valueFromASTUntyped } from '@0no-co/graphql.web';\n\nimport { getName } from './node';\n\nimport type { Variables } from '../types';\n\n/** Evaluates a fields arguments taking vars into account */\nexport const getFieldArguments = (\n  node: FieldNode | DirectiveNode,\n  vars: Variables\n): null | Variables => {\n  let args: null | Variables = null;\n  if (node.arguments) {\n    for (let i = 0, l = node.arguments.length; i < l; i++) {\n      const arg = node.arguments[i];\n      const value = valueFromASTUntyped(arg.value, vars);\n      if (value !== undefined && value !== null) {\n        if (!args) args = {};\n        args[getName(arg)] = value as any;\n      }\n    }\n  }\n  return args;\n};\n\n/** Returns a filtered form of variables with values missing that the query doesn't require */\nexport const filterVariables = (\n  node: OperationDefinitionNode,\n  input: void | object\n) => {\n  if (!input || !node.variableDefinitions) {\n    return undefined;\n  }\n\n  const vars = {};\n  for (let i = 0, l = node.variableDefinitions.length; i < l; i++) {\n    const name = getName(node.variableDefinitions[i].variable);\n    vars[name] = input[name];\n  }\n\n  return vars;\n};\n\n/** Returns a normalized form of variables with defaulted values */\nexport const normalizeVariables = (\n  node: OperationDefinitionNode,\n  input: void | Record<string, unknown>\n): Variables => {\n  const vars = {};\n  if (!input) return vars;\n\n  if (node.variableDefinitions) {\n    for (let i = 0, l = node.variableDefinitions.length; i < l; i++) {\n      const def = node.variableDefinitions[i];\n      const name = getName(def.variable);\n      vars[name] =\n        input[name] === undefined && def.defaultValue\n          ? valueFromASTUntyped(def.defaultValue, input)\n          : input[name];\n    }\n  }\n\n  for (const key in input) {\n    if (!(key in vars)) vars[key] = input[key];\n  }\n\n  return vars;\n};\n"
  },
  {
    "path": "exchanges/graphcache/src/cacheExchange-types.test.ts",
    "content": "import { describe, it } from 'vitest';\nimport {\n  cacheExchange,\n  Resolver as GraphCacheResolver,\n  UpdateResolver as GraphCacheUpdateResolver,\n  OptimisticMutationResolver as GraphCacheOptimisticMutationResolver,\n} from './index';\n\ntype Maybe<T> = T | null;\n\ntype Scalars = {\n  ID: string;\n  String: string;\n  Boolean: boolean;\n  Int: number;\n  Float: number;\n};\ntype Author = {\n  __typename?: 'Author';\n  id?: Maybe<Scalars['ID']>;\n  name?: Maybe<Scalars['String']>;\n  friends?: Maybe<Array<Maybe<Author>>>;\n  friendsPaginated?: Maybe<Array<Maybe<Author>>>;\n};\n\ntype MutationToggleTodoArgs = {\n  id: Scalars['ID'];\n};\n\ntype Query = {\n  __typename?: 'Query';\n  todos?: Maybe<Array<Maybe<Todo>>>;\n};\n\ntype Todo = {\n  __typename?: 'Todo';\n  id?: Maybe<Scalars['ID']>;\n  text?: Maybe<Scalars['String']>;\n  complete?: Maybe<Scalars['Boolean']>;\n  author?: Maybe<Author>;\n};\n\ntype WithTypename<T extends { __typename?: any }> = {\n  [K in Exclude<keyof T, '__typename'>]?: T[K];\n} & { __typename: NonNullable<T['__typename']> };\n\ntype GraphCacheKeysConfig = {\n  Todo?: (data: WithTypename<Todo>) => null | string;\n};\n\ntype GraphCacheResolvers = {\n  Query?: {\n    todos?: GraphCacheResolver<\n      WithTypename<Query>,\n      Record<string, never>,\n      Array<WithTypename<Todo> | string>\n    >;\n  };\n  Todo?: {\n    id?: GraphCacheResolver<\n      WithTypename<Todo>,\n      Record<string, never>,\n      Scalars['ID'] | string\n    >;\n    text?: GraphCacheResolver<\n      WithTypename<Todo>,\n      Record<string, never>,\n      Scalars['String'] | string\n    >;\n    complete?: GraphCacheResolver<\n      WithTypename<Todo>,\n      Record<string, never>,\n      Scalars['Boolean'] | string\n    >;\n    author?: GraphCacheResolver<\n      WithTypename<Todo>,\n      Record<string, never>,\n      WithTypename<Author> | string\n    >;\n  };\n};\n\ntype GraphCacheOptimisticUpdaters = {\n  toggleTodo?: GraphCacheOptimisticMutationResolver<\n    MutationToggleTodoArgs,\n    WithTypename<Todo>\n  >;\n};\n\ntype GraphCacheUpdaters = {\n  Mutation?: {\n    toggleTodo?: GraphCacheUpdateResolver<\n      { toggleTodo: WithTypename<Todo> },\n      MutationToggleTodoArgs\n    >;\n  };\n  Subscription?: {};\n};\n\ntype GraphCacheConfig = {\n  updates?: GraphCacheUpdaters;\n  keys?: GraphCacheKeysConfig;\n  optimistic?: GraphCacheOptimisticUpdaters;\n  resolvers?: GraphCacheResolvers;\n};\n\ndescribe('typings', function () {\n  it('should work with a generic', function () {\n    cacheExchange<GraphCacheConfig>({\n      keys: {\n        Todo: data => data.id || null,\n      },\n      updates: {\n        Mutation: {\n          toggleTodo: result => {\n            result.toggleTodo.author?.name;\n          },\n        },\n      },\n      resolvers: {\n        Todo: {\n          id: parent => parent.id + '_' + parent.complete,\n        },\n      },\n      optimistic: {\n        toggleTodo: (args, cache) => {\n          return {\n            __typename: 'Todo',\n            complete: !cache.resolve(\n              { __typename: 'Todo', id: args.id },\n              'complete'\n            ),\n            id: args.id,\n          };\n        },\n      },\n    });\n  });\n});\n"
  },
  {
    "path": "exchanges/graphcache/src/cacheExchange.test.ts",
    "content": "import {\n  gql,\n  createClient,\n  ExchangeIO,\n  Operation,\n  OperationResult,\n  CombinedError,\n} from '@urql/core';\n\nimport { print, stripIgnoredCharacters } from 'graphql';\nimport { vi, expect, it, describe } from 'vitest';\n\nimport {\n  Source,\n  pipe,\n  share,\n  map,\n  merge,\n  mergeMap,\n  filter,\n  fromValue,\n  makeSubject,\n  tap,\n  publish,\n  delay,\n} from 'wonka';\n\nimport { minifyIntrospectionQuery } from '@urql/introspection';\nimport { queryResponse } from '../../../packages/core/src/test-utils';\nimport { cacheExchange } from './cacheExchange';\n\nconst queryOne = gql`\n  {\n    author {\n      id\n      name\n    }\n    unrelated {\n      id\n    }\n  }\n`;\n\nconst queryOneData = {\n  __typename: 'Query',\n  author: {\n    __typename: 'Author',\n    id: '123',\n    name: 'Author',\n  },\n  unrelated: {\n    __typename: 'Unrelated',\n    id: 'unrelated',\n  },\n};\n\nconst dispatchDebug = vi.fn();\n\ndescribe('data dependencies', () => {\n  it('writes queries to the cache', () => {\n    const client = createClient({\n      url: 'http://0.0.0.0',\n      exchanges: [],\n    });\n    const op = client.createRequestOperation('query', {\n      key: 1,\n      query: queryOne,\n      variables: undefined,\n    });\n\n    const expected = {\n      __typename: 'Query',\n      author: {\n        id: '123',\n        name: 'Author',\n        __typename: 'Author',\n      },\n      unrelated: {\n        id: 'unrelated',\n        __typename: 'Unrelated',\n      },\n    };\n\n    const response = vi.fn((forwardOp: Operation): OperationResult => {\n      expect(forwardOp.key).toBe(op.key);\n      return { ...queryResponse, operation: forwardOp, data: expected };\n    });\n\n    const { source: ops$, next } = makeSubject<Operation>();\n    const result = vi.fn();\n    const forward: ExchangeIO = ops$ => pipe(ops$, map(response), share);\n\n    pipe(\n      cacheExchange({})({ forward, client, dispatchDebug })(ops$),\n      tap(result),\n      publish\n    );\n\n    next(op);\n    next(op);\n    expect(response).toHaveBeenCalledTimes(1);\n    expect(result).toHaveBeenCalledTimes(2);\n\n    expect(expected).toMatchObject(result.mock.calls[0][0].data);\n    expect(result.mock.calls[1][0]).toHaveProperty(\n      'operation.context.meta.cacheOutcome',\n      'hit'\n    );\n    expect(expected).toMatchObject(result.mock.calls[1][0].data);\n    expect(result.mock.calls[1][0].data).toBe(result.mock.calls[0][0].data);\n  });\n\n  it('logs cache misses', () => {\n    const client = createClient({\n      url: 'http://0.0.0.0',\n      exchanges: [],\n    });\n    const op = client.createRequestOperation('query', {\n      key: 1,\n      query: queryOne,\n      variables: undefined,\n    });\n\n    const expected = {\n      __typename: 'Query',\n      author: {\n        id: '123',\n        name: 'Author',\n        __typename: 'Author',\n      },\n      unrelated: {\n        id: 'unrelated',\n        __typename: 'Unrelated',\n      },\n    };\n\n    const response = vi.fn((forwardOp: Operation): OperationResult => {\n      expect(forwardOp.key).toBe(op.key);\n      return { ...queryResponse, operation: forwardOp, data: expected };\n    });\n\n    const { source: ops$, next } = makeSubject<Operation>();\n    const result = vi.fn();\n    const forward: ExchangeIO = ops$ => pipe(ops$, map(response), share);\n\n    const messages: string[] = [];\n    pipe(\n      cacheExchange({\n        logger(severity, message) {\n          if (severity === 'debug') {\n            messages.push(message);\n          }\n        },\n      })({ forward, client, dispatchDebug })(ops$),\n      tap(result),\n      publish\n    );\n\n    next(op);\n    next(op);\n    next({\n      ...op,\n      query: gql`\n        query ($id: ID!) {\n          author(id: $id) {\n            id\n            name\n          }\n        }\n      `,\n      variables: { id: '123' },\n    });\n    expect(response).toHaveBeenCalledTimes(1);\n    expect(result).toHaveBeenCalledTimes(2);\n\n    expect(expected).toMatchObject(result.mock.calls[0][0].data);\n    expect(result.mock.calls[1][0]).toHaveProperty(\n      'operation.context.meta.cacheOutcome',\n      'hit'\n    );\n    expect(expected).toMatchObject(result.mock.calls[1][0].data);\n    expect(result.mock.calls[1][0].data).toBe(result.mock.calls[0][0].data);\n    expect(messages).toEqual([\n      'No value for field \"author\" on entity \"Query\"',\n      'No value for field \"author\" with args {\"id\":\"123\"} on entity \"Query\"',\n    ]);\n  });\n\n  it('respects cache-only operations', () => {\n    const client = createClient({\n      url: 'http://0.0.0.0',\n      exchanges: [],\n    });\n    const op = client.createRequestOperation(\n      'query',\n      {\n        key: 1,\n        query: queryOne,\n        variables: undefined,\n      },\n      {\n        requestPolicy: 'cache-only',\n      }\n    );\n\n    const response = vi.fn((forwardOp: Operation): OperationResult => {\n      expect(forwardOp.key).toBe(op.key);\n      return { ...queryResponse, operation: forwardOp, data: queryOneData };\n    });\n\n    const { source: ops$, next } = makeSubject<Operation>();\n    const result = vi.fn();\n    const forward: ExchangeIO = ops$ => pipe(ops$, map(response), share);\n\n    pipe(\n      cacheExchange({})({ forward, client, dispatchDebug })(ops$),\n      tap(result),\n      publish\n    );\n\n    next(op);\n    expect(response).toHaveBeenCalledTimes(0);\n    expect(result).toHaveBeenCalledTimes(1);\n\n    expect(result.mock.calls[0][0]).toHaveProperty(\n      'operation.context.meta.cacheOutcome',\n      'miss'\n    );\n\n    expect(result.mock.calls[0][0].data).toBe(null);\n  });\n\n  it('updates related queries when their data changes', () => {\n    const queryMultiple = gql`\n      {\n        authors {\n          id\n          name\n        }\n      }\n    `;\n\n    const queryMultipleData = {\n      __typename: 'Query',\n      authors: [\n        {\n          __typename: 'Author',\n          id: '123',\n          name: 'New Author Name',\n        },\n      ],\n    };\n\n    const client = createClient({\n      url: 'http://0.0.0.0',\n      exchanges: [],\n    });\n    const { source: ops$, next } = makeSubject<Operation>();\n\n    const reexec = vi\n      .spyOn(client, 'reexecuteOperation')\n      .mockImplementation(next);\n\n    const opOne = client.createRequestOperation('query', {\n      key: 1,\n      query: queryOne,\n      variables: undefined,\n    });\n\n    const opMultiple = client.createRequestOperation('query', {\n      key: 2,\n      query: queryMultiple,\n      variables: undefined,\n    });\n\n    const response = vi.fn((forwardOp: Operation): OperationResult => {\n      if (forwardOp.key === 1) {\n        return { ...queryResponse, operation: opOne, data: queryOneData };\n      } else if (forwardOp.key === 2) {\n        return {\n          ...queryResponse,\n          operation: opMultiple,\n          data: queryMultipleData,\n        };\n      }\n\n      return undefined as any;\n    });\n\n    const forward: ExchangeIO = ops$ => pipe(ops$, map(response), share);\n    const result = vi.fn();\n\n    pipe(\n      cacheExchange({})({ forward, client, dispatchDebug })(ops$),\n      tap(result),\n      publish\n    );\n\n    next(opOne);\n    expect(response).toHaveBeenCalledTimes(1);\n    expect(result).toHaveBeenCalledTimes(1);\n\n    next(opMultiple);\n    expect(response).toHaveBeenCalledTimes(2);\n    expect(reexec.mock.calls[0][0]).toHaveProperty('key', opOne.key);\n    expect(result).toHaveBeenCalledTimes(3);\n\n    // test for reference reuse\n    const firstDataOne = result.mock.calls[0][0].data;\n    const firstDataTwo = result.mock.calls[1][0].data;\n    expect(firstDataOne).not.toBe(firstDataTwo);\n    expect(firstDataOne.author).not.toBe(firstDataTwo.author);\n    expect(firstDataOne.unrelated).toBe(firstDataTwo.unrelated);\n  });\n\n  it('updates related queries when a mutation update touches query data', () => {\n    vi.useFakeTimers();\n\n    const balanceFragment = gql`\n      fragment BalanceFragment on Author {\n        id\n        balance {\n          amount\n        }\n      }\n    `;\n\n    const queryById = gql`\n      query ($id: ID!) {\n        author(id: $id) {\n          id\n          name\n          ...BalanceFragment\n        }\n      }\n\n      ${balanceFragment}\n    `;\n\n    const queryByIdDataA = {\n      __typename: 'Query',\n      author: {\n        __typename: 'Author',\n        id: '1',\n        name: 'Author 1',\n        balance: {\n          __typename: 'Balance',\n          amount: 100,\n        },\n      },\n    };\n\n    const queryByIdDataB = {\n      __typename: 'Query',\n      author: {\n        __typename: 'Author',\n        id: '2',\n        name: 'Author 2',\n        balance: {\n          __typename: 'Balance',\n          amount: 200,\n        },\n      },\n    };\n\n    const mutation = gql`\n      mutation ($userId: ID!, $amount: Int!) {\n        updateBalance(userId: $userId, amount: $amount) {\n          userId\n          balance {\n            amount\n          }\n        }\n      }\n    `;\n\n    const mutationData = {\n      __typename: 'Mutation',\n      updateBalance: {\n        __typename: 'UpdateBalanceResult',\n        userId: '1',\n        balance: {\n          __typename: 'Balance',\n          amount: 1000,\n        },\n      },\n    };\n\n    const client = createClient({\n      url: 'http://0.0.0.0',\n      exchanges: [],\n    });\n    const { source: ops$, next } = makeSubject<Operation>();\n\n    const reexec = vi\n      .spyOn(client, 'reexecuteOperation')\n      .mockImplementation(next);\n\n    const opOne = client.createRequestOperation('query', {\n      key: 1,\n      query: queryById,\n      variables: { id: 1 },\n    });\n\n    const opTwo = client.createRequestOperation('query', {\n      key: 2,\n      query: queryById,\n      variables: { id: 2 },\n    });\n\n    const opMutation = client.createRequestOperation('mutation', {\n      key: 3,\n      query: mutation,\n      variables: { userId: '1', amount: 1000 },\n    });\n\n    const response = vi.fn((forwardOp: Operation): OperationResult => {\n      if (forwardOp.key === 1) {\n        return { ...queryResponse, operation: opOne, data: queryByIdDataA };\n      } else if (forwardOp.key === 2) {\n        return { ...queryResponse, operation: opTwo, data: queryByIdDataB };\n      } else if (forwardOp.key === 3) {\n        return {\n          ...queryResponse,\n          operation: opMutation,\n          data: mutationData,\n        };\n      }\n\n      return undefined as any;\n    });\n\n    const result = vi.fn();\n    const forward: ExchangeIO = ops$ =>\n      pipe(ops$, delay(1), map(response), share);\n\n    const updates = {\n      Mutation: {\n        updateBalance: vi.fn((result, _args, cache) => {\n          const {\n            updateBalance: { userId, balance },\n          } = result;\n          cache.writeFragment(balanceFragment, { id: userId, balance });\n        }),\n      },\n    };\n\n    const keys = {\n      Balance: () => null,\n    };\n\n    pipe(\n      cacheExchange({ updates, keys })({ forward, client, dispatchDebug })(\n        ops$\n      ),\n      tap(result),\n      publish\n    );\n\n    next(opTwo);\n    vi.runAllTimers();\n    expect(response).toHaveBeenCalledTimes(1);\n\n    next(opOne);\n    vi.runAllTimers();\n    expect(response).toHaveBeenCalledTimes(2);\n\n    next(opMutation);\n    vi.runAllTimers();\n\n    expect(response).toHaveBeenCalledTimes(3);\n    expect(updates.Mutation.updateBalance).toHaveBeenCalledTimes(1);\n\n    expect(reexec).toHaveBeenCalledTimes(1);\n    expect(reexec.mock.calls[0][0].key).toBe(1);\n\n    expect(result.mock.calls[2][0]).toHaveProperty(\n      'data.author.balance.amount',\n      1000\n    );\n  });\n\n  it('does not notify related queries when a mutation update does not change the data', () => {\n    vi.useFakeTimers();\n\n    const balanceFragment = gql`\n      fragment BalanceFragment on Author {\n        id\n        balance {\n          amount\n        }\n      }\n    `;\n\n    const queryById = gql`\n      query ($id: ID!) {\n        author(id: $id) {\n          id\n          name\n          ...BalanceFragment\n        }\n      }\n\n      ${balanceFragment}\n    `;\n\n    const queryByIdDataA = {\n      __typename: 'Query',\n      author: {\n        __typename: 'Author',\n        id: '1',\n        name: 'Author 1',\n        balance: {\n          __typename: 'Balance',\n          amount: 100,\n        },\n      },\n    };\n\n    const queryByIdDataB = {\n      __typename: 'Query',\n      author: {\n        __typename: 'Author',\n        id: '2',\n        name: 'Author 2',\n        balance: {\n          __typename: 'Balance',\n          amount: 200,\n        },\n      },\n    };\n\n    const mutation = gql`\n      mutation ($userId: ID!, $amount: Int!) {\n        updateBalance(userId: $userId, amount: $amount) {\n          userId\n          balance {\n            amount\n          }\n        }\n      }\n    `;\n\n    const mutationData = {\n      __typename: 'Mutation',\n      updateBalance: {\n        __typename: 'UpdateBalanceResult',\n        userId: '1',\n        balance: {\n          __typename: 'Balance',\n          amount: 100,\n        },\n      },\n    };\n\n    const client = createClient({\n      url: 'http://0.0.0.0',\n      exchanges: [],\n    });\n    const { source: ops$, next } = makeSubject<Operation>();\n\n    const reexec = vi\n      .spyOn(client, 'reexecuteOperation')\n      .mockImplementation(next);\n\n    const opOne = client.createRequestOperation('query', {\n      key: 1,\n      query: queryById,\n      variables: { id: 1 },\n    });\n\n    const opTwo = client.createRequestOperation('query', {\n      key: 2,\n      query: queryById,\n      variables: { id: 2 },\n    });\n\n    const opMutation = client.createRequestOperation('mutation', {\n      key: 3,\n      query: mutation,\n      variables: { userId: '1', amount: 1000 },\n    });\n\n    const response = vi.fn((forwardOp: Operation): OperationResult => {\n      if (forwardOp.key === 1) {\n        return { ...queryResponse, operation: opOne, data: queryByIdDataA };\n      } else if (forwardOp.key === 2) {\n        return { ...queryResponse, operation: opTwo, data: queryByIdDataB };\n      } else if (forwardOp.key === 3) {\n        return {\n          ...queryResponse,\n          operation: opMutation,\n          data: mutationData,\n        };\n      }\n\n      return undefined as any;\n    });\n\n    const result = vi.fn();\n    const forward: ExchangeIO = ops$ =>\n      pipe(ops$, delay(1), map(response), share);\n\n    const updates = {\n      Mutation: {\n        updateBalance: vi.fn((result, _args, cache) => {\n          const {\n            updateBalance: { userId, balance },\n          } = result;\n          cache.writeFragment(balanceFragment, { id: userId, balance });\n        }),\n      },\n    };\n\n    const keys = {\n      Balance: () => null,\n    };\n\n    pipe(\n      cacheExchange({ updates, keys })({ forward, client, dispatchDebug })(\n        ops$\n      ),\n      tap(result),\n      publish\n    );\n\n    next(opTwo);\n    vi.runAllTimers();\n    expect(response).toHaveBeenCalledTimes(1);\n\n    next(opOne);\n    vi.runAllTimers();\n    expect(response).toHaveBeenCalledTimes(2);\n\n    next(opMutation);\n    vi.runAllTimers();\n\n    expect(response).toHaveBeenCalledTimes(3);\n    expect(updates.Mutation.updateBalance).toHaveBeenCalledTimes(1);\n\n    expect(reexec).toHaveBeenCalledTimes(0);\n  });\n\n  it('does nothing when no related queries have changed', () => {\n    const queryUnrelated = gql`\n      {\n        user {\n          id\n          name\n        }\n      }\n    `;\n\n    const queryUnrelatedData = {\n      __typename: 'Query',\n      user: {\n        __typename: 'User',\n        id: 'me',\n        name: 'Me',\n      },\n    };\n\n    const client = createClient({\n      url: 'http://0.0.0.0',\n      exchanges: [],\n    });\n    const { source: ops$, next } = makeSubject<Operation>();\n    const reexec = vi\n      .spyOn(client, 'reexecuteOperation')\n      .mockImplementation(next);\n\n    const opOne = client.createRequestOperation('query', {\n      key: 1,\n      query: queryOne,\n      variables: undefined,\n    });\n    const opUnrelated = client.createRequestOperation('query', {\n      key: 2,\n      query: queryUnrelated,\n      variables: undefined,\n    });\n\n    const response = vi.fn((forwardOp: Operation): OperationResult => {\n      if (forwardOp.key === 1) {\n        return { ...queryResponse, operation: opOne, data: queryOneData };\n      } else if (forwardOp.key === 2) {\n        return {\n          ...queryResponse,\n          operation: opUnrelated,\n          data: queryUnrelatedData,\n        };\n      }\n\n      return undefined as any;\n    });\n\n    const forward: ExchangeIO = ops$ => pipe(ops$, map(response), share);\n    const result = vi.fn();\n\n    pipe(\n      cacheExchange({})({ forward, client, dispatchDebug })(ops$),\n      tap(result),\n      publish\n    );\n\n    next(opOne);\n    expect(response).toHaveBeenCalledTimes(1);\n\n    next(opUnrelated);\n    expect(response).toHaveBeenCalledTimes(2);\n\n    expect(reexec).not.toHaveBeenCalled();\n    expect(result).toHaveBeenCalledTimes(2);\n  });\n\n  it('does not reach updater when mutation has no selectionset in optimistic phase', () => {\n    vi.useFakeTimers();\n\n    const mutation = gql`\n      mutation {\n        concealAuthor\n      }\n    `;\n\n    const mutationData = {\n      __typename: 'Mutation',\n      concealAuthor: true,\n    };\n\n    const client = createClient({\n      url: 'http://0.0.0.0',\n      exchanges: [],\n    });\n    const { source: ops$, next } = makeSubject<Operation>();\n\n    vi.spyOn(client, 'reexecuteOperation').mockImplementation(next);\n\n    const opMutation = client.createRequestOperation('mutation', {\n      key: 1,\n      query: mutation,\n      variables: undefined,\n    });\n\n    const response = vi.fn((forwardOp: Operation): OperationResult => {\n      if (forwardOp.key === 1) {\n        return {\n          ...queryResponse,\n          operation: opMutation,\n          data: mutationData,\n        };\n      }\n\n      return undefined as any;\n    });\n\n    const result = vi.fn();\n    const forward: ExchangeIO = ops$ =>\n      pipe(ops$, delay(1), map(response), share);\n\n    const updates = {\n      Mutation: {\n        concealAuthor: vi.fn(),\n      },\n    };\n\n    pipe(\n      cacheExchange({ updates })({ forward, client, dispatchDebug })(ops$),\n      tap(result),\n      publish\n    );\n\n    next(opMutation);\n    expect(updates.Mutation.concealAuthor).toHaveBeenCalledTimes(0);\n\n    vi.runAllTimers();\n    expect(updates.Mutation.concealAuthor).toHaveBeenCalledTimes(1);\n  });\n\n  it('does reach updater when mutation has no selectionset in optimistic phase with optimistic update', () => {\n    vi.useFakeTimers();\n\n    const mutation = gql`\n      mutation {\n        concealAuthor\n      }\n    `;\n\n    const mutationData = {\n      __typename: 'Mutation',\n      concealAuthor: true,\n    };\n\n    const client = createClient({\n      url: 'http://0.0.0.0',\n      exchanges: [],\n    });\n    const { source: ops$, next } = makeSubject<Operation>();\n\n    vi.spyOn(client, 'reexecuteOperation').mockImplementation(next);\n\n    const opMutation = client.createRequestOperation('mutation', {\n      key: 1,\n      query: mutation,\n      variables: undefined,\n    });\n\n    const response = vi.fn((forwardOp: Operation): OperationResult => {\n      if (forwardOp.key === 1) {\n        return {\n          ...queryResponse,\n          operation: opMutation,\n          data: mutationData,\n        };\n      }\n\n      return undefined as any;\n    });\n\n    const result = vi.fn();\n    const forward: ExchangeIO = ops$ =>\n      pipe(ops$, delay(1), map(response), share);\n\n    const updates = {\n      Mutation: {\n        concealAuthor: vi.fn(),\n      },\n    };\n\n    const optimistic = {\n      concealAuthor: vi.fn(() => true) as any,\n    };\n\n    pipe(\n      cacheExchange({ updates, optimistic })({\n        forward,\n        client,\n        dispatchDebug,\n      })(ops$),\n      tap(result),\n      publish\n    );\n\n    next(opMutation);\n    expect(optimistic.concealAuthor).toHaveBeenCalledTimes(1);\n    expect(updates.Mutation.concealAuthor).toHaveBeenCalledTimes(1);\n\n    vi.runAllTimers();\n    expect(updates.Mutation.concealAuthor).toHaveBeenCalledTimes(2);\n  });\n\n  it('marks errored null fields as uncached but delivers them as expected', () => {\n    const client = createClient({\n      url: 'http://0.0.0.0',\n      exchanges: [],\n    });\n    const { source: ops$, next } = makeSubject<Operation>();\n\n    const query = gql`\n      {\n        field\n        author {\n          id\n        }\n      }\n    `;\n\n    const operation = client.createRequestOperation('query', {\n      key: 1,\n      query,\n      variables: undefined,\n    });\n\n    const queryResult: OperationResult = {\n      ...queryResponse,\n      operation,\n      data: {\n        __typename: 'Query',\n        field: 'test',\n        author: null,\n      },\n      error: new CombinedError({\n        graphQLErrors: [\n          {\n            message: 'Test',\n            path: ['author'],\n          },\n        ],\n      }),\n    };\n\n    const reexecuteOperation = vi\n      .spyOn(client, 'reexecuteOperation')\n      .mockImplementation(next);\n\n    const response = vi.fn((forwardOp: Operation): OperationResult => {\n      if (forwardOp.key === 1) return queryResult;\n      return undefined as any;\n    });\n\n    const result = vi.fn();\n    const forward: ExchangeIO = ops$ => pipe(ops$, map(response), share);\n\n    pipe(\n      cacheExchange({})({ forward, client, dispatchDebug })(ops$),\n      tap(result),\n      publish\n    );\n\n    next(operation);\n\n    expect(response).toHaveBeenCalledTimes(1);\n    expect(result).toHaveBeenCalledTimes(1);\n    expect(reexecuteOperation).toHaveBeenCalledTimes(0);\n    expect(result.mock.calls[0][0]).toHaveProperty('data.author', null);\n  });\n\n  it('mutation does not change number of reexecute request after a query', () => {\n    const client = createClient({\n      url: 'http://0.0.0.0',\n      exchanges: [],\n    });\n\n    const { source: ops$, next: nextOp } = makeSubject<Operation>();\n\n    const reexec = vi\n      .spyOn(client, 'reexecuteOperation')\n      .mockImplementation(nextOp);\n\n    const mutation = gql`\n      mutation {\n        updateNode {\n          __typename\n          id\n        }\n      }\n    `;\n\n    const normalQuery = gql`\n      {\n        __typename\n        item {\n          __typename\n          id\n        }\n      }\n    `;\n\n    const extendedQuery = gql`\n      {\n        __typename\n        item {\n          __typename\n          extended: id\n          extra @_optional\n        }\n      }\n    `;\n\n    const mutationOp = client.createRequestOperation('mutation', {\n      key: 0,\n      query: mutation,\n      variables: undefined,\n    });\n\n    const normalOp = client.createRequestOperation(\n      'query',\n      {\n        key: 1,\n        query: normalQuery,\n        variables: undefined,\n      },\n      {\n        requestPolicy: 'cache-and-network',\n      }\n    );\n\n    const extendedOp = client.createRequestOperation(\n      'query',\n      {\n        key: 2,\n        query: extendedQuery,\n        variables: undefined,\n      },\n      {\n        requestPolicy: 'cache-only',\n      }\n    );\n\n    const response = vi.fn((forwardOp: Operation): OperationResult => {\n      if (forwardOp.key === 0) {\n        return {\n          operation: mutationOp,\n          data: {\n            __typename: 'Mutation',\n            updateNode: {\n              __typename: 'Node',\n              id: 'id',\n            },\n          },\n          stale: false,\n          hasNext: false,\n        };\n      } else if (forwardOp.key === 1) {\n        return {\n          operation: normalOp,\n          data: {\n            __typename: 'Query',\n            item: {\n              __typename: 'Node',\n              id: 'id',\n            },\n          },\n          stale: false,\n          hasNext: false,\n        };\n      } else if (forwardOp.key === 2) {\n        return {\n          operation: extendedOp,\n          data: {\n            __typename: 'Query',\n            item: {\n              __typename: 'Node',\n              extended: 'id',\n              extra: 'extra',\n            },\n          },\n          stale: false,\n          hasNext: false,\n        };\n      }\n\n      return undefined as any;\n    });\n\n    const forward = (ops$: Source<Operation>): Source<OperationResult> =>\n      pipe(ops$, map(response), share);\n\n    pipe(cacheExchange()({ forward, client, dispatchDebug })(ops$), publish);\n\n    nextOp(normalOp);\n    expect(reexec).toHaveBeenCalledTimes(0);\n\n    nextOp(extendedOp);\n    expect(reexec).toHaveBeenCalledTimes(0);\n\n    // re-execute first operation\n    reexec.mockClear();\n    nextOp(normalOp);\n    expect(reexec).toHaveBeenCalledTimes(4);\n\n    nextOp(mutationOp);\n\n    // re-execute first operation after mutation\n    reexec.mockClear();\n    nextOp(normalOp);\n    expect(reexec).toHaveBeenCalledTimes(4);\n  });\n});\n\ndescribe('directives', () => {\n  it('returns optional fields as partial', () => {\n    const client = createClient({\n      url: 'http://0.0.0.0',\n      exchanges: [],\n    });\n    const { source: ops$, next } = makeSubject<Operation>();\n\n    const query = gql`\n      {\n        todos {\n          id\n          text\n          completed @_optional\n        }\n      }\n    `;\n\n    const operation = client.createRequestOperation('query', {\n      key: 1,\n      query,\n      variables: undefined,\n    });\n\n    const queryResult: OperationResult = {\n      ...queryResponse,\n      operation,\n      data: {\n        __typename: 'Query',\n        todos: [\n          {\n            id: '1',\n            text: 'learn urql',\n            __typename: 'Todo',\n          },\n        ],\n      },\n    };\n\n    const reexecuteOperation = vi\n      .spyOn(client, 'reexecuteOperation')\n      .mockImplementation(next);\n\n    const response = vi.fn((forwardOp: Operation): OperationResult => {\n      if (forwardOp.key === 1) return queryResult;\n      return undefined as any;\n    });\n\n    const result = vi.fn();\n    const forward: ExchangeIO = ops$ => pipe(ops$, map(response), share);\n\n    pipe(\n      cacheExchange({})({ forward, client, dispatchDebug })(ops$),\n      tap(result),\n      publish\n    );\n\n    next(operation);\n\n    expect(response).toHaveBeenCalledTimes(1);\n    expect(result).toHaveBeenCalledTimes(1);\n    expect(reexecuteOperation).toHaveBeenCalledTimes(0);\n    expect(result.mock.calls[0][0].data).toEqual({\n      todos: [\n        {\n          completed: null,\n          id: '1',\n          text: 'learn urql',\n        },\n      ],\n    });\n  });\n\n  it('Does not return partial data for nested selections', () => {\n    const client = createClient({\n      url: 'http://0.0.0.0',\n      exchanges: [],\n    });\n    const { source: ops$, next } = makeSubject<Operation>();\n\n    const query = gql`\n      {\n        todo {\n          ... on Todo @_optional {\n            id\n            text\n            author {\n              id\n              name\n            }\n          }\n        }\n      }\n    `;\n\n    const operation = client.createRequestOperation('query', {\n      key: 1,\n      query,\n      variables: undefined,\n    });\n\n    const queryResult: OperationResult = {\n      ...queryResponse,\n      operation,\n      data: {\n        __typename: 'Query',\n        todo: {\n          id: '1',\n          text: 'learn urql',\n          __typename: 'Todo',\n          author: {\n            __typename: 'Author',\n          },\n        },\n      },\n    };\n\n    const reexecuteOperation = vi\n      .spyOn(client, 'reexecuteOperation')\n      .mockImplementation(next);\n\n    const response = vi.fn((forwardOp: Operation): OperationResult => {\n      if (forwardOp.key === 1) return queryResult;\n      return undefined as any;\n    });\n\n    const result = vi.fn();\n    const forward: ExchangeIO = ops$ => pipe(ops$, map(response), share);\n\n    pipe(\n      cacheExchange({})({ forward, client, dispatchDebug })(ops$),\n      tap(result),\n      publish\n    );\n\n    next(operation);\n\n    expect(response).toHaveBeenCalledTimes(1);\n    expect(result).toHaveBeenCalledTimes(1);\n    expect(reexecuteOperation).toHaveBeenCalledTimes(0);\n    expect(result.mock.calls[0][0].data).toEqual(null);\n  });\n\n  it('returns partial results when an inline-fragment is marked as optional', () => {\n    const client = createClient({\n      url: 'http://0.0.0.0',\n      exchanges: [],\n    });\n    const { source: ops$, next } = makeSubject<Operation>();\n\n    const query = gql`\n      {\n        todos {\n          id\n          text\n          ... @_optional {\n            ... on Todo {\n              completed\n            }\n          }\n        }\n      }\n    `;\n\n    const operation = client.createRequestOperation('query', {\n      key: 1,\n      query,\n      variables: undefined,\n    });\n\n    const queryResult: OperationResult = {\n      ...queryResponse,\n      operation,\n      data: {\n        __typename: 'Query',\n        todos: [\n          {\n            id: '1',\n            text: 'learn urql',\n            __typename: 'Todo',\n          },\n        ],\n      },\n    };\n\n    const reexecuteOperation = vi\n      .spyOn(client, 'reexecuteOperation')\n      .mockImplementation(next);\n\n    const response = vi.fn((forwardOp: Operation): OperationResult => {\n      if (forwardOp.key === 1) return queryResult;\n      return undefined as any;\n    });\n\n    const result = vi.fn();\n    const forward: ExchangeIO = ops$ => pipe(ops$, map(response), share);\n\n    pipe(\n      cacheExchange({})({ forward, client, dispatchDebug })(ops$),\n      tap(result),\n      publish\n    );\n\n    next(operation);\n\n    expect(response).toHaveBeenCalledTimes(1);\n    expect(result).toHaveBeenCalledTimes(1);\n    expect(reexecuteOperation).toHaveBeenCalledTimes(0);\n    expect(result.mock.calls[0][0].data).toEqual({\n      todos: [\n        {\n          completed: null,\n          id: '1',\n          text: 'learn urql',\n        },\n      ],\n    });\n  });\n\n  it('does not return partial results when an inline-fragment is marked as optional with a required child fragment', () => {\n    const client = createClient({\n      url: 'http://0.0.0.0',\n      exchanges: [],\n    });\n    const { source: ops$, next } = makeSubject<Operation>();\n\n    const query = gql`\n      {\n        todos {\n          id\n          ... on Todo @_optional {\n            text\n            ... on Todo @_required {\n              completed\n            }\n          }\n        }\n      }\n    `;\n\n    const operation = client.createRequestOperation('query', {\n      key: 1,\n      query,\n      variables: undefined,\n    });\n\n    const queryResult: OperationResult = {\n      ...queryResponse,\n      operation,\n      data: {\n        __typename: 'Query',\n        todos: [\n          {\n            id: '1',\n            text: 'learn urql',\n            __typename: 'Todo',\n          },\n        ],\n      },\n    };\n\n    const reexecuteOperation = vi\n      .spyOn(client, 'reexecuteOperation')\n      .mockImplementation(next);\n\n    const response = vi.fn((forwardOp: Operation): OperationResult => {\n      if (forwardOp.key === 1) return queryResult;\n      return undefined as any;\n    });\n\n    const result = vi.fn();\n    const forward: ExchangeIO = ops$ => pipe(ops$, map(response), share);\n\n    pipe(\n      cacheExchange({})({ forward, client, dispatchDebug })(ops$),\n      tap(result),\n      publish\n    );\n\n    next(operation);\n\n    expect(response).toHaveBeenCalledTimes(1);\n    expect(result).toHaveBeenCalledTimes(1);\n    expect(reexecuteOperation).toHaveBeenCalledTimes(0);\n    expect(result.mock.calls[0][0].data).toEqual(null);\n  });\n\n  it('does not return partial results when an inline-fragment is marked as optional with a required field', () => {\n    const client = createClient({\n      url: 'http://0.0.0.0',\n      exchanges: [],\n    });\n    const { source: ops$, next } = makeSubject<Operation>();\n\n    const query = gql`\n      {\n        todos {\n          id\n          ... on Todo @_optional {\n            text\n            completed @_required\n          }\n        }\n      }\n    `;\n\n    const operation = client.createRequestOperation('query', {\n      key: 1,\n      query,\n      variables: undefined,\n    });\n\n    const queryResult: OperationResult = {\n      ...queryResponse,\n      operation,\n      data: {\n        __typename: 'Query',\n        todos: [\n          {\n            id: '1',\n            text: 'learn urql',\n            __typename: 'Todo',\n          },\n        ],\n      },\n    };\n\n    const reexecuteOperation = vi\n      .spyOn(client, 'reexecuteOperation')\n      .mockImplementation(next);\n\n    const response = vi.fn((forwardOp: Operation): OperationResult => {\n      if (forwardOp.key === 1) return queryResult;\n      return undefined as any;\n    });\n\n    const result = vi.fn();\n    const forward: ExchangeIO = ops$ => pipe(ops$, map(response), share);\n\n    pipe(\n      cacheExchange({})({ forward, client, dispatchDebug })(ops$),\n      tap(result),\n      publish\n    );\n\n    next(operation);\n\n    expect(response).toHaveBeenCalledTimes(1);\n    expect(result).toHaveBeenCalledTimes(1);\n    expect(reexecuteOperation).toHaveBeenCalledTimes(0);\n    expect(result.mock.calls[0][0].data).toEqual(null);\n  });\n\n  it('returns partial results when a fragment-definition is marked as optional', () => {\n    const client = createClient({\n      url: 'http://0.0.0.0',\n      exchanges: [],\n    });\n    const { source: ops$, next } = makeSubject<Operation>();\n\n    const query = gql`\n      {\n        todos {\n          id\n          text\n          ...Fields\n        }\n      }\n\n      fragment Fields on Todo @_optional {\n        completed\n      }\n    `;\n\n    const operation = client.createRequestOperation('query', {\n      key: 1,\n      query,\n      variables: undefined,\n    });\n\n    const queryResult: OperationResult = {\n      ...queryResponse,\n      operation,\n      data: {\n        __typename: 'Query',\n        todos: [\n          {\n            id: '1',\n            text: 'learn urql',\n            __typename: 'Todo',\n          },\n        ],\n      },\n    };\n\n    const reexecuteOperation = vi\n      .spyOn(client, 'reexecuteOperation')\n      .mockImplementation(next);\n\n    const response = vi.fn((forwardOp: Operation): OperationResult => {\n      if (forwardOp.key === 1) return queryResult;\n      return undefined as any;\n    });\n\n    const result = vi.fn();\n    const forward: ExchangeIO = ops$ => pipe(ops$, map(response), share);\n\n    pipe(\n      cacheExchange({})({ forward, client, dispatchDebug })(ops$),\n      tap(result),\n      publish\n    );\n\n    next(operation);\n\n    expect(response).toHaveBeenCalledTimes(1);\n    expect(result).toHaveBeenCalledTimes(1);\n    expect(reexecuteOperation).toHaveBeenCalledTimes(0);\n    expect(result.mock.calls[0][0].data).toEqual(null);\n  });\n\n  it('does not return missing required fields', () => {\n    const client = createClient({\n      url: 'http://0.0.0.0',\n      exchanges: [],\n    });\n    const { source: ops$, next } = makeSubject<Operation>();\n\n    const query = gql`\n      {\n        todos {\n          id\n          text\n          completed @_required\n        }\n      }\n    `;\n\n    const operation = client.createRequestOperation('query', {\n      key: 1,\n      query,\n      variables: undefined,\n    });\n\n    const queryResult: OperationResult = {\n      ...queryResponse,\n      operation,\n      data: {\n        __typename: 'Query',\n        todos: [\n          {\n            id: '1',\n            text: 'learn urql',\n            __typename: 'Todo',\n          },\n        ],\n      },\n    };\n\n    const reexecuteOperation = vi\n      .spyOn(client, 'reexecuteOperation')\n      .mockImplementation(next);\n\n    const response = vi.fn((forwardOp: Operation): OperationResult => {\n      if (forwardOp.key === 1) return queryResult;\n      return undefined as any;\n    });\n\n    const result = vi.fn();\n    const forward: ExchangeIO = ops$ => pipe(ops$, map(response), share);\n\n    pipe(\n      cacheExchange({})({ forward, client, dispatchDebug })(ops$),\n      tap(result),\n      publish\n    );\n\n    next(operation);\n\n    expect(response).toHaveBeenCalledTimes(1);\n    expect(result).toHaveBeenCalledTimes(1);\n    expect(\n      stripIgnoredCharacters(print(response.mock.calls[0][0].query))\n    ).toEqual('{todos{id text completed __typename}}');\n    expect(reexecuteOperation).toHaveBeenCalledTimes(0);\n    expect(result.mock.calls[0][0].data).toEqual(null);\n  });\n\n  it('does not return missing fields when nullable fields from a defined schema are marked as required in the query', () => {\n    const client = createClient({\n      url: 'http://0.0.0.0',\n      exchanges: [],\n    });\n    const { source: ops$, next } = makeSubject<Operation>();\n\n    const initialQuery = gql`\n      query {\n        latestTodo {\n          id\n        }\n      }\n    `;\n\n    const query = gql`\n      {\n        latestTodo {\n          id\n          author @_required {\n            id\n            name\n          }\n        }\n      }\n    `;\n\n    const initialQueryOperation = client.createRequestOperation('query', {\n      key: 1,\n      query: initialQuery,\n      variables: undefined,\n    });\n\n    const queryOperation = client.createRequestOperation('query', {\n      key: 2,\n      query,\n      variables: undefined,\n    });\n\n    const initialQueryResult: OperationResult = {\n      ...queryResponse,\n      operation: initialQueryOperation,\n      data: {\n        __typename: 'Query',\n        latestTodo: {\n          __typename: 'Todo',\n          id: '1',\n        },\n      },\n    };\n\n    const queryResult: OperationResult = {\n      ...queryResponse,\n      operation: queryOperation,\n      data: {\n        __typename: 'Query',\n        latestTodo: {\n          __typename: 'Todo',\n          id: '1',\n          author: null,\n        },\n      },\n    };\n\n    const response = vi.fn((forwardOp: Operation): OperationResult => {\n      if (forwardOp.key === 1) {\n        return initialQueryResult;\n      } else if (forwardOp.key === 2) {\n        return queryResult;\n      }\n      return undefined as any;\n    });\n\n    const result = vi.fn();\n    const forward: ExchangeIO = ops$ => pipe(ops$, map(response), share);\n\n    pipe(\n      cacheExchange({\n        schema: minifyIntrospectionQuery(\n          // eslint-disable-next-line\n          require('./test-utils/simple_schema.json')\n        ),\n      })({ forward, client, dispatchDebug })(ops$),\n      tap(result),\n      publish\n    );\n\n    next(initialQueryOperation);\n    vi.runAllTimers();\n    next(queryOperation);\n    vi.runAllTimers();\n\n    expect(result.mock.calls[0][0].data).toEqual({\n      latestTodo: {\n        id: '1',\n      },\n    });\n    expect(result.mock.calls[1][0].data).toEqual(null);\n  });\n});\n\ndescribe('optimistic updates', () => {\n  it('writes optimistic mutations to the cache', () => {\n    vi.useFakeTimers();\n\n    const mutation = gql`\n      mutation {\n        concealAuthor {\n          id\n          name\n        }\n      }\n    `;\n\n    const optimisticMutationData = {\n      __typename: 'Mutation',\n      concealAuthor: {\n        __typename: 'Author',\n        id: '123',\n        name() {\n          return '[REDACTED OFFLINE]';\n        },\n      },\n    };\n\n    const mutationData = {\n      __typename: 'Mutation',\n      concealAuthor: {\n        __typename: 'Author',\n        id: '123',\n        name: '[REDACTED ONLINE]',\n      },\n    };\n\n    const client = createClient({\n      url: 'http://0.0.0.0',\n      exchanges: [],\n    });\n    const { source: ops$, next } = makeSubject<Operation>();\n\n    const reexec = vi\n      .spyOn(client, 'reexecuteOperation')\n      .mockImplementation(next);\n\n    const opOne = client.createRequestOperation('query', {\n      key: 1,\n      query: queryOne,\n      variables: undefined,\n    });\n\n    const opMutation = client.createRequestOperation('mutation', {\n      key: 2,\n      query: mutation,\n      variables: undefined,\n    });\n\n    const response = vi.fn((forwardOp: Operation): OperationResult => {\n      if (forwardOp.key === 1) {\n        return { ...queryResponse, operation: opOne, data: queryOneData };\n      } else if (forwardOp.key === 2) {\n        return {\n          ...queryResponse,\n          operation: opMutation,\n          data: mutationData,\n        };\n      }\n\n      return undefined as any;\n    });\n\n    const result = vi.fn();\n    const forward: ExchangeIO = ops$ =>\n      pipe(ops$, delay(1), map(response), share);\n\n    const optimistic = {\n      concealAuthor: vi.fn(() => optimisticMutationData.concealAuthor) as any,\n    };\n\n    pipe(\n      cacheExchange({ optimistic })({ forward, client, dispatchDebug })(ops$),\n      tap(result),\n      publish\n    );\n\n    next(opOne);\n    vi.runAllTimers();\n    expect(response).toHaveBeenCalledTimes(1);\n\n    next(opMutation);\n    expect(response).toHaveBeenCalledTimes(1);\n    expect(optimistic.concealAuthor).toHaveBeenCalledTimes(1);\n    expect(reexec).toHaveBeenCalledTimes(1);\n\n    expect(result.mock.calls[1][0]?.data).toMatchObject({\n      author: { name: '[REDACTED OFFLINE]' },\n    });\n\n    vi.runAllTimers();\n    expect(response).toHaveBeenCalledTimes(2);\n    expect(result).toHaveBeenCalledTimes(4);\n  });\n\n  it('batches optimistic mutation result application', () => {\n    vi.useFakeTimers();\n\n    const mutation = gql`\n      mutation {\n        concealAuthor {\n          id\n          name\n        }\n      }\n    `;\n\n    const optimisticMutationData = {\n      __typename: 'Mutation',\n      concealAuthor: {\n        __typename: 'Author',\n        id: '123',\n        name: '[REDACTED OFFLINE]',\n      },\n    };\n\n    const mutationData = {\n      __typename: 'Mutation',\n      concealAuthor: {\n        __typename: 'Author',\n        id: '123',\n        name: '[REDACTED ONLINE]',\n      },\n    };\n\n    const client = createClient({\n      url: 'http://0.0.0.0',\n      exchanges: [],\n    });\n    const { source: ops$, next } = makeSubject<Operation>();\n\n    const reexec = vi\n      .spyOn(client, 'reexecuteOperation')\n      .mockImplementation(next);\n\n    const opOne = client.createRequestOperation('query', {\n      key: 1,\n      query: queryOne,\n      variables: undefined,\n    });\n\n    const opMutationOne = client.createRequestOperation('mutation', {\n      key: 2,\n      query: mutation,\n      variables: undefined,\n    });\n\n    const opMutationTwo = client.createRequestOperation('mutation', {\n      key: 3,\n      query: mutation,\n      variables: undefined,\n    });\n\n    const response = vi.fn((forwardOp: Operation): OperationResult => {\n      if (forwardOp.key === 1) {\n        return { ...queryResponse, operation: opOne, data: queryOneData };\n      } else if (forwardOp.key === 2) {\n        return {\n          ...queryResponse,\n          operation: opMutationOne,\n          data: mutationData,\n        };\n      } else if (forwardOp.key === 3) {\n        return {\n          ...queryResponse,\n          operation: opMutationTwo,\n          data: mutationData,\n        };\n      }\n\n      return undefined as any;\n    });\n\n    const result = vi.fn();\n    const forward: ExchangeIO = ops$ =>\n      pipe(ops$, delay(3), map(response), share);\n\n    const optimistic = {\n      concealAuthor: vi.fn(() => optimisticMutationData.concealAuthor) as any,\n    };\n\n    pipe(\n      cacheExchange({ optimistic })({ forward, client, dispatchDebug })(ops$),\n      filter(x => x.operation.kind === 'mutation'),\n      tap(result),\n      publish\n    );\n\n    next(opOne);\n    vi.runAllTimers();\n    expect(response).toHaveBeenCalledTimes(1);\n    expect(result).toHaveBeenCalledTimes(0);\n\n    next(opMutationOne);\n    vi.advanceTimersByTime(1);\n    next(opMutationTwo);\n\n    expect(response).toHaveBeenCalledTimes(1);\n    expect(optimistic.concealAuthor).toHaveBeenCalledTimes(2);\n    expect(reexec).toHaveBeenCalledTimes(1);\n    expect(result).toHaveBeenCalledTimes(0);\n\n    vi.advanceTimersByTime(2);\n    expect(response).toHaveBeenCalledTimes(2);\n    expect(reexec).toHaveBeenCalledTimes(2);\n    expect(result).toHaveBeenCalledTimes(1);\n\n    vi.runAllTimers();\n    expect(response).toHaveBeenCalledTimes(3);\n    expect(reexec).toHaveBeenCalledTimes(2);\n    expect(result).toHaveBeenCalledTimes(2);\n  });\n\n  it('blocks refetches of overlapping queries', () => {\n    vi.useFakeTimers();\n\n    const mutation = gql`\n      mutation {\n        concealAuthor {\n          id\n          name\n        }\n      }\n    `;\n\n    const optimisticMutationData = {\n      __typename: 'Mutation',\n      concealAuthor: {\n        __typename: 'Author',\n        id: '123',\n        name: '[REDACTED OFFLINE]',\n      },\n    };\n\n    const client = createClient({\n      url: 'http://0.0.0.0',\n      exchanges: [],\n    });\n    const { source: ops$, next } = makeSubject<Operation>();\n\n    const reexec = vi\n      .spyOn(client, 'reexecuteOperation')\n      .mockImplementation(next);\n\n    const opOne = client.createRequestOperation(\n      'query',\n      {\n        key: 1,\n        query: queryOne,\n        variables: undefined,\n      },\n      {\n        requestPolicy: 'cache-and-network',\n      }\n    );\n\n    const opMutation = client.createRequestOperation('mutation', {\n      key: 2,\n      query: mutation,\n      variables: undefined,\n    });\n\n    const response = vi.fn((forwardOp: Operation): OperationResult => {\n      if (forwardOp.key === 1) {\n        return { ...queryResponse, operation: opOne, data: queryOneData };\n      }\n\n      return undefined as any;\n    });\n\n    const result = vi.fn();\n    const forward: ExchangeIO = ops$ =>\n      pipe(\n        ops$,\n        delay(1),\n        filter(x => x.kind !== 'mutation'),\n        map(response),\n        share\n      );\n\n    const optimistic = {\n      concealAuthor: vi.fn(() => optimisticMutationData.concealAuthor) as any,\n    };\n\n    pipe(\n      cacheExchange({ optimistic })({ forward, client, dispatchDebug })(ops$),\n      tap(result),\n      publish\n    );\n\n    next(opOne);\n    vi.runAllTimers();\n    expect(response).toHaveBeenCalledTimes(1);\n\n    next(opMutation);\n    expect(response).toHaveBeenCalledTimes(1);\n    expect(optimistic.concealAuthor).toHaveBeenCalledTimes(1);\n    expect(reexec).toHaveBeenCalledTimes(1);\n\n    expect(reexec.mock.calls[0][0]).toHaveProperty(\n      'context.requestPolicy',\n      'cache-first'\n    );\n\n    vi.runAllTimers();\n    expect(response).toHaveBeenCalledTimes(1);\n\n    next(opOne);\n    expect(response).toHaveBeenCalledTimes(1);\n    expect(reexec).toHaveBeenCalledTimes(1);\n  });\n\n  it('correctly clears on error', () => {\n    vi.useFakeTimers();\n\n    const authorsQuery = gql`\n      query {\n        authors {\n          id\n          name\n        }\n      }\n    `;\n\n    const authorsQueryData = {\n      __typename: 'Query',\n      authors: [\n        {\n          __typename: 'Author',\n          id: '1',\n          name: 'Author',\n        },\n      ],\n    };\n\n    const mutation = gql`\n      mutation {\n        addAuthor {\n          id\n          name\n        }\n      }\n    `;\n\n    const optimisticMutationData = {\n      __typename: 'Mutation',\n      addAuthor: {\n        __typename: 'Author',\n        id: '123',\n        name: '[REDACTED OFFLINE]',\n      },\n    };\n\n    const client = createClient({\n      url: 'http://0.0.0.0',\n      exchanges: [],\n    });\n    const { source: ops$, next } = makeSubject<Operation>();\n\n    const reexec = vi\n      .spyOn(client, 'reexecuteOperation')\n      .mockImplementation(next);\n\n    const opOne = client.createRequestOperation('query', {\n      key: 1,\n      query: authorsQuery,\n      variables: undefined,\n    });\n\n    const opMutation = client.createRequestOperation('mutation', {\n      key: 2,\n      query: mutation,\n      variables: undefined,\n    });\n\n    const response = vi.fn((forwardOp: Operation): OperationResult => {\n      if (forwardOp.key === 1) {\n        return { ...queryResponse, operation: opOne, data: authorsQueryData };\n      } else if (forwardOp.key === 2) {\n        return {\n          ...queryResponse,\n          operation: opMutation,\n          error: 'error' as any,\n          data: { __typename: 'Mutation', addAuthor: null },\n        };\n      }\n\n      return undefined as any;\n    });\n\n    const result = vi.fn();\n    const forward: ExchangeIO = ops$ =>\n      pipe(ops$, delay(1), map(response), share);\n\n    const optimistic = {\n      addAuthor: vi.fn(() => optimisticMutationData.addAuthor) as any,\n    };\n\n    const updates = {\n      Mutation: {\n        addAuthor: vi.fn((data, _, cache) => {\n          cache.updateQuery({ query: authorsQuery }, (prevData: any) => ({\n            ...prevData,\n            authors: [...prevData.authors, data.addAuthor],\n          }));\n        }),\n      },\n    };\n\n    pipe(\n      cacheExchange({ optimistic, updates })({\n        forward,\n        client,\n        dispatchDebug,\n      })(ops$),\n      tap(result),\n      publish\n    );\n\n    next(opOne);\n    vi.runAllTimers();\n    expect(response).toHaveBeenCalledTimes(1);\n\n    next(opMutation);\n    expect(response).toHaveBeenCalledTimes(1);\n    expect(optimistic.addAuthor).toHaveBeenCalledTimes(1);\n    expect(updates.Mutation.addAuthor).toHaveBeenCalledTimes(1);\n    expect(reexec).toHaveBeenCalledTimes(1);\n\n    vi.runAllTimers();\n\n    expect(updates.Mutation.addAuthor).toHaveBeenCalledTimes(2);\n    expect(response).toHaveBeenCalledTimes(2);\n    expect(result).toHaveBeenCalledTimes(4);\n    expect(reexec).toHaveBeenCalledTimes(2);\n\n    next(opOne);\n    vi.runAllTimers();\n    expect(result).toHaveBeenCalledTimes(5);\n  });\n\n  it('does not block subsequent query operations', () => {\n    vi.useFakeTimers();\n\n    const authorsQuery = gql`\n      query {\n        authors {\n          id\n          name\n        }\n      }\n    `;\n\n    const authorsQueryData = {\n      __typename: 'Query',\n      authors: [\n        {\n          __typename: 'Author',\n          id: '123',\n          name: 'Author',\n        },\n      ],\n    };\n\n    const mutation = gql`\n      mutation {\n        deleteAuthor {\n          id\n          name\n        }\n      }\n    `;\n\n    const optimisticMutationData = {\n      __typename: 'Mutation',\n      deleteAuthor: {\n        __typename: 'Author',\n        id: '123',\n        name: '[REDACTED OFFLINE]',\n      },\n    };\n\n    const client = createClient({\n      url: 'http://0.0.0.0',\n      exchanges: [],\n    });\n    const { source: ops$, next } = makeSubject<Operation>();\n\n    const reexec = vi\n      .spyOn(client, 'reexecuteOperation')\n      .mockImplementation(next);\n\n    const opOne = client.createRequestOperation('query', {\n      key: 1,\n      query: authorsQuery,\n      variables: undefined,\n    });\n\n    const opMutation = client.createRequestOperation('mutation', {\n      key: 2,\n      query: mutation,\n      variables: undefined,\n    });\n\n    const response = vi.fn((forwardOp: Operation): OperationResult => {\n      if (forwardOp.key === 1) {\n        return { ...queryResponse, operation: opOne, data: authorsQueryData };\n      } else if (forwardOp.key === 2) {\n        return {\n          ...queryResponse,\n          operation: opMutation,\n          data: {\n            __typename: 'Mutation',\n            deleteAuthor: optimisticMutationData.deleteAuthor,\n          },\n        };\n      }\n\n      return undefined as any;\n    });\n\n    const result = vi.fn();\n    const forward: ExchangeIO = ops$ =>\n      pipe(ops$, delay(1), map(response), share);\n\n    const optimistic = {\n      deleteAuthor: vi.fn(() => optimisticMutationData.deleteAuthor) as any,\n    };\n\n    const updates = {\n      Mutation: {\n        deleteAuthor: vi.fn((_data, _, cache) => {\n          cache.invalidate({\n            __typename: 'Author',\n            id: optimisticMutationData.deleteAuthor.id,\n          });\n        }),\n      },\n    };\n\n    pipe(\n      cacheExchange({ optimistic, updates })({\n        forward,\n        client,\n        dispatchDebug,\n      })(ops$),\n      tap(result),\n      publish\n    );\n\n    next(opOne);\n    vi.runAllTimers();\n    expect(response).toHaveBeenCalledTimes(1);\n    expect(result).toHaveBeenCalledTimes(1);\n\n    next(opMutation);\n    expect(response).toHaveBeenCalledTimes(1);\n    expect(optimistic.deleteAuthor).toHaveBeenCalledTimes(1);\n    expect(updates.Mutation.deleteAuthor).toHaveBeenCalledTimes(1);\n    expect(reexec).toHaveBeenCalledTimes(1);\n    expect(result).toHaveBeenCalledTimes(1);\n\n    vi.runAllTimers();\n\n    expect(updates.Mutation.deleteAuthor).toHaveBeenCalledTimes(2);\n    expect(response).toHaveBeenCalledTimes(2);\n    expect(result).toHaveBeenCalledTimes(2);\n    expect(reexec).toHaveBeenCalledTimes(2);\n    expect(reexec.mock.calls[1][0]).toMatchObject(opOne);\n\n    next(opOne);\n    vi.runAllTimers();\n    expect(result).toHaveBeenCalledTimes(3);\n  });\n});\n\ndescribe('mutation updates', () => {\n  it('invalidates the type when the entity is not present in the cache', () => {\n    vi.useFakeTimers();\n\n    const authorsQuery = gql`\n      query {\n        authors {\n          id\n          name\n        }\n      }\n    `;\n\n    const authorsQueryData = {\n      __typename: 'Query',\n      authors: [\n        {\n          __typename: 'Author',\n          id: '1',\n          name: 'Author',\n        },\n      ],\n    };\n\n    const mutation = gql`\n      mutation {\n        addAuthor {\n          id\n          name\n        }\n      }\n    `;\n\n    const client = createClient({\n      url: 'http://0.0.0.0',\n      exchanges: [],\n    });\n    const { source: ops$, next } = makeSubject<Operation>();\n\n    const reexec = vi\n      .spyOn(client, 'reexecuteOperation')\n      .mockImplementation(next);\n\n    const opOne = client.createRequestOperation('query', {\n      key: 1,\n      query: authorsQuery,\n      variables: undefined,\n    });\n\n    const opMutation = client.createRequestOperation('mutation', {\n      key: 2,\n      query: mutation,\n      variables: undefined,\n    });\n\n    const response = vi.fn((forwardOp: Operation): OperationResult => {\n      if (forwardOp.key === 1) {\n        return { ...queryResponse, operation: opOne, data: authorsQueryData };\n      } else if (forwardOp.key === 2) {\n        return {\n          ...queryResponse,\n          operation: opMutation,\n          data: {\n            __typename: 'Mutation',\n            addAuthor: { id: '2', name: 'Author 2', __typename: 'Author' },\n          },\n        };\n      }\n\n      return undefined as any;\n    });\n\n    const result = vi.fn();\n    const forward: ExchangeIO = ops$ =>\n      pipe(ops$, delay(1), map(response), share);\n\n    pipe(\n      cacheExchange()({\n        forward,\n        client,\n        dispatchDebug,\n      })(ops$),\n      tap(result),\n      publish\n    );\n\n    next(opOne);\n    vi.runAllTimers();\n    expect(response).toHaveBeenCalledTimes(1);\n\n    next(opMutation);\n    expect(response).toHaveBeenCalledTimes(1);\n    expect(reexec).toHaveBeenCalledTimes(0);\n\n    vi.runAllTimers();\n\n    expect(response).toHaveBeenCalledTimes(2);\n    expect(result).toHaveBeenCalledTimes(2);\n    expect(reexec).toHaveBeenCalledTimes(1);\n\n    next(opOne);\n    vi.runAllTimers();\n    expect(response).toHaveBeenCalledTimes(3);\n    expect(result).toHaveBeenCalledTimes(3);\n    expect(result.mock.calls[1][0].data).toEqual({\n      addAuthor: {\n        id: '2',\n        name: 'Author 2',\n      },\n    });\n  });\n});\n\ndescribe('extra variables', () => {\n  it('allows extra variables to be applied to updates', () => {\n    vi.useFakeTimers();\n\n    const mutation = gql`\n      mutation TestMutation($test: Boolean) {\n        test(test: $test) {\n          id\n        }\n      }\n    `;\n\n    const mutationData = {\n      __typename: 'Mutation',\n      test: {\n        __typename: 'Author',\n        id: '123',\n      },\n    };\n\n    const client = createClient({\n      url: 'http://0.0.0.0',\n      exchanges: [],\n    });\n\n    const { source: ops$, next } = makeSubject<Operation>();\n\n    const opQuery = client.createRequestOperation('query', {\n      key: 1,\n      query: queryOne,\n      variables: undefined,\n    });\n\n    const opMutation = client.createRequestOperation('mutation', {\n      key: 2,\n      query: mutation,\n      variables: {\n        test: true,\n        extra: 'extra',\n      },\n    });\n\n    const response = vi.fn((forwardOp: Operation): OperationResult => {\n      if (forwardOp.key === 1) {\n        return { ...queryResponse, operation: forwardOp, data: queryOneData };\n      } else if (forwardOp.key === 2) {\n        return {\n          ...queryResponse,\n          operation: forwardOp,\n          data: mutationData,\n        };\n      }\n\n      return undefined as any;\n    });\n\n    const result = vi.fn();\n    const forward: ExchangeIO = ops$ =>\n      pipe(ops$, delay(3), map(response), share);\n\n    const optimistic = {\n      test: vi.fn() as any,\n    };\n\n    const updates = {\n      Mutation: {\n        test: vi.fn() as any,\n      },\n    };\n\n    pipe(\n      cacheExchange({ optimistic, updates })({\n        forward,\n        client,\n        dispatchDebug,\n      })(ops$),\n      filter(x => x.operation.kind === 'mutation'),\n      tap(result),\n      publish\n    );\n\n    next(opQuery);\n    vi.runAllTimers();\n    expect(response).toHaveBeenCalledTimes(1);\n    expect(result).toHaveBeenCalledTimes(0);\n\n    next(opMutation);\n    vi.advanceTimersByTime(1);\n\n    expect(response).toHaveBeenCalledTimes(1);\n    expect(result).toHaveBeenCalledTimes(0);\n    expect(optimistic.test).toHaveBeenCalledTimes(1);\n\n    expect(optimistic.test.mock.calls[0][2].variables).toEqual({\n      test: true,\n      extra: 'extra',\n    });\n\n    vi.runAllTimers();\n\n    expect(response).toHaveBeenCalledTimes(2);\n    expect(result).toHaveBeenCalledTimes(1);\n    expect(updates.Mutation.test).toHaveBeenCalledTimes(2);\n\n    expect(updates.Mutation.test.mock.calls[1][3].variables).toEqual({\n      test: true,\n      extra: 'extra',\n    });\n  });\n});\n\ndescribe('custom resolvers', () => {\n  it('follows resolvers on initial write', () => {\n    const client = createClient({\n      url: 'http://0.0.0.0',\n      exchanges: [],\n    });\n    const { source: ops$, next } = makeSubject<Operation>();\n\n    const opOne = client.createRequestOperation('query', {\n      key: 1,\n      query: queryOne,\n      variables: undefined,\n    });\n\n    const response = vi.fn((forwardOp: Operation): OperationResult => {\n      if (forwardOp.key === 1) {\n        return { ...queryResponse, operation: opOne, data: queryOneData };\n      }\n\n      return undefined as any;\n    });\n\n    const forward: ExchangeIO = ops$ => pipe(ops$, map(response), share);\n\n    const result = vi.fn();\n    const fakeResolver = vi.fn();\n\n    pipe(\n      cacheExchange({\n        resolvers: {\n          Author: {\n            name: () => {\n              fakeResolver();\n              return 'newName';\n            },\n          },\n        },\n      })({ forward, client, dispatchDebug })(ops$),\n      tap(result),\n      publish\n    );\n\n    next(opOne);\n    expect(response).toHaveBeenCalledTimes(1);\n    expect(fakeResolver).toHaveBeenCalledTimes(1);\n    expect(result).toHaveBeenCalledTimes(1);\n    expect(result.mock.calls[0][0].data).toMatchObject({\n      author: {\n        id: '123',\n        name: 'newName',\n      },\n    });\n  });\n\n  it('follows resolvers for mutations', () => {\n    vi.useFakeTimers();\n\n    const mutation = gql`\n      mutation {\n        concealAuthor {\n          id\n          name\n          __typename\n        }\n      }\n    `;\n\n    const mutationData = {\n      __typename: 'Mutation',\n      concealAuthor: {\n        __typename: 'Author',\n        id: '123',\n        name: '[REDACTED ONLINE]',\n      },\n    };\n\n    const client = createClient({\n      url: 'http://0.0.0.0',\n      exchanges: [],\n    });\n    const { source: ops$, next } = makeSubject<Operation>();\n\n    const opOne = client.createRequestOperation('query', {\n      key: 1,\n      query: queryOne,\n      variables: undefined,\n    });\n\n    const opMutation = client.createRequestOperation('mutation', {\n      key: 2,\n      query: mutation,\n      variables: undefined,\n    });\n\n    const response = vi.fn((forwardOp: Operation): OperationResult => {\n      if (forwardOp.key === 1) {\n        return { ...queryResponse, operation: opOne, data: queryOneData };\n      } else if (forwardOp.key === 2) {\n        return {\n          ...queryResponse,\n          operation: opMutation,\n          data: mutationData,\n        };\n      }\n\n      return undefined as any;\n    });\n\n    const result = vi.fn();\n    const forward: ExchangeIO = ops$ =>\n      pipe(ops$, delay(1), map(response), share);\n\n    const fakeResolver = vi.fn();\n\n    pipe(\n      cacheExchange({\n        resolvers: {\n          Author: {\n            name: () => {\n              fakeResolver();\n              return 'newName';\n            },\n          },\n        },\n      })({ forward, client, dispatchDebug })(ops$),\n      tap(result),\n      publish\n    );\n\n    next(opOne);\n    vi.runAllTimers();\n    expect(response).toHaveBeenCalledTimes(1);\n\n    next(opMutation);\n    expect(response).toHaveBeenCalledTimes(1);\n    expect(fakeResolver).toHaveBeenCalledTimes(1);\n\n    vi.runAllTimers();\n    expect(result.mock.calls[1][0].data).toEqual({\n      concealAuthor: {\n        __typename: 'Author',\n        id: '123',\n        name: 'newName',\n      },\n    });\n  });\n\n  it('follows nested resolvers for mutations', () => {\n    vi.useFakeTimers();\n\n    const mutation = gql`\n      mutation {\n        concealAuthors {\n          id\n          name\n          book {\n            id\n            title\n            __typename\n          }\n          __typename\n        }\n      }\n    `;\n\n    const client = createClient({\n      url: 'http://0.0.0.0',\n      exchanges: [],\n    });\n    const { source: ops$, next } = makeSubject<Operation>();\n\n    const query = gql`\n      query {\n        authors {\n          id\n          name\n          book {\n            id\n            title\n            __typename\n          }\n          __typename\n        }\n      }\n    `;\n\n    const queryOperation = client.createRequestOperation('query', {\n      key: 1,\n      query,\n      variables: undefined,\n    });\n\n    const mutationOperation = client.createRequestOperation('mutation', {\n      key: 2,\n      query: mutation,\n      variables: undefined,\n    });\n\n    const mutationData = {\n      __typename: 'Mutation',\n      concealAuthors: [\n        {\n          __typename: 'Author',\n          id: '123',\n          book: null,\n          name: '[REDACTED ONLINE]',\n        },\n        {\n          __typename: 'Author',\n          id: '456',\n          name: 'Formidable',\n          book: {\n            id: '1',\n            title: 'AwesomeGQL',\n            __typename: 'Book',\n          },\n        },\n      ],\n    };\n\n    const queryData = {\n      __typename: 'Query',\n      authors: [\n        {\n          __typename: 'Author',\n          id: '123',\n          name: '[REDACTED ONLINE]',\n          book: null,\n        },\n        {\n          __typename: 'Author',\n          id: '456',\n          name: 'Formidable',\n          book: {\n            id: '1',\n            title: 'AwesomeGQL',\n            __typename: 'Book',\n          },\n        },\n      ],\n    };\n\n    const response = vi.fn((forwardOp: Operation): OperationResult => {\n      if (forwardOp.key === 1) {\n        return {\n          ...queryResponse,\n          operation: queryOperation,\n          data: queryData,\n        };\n      } else if (forwardOp.key === 2) {\n        return {\n          ...queryResponse,\n          operation: mutationOperation,\n          data: mutationData,\n        };\n      }\n\n      return undefined as any;\n    });\n\n    const result = vi.fn();\n    const forward: ExchangeIO = ops$ =>\n      pipe(ops$, delay(1), map(response), share);\n\n    const fakeResolver = vi.fn();\n    const called: any[] = [];\n\n    pipe(\n      cacheExchange({\n        resolvers: {\n          Query: {\n            // TS-check\n            author: (_parent, args) => ({ __typename: 'Author', id: args.id }),\n          },\n          Author: {\n            name: parent => {\n              called.push(parent.name);\n              fakeResolver();\n              return 'Secret Author';\n            },\n          },\n          Book: {\n            title: parent => {\n              called.push(parent.title);\n              fakeResolver();\n              return 'Secret Book';\n            },\n          },\n        },\n      })({ forward, client, dispatchDebug })(ops$),\n      tap(result),\n      publish\n    );\n\n    next(queryOperation);\n    vi.runAllTimers();\n    expect(response).toHaveBeenCalledTimes(1);\n    expect(fakeResolver).toHaveBeenCalledTimes(3);\n\n    next(mutationOperation);\n    vi.runAllTimers();\n    expect(response).toHaveBeenCalledTimes(2);\n    expect(fakeResolver).toHaveBeenCalledTimes(6);\n    expect(result.mock.calls[1][0].data).toEqual({\n      concealAuthors: [\n        {\n          __typename: 'Author',\n          id: '123',\n          book: null,\n          name: 'Secret Author',\n        },\n        {\n          __typename: 'Author',\n          id: '456',\n          name: 'Secret Author',\n          book: {\n            id: '1',\n            title: 'Secret Book',\n            __typename: 'Book',\n          },\n        },\n      ],\n    });\n\n    expect(called).toEqual([\n      // Query\n      '[REDACTED ONLINE]',\n      'Formidable',\n      'AwesomeGQL',\n      // Mutation\n      '[REDACTED ONLINE]',\n      'Formidable',\n      'AwesomeGQL',\n    ]);\n  });\n});\n\ndescribe('schema awareness', () => {\n  it('reexecutes query and returns data on partial result', () => {\n    vi.useFakeTimers();\n    const client = createClient({\n      url: 'http://0.0.0.0',\n      exchanges: [],\n    });\n    const { source: ops$, next } = makeSubject<Operation>();\n    const reexec = vi\n      .spyOn(client, 'reexecuteOperation')\n      // Empty mock to avoid going in an endless loop, since we would again return\n      // partial data.\n      .mockImplementation(() => undefined);\n\n    const initialQuery = gql`\n      query {\n        todos {\n          id\n          text\n          __typename\n        }\n      }\n    `;\n\n    const query = gql`\n      query {\n        todos {\n          id\n          text\n          complete\n          author {\n            id\n            name\n            __typename\n          }\n          __typename\n        }\n      }\n    `;\n\n    const initialQueryOperation = client.createRequestOperation('query', {\n      key: 1,\n      query: initialQuery,\n      variables: undefined,\n    });\n\n    const queryOperation = client.createRequestOperation('query', {\n      key: 2,\n      query,\n      variables: undefined,\n    });\n\n    const queryData = {\n      __typename: 'Query',\n      todos: [\n        {\n          __typename: 'Todo',\n          id: '123',\n          text: 'Learn',\n        },\n        {\n          __typename: 'Todo',\n          id: '456',\n          text: 'Teach',\n        },\n      ],\n    };\n\n    const response = vi.fn((forwardOp: Operation): OperationResult => {\n      if (forwardOp.key === 1) {\n        return {\n          ...queryResponse,\n          operation: initialQueryOperation,\n          data: queryData,\n        };\n      } else if (forwardOp.key === 2) {\n        return {\n          ...queryResponse,\n          operation: queryOperation,\n          data: queryData,\n        };\n      }\n\n      return undefined as any;\n    });\n\n    const result = vi.fn();\n    const forward: ExchangeIO = ops$ =>\n      pipe(ops$, delay(1), map(response), share);\n\n    pipe(\n      cacheExchange({\n        schema: minifyIntrospectionQuery(\n          // eslint-disable-next-line\n          require('./test-utils/simple_schema.json')\n        ),\n      })({ forward, client, dispatchDebug })(ops$),\n      tap(result),\n      publish\n    );\n\n    next(initialQueryOperation);\n    vi.runAllTimers();\n    expect(response).toHaveBeenCalledTimes(1);\n    expect(reexec).toHaveBeenCalledTimes(0);\n    expect(result.mock.calls[0][0].data).toMatchObject({\n      todos: [\n        {\n          __typename: 'Todo',\n          id: '123',\n          text: 'Learn',\n        },\n        {\n          __typename: 'Todo',\n          id: '456',\n          text: 'Teach',\n        },\n      ],\n    });\n\n    next(queryOperation);\n    vi.runAllTimers();\n    expect(result).toHaveBeenCalledTimes(2);\n    expect(reexec).toHaveBeenCalledTimes(1);\n    expect(result.mock.calls[1][0].stale).toBe(true);\n    expect(result.mock.calls[1][0].data).toEqual({\n      todos: [\n        {\n          __typename: 'Todo',\n          author: null,\n          complete: null,\n          id: '123',\n          text: 'Learn',\n        },\n        {\n          __typename: 'Todo',\n          author: null,\n          complete: null,\n          id: '456',\n          text: 'Teach',\n        },\n      ],\n    });\n\n    expect(result.mock.calls[1][0]).toHaveProperty(\n      'operation.context.meta.cacheOutcome',\n      'partial'\n    );\n  });\n\n  it('reexecutes query and returns data on partial results for nullable lists', () => {\n    vi.useFakeTimers();\n    const client = createClient({\n      url: 'http://0.0.0.0',\n      exchanges: [],\n    });\n    const { source: ops$, next } = makeSubject<Operation>();\n    const reexec = vi\n      .spyOn(client, 'reexecuteOperation')\n      // Empty mock to avoid going in an endless loop, since we would again return\n      // partial data.\n      .mockImplementation(() => undefined);\n\n    const initialQuery = gql`\n      query {\n        todos {\n          id\n          __typename\n        }\n      }\n    `;\n\n    const query = gql`\n      query {\n        todos {\n          id\n          text\n          __typename\n        }\n      }\n    `;\n\n    const initialQueryOperation = client.createRequestOperation('query', {\n      key: 1,\n      query: initialQuery,\n      variables: undefined,\n    });\n\n    const queryOperation = client.createRequestOperation('query', {\n      key: 2,\n      query,\n      variables: undefined,\n    });\n\n    const queryData = {\n      __typename: 'Query',\n      todos: [\n        {\n          __typename: 'Todo',\n          id: '123',\n        },\n        {\n          __typename: 'Todo',\n          id: '456',\n        },\n      ],\n    };\n\n    const response = vi.fn((forwardOp: Operation): OperationResult => {\n      if (forwardOp.key === 1) {\n        return {\n          ...queryResponse,\n          operation: initialQueryOperation,\n          data: queryData,\n        };\n      } else if (forwardOp.key === 2) {\n        return {\n          ...queryResponse,\n          operation: queryOperation,\n          data: queryData,\n        };\n      }\n\n      return undefined as any;\n    });\n\n    const result = vi.fn();\n    const forward: ExchangeIO = ops$ =>\n      pipe(ops$, delay(1), map(response), share);\n\n    pipe(\n      cacheExchange({\n        schema: minifyIntrospectionQuery(\n          // eslint-disable-next-line\n          require('./test-utils/simple_schema.json')\n        ),\n      })({ forward, client, dispatchDebug })(ops$),\n      tap(result),\n      publish\n    );\n\n    next(initialQueryOperation);\n    vi.runAllTimers();\n    expect(response).toHaveBeenCalledTimes(1);\n    expect(reexec).toHaveBeenCalledTimes(0);\n    expect(result.mock.calls[0][0].data).toMatchObject({\n      todos: [\n        {\n          __typename: 'Todo',\n          id: '123',\n        },\n        {\n          __typename: 'Todo',\n          id: '456',\n        },\n      ],\n    });\n\n    next(queryOperation);\n    vi.runAllTimers();\n    expect(result).toHaveBeenCalledTimes(2);\n    expect(reexec).toHaveBeenCalledTimes(1);\n    expect(result.mock.calls[1][0].stale).toBe(true);\n    expect(result.mock.calls[1][0].data).toEqual({\n      todos: [null, null],\n    });\n\n    expect(result.mock.calls[1][0]).toHaveProperty(\n      'operation.context.meta.cacheOutcome',\n      'partial'\n    );\n  });\n});\n\ndescribe('looping protection', () => {\n  it('applies stale to blocked looping queries', () => {\n    let normalData: OperationResult | undefined;\n    let extendedData: OperationResult | undefined;\n\n    const client = createClient({\n      url: 'http://0.0.0.0',\n      exchanges: [],\n    });\n\n    const { source: ops$, next: nextOp } = makeSubject<Operation>();\n    const { source: res$, next: nextRes } = makeSubject<OperationResult>();\n\n    vi.spyOn(client, 'reexecuteOperation').mockImplementation(nextOp);\n\n    const normalQuery = gql`\n      {\n        __typename\n        item {\n          __typename\n          id\n        }\n      }\n    `;\n\n    const extendedQuery = gql`\n      {\n        __typename\n        item {\n          __typename\n          extended: id\n          extra @_optional\n        }\n      }\n    `;\n\n    const forward = (ops$: Source<Operation>): Source<OperationResult> =>\n      share(\n        merge([\n          pipe(\n            ops$,\n            filter(() => false)\n          ) as any,\n          res$,\n        ])\n      );\n\n    pipe(\n      cacheExchange()({ forward, client, dispatchDebug })(ops$),\n      tap(result => {\n        if (result.operation.kind === 'query') {\n          if (result.operation.key === 1) {\n            normalData = result;\n          } else if (result.operation.key === 2) {\n            extendedData = result;\n          }\n        }\n      }),\n      publish\n    );\n\n    const normalOp = client.createRequestOperation(\n      'query',\n      {\n        key: 1,\n        query: normalQuery,\n        variables: undefined,\n      },\n      {\n        requestPolicy: 'cache-first',\n      }\n    );\n\n    const extendedOp = client.createRequestOperation(\n      'query',\n      {\n        key: 2,\n        query: extendedQuery,\n        variables: undefined,\n      },\n      {\n        requestPolicy: 'cache-first',\n      }\n    );\n\n    nextOp(normalOp);\n\n    nextRes({\n      operation: normalOp,\n      data: {\n        __typename: 'Query',\n        item: {\n          __typename: 'Node',\n          id: 'id',\n        },\n      },\n      stale: false,\n      hasNext: false,\n    });\n\n    expect(normalData).toMatchObject({ stale: false });\n    expect(client.reexecuteOperation).toHaveBeenCalledTimes(0);\n\n    nextOp(extendedOp);\n\n    expect(extendedData).toMatchObject({ stale: true });\n    expect(client.reexecuteOperation).toHaveBeenCalledTimes(1);\n\n    // Out of band re-execute first operation\n    nextOp(normalOp);\n    nextRes({\n      ...queryResponse,\n      operation: normalOp,\n      data: {\n        __typename: 'Query',\n        item: {\n          __typename: 'Node',\n          id: 'id',\n        },\n      },\n    });\n\n    expect(normalData).toMatchObject({ stale: false });\n    expect(extendedData).toMatchObject({ stale: true });\n    expect(client.reexecuteOperation).toHaveBeenCalledTimes(3);\n\n    nextOp(extendedOp);\n\n    expect(normalData).toMatchObject({ stale: false });\n    expect(extendedData).toMatchObject({ stale: true });\n    expect(client.reexecuteOperation).toHaveBeenCalledTimes(3);\n\n    nextRes({\n      ...queryResponse,\n      operation: extendedOp,\n      data: {\n        __typename: 'Query',\n        item: {\n          __typename: 'Node',\n          extended: 'id',\n          extra: 'extra',\n        },\n      },\n    });\n\n    expect(extendedData).toMatchObject({ stale: false });\n    expect(client.reexecuteOperation).toHaveBeenCalledTimes(4);\n  });\n});\n\ndescribe('commutativity', () => {\n  it('applies results that come in out-of-order commutatively and consistently', () => {\n    vi.useFakeTimers();\n\n    let data: any;\n\n    const client = createClient({\n      url: 'http://0.0.0.0',\n      requestPolicy: 'cache-and-network',\n      exchanges: [],\n    });\n    const { source: ops$, next: next } = makeSubject<Operation>();\n    const query = gql`\n      {\n        index\n      }\n    `;\n\n    const result = (operation: Operation): Source<OperationResult> =>\n      pipe(\n        fromValue({\n          ...queryResponse,\n          operation,\n          data: {\n            __typename: 'Query',\n            index: operation.key,\n          },\n        }),\n        delay(operation.key === 2 ? 5 : operation.key * 10)\n      );\n\n    const output = vi.fn(result => {\n      data = result.data;\n    });\n\n    const forward = (ops$: Source<Operation>): Source<OperationResult> =>\n      pipe(\n        ops$,\n        filter(op => op.kind !== 'teardown'),\n        mergeMap(result)\n      );\n\n    pipe(\n      cacheExchange()({ forward, client, dispatchDebug })(ops$),\n      tap(output),\n      publish\n    );\n\n    next(\n      client.createRequestOperation('query', {\n        key: 1,\n        query,\n        variables: undefined,\n      })\n    );\n\n    next(\n      client.createRequestOperation('query', {\n        key: 2,\n        query,\n        variables: undefined,\n      })\n    );\n\n    // This shouldn't have any effect:\n    next(\n      client.createRequestOperation('teardown', {\n        key: 2,\n        query,\n        variables: undefined,\n      })\n    );\n\n    next(\n      client.createRequestOperation('query', {\n        key: 3,\n        query,\n        variables: undefined,\n      })\n    );\n\n    vi.advanceTimersByTime(5);\n    expect(output).toHaveBeenCalledTimes(1);\n    expect(data.index).toBe(2);\n\n    vi.advanceTimersByTime(10);\n    expect(output).toHaveBeenCalledTimes(2);\n    expect(data.index).toBe(2);\n\n    vi.advanceTimersByTime(30);\n    expect(output).toHaveBeenCalledTimes(3);\n    expect(data.index).toBe(3);\n  });\n\n  it('applies optimistic updates on top of commutative queries as query result comes in', () => {\n    let data: any;\n    const client = createClient({\n      url: 'http://0.0.0.0',\n      exchanges: [],\n    });\n    const { source: ops$, next: nextOp } = makeSubject<Operation>();\n    const { source: res$, next: nextRes } = makeSubject<OperationResult>();\n\n    const reexec = vi\n      .spyOn(client, 'reexecuteOperation')\n      .mockImplementation(nextOp);\n\n    const query = gql`\n      {\n        node {\n          id\n          name\n        }\n      }\n    `;\n\n    const mutation = gql`\n      mutation {\n        node {\n          id\n          name\n        }\n      }\n    `;\n\n    const forward = (ops$: Source<Operation>): Source<OperationResult> =>\n      share(\n        merge([\n          pipe(\n            ops$,\n            filter(() => false)\n          ) as any,\n          res$,\n        ])\n      );\n\n    const optimistic = {\n      node: () => ({\n        __typename: 'Node',\n        id: 'node',\n        name: 'optimistic',\n      }),\n    };\n\n    pipe(\n      cacheExchange({ optimistic })({ forward, client, dispatchDebug })(ops$),\n      tap(result => {\n        if (result.operation.kind === 'query') {\n          data = result.data;\n        }\n      }),\n      publish\n    );\n\n    const queryOpA = client.createRequestOperation('query', {\n      key: 1,\n      query,\n      variables: undefined,\n    });\n\n    const mutationOp = client.createRequestOperation('mutation', {\n      key: 2,\n      query: mutation,\n      variables: undefined,\n    });\n\n    expect(data).toBe(undefined);\n\n    nextOp(queryOpA);\n\n    nextRes({\n      ...queryResponse,\n      operation: queryOpA,\n      data: {\n        __typename: 'Query',\n        node: {\n          __typename: 'Node',\n          id: 'node',\n          name: 'query a',\n        },\n      },\n    });\n\n    expect(data).toHaveProperty('node.name', 'query a');\n\n    nextOp(mutationOp);\n    expect(reexec).toHaveBeenCalledTimes(1);\n    expect(data).toHaveProperty('node.name', 'optimistic');\n  });\n\n  it('applies mutation results on top of commutative queries', () => {\n    let data: any;\n    const client = createClient({\n      url: 'http://0.0.0.0',\n      exchanges: [],\n    });\n    const { source: ops$, next: nextOp } = makeSubject<Operation>();\n    const { source: res$, next: nextRes } = makeSubject<OperationResult>();\n\n    const reexec = vi\n      .spyOn(client, 'reexecuteOperation')\n      .mockImplementation(nextOp);\n\n    const query = gql`\n      {\n        node {\n          id\n          name\n        }\n      }\n    `;\n\n    const mutation = gql`\n      mutation {\n        node {\n          id\n          name\n        }\n      }\n    `;\n\n    const forward = (ops$: Source<Operation>): Source<OperationResult> =>\n      share(\n        merge([\n          pipe(\n            ops$,\n            filter(() => false)\n          ) as any,\n          res$,\n        ])\n      );\n\n    pipe(\n      cacheExchange()({ forward, client, dispatchDebug })(ops$),\n      tap(result => {\n        if (result.operation.kind === 'query') {\n          data = result.data;\n        }\n      }),\n      publish\n    );\n\n    const queryOpA = client.createRequestOperation('query', {\n      key: 1,\n      query,\n      variables: undefined,\n    });\n\n    const mutationOp = client.createRequestOperation('mutation', {\n      key: 2,\n      query: mutation,\n      variables: undefined,\n    });\n\n    const queryOpB = client.createRequestOperation('query', {\n      key: 3,\n      query,\n      variables: undefined,\n    });\n\n    expect(data).toBe(undefined);\n\n    nextOp(queryOpA);\n    nextOp(mutationOp);\n    nextOp(queryOpB);\n\n    nextRes({\n      ...queryResponse,\n      operation: queryOpA,\n      data: {\n        __typename: 'Query',\n        node: {\n          __typename: 'Node',\n          id: 'node',\n          name: 'query a',\n        },\n      },\n    });\n\n    expect(data).toHaveProperty('node.name', 'query a');\n\n    nextRes({\n      ...queryResponse,\n      operation: mutationOp,\n      data: {\n        __typename: 'Mutation',\n        node: {\n          __typename: 'Node',\n          id: 'node',\n          name: 'mutation',\n        },\n      },\n    });\n\n    expect(reexec).toHaveBeenCalledTimes(3);\n    expect(data).toHaveProperty('node.name', 'mutation');\n\n    nextRes({\n      ...queryResponse,\n      operation: queryOpB,\n      data: {\n        __typename: 'Query',\n        node: {\n          __typename: 'Node',\n          id: 'node',\n          name: 'query b',\n        },\n      },\n    });\n\n    expect(reexec).toHaveBeenCalledTimes(4);\n    expect(data).toHaveProperty('node.name', 'mutation');\n  });\n\n  it('applies optimistic updates on top of commutative queries until mutation resolves', () => {\n    let data: any;\n    const client = createClient({\n      url: 'http://0.0.0.0',\n      exchanges: [],\n    });\n    const { source: ops$, next: nextOp } = makeSubject<Operation>();\n    const { source: res$, next: nextRes } = makeSubject<OperationResult>();\n\n    vi.spyOn(client, 'reexecuteOperation').mockImplementation(nextOp);\n\n    const query = gql`\n      {\n        node {\n          id\n          name\n        }\n      }\n    `;\n\n    const mutation = gql`\n      mutation {\n        node {\n          id\n          name\n          optimistic\n        }\n      }\n    `;\n\n    const forward = (ops$: Source<Operation>): Source<OperationResult> =>\n      share(\n        merge([\n          pipe(\n            ops$,\n            filter(() => false)\n          ) as any,\n          res$,\n        ])\n      );\n\n    const optimistic = {\n      node: () => ({\n        __typename: 'Node',\n        id: 'node',\n        name: 'optimistic',\n      }),\n    };\n\n    pipe(\n      cacheExchange({ optimistic })({ forward, client, dispatchDebug })(ops$),\n      tap(result => {\n        if (result.operation.kind === 'query') {\n          data = result.data;\n        }\n      }),\n      publish\n    );\n\n    const queryOp = client.createRequestOperation('query', {\n      key: 1,\n      query,\n      variables: undefined,\n    });\n    const mutationOp = client.createRequestOperation('mutation', {\n      key: 2,\n      query: mutation,\n      variables: undefined,\n    });\n\n    expect(data).toBe(undefined);\n\n    nextOp(queryOp);\n    nextOp(mutationOp);\n\n    nextRes({\n      ...queryResponse,\n      operation: queryOp,\n      data: {\n        __typename: 'Query',\n        node: {\n          __typename: 'Node',\n          id: 'node',\n          name: 'query a',\n        },\n      },\n    });\n\n    expect(data).toHaveProperty('node.name', 'optimistic');\n\n    nextRes({\n      ...queryResponse,\n      operation: mutationOp,\n      data: {\n        __typename: 'Query',\n        node: {\n          __typename: 'Node',\n          id: 'node',\n          name: 'mutation',\n        },\n      },\n    });\n\n    expect(data).toHaveProperty('node.name', 'mutation');\n  });\n\n  it('allows subscription results to be commutative when necessary', () => {\n    let data: any;\n    const client = createClient({\n      url: 'http://0.0.0.0',\n      exchanges: [],\n    });\n    const { source: ops$, next: nextOp } = makeSubject<Operation>();\n    const { source: res$, next: nextRes } = makeSubject<OperationResult>();\n\n    vi.spyOn(client, 'reexecuteOperation').mockImplementation(nextOp);\n\n    const query = gql`\n      {\n        node {\n          id\n          name\n        }\n      }\n    `;\n\n    const subscription = gql`\n      subscription {\n        node {\n          id\n          name\n        }\n      }\n    `;\n\n    const forward = (ops$: Source<Operation>): Source<OperationResult> =>\n      share(\n        merge([\n          pipe(\n            ops$,\n            filter(() => false)\n          ) as any,\n          res$,\n        ])\n      );\n\n    pipe(\n      cacheExchange()({ forward, client, dispatchDebug })(ops$),\n      tap(result => {\n        if (result.operation.kind === 'query') {\n          data = result.data;\n        }\n      }),\n      publish\n    );\n\n    const queryOpA = client.createRequestOperation('query', {\n      key: 1,\n      query,\n      variables: undefined,\n    });\n\n    const subscriptionOp = client.createRequestOperation('subscription', {\n      key: 3,\n      query: subscription,\n      variables: undefined,\n    });\n\n    nextOp(queryOpA);\n    // Force commutative layers to be created:\n    nextOp(\n      client.createRequestOperation('query', {\n        key: 2,\n        query,\n        variables: undefined,\n      })\n    );\n\n    nextOp(subscriptionOp);\n\n    nextRes({\n      ...queryResponse,\n      operation: queryOpA,\n      data: {\n        __typename: 'Query',\n        node: {\n          __typename: 'Node',\n          id: 'node',\n          name: 'query a',\n        },\n      },\n    });\n\n    nextRes({\n      ...queryResponse,\n      operation: subscriptionOp,\n      data: {\n        node: {\n          __typename: 'Node',\n          id: 'node',\n          name: 'subscription',\n        },\n      },\n    });\n\n    expect(data).toHaveProperty('node.name', 'subscription');\n  });\n\n  it('allows subscription results to be commutative above mutations', () => {\n    let data: any;\n    const client = createClient({\n      url: 'http://0.0.0.0',\n      exchanges: [],\n    });\n    const { source: ops$, next: nextOp } = makeSubject<Operation>();\n    const { source: res$, next: nextRes } = makeSubject<OperationResult>();\n\n    vi.spyOn(client, 'reexecuteOperation').mockImplementation(nextOp);\n\n    const query = gql`\n      {\n        node {\n          id\n          name\n        }\n      }\n    `;\n\n    const subscription = gql`\n      subscription {\n        node {\n          id\n          name\n        }\n      }\n    `;\n\n    const mutation = gql`\n      mutation {\n        node {\n          id\n          name\n        }\n      }\n    `;\n\n    const forward = (ops$: Source<Operation>): Source<OperationResult> =>\n      share(\n        merge([\n          pipe(\n            ops$,\n            filter(() => false)\n          ) as any,\n          res$,\n        ])\n      );\n\n    pipe(\n      cacheExchange()({ forward, client, dispatchDebug })(ops$),\n      tap(result => {\n        if (result.operation.kind === 'query') {\n          data = result.data;\n        }\n      }),\n      publish\n    );\n\n    const queryOpA = client.createRequestOperation('query', {\n      key: 1,\n      query,\n      variables: undefined,\n    });\n\n    const subscriptionOp = client.createRequestOperation('subscription', {\n      key: 2,\n      query: subscription,\n      variables: undefined,\n    });\n\n    const mutationOp = client.createRequestOperation('mutation', {\n      key: 3,\n      query: mutation,\n      variables: undefined,\n    });\n\n    nextOp(queryOpA);\n    // Force commutative layers to be created:\n    nextOp(\n      client.createRequestOperation('query', {\n        key: 2,\n        query,\n        variables: undefined,\n      })\n    );\n\n    nextOp(subscriptionOp);\n\n    nextRes({\n      ...queryResponse,\n      operation: queryOpA,\n      data: {\n        __typename: 'Query',\n        node: {\n          __typename: 'Node',\n          id: 'node',\n          name: 'query a',\n        },\n      },\n    });\n\n    nextOp(mutationOp);\n\n    nextRes({\n      ...queryResponse,\n      operation: mutationOp,\n      data: {\n        node: {\n          __typename: 'Node',\n          id: 'node',\n          name: 'mutation',\n        },\n      },\n    });\n\n    nextRes({\n      ...queryResponse,\n      operation: subscriptionOp,\n      data: {\n        node: {\n          __typename: 'Node',\n          id: 'node',\n          name: 'subscription a',\n        },\n      },\n    });\n\n    nextRes({\n      ...queryResponse,\n      operation: subscriptionOp,\n      data: {\n        node: {\n          __typename: 'Node',\n          id: 'node',\n          name: 'subscription b',\n        },\n      },\n    });\n\n    expect(data).toHaveProperty('node.name', 'subscription b');\n  });\n\n  it('applies deferred results to previous layers', () => {\n    let normalData: OperationResult | undefined;\n    let deferredData: OperationResult | undefined;\n    let combinedData: OperationResult | undefined;\n\n    const client = createClient({\n      url: 'http://0.0.0.0',\n      exchanges: [],\n    });\n    const { source: ops$, next: nextOp } = makeSubject<Operation>();\n    const { source: res$, next: nextRes } = makeSubject<OperationResult>();\n    client.reexecuteOperation = nextOp;\n\n    const normalQuery = gql`\n      {\n        node {\n          id\n          name\n        }\n      }\n    `;\n\n    const deferredQuery = gql`\n      {\n        ... @defer {\n          deferred {\n            id\n            name\n          }\n        }\n      }\n    `;\n\n    const combinedQuery = gql`\n      {\n        node {\n          id\n          name\n        }\n        ... @defer {\n          deferred {\n            id\n            name\n          }\n        }\n      }\n    `;\n\n    const forward = (operations$: Source<Operation>): Source<OperationResult> =>\n      share(\n        merge([\n          pipe(\n            operations$,\n            filter(() => false)\n          ) as any,\n          res$,\n        ])\n      );\n\n    pipe(\n      cacheExchange()({ forward, client, dispatchDebug })(ops$),\n      tap(result => {\n        if (result.operation.kind === 'query') {\n          if (result.operation.key === 1) {\n            deferredData = result;\n          } else if (result.operation.key === 42) {\n            combinedData = result;\n          } else {\n            normalData = result;\n          }\n        }\n      }),\n      publish\n    );\n\n    const combinedOp = client.createRequestOperation('query', {\n      key: 42,\n      query: combinedQuery,\n      variables: undefined,\n    });\n    const deferredOp = client.createRequestOperation('query', {\n      key: 1,\n      query: deferredQuery,\n      variables: undefined,\n    });\n    const normalOp = client.createRequestOperation('query', {\n      key: 2,\n      query: normalQuery,\n      variables: undefined,\n    });\n\n    nextOp(combinedOp);\n    nextOp(deferredOp);\n    nextOp(normalOp);\n\n    nextRes({\n      ...queryResponse,\n      operation: deferredOp,\n      data: {\n        __typename: 'Query',\n      },\n      hasNext: true,\n    });\n\n    expect(deferredData).not.toHaveProperty('deferred');\n\n    nextRes({\n      ...queryResponse,\n      operation: normalOp,\n      data: {\n        __typename: 'Query',\n        node: {\n          __typename: 'Node',\n          id: 2,\n          name: 'normal',\n        },\n      },\n    });\n\n    expect(normalData).toHaveProperty('data.node.id', 2);\n    expect(combinedData).not.toHaveProperty('data.deferred');\n    expect(combinedData).toHaveProperty('data.node.id', 2);\n\n    nextRes({\n      ...queryResponse,\n      operation: deferredOp,\n      data: {\n        __typename: 'Query',\n        deferred: {\n          __typename: 'Node',\n          id: 1,\n          name: 'deferred',\n        },\n      },\n      hasNext: true,\n    });\n\n    expect(deferredData).toHaveProperty('hasNext', true);\n    expect(deferredData).toHaveProperty('data.deferred.id', 1);\n\n    expect(combinedData).toHaveProperty('hasNext', false);\n    expect(combinedData).toHaveProperty('data.deferred.id', 1);\n    expect(combinedData).toHaveProperty('data.node.id', 2);\n  });\n\n  it('applies deferred logic only to deferred operations', () => {\n    let failingData: OperationResult | undefined;\n\n    const client = createClient({\n      url: 'http://0.0.0.0',\n      exchanges: [],\n    });\n\n    const { source: ops$, next: nextOp } = makeSubject<Operation>();\n    const { source: res$ } = makeSubject<OperationResult>();\n\n    const deferredQuery = gql`\n      {\n        ... @defer {\n          deferred {\n            id\n            name\n          }\n        }\n      }\n    `;\n\n    const failingQuery = gql`\n      {\n        deferred {\n          id\n          name\n        }\n      }\n    `;\n\n    const forward = (ops$: Source<Operation>): Source<OperationResult> =>\n      share(\n        merge([\n          pipe(\n            ops$,\n            filter(() => false)\n          ) as any,\n          res$,\n        ])\n      );\n\n    pipe(\n      cacheExchange()({ forward, client, dispatchDebug })(ops$),\n      tap(result => {\n        if (result.operation.kind === 'query') {\n          if (result.operation.key === 1) {\n            failingData = result;\n          }\n        }\n      }),\n      publish\n    );\n\n    const failingOp = client.createRequestOperation('query', {\n      key: 1,\n      query: failingQuery,\n      variables: undefined,\n    });\n    const deferredOp = client.createRequestOperation('query', {\n      key: 2,\n      query: deferredQuery,\n      variables: undefined,\n    });\n\n    nextOp(deferredOp);\n    nextOp(failingOp);\n\n    expect(failingData).not.toMatchObject({ hasNext: true });\n  });\n});\n\ndescribe('abstract types', () => {\n  it('works with two responses giving different concrete types for a union', () => {\n    const query = gql`\n      query ($id: ID!) {\n        field(id: $id) {\n          id\n          union {\n            ... on Type1 {\n              id\n              name\n              __typename\n            }\n            ... on Type2 {\n              id\n              title\n              __typename\n            }\n          }\n          __typename\n        }\n      }\n    `;\n    const client = createClient({\n      url: 'http://0.0.0.0',\n      exchanges: [],\n    });\n    const { source: ops$, next } = makeSubject<Operation>();\n    const operation1 = client.createRequestOperation('query', {\n      key: 1,\n      query,\n      variables: { id: '1' },\n    });\n    const operation2 = client.createRequestOperation('query', {\n      key: 2,\n      query,\n      variables: { id: '2' },\n    });\n    const queryResult1: OperationResult = {\n      ...queryResponse,\n      operation: operation1,\n      data: {\n        __typename: 'Query',\n        field: {\n          id: '1',\n          __typename: 'Todo',\n          union: {\n            id: '1',\n            name: 'test',\n            __typename: 'Type1',\n          },\n        },\n      },\n    };\n\n    const queryResult2: OperationResult = {\n      ...queryResponse,\n      operation: operation2,\n      data: {\n        __typename: 'Query',\n        field: {\n          id: '2',\n          __typename: 'Todo',\n          union: {\n            id: '2',\n            title: 'test',\n            __typename: 'Type2',\n          },\n        },\n      },\n    };\n\n    vi.spyOn(client, 'reexecuteOperation').mockImplementation(next);\n    const response = vi.fn((forwardOp: Operation): OperationResult => {\n      if (forwardOp.key === 1) return queryResult1;\n      if (forwardOp.key === 2) return queryResult2;\n      return undefined as any;\n    });\n\n    const result = vi.fn();\n    const forward: ExchangeIO = ops$ => pipe(ops$, map(response), share);\n\n    pipe(\n      cacheExchange({})({ forward, client, dispatchDebug })(ops$),\n      tap(result),\n      publish\n    );\n\n    next(operation1);\n    expect(response).toHaveBeenCalledTimes(1);\n    expect(result).toHaveBeenCalledTimes(1);\n    expect(result.mock.calls[0][0].data).toEqual({\n      field: {\n        __typename: 'Todo',\n        id: '1',\n        union: {\n          __typename: 'Type1',\n          id: '1',\n          name: 'test',\n        },\n      },\n    });\n\n    next(operation2);\n    expect(response).toHaveBeenCalledTimes(2);\n    expect(result).toHaveBeenCalledTimes(2);\n    expect(result.mock.calls[1][0].data).toEqual({\n      field: {\n        __typename: 'Todo',\n        id: '2',\n        union: {\n          __typename: 'Type2',\n          id: '2',\n          title: 'test',\n        },\n      },\n    });\n  });\n});\n"
  },
  {
    "path": "exchanges/graphcache/src/cacheExchange.ts",
    "content": "import type {\n  Exchange,\n  Operation,\n  OperationResult,\n  RequestPolicy,\n  CacheOutcome,\n} from '@urql/core';\nimport { formatDocument, makeOperation } from '@urql/core';\n\nimport type { Source } from 'wonka';\nimport {\n  filter,\n  map,\n  merge,\n  pipe,\n  share,\n  fromArray,\n  mergeMap,\n  empty,\n} from 'wonka';\n\nimport { _query } from './operations/query';\nimport { _write } from './operations/write';\nimport { addMetadata, toRequestPolicy } from './helpers/operation';\nimport { filterVariables, getMainOperation } from './ast';\nimport { Store } from './store/store';\nimport type { Data, Dependencies, CacheExchangeOpts } from './types';\n\nimport {\n  initDataState,\n  clearDataState,\n  noopDataState,\n  hydrateData,\n  reserveLayer,\n  hasLayer,\n} from './store/data';\n\ninterface OperationResultWithMeta extends Partial<OperationResult> {\n  operation: Operation;\n  outcome: CacheOutcome;\n  dependencies: Dependencies;\n  hasNext: boolean;\n}\n\ntype Operations = Set<number>;\ntype OperationMap = Map<number, Operation>;\ntype ResultMap = Map<number, Data | null>;\ntype OptimisticDependencies = Map<number, Dependencies>;\ntype DependentOperations = Map<string, Operations>;\n\n/** Exchange factory that creates a normalized cache exchange.\n *\n * @param opts - A {@link CacheExchangeOpts} configuration object.\n * @returns the created normalized cache {@link Exchange}.\n *\n * @remarks\n * Graphcache is a normalized cache, enabled by using the `cacheExchange`\n * in place of `@urql/core`’s. A normalized GraphQL cache uses typenames\n * and key fields in the result to share a single copy for each unique\n * entity across all queries.\n *\n * The `cacheExchange` may be passed a {@link CacheExchangeOpts} object\n * to define custom resolvers, custom updates for mutations,\n * optimistic updates, or to add custom key fields per type.\n *\n * @see {@link https://urql.dev/goto/docs/graphcache} for the full Graphcache docs.\n */\nexport const cacheExchange =\n  <C extends Partial<CacheExchangeOpts>>(opts?: C): Exchange =>\n  ({ forward, client, dispatchDebug }) => {\n    const store = new Store<C>(opts);\n\n    if (opts && opts.storage) {\n      store.data.hydrating = true;\n      opts.storage.readData().then(entries => {\n        hydrateData(store.data, opts!.storage!, entries);\n        if (opts.storage!.onCacheHydrated) opts.storage!.onCacheHydrated();\n      });\n    }\n\n    const optimisticKeysToDependencies: OptimisticDependencies = new Map();\n    const mutationResultBuffer: OperationResult[] = [];\n    const operations: OperationMap = new Map();\n    const results: ResultMap = new Map();\n    const blockedDependencies: Dependencies = new Set();\n    const requestedRefetch: Operations = new Set();\n    const deps: DependentOperations = new Map();\n\n    let reexecutingOperations: Operations = new Set();\n    let dependentOperations: Operations = new Set();\n\n    const isBlockedByOptimisticUpdate = (\n      dependencies: Dependencies\n    ): boolean => {\n      for (const dep of dependencies.values())\n        if (blockedDependencies.has(dep)) return true;\n      return false;\n    };\n\n    const collectPendingOperations = (\n      pendingOperations: Operations,\n      dependencies: undefined | Dependencies\n    ) => {\n      if (dependencies) {\n        // Collect operations that will be updated due to cache changes\n        for (const dep of dependencies.values()) {\n          const keys = deps.get(dep);\n          if (keys) for (const key of keys.values()) pendingOperations.add(key);\n        }\n      }\n    };\n\n    const executePendingOperations = (\n      operation: Operation,\n      pendingOperations: Operations,\n      isOptimistic: boolean\n    ) => {\n      // Reexecute collected operations and delete them from the mapping\n      for (const key of pendingOperations.values()) {\n        if (key !== operation.key) {\n          const op = operations.get(key);\n          if (op) {\n            // Collect all dependent operations if the reexecuting operation is a query\n            if (operation.kind === 'query') dependentOperations.add(key);\n            let policy: RequestPolicy = 'cache-first';\n            if (requestedRefetch.has(key)) {\n              requestedRefetch.delete(key);\n              policy = 'cache-and-network';\n            }\n            client.reexecuteOperation(toRequestPolicy(op, policy));\n          }\n        }\n      }\n\n      if (!isOptimistic) {\n        // Upon completion, all dependent operations become reexecuting operations, preventing\n        // them from reexecuting prior operations again, causing infinite loops\n        const _reexecutingOperations = reexecutingOperations;\n        reexecutingOperations = dependentOperations;\n        if (operation.kind === 'query') {\n          reexecutingOperations.add(operation.key);\n        }\n        (dependentOperations = _reexecutingOperations).clear();\n      }\n    };\n\n    // This registers queries with the data layer to ensure commutativity\n    const prepareForwardedOperation = (operation: Operation) => {\n      let optimistic = false;\n      if (operation.kind === 'query') {\n        // Pre-reserve the position of the result layer\n        reserveLayer(store.data, operation.key);\n        operations.set(operation.key, operation);\n      } else if (operation.kind === 'teardown') {\n        // Delete reference to operation if any exists to release it\n        operations.delete(operation.key);\n        results.delete(operation.key);\n        reexecutingOperations.delete(operation.key);\n        // Mark operation layer as done\n        noopDataState(store.data, operation.key);\n        return operation;\n      } else if (\n        operation.kind === 'mutation' &&\n        operation.context.requestPolicy !== 'network-only'\n      ) {\n        operations.set(operation.key, operation);\n        // This executes an optimistic update for mutations and registers it if necessary\n        initDataState('write', store.data, operation.key, true, false);\n        const { dependencies } = _write(\n          store,\n          operation as any,\n          undefined,\n          undefined\n        );\n        clearDataState();\n        if (dependencies.size) {\n          // Update blocked optimistic dependencies\n          for (const dep of dependencies.values()) blockedDependencies.add(dep);\n          // Store optimistic dependencies for update\n          optimisticKeysToDependencies.set(operation.key, dependencies);\n          // Update related queries\n          const pendingOperations: Operations = new Set();\n          collectPendingOperations(pendingOperations, dependencies);\n          executePendingOperations(operation, pendingOperations, true);\n          // Mark operation as optimistic\n          optimistic = true;\n        }\n      }\n\n      return makeOperation(\n        operation.kind,\n        {\n          key: operation.key,\n          query: formatDocument(operation.query),\n          variables: operation.variables\n            ? filterVariables(\n                getMainOperation(operation.query),\n                operation.variables\n              )\n            : operation.variables,\n        },\n        { ...operation.context, optimistic }\n      );\n    };\n\n    // This updates the known dependencies for the passed operation\n    const updateDependencies = (op: Operation, dependencies: Dependencies) => {\n      for (const dep of dependencies.values()) {\n        let depOps = deps.get(dep);\n        if (!depOps) deps.set(dep, (depOps = new Set()));\n        depOps.add(op.key);\n      }\n    };\n\n    // Retrieves a query result from cache and adds an `isComplete` hint\n    // This hint indicates whether the result is \"complete\" or not\n    const operationResultFromCache = (\n      operation: Operation\n    ): OperationResultWithMeta => {\n      initDataState('read', store.data, undefined, false, false);\n      const result = _query(\n        store,\n        operation,\n        results.get(operation.key),\n        undefined\n      );\n      clearDataState();\n      const cacheOutcome: CacheOutcome = result.data\n        ? !result.partial && !result.hasNext\n          ? 'hit'\n          : 'partial'\n        : 'miss';\n\n      results.set(operation.key, result.data);\n      operations.set(operation.key, operation);\n      updateDependencies(operation, result.dependencies);\n\n      return {\n        outcome: cacheOutcome,\n        operation,\n        data: result.data,\n        dependencies: result.dependencies,\n        hasNext: result.hasNext,\n      };\n    };\n\n    // Take any OperationResult and update the cache with it\n    const updateCacheWithResult = (\n      result: OperationResult,\n      pendingOperations: Operations\n    ): OperationResult => {\n      // Retrieve the original operation to get unfiltered variables\n      const operation =\n        operations.get(result.operation.key) || result.operation;\n      if (operation.kind === 'mutation') {\n        // Collect previous dependencies that have been written for optimistic updates\n        const dependencies = optimisticKeysToDependencies.get(operation.key);\n        collectPendingOperations(pendingOperations, dependencies);\n        optimisticKeysToDependencies.delete(operation.key);\n      }\n\n      if (operation.kind === 'subscription' || result.hasNext)\n        reserveLayer(store.data, operation.key, true);\n\n      let queryDependencies: undefined | Dependencies;\n      let data: Data | null = result.data;\n      if (data) {\n        // Write the result to cache and collect all dependencies that need to be\n        // updated\n        initDataState('write', store.data, operation.key, false, false);\n        const writeDependencies = _write(\n          store,\n          operation,\n          data,\n          result.error\n        ).dependencies;\n        clearDataState();\n        collectPendingOperations(pendingOperations, writeDependencies);\n        const prevData =\n          operation.kind === 'query' ? results.get(operation.key) : null;\n        initDataState(\n          'read',\n          store.data,\n          operation.key,\n          false,\n          prevData !== data\n        );\n        const queryResult = _query(\n          store,\n          operation,\n          prevData || data,\n          result.error\n        );\n        clearDataState();\n        data = queryResult.data;\n        if (operation.kind === 'query') {\n          // Collect the query's dependencies for future pending operation updates\n          queryDependencies = queryResult.dependencies;\n          collectPendingOperations(pendingOperations, queryDependencies);\n          results.set(operation.key, data);\n        }\n      } else {\n        noopDataState(store.data, operation.key);\n      }\n\n      // Update this operation's dependencies if it's a query\n      if (queryDependencies) {\n        updateDependencies(result.operation, queryDependencies);\n      }\n\n      return {\n        operation,\n        data,\n        error: result.error,\n        extensions: result.extensions,\n        hasNext: result.hasNext,\n        stale: result.stale,\n      };\n    };\n\n    return operations$ => {\n      // Filter by operations that are cacheable and attempt to query them from the cache\n      const cacheOps$ = pipe(\n        operations$,\n        filter(\n          op =>\n            op.kind === 'query' && op.context.requestPolicy !== 'network-only'\n        ),\n        map(operationResultFromCache),\n        share\n      );\n\n      const nonCacheOps$ = pipe(\n        operations$,\n        filter(\n          op =>\n            op.kind !== 'query' || op.context.requestPolicy === 'network-only'\n        )\n      );\n\n      // Rebound operations that are incomplete, i.e. couldn't be queried just from the cache\n      const cacheMissOps$ = pipe(\n        cacheOps$,\n        filter(\n          res =>\n            res.outcome === 'miss' &&\n            res.operation.context.requestPolicy !== 'cache-only' &&\n            !isBlockedByOptimisticUpdate(res.dependencies) &&\n            !reexecutingOperations.has(res.operation.key)\n        ),\n        map(res => {\n          dispatchDebug({\n            type: 'cacheMiss',\n            message: 'The result could not be retrieved from the cache',\n            operation: res.operation,\n          });\n          return addMetadata(res.operation, { cacheOutcome: 'miss' });\n        })\n      );\n\n      // Resolve OperationResults that the cache was able to assemble completely and trigger\n      // a network request if the current operation's policy is cache-and-network\n      const cacheResult$ = pipe(\n        cacheOps$,\n        filter(\n          res =>\n            res.outcome !== 'miss' ||\n            res.operation.context.requestPolicy === 'cache-only'\n        ),\n        map((res: OperationResultWithMeta): OperationResult => {\n          const { requestPolicy } = res.operation.context;\n\n          // We reexecute requests marked as `cache-and-network`, and partial responses,\n          // if we wouldn't cause a request loop\n          const shouldReexecute =\n            requestPolicy !== 'cache-only' &&\n            (res.hasNext ||\n              requestPolicy === 'cache-and-network' ||\n              (requestPolicy === 'cache-first' &&\n                res.outcome === 'partial' &&\n                !reexecutingOperations.has(res.operation.key)));\n          // Set stale to true anyway, even if the reexecute will be blocked, if the operation\n          // is in progress. We can be reasonably sure of that if a layer has been reserved for it.\n          const stale =\n            requestPolicy !== 'cache-only' &&\n            (shouldReexecute ||\n              (res.outcome === 'partial' &&\n                reexecutingOperations.has(res.operation.key) &&\n                hasLayer(store.data, res.operation.key)));\n\n          const result: OperationResult = {\n            operation: addMetadata(res.operation, {\n              cacheOutcome: res.outcome,\n            }),\n            data: res.data,\n            error: res.error,\n            extensions: res.extensions,\n            stale: stale && !res.hasNext,\n            hasNext: shouldReexecute && res.hasNext,\n          };\n\n          if (!shouldReexecute) {\n            /*noop*/\n          } else if (!isBlockedByOptimisticUpdate(res.dependencies)) {\n            client.reexecuteOperation(\n              toRequestPolicy(\n                operations.get(res.operation.key) || res.operation,\n                'network-only'\n              )\n            );\n          } else if (requestPolicy === 'cache-and-network') {\n            requestedRefetch.add(res.operation.key);\n          }\n\n          dispatchDebug({\n            type: 'cacheHit',\n            message: `A requested operation was found and returned from the cache.`,\n            operation: res.operation,\n            data: {\n              value: result,\n            },\n          });\n\n          return result;\n        })\n      );\n\n      // Forward operations that aren't cacheable and rebound operations\n      // Also update the cache with any network results\n      const result$ = pipe(\n        merge([nonCacheOps$, cacheMissOps$]),\n        map(prepareForwardedOperation),\n        forward\n      );\n\n      // Results that can immediately be resolved\n      const nonOptimisticResults$ = pipe(\n        result$,\n        filter(\n          result => !optimisticKeysToDependencies.has(result.operation.key)\n        ),\n        map(result => {\n          const pendingOperations: Operations = new Set();\n          // Update the cache with the incoming API result\n          const cacheResult = updateCacheWithResult(result, pendingOperations);\n          // Execute all dependent queries\n          executePendingOperations(result.operation, pendingOperations, false);\n          return cacheResult;\n        })\n      );\n\n      // Prevent mutations that were previously optimistic from being flushed\n      // immediately and instead clear them out slowly\n      const optimisticMutationCompletion$ = pipe(\n        result$,\n        filter(result =>\n          optimisticKeysToDependencies.has(result.operation.key)\n        ),\n        mergeMap((result: OperationResult): Source<OperationResult> => {\n          const length = mutationResultBuffer.push(result);\n          if (length < optimisticKeysToDependencies.size) {\n            return empty;\n          }\n\n          for (let i = 0; i < mutationResultBuffer.length; i++) {\n            reserveLayer(store.data, mutationResultBuffer[i].operation.key);\n          }\n\n          blockedDependencies.clear();\n\n          const results: OperationResult[] = [];\n          const pendingOperations: Operations = new Set();\n\n          let bufferedResult: OperationResult | void;\n          while ((bufferedResult = mutationResultBuffer.shift()))\n            results.push(\n              updateCacheWithResult(bufferedResult, pendingOperations)\n            );\n\n          // Execute all dependent queries as a single batch\n          executePendingOperations(result.operation, pendingOperations, false);\n\n          return fromArray(results);\n        })\n      );\n\n      return merge([\n        nonOptimisticResults$,\n        optimisticMutationCompletion$,\n        cacheResult$,\n      ]);\n    };\n  };\n"
  },
  {
    "path": "exchanges/graphcache/src/default-storage/index.ts",
    "content": "import type {\n  SerializedEntries,\n  SerializedRequest,\n  StorageAdapter,\n} from '../types';\n\nconst getRequestPromise = <T>(request: IDBRequest<T>): Promise<T> => {\n  return new Promise((resolve, reject) => {\n    request.onerror = () => {\n      reject(request.error);\n    };\n\n    request.onsuccess = () => {\n      resolve(request.result);\n    };\n  });\n};\n\nconst getTransactionPromise = (transaction: IDBTransaction): Promise<any> => {\n  return new Promise((resolve, reject) => {\n    transaction.onerror = () => {\n      reject(transaction.error);\n    };\n\n    transaction.oncomplete = resolve;\n  });\n};\n\nexport interface StorageOptions {\n  /** Name of the IndexedDB database that will be used.\n   * @defaultValue `'graphcache-v4'`\n   */\n  idbName?: string;\n  /** Maximum age of cache entries (in days) after which data is discarded.\n   * @defaultValue `7` days\n   */\n  maxAge?: number;\n  /** Gets Called when the exchange has hydrated the data from storage. */\n  onCacheHydrated?: () => void;\n}\n\n/** Sample storage adapter persisting to IndexedDB. */\nexport interface DefaultStorage extends StorageAdapter {\n  /** Clears the entire IndexedDB storage. */\n  clear(): Promise<any>;\n}\n\n/** Creates a default {@link StorageAdapter} which uses IndexedDB for storage.\n *\n * @param opts - A {@link StorageOptions} configuration object.\n * @returns the created {@link StorageAdapter}.\n *\n * @remarks\n * The default storage uses IndexedDB to persist the normalized cache for\n * offline use. It demonstrates that the cache can be chunked by timestamps.\n *\n * Note: We have no data on stability of this storage and our Offline Support\n * for large APIs or longterm use. Proceed with caution.\n */\nexport const makeDefaultStorage = (opts?: StorageOptions): DefaultStorage => {\n  if (!opts) opts = {};\n\n  let callback: (() => void) | undefined;\n\n  const DB_NAME = opts.idbName || 'graphcache-v4';\n  const ENTRIES_STORE_NAME = 'entries';\n  const METADATA_STORE_NAME = 'metadata';\n\n  let batch: Record<string, string | undefined> = Object.create(null);\n  const timestamp = Math.floor(new Date().valueOf() / (1000 * 60 * 60 * 24));\n  const maxAge = timestamp - (opts.maxAge || 7);\n\n  const req = indexedDB.open(DB_NAME, 1);\n  const database$ = getRequestPromise(req);\n\n  req.onupgradeneeded = () => {\n    req.result.createObjectStore(ENTRIES_STORE_NAME);\n    req.result.createObjectStore(METADATA_STORE_NAME);\n  };\n\n  return {\n    clear() {\n      return database$.then(database => {\n        const transaction = database.transaction(\n          [METADATA_STORE_NAME, ENTRIES_STORE_NAME],\n          'readwrite'\n        );\n        transaction.objectStore(METADATA_STORE_NAME).clear();\n        transaction.objectStore(ENTRIES_STORE_NAME).clear();\n        batch = Object.create(null);\n        return getTransactionPromise(transaction);\n      });\n    },\n\n    readMetadata(): Promise<null | SerializedRequest[]> {\n      return database$.then(\n        database => {\n          return getRequestPromise<SerializedRequest[]>(\n            database\n              .transaction(METADATA_STORE_NAME, 'readonly')\n              .objectStore(METADATA_STORE_NAME)\n              .get(METADATA_STORE_NAME)\n          );\n        },\n        () => null\n      );\n    },\n\n    writeMetadata(metadata: SerializedRequest[]) {\n      database$.then(\n        database => {\n          return getRequestPromise(\n            database\n              .transaction(METADATA_STORE_NAME, 'readwrite')\n              .objectStore(METADATA_STORE_NAME)\n              .put(metadata, METADATA_STORE_NAME)\n          );\n        },\n        () => {\n          /* noop */\n        }\n      );\n    },\n\n    writeData(entries: SerializedEntries): Promise<void> {\n      Object.assign(batch, entries);\n      const toUndefined = () => undefined;\n\n      return database$\n        .then(database => {\n          return getRequestPromise(\n            database\n              .transaction(ENTRIES_STORE_NAME, 'readwrite')\n              .objectStore(ENTRIES_STORE_NAME)\n              .put(batch, timestamp)\n          );\n        })\n        .then(toUndefined, toUndefined);\n    },\n\n    readData(): Promise<SerializedEntries> {\n      const data: SerializedEntries = {};\n      return database$\n        .then(database => {\n          const transaction = database.transaction(\n            ENTRIES_STORE_NAME,\n            'readwrite'\n          );\n\n          const store = transaction.objectStore(ENTRIES_STORE_NAME);\n          const request = (store.openKeyCursor || store.openCursor).call(store);\n\n          request.onsuccess = function () {\n            if (this.result) {\n              const { key } = this.result;\n              if (typeof key !== 'number' || key < maxAge) {\n                store.delete(key);\n              } else {\n                const request = store.get(key);\n                request.onsuccess = () => {\n                  const result = request.result;\n                  if (key === timestamp) Object.assign(batch, result);\n                  Object.assign(data, result);\n                };\n              }\n\n              this.result.continue();\n            }\n          };\n\n          return getTransactionPromise(transaction);\n        })\n        .then(\n          () => data,\n          () => batch\n        );\n    },\n    onCacheHydrated: opts.onCacheHydrated,\n    onOnline(cb: () => void) {\n      if (callback) {\n        window.removeEventListener('online', callback);\n        callback = undefined;\n      }\n\n      window.addEventListener(\n        'online',\n        (callback = () => {\n          cb();\n        })\n      );\n    },\n  };\n};\n"
  },
  {
    "path": "exchanges/graphcache/src/extras/index.ts",
    "content": "export { relayPagination } from './relayPagination';\nexport { simplePagination } from './simplePagination';\n"
  },
  {
    "path": "exchanges/graphcache/src/extras/relayPagination.test.ts",
    "content": "import { gql } from '@urql/core';\nimport { it, expect, describe } from 'vitest';\nimport { __initAnd_query as query } from '../operations/query';\nimport { __initAnd_write as write } from '../operations/write';\nimport { Store } from '../store/store';\nimport { relayPagination } from './relayPagination';\n\nfunction itemNode(numItem: number) {\n  return {\n    __typename: 'Item',\n    id: numItem + '',\n  };\n}\n\nfunction itemEdge(numItem: number) {\n  return {\n    __typename: 'ItemEdge',\n    node: itemNode(numItem),\n  };\n}\n\ndescribe('as resolver', () => {\n  it('works with forward pagination', () => {\n    const Pagination = gql`\n      query ($cursor: String) {\n        __typename\n        items(first: 1, after: $cursor) {\n          __typename\n          edges {\n            __typename\n            node {\n              __typename\n              id\n            }\n          }\n          nodes {\n            __typename\n            id\n          }\n          pageInfo {\n            __typename\n            hasNextPage\n            endCursor\n          }\n        }\n      }\n    `;\n\n    const store = new Store({\n      resolvers: {\n        Query: {\n          items: relayPagination(),\n        },\n      },\n    });\n\n    const pageOne = {\n      __typename: 'Query',\n      items: {\n        __typename: 'ItemsConnection',\n        edges: [itemEdge(1)],\n        nodes: [itemNode(1)],\n        pageInfo: {\n          __typename: 'PageInfo',\n          hasNextPage: true,\n          endCursor: '1',\n        },\n      },\n    };\n\n    const pageTwo = {\n      __typename: 'Query',\n      items: {\n        __typename: 'ItemsConnection',\n        edges: [itemEdge(2)],\n        nodes: [itemNode(2)],\n        pageInfo: {\n          __typename: 'PageInfo',\n          hasNextPage: false,\n          endCursor: null,\n        },\n      },\n    };\n\n    write(store, { query: Pagination, variables: { cursor: null } }, pageOne);\n    write(store, { query: Pagination, variables: { cursor: '1' } }, pageTwo);\n\n    const res = query(store, { query: Pagination });\n\n    expect(res.partial).toBe(false);\n    expect(res.data).toEqual({\n      ...pageTwo,\n      items: {\n        ...pageTwo.items,\n        edges: [pageOne.items.edges[0], pageTwo.items.edges[0]],\n        nodes: [pageOne.items.nodes[0], pageTwo.items.nodes[0]],\n      },\n    });\n  });\n\n  it('works with backwards pagination', () => {\n    const Pagination = gql`\n      query ($cursor: String) {\n        __typename\n        items(last: 1, before: $cursor) {\n          __typename\n          edges {\n            __typename\n            node {\n              __typename\n              id\n            }\n          }\n          nodes {\n            __typename\n            id\n          }\n          pageInfo {\n            __typename\n            hasPreviousPage\n            startCursor\n          }\n        }\n      }\n    `;\n\n    const store = new Store({\n      resolvers: {\n        Query: {\n          items: relayPagination(),\n        },\n      },\n    });\n\n    const pageOne = {\n      __typename: 'Query',\n      items: {\n        __typename: 'ItemsConnection',\n        edges: [itemEdge(2)],\n        nodes: [itemNode(2)],\n        pageInfo: {\n          __typename: 'PageInfo',\n          hasPreviousPage: true,\n          startCursor: '2',\n        },\n      },\n    };\n\n    const pageTwo = {\n      __typename: 'Query',\n      items: {\n        __typename: 'ItemsConnection',\n        edges: [itemEdge(1)],\n        nodes: [itemNode(1)],\n        pageInfo: {\n          __typename: 'PageInfo',\n          hasPreviousPage: false,\n          startCursor: null,\n        },\n      },\n    };\n\n    write(store, { query: Pagination, variables: { cursor: null } }, pageOne);\n    write(store, { query: Pagination, variables: { cursor: '2' } }, pageTwo);\n\n    const res = query(store, { query: Pagination });\n\n    expect(res.partial).toBe(false);\n    expect(res.data).toEqual({\n      ...pageTwo,\n      items: {\n        ...pageTwo.items,\n        edges: [pageTwo.items.edges[0], pageOne.items.edges[0]],\n        nodes: [pageTwo.items.nodes[0], pageOne.items.nodes[0]],\n      },\n    });\n  });\n\n  it('handles duplicate edges', () => {\n    const Pagination = gql`\n      query ($cursor: String) {\n        __typename\n        items(first: 2, after: $cursor) {\n          __typename\n          edges {\n            __typename\n            node {\n              __typename\n              id\n            }\n          }\n          nodes {\n            __typename\n            id\n          }\n          pageInfo {\n            __typename\n            hasNextPage\n            endCursor\n          }\n        }\n      }\n    `;\n\n    const store = new Store({\n      resolvers: {\n        Query: {\n          items: relayPagination(),\n        },\n      },\n    });\n\n    const pageOne = {\n      __typename: 'Query',\n      items: {\n        __typename: 'ItemsConnection',\n        edges: [itemEdge(1), itemEdge(2)],\n        nodes: [itemNode(1), itemNode(2)],\n        pageInfo: {\n          __typename: 'PageInfo',\n          hasNextPage: true,\n          endCursor: '2',\n        },\n      },\n    };\n\n    const pageTwo = {\n      __typename: 'Query',\n      items: {\n        __typename: 'ItemsConnection',\n        edges: [itemEdge(2), itemEdge(3)],\n        nodes: [itemNode(2), itemNode(3)],\n        pageInfo: {\n          __typename: 'PageInfo',\n          hasNextPage: false,\n          endCursor: null,\n        },\n      },\n    };\n\n    write(store, { query: Pagination, variables: { cursor: null } }, pageOne);\n    write(store, { query: Pagination, variables: { cursor: '1' } }, pageTwo);\n\n    const res = query(store, { query: Pagination });\n\n    expect(res.partial).toBe(false);\n    expect(res.data).toEqual({\n      ...pageTwo,\n      items: {\n        ...pageTwo.items,\n        edges: [\n          pageOne.items.edges[0],\n          pageTwo.items.edges[0],\n          pageTwo.items.edges[1],\n        ],\n        nodes: [\n          pageOne.items.nodes[0],\n          pageTwo.items.nodes[0],\n          pageTwo.items.nodes[1],\n        ],\n      },\n    });\n  });\n\n  it('works with simultaneous forward and backward pagination (outwards merging)', () => {\n    const Pagination = gql`\n      query ($first: Int, $last: Int, $before: String, $after: String) {\n        __typename\n        items(first: $first, last: $last, before: $before, after: $after) {\n          __typename\n          edges {\n            __typename\n            node {\n              __typename\n              id\n            }\n          }\n          nodes {\n            __typename\n            id\n          }\n          pageInfo {\n            __typename\n            hasPreviousPage\n            hasNextPage\n            startCursor\n            endCursor\n          }\n        }\n      }\n    `;\n\n    const store = new Store({\n      resolvers: {\n        Query: {\n          items: relayPagination({ mergeMode: 'outwards' }),\n        },\n      },\n    });\n\n    const pageOne = {\n      __typename: 'Query',\n      items: {\n        __typename: 'ItemsConnection',\n        edges: [itemEdge(1)],\n        nodes: [itemNode(1)],\n        pageInfo: {\n          __typename: 'PageInfo',\n          hasNextPage: true,\n          hasPreviousPage: false,\n          startCursor: null,\n          endCursor: '1',\n        },\n      },\n    };\n\n    const pageTwo = {\n      __typename: 'Query',\n      items: {\n        __typename: 'ItemsConnection',\n        edges: [itemEdge(2)],\n        nodes: [itemNode(2)],\n        pageInfo: {\n          __typename: 'PageInfo',\n          hasNextPage: true,\n          hasPreviousPage: true,\n          startCursor: '2',\n          endCursor: '2',\n        },\n      },\n    };\n\n    const pageThree = {\n      __typename: 'Query',\n      items: {\n        __typename: 'ItemsConnection',\n        edges: [itemEdge(-1)],\n        nodes: [itemNode(-1)],\n        pageInfo: {\n          __typename: 'PageInfo',\n          hasNextPage: false,\n          hasPreviousPage: true,\n          startCursor: '-1',\n          endCursor: null,\n        },\n      },\n    };\n\n    write(\n      store,\n      { query: Pagination, variables: { after: '1', first: 1 } },\n      pageOne\n    );\n    write(\n      store,\n      { query: Pagination, variables: { after: '2', first: 1 } },\n      pageTwo\n    );\n    write(\n      store,\n      { query: Pagination, variables: { before: '1', last: 1 } },\n      pageThree\n    );\n\n    const res = query(store, {\n      query: Pagination,\n      variables: { before: '1', last: 1 },\n    });\n\n    expect(res.partial).toBe(false);\n    expect(res.data).toEqual({\n      ...pageThree,\n      items: {\n        ...pageThree.items,\n        edges: [\n          pageThree.items.edges[0],\n          pageOne.items.edges[0],\n          pageTwo.items.edges[0],\n        ],\n        nodes: [\n          pageThree.items.nodes[0],\n          pageOne.items.nodes[0],\n          pageTwo.items.nodes[0],\n        ],\n        pageInfo: {\n          ...pageThree.items.pageInfo,\n          hasPreviousPage: true,\n          hasNextPage: true,\n          startCursor: '-1',\n          endCursor: '2',\n        },\n      },\n    });\n  });\n\n  it('works with simultaneous forward and backward pagination (inwards merging)', () => {\n    const Pagination = gql`\n      query ($first: Int, $last: Int, $before: String, $after: String) {\n        __typename\n        items(first: $first, last: $last, before: $before, after: $after) {\n          __typename\n          edges {\n            __typename\n            node {\n              __typename\n              id\n            }\n          }\n          nodes {\n            __typename\n            id\n          }\n          pageInfo {\n            __typename\n            hasPreviousPage\n            hasNextPage\n            startCursor\n            endCursor\n          }\n        }\n      }\n    `;\n\n    const store = new Store({\n      resolvers: {\n        Query: {\n          items: relayPagination({ mergeMode: 'inwards' }),\n        },\n      },\n    });\n\n    const pageOne = {\n      __typename: 'Query',\n      items: {\n        __typename: 'ItemsConnection',\n        edges: [itemEdge(1)],\n        nodes: [itemNode(1)],\n        pageInfo: {\n          __typename: 'PageInfo',\n          hasNextPage: true,\n          hasPreviousPage: false,\n          startCursor: null,\n          endCursor: '1',\n        },\n      },\n    };\n\n    const pageTwo = {\n      __typename: 'Query',\n      items: {\n        __typename: 'ItemsConnection',\n        edges: [itemEdge(2)],\n        nodes: [itemNode(2)],\n        pageInfo: {\n          __typename: 'PageInfo',\n          hasNextPage: true,\n          hasPreviousPage: true,\n          startCursor: '2',\n          endCursor: '2',\n        },\n      },\n    };\n\n    const pageThree = {\n      __typename: 'Query',\n      items: {\n        __typename: 'ItemsConnection',\n        edges: [itemEdge(-1)],\n        nodes: [itemNode(-1)],\n        pageInfo: {\n          __typename: 'PageInfo',\n          hasNextPage: false,\n          hasPreviousPage: true,\n          startCursor: '-1',\n          endCursor: null,\n        },\n      },\n    };\n\n    write(\n      store,\n      { query: Pagination, variables: { after: '1', first: 1 } },\n      pageOne\n    );\n    write(\n      store,\n      { query: Pagination, variables: { after: '2', first: 1 } },\n      pageTwo\n    );\n    write(\n      store,\n      { query: Pagination, variables: { before: '1', last: 1 } },\n      pageThree\n    );\n\n    const res = query(store, {\n      query: Pagination,\n      variables: { before: '1', last: 1 },\n    });\n\n    expect(res.partial).toBe(false);\n    expect(res.data).toEqual({\n      ...pageThree,\n      items: {\n        ...pageThree.items,\n        edges: [\n          pageOne.items.edges[0],\n          pageTwo.items.edges[0],\n          pageThree.items.edges[0],\n        ],\n        nodes: [\n          pageOne.items.nodes[0],\n          pageTwo.items.nodes[0],\n          pageThree.items.nodes[0],\n        ],\n        pageInfo: {\n          ...pageThree.items.pageInfo,\n          hasPreviousPage: true,\n          hasNextPage: true,\n          startCursor: '-1',\n          endCursor: '2',\n        },\n      },\n    });\n  });\n\n  it('prevents overlapping of pagination on different arguments', () => {\n    const Pagination = gql`\n      query ($filter: String) {\n        items(first: 1, filter: $filter) {\n          __typename\n          edges {\n            __typename\n            node {\n              __typename\n              id\n            }\n          }\n          nodes {\n            __typename\n            id\n          }\n          pageInfo {\n            __typename\n            hasNextPage\n            endCursor\n          }\n        }\n      }\n    `;\n\n    const store = new Store({\n      resolvers: {\n        Query: {\n          items: relayPagination(),\n        },\n      },\n    });\n\n    const page = withId => ({\n      __typename: 'Query',\n      items: {\n        __typename: 'ItemsConnection',\n        edges: [itemEdge(withId)],\n        nodes: [itemNode(withId)],\n        pageInfo: {\n          __typename: 'PageInfo',\n          hasNextPage: false,\n          endCursor: null,\n        },\n      },\n    });\n\n    write(\n      store,\n      { query: Pagination, variables: { filter: 'one' } },\n      page('one')\n    );\n    write(\n      store,\n      { query: Pagination, variables: { filter: 'two' } },\n      page('two')\n    );\n\n    const resOne = query(store, {\n      query: Pagination,\n      variables: { filter: 'one' },\n    });\n    const resTwo = query(store, {\n      query: Pagination,\n      variables: { filter: 'two' },\n    });\n    const resThree = query(store, {\n      query: Pagination,\n      variables: { filter: 'three' },\n    });\n\n    expect(resOne.data).toHaveProperty('items.edges[0].node.id', 'one');\n    expect(resOne.data).toHaveProperty('items.edges.length', 1);\n\n    expect(resTwo.data).toHaveProperty('items.edges[0].node.id', 'two');\n    expect(resTwo.data).toHaveProperty('items.edges.length', 1);\n\n    expect(resThree.data).toEqual(null);\n  });\n\n  it('returns an empty array of edges when the cache has zero edges stored', () => {\n    const Pagination = gql`\n      query {\n        items(first: 1) {\n          __typename\n          edges {\n            __typename\n          }\n          nodes {\n            __typename\n          }\n        }\n      }\n    `;\n\n    const store = new Store({\n      resolvers: {\n        Query: {\n          items: relayPagination(),\n        },\n      },\n    });\n\n    write(\n      store,\n      { query: Pagination },\n      {\n        __typename: 'Query',\n        items: {\n          __typename: 'ItemsConnection',\n          edges: [],\n          nodes: [],\n        },\n      }\n    );\n\n    const res = query(store, {\n      query: Pagination,\n    });\n\n    expect(res.data).toHaveProperty('items', {\n      __typename: 'ItemsConnection',\n      edges: [],\n      nodes: [],\n    });\n  });\n\n  it('returns other fields on the same level as the edges', () => {\n    const Pagination = gql`\n      query {\n        __typename\n        items(first: 1) {\n          __typename\n          totalCount\n        }\n      }\n    `;\n\n    const store = new Store({\n      resolvers: {\n        Query: {\n          items: relayPagination(),\n        },\n      },\n    });\n\n    write(\n      store,\n      { query: Pagination },\n      {\n        __typename: 'Query',\n        items: {\n          __typename: 'ItemsConnection',\n          totalCount: 2,\n        },\n      }\n    );\n\n    const resOne = query(store, {\n      query: Pagination,\n    });\n\n    expect(resOne.data).toHaveProperty('items', {\n      __typename: 'ItemsConnection',\n      totalCount: 2,\n    });\n  });\n\n  it('returns a subset of the cached items if the query requests less items than the cached ones', () => {\n    const Pagination = gql`\n      query ($first: Int, $last: Int, $before: String, $after: String) {\n        __typename\n        items(first: $first, last: $last, before: $before, after: $after) {\n          __typename\n          edges {\n            __typename\n            node {\n              __typename\n              id\n            }\n          }\n          nodes {\n            __typename\n            id\n          }\n          pageInfo {\n            __typename\n            hasPreviousPage\n            hasNextPage\n            startCursor\n            endCursor\n          }\n        }\n      }\n    `;\n\n    const store = new Store({\n      schema: require('../test-utils/relayPagination_schema.json'),\n      resolvers: {\n        Query: {\n          items: relayPagination({ mergeMode: 'outwards' }),\n        },\n      },\n    });\n\n    const results = {\n      __typename: 'Query',\n      items: {\n        __typename: 'ItemsConnection',\n        edges: [\n          itemEdge(1),\n          itemEdge(2),\n          itemEdge(3),\n          itemEdge(4),\n          itemEdge(5),\n        ],\n        nodes: [\n          itemNode(1),\n          itemNode(2),\n          itemNode(3),\n          itemNode(4),\n          itemNode(5),\n        ],\n        pageInfo: {\n          __typename: 'PageInfo',\n          hasNextPage: true,\n          hasPreviousPage: false,\n          startCursor: '1',\n          endCursor: '5',\n        },\n      },\n    };\n\n    write(store, { query: Pagination, variables: { first: 2 } }, results);\n\n    const res = query(store, {\n      query: Pagination,\n      variables: { first: 2 },\n    });\n\n    expect(res.partial).toBe(false);\n    expect(res.data).toEqual(results);\n  });\n\n  it(\"returns the cached items even if they don't fullfil the query\", () => {\n    const Pagination = gql`\n      query ($first: Int, $last: Int, $before: String, $after: String) {\n        __typename\n        items(first: $first, last: $last, before: $before, after: $after) {\n          __typename\n          edges {\n            __typename\n            node {\n              __typename\n              id\n            }\n          }\n          nodes {\n            __typename\n            id\n          }\n          pageInfo {\n            __typename\n            hasPreviousPage\n            hasNextPage\n            startCursor\n            endCursor\n          }\n        }\n      }\n    `;\n\n    const store = new Store({\n      schema: require('../test-utils/relayPagination_schema.json'),\n      resolvers: {\n        Query: {\n          items: relayPagination(),\n        },\n      },\n    });\n\n    const results = {\n      __typename: 'Query',\n      items: {\n        __typename: 'ItemsConnection',\n        edges: [\n          itemEdge(1),\n          itemEdge(2),\n          itemEdge(3),\n          itemEdge(4),\n          itemEdge(5),\n        ],\n        nodes: [\n          itemNode(1),\n          itemNode(2),\n          itemNode(3),\n          itemNode(4),\n          itemNode(5),\n        ],\n        pageInfo: {\n          __typename: 'PageInfo',\n          hasNextPage: true,\n          hasPreviousPage: false,\n          startCursor: '1',\n          endCursor: '5',\n        },\n      },\n    };\n\n    write(\n      store,\n      { query: Pagination, variables: { after: '3', first: 3, last: 3 } },\n      results\n    );\n\n    const res = query(store, {\n      query: Pagination,\n      variables: { after: '3', first: 3, last: 3 },\n    });\n\n    expect(res.partial).toBe(false);\n    expect(res.data).toEqual(results);\n  });\n\n  it('returns the cached items even when they come from a different query', () => {\n    const Pagination = gql`\n      query ($first: Int, $last: Int, $before: String, $after: String) {\n        __typename\n        items(first: $first, last: $last, before: $before, after: $after) {\n          __typename\n          edges {\n            __typename\n            node {\n              __typename\n              id\n            }\n          }\n          nodes {\n            __typename\n            id\n          }\n          pageInfo {\n            __typename\n            hasPreviousPage\n            hasNextPage\n            startCursor\n            endCursor\n          }\n        }\n      }\n    `;\n\n    const store = new Store({\n      schema: require('../test-utils/relayPagination_schema.json'),\n      resolvers: {\n        Query: {\n          items: relayPagination(),\n        },\n      },\n    });\n\n    const results = {\n      __typename: 'Query',\n      items: {\n        __typename: 'ItemsConnection',\n        edges: [\n          itemEdge(1),\n          itemEdge(2),\n          itemEdge(3),\n          itemEdge(4),\n          itemEdge(5),\n        ],\n        nodes: [\n          itemNode(1),\n          itemNode(2),\n          itemNode(3),\n          itemNode(4),\n          itemNode(5),\n        ],\n        pageInfo: {\n          __typename: 'PageInfo',\n          hasNextPage: true,\n          hasPreviousPage: false,\n          startCursor: '1',\n          endCursor: '5',\n        },\n      },\n    };\n\n    write(store, { query: Pagination, variables: { first: 5 } }, results);\n\n    const res = query(store, {\n      query: Pagination,\n      variables: { after: '3', first: 2, last: 2 },\n    });\n\n    expect(res.partial).toBe(true);\n    expect(res.data).toEqual(results);\n  });\n\n  it('caches and retrieves correctly queries with inwards pagination', () => {\n    const Pagination = gql`\n      query ($first: Int, $last: Int, $before: String, $after: String) {\n        __typename\n        items(first: $first, last: $last, before: $before, after: $after) {\n          __typename\n          edges {\n            __typename\n            node {\n              __typename\n              id\n            }\n          }\n          nodes {\n            __typename\n            id\n          }\n          pageInfo {\n            __typename\n            hasPreviousPage\n            hasNextPage\n            startCursor\n            endCursor\n          }\n        }\n      }\n    `;\n\n    const store = new Store({\n      schema: require('../test-utils/relayPagination_schema.json'),\n      resolvers: {\n        Query: {\n          items: relayPagination(),\n        },\n      },\n    });\n\n    const results = {\n      __typename: 'Query',\n      items: {\n        __typename: 'ItemsConnection',\n        edges: [\n          itemEdge(1),\n          itemEdge(2),\n          itemEdge(3),\n          itemEdge(4),\n          itemEdge(5),\n        ],\n        nodes: [\n          itemNode(1),\n          itemNode(2),\n          itemNode(3),\n          itemNode(4),\n          itemNode(5),\n        ],\n        pageInfo: {\n          __typename: 'PageInfo',\n          hasNextPage: true,\n          hasPreviousPage: false,\n          startCursor: '1',\n          endCursor: '5',\n        },\n      },\n    };\n\n    write(\n      store,\n      { query: Pagination, variables: { after: '2', first: 2, last: 2 } },\n      results\n    );\n\n    const res = query(store, {\n      query: Pagination,\n      variables: { after: '2', first: 2, last: 2 },\n    });\n\n    expect(res.partial).toBe(false);\n    expect(res.data).toEqual(results);\n  });\n\n  it('does not include a previous result when adding parameters', () => {\n    const Pagination = gql`\n      query ($first: Int, $filter: String) {\n        __typename\n        items(first: $first, filter: $filter) {\n          __typename\n          edges {\n            __typename\n            node {\n              __typename\n              id\n            }\n          }\n          nodes {\n            __typename\n            id\n          }\n          pageInfo {\n            __typename\n            hasPreviousPage\n            hasNextPage\n            startCursor\n            endCursor\n          }\n        }\n      }\n    `;\n\n    const store = new Store({\n      resolvers: {\n        Query: {\n          items: relayPagination(),\n        },\n      },\n    });\n\n    const results = {\n      __typename: 'Query',\n      items: {\n        __typename: 'ItemsConnection',\n        edges: [itemEdge(1), itemEdge(2)],\n        nodes: [itemNode(1), itemNode(2)],\n        pageInfo: {\n          __typename: 'PageInfo',\n          hasNextPage: true,\n          hasPreviousPage: false,\n          startCursor: '1',\n          endCursor: '2',\n        },\n      },\n    };\n\n    const results2 = {\n      __typename: 'Query',\n      items: {\n        __typename: 'ItemsConnection',\n        edges: [],\n        nodes: [],\n        pageInfo: {\n          __typename: 'PageInfo',\n          hasNextPage: false,\n          hasPreviousPage: false,\n          startCursor: '1',\n          endCursor: '2',\n        },\n      },\n    };\n\n    write(store, { query: Pagination, variables: { first: 2 } }, results);\n\n    write(\n      store,\n      { query: Pagination, variables: { first: 2, filter: 'b' } },\n      results2\n    );\n\n    const res = query(store, {\n      query: Pagination,\n      variables: { first: 2, filter: 'b' },\n    });\n    expect(res.data).toEqual(results2);\n  });\n\n  it('Works with edges absent from query', () => {\n    const Pagination = gql`\n      query ($first: Int, $last: Int, $before: String, $after: String) {\n        __typename\n        items(first: $first, last: $last, before: $before, after: $after) {\n          __typename\n          nodes {\n            __typename\n            id\n          }\n          pageInfo {\n            __typename\n            hasPreviousPage\n            hasNextPage\n            startCursor\n            endCursor\n          }\n        }\n      }\n    `;\n\n    const store = new Store({\n      schema: require('../test-utils/relayPagination_schema.json'),\n      resolvers: {\n        Query: {\n          items: relayPagination({ mergeMode: 'outwards' }),\n        },\n      },\n    });\n\n    const results = {\n      __typename: 'Query',\n      items: {\n        __typename: 'ItemsConnection',\n        nodes: [\n          itemNode(1),\n          itemNode(2),\n          itemNode(3),\n          itemNode(4),\n          itemNode(5),\n        ],\n        pageInfo: {\n          __typename: 'PageInfo',\n          hasNextPage: true,\n          hasPreviousPage: false,\n          startCursor: '1',\n          endCursor: '5',\n        },\n      },\n    };\n\n    write(store, { query: Pagination, variables: { first: 2 } }, results);\n\n    const res = query(store, {\n      query: Pagination,\n      variables: { first: 2 },\n    });\n\n    expect(res.partial).toBe(false);\n    expect(res.data).toEqual(results);\n  });\n\n  it('Works with nodes absent from query', () => {\n    const Pagination = gql`\n      query ($first: Int, $last: Int, $before: String, $after: String) {\n        __typename\n        items(first: $first, last: $last, before: $before, after: $after) {\n          __typename\n          edges {\n            __typename\n            node {\n              __typename\n              id\n            }\n          }\n          pageInfo {\n            __typename\n            hasPreviousPage\n            hasNextPage\n            startCursor\n            endCursor\n          }\n        }\n      }\n    `;\n\n    const store = new Store({\n      schema: require('../test-utils/relayPagination_schema.json'),\n      resolvers: {\n        Query: {\n          items: relayPagination({ mergeMode: 'outwards' }),\n        },\n      },\n    });\n\n    const results = {\n      __typename: 'Query',\n      items: {\n        __typename: 'ItemsConnection',\n        edges: [\n          itemEdge(1),\n          itemEdge(2),\n          itemEdge(3),\n          itemEdge(4),\n          itemEdge(5),\n        ],\n        pageInfo: {\n          __typename: 'PageInfo',\n          hasNextPage: true,\n          hasPreviousPage: false,\n          startCursor: '1',\n          endCursor: '5',\n        },\n      },\n    };\n\n    write(store, { query: Pagination, variables: { first: 2 } }, results);\n\n    const res = query(store, {\n      query: Pagination,\n      variables: { first: 2 },\n    });\n\n    expect(res.partial).toBe(false);\n    expect(res.data).toEqual(results);\n  });\n\n  it('handles subsequent queries with larger last values', () => {\n    const Pagination = gql`\n      query ($last: Int!) {\n        __typename\n        items(last: $last) {\n          __typename\n          edges {\n            __typename\n            node {\n              __typename\n              id\n            }\n          }\n          nodes {\n            __typename\n            id\n          }\n          pageInfo {\n            __typename\n            hasPreviousPage\n            startCursor\n          }\n        }\n      }\n    `;\n\n    const store = new Store({\n      resolvers: {\n        Query: {\n          items: relayPagination(),\n        },\n      },\n    });\n\n    const pageOne = {\n      __typename: 'Query',\n      items: {\n        __typename: 'ItemsConnection',\n        edges: [itemEdge(2)],\n        nodes: [itemNode(2)],\n        pageInfo: {\n          __typename: 'PageInfo',\n          hasPreviousPage: true,\n          startCursor: '2',\n        },\n      },\n    };\n\n    const pageTwo = {\n      __typename: 'Query',\n      items: {\n        __typename: 'ItemsConnection',\n        edges: [itemEdge(1), itemEdge(2)],\n        nodes: [itemNode(1), itemNode(2)],\n        pageInfo: {\n          __typename: 'PageInfo',\n          hasPreviousPage: false,\n          startCursor: '1',\n        },\n      },\n    };\n\n    const pageThree = {\n      __typename: 'Query',\n      items: {\n        __typename: 'ItemsConnection',\n        edges: [itemEdge(0), itemEdge(1), itemEdge(2)],\n        nodes: [itemNode(0), itemNode(1), itemNode(2)],\n        pageInfo: {\n          __typename: 'PageInfo',\n          hasPreviousPage: false,\n          startCursor: '0',\n        },\n      },\n    };\n\n    write(store, { query: Pagination, variables: { last: 1 } }, pageOne);\n    write(store, { query: Pagination, variables: { last: 2 } }, pageTwo);\n\n    let res = query(store, { query: Pagination, variables: { last: 2 } });\n\n    expect(res.partial).toBe(false);\n    expect(res.data).toEqual(pageTwo);\n\n    write(store, { query: Pagination, variables: { last: 3 } }, pageThree);\n\n    res = query(store, { query: Pagination, variables: { last: 3 } });\n\n    expect(res.partial).toBe(false);\n    expect(res.data).toEqual(pageThree);\n  });\n\n  it('handles subsequent queries with larger first values', () => {\n    const Pagination = gql`\n      query ($first: Int!) {\n        __typename\n        items(first: $first) {\n          __typename\n          edges {\n            __typename\n            node {\n              __typename\n              id\n            }\n          }\n          nodes {\n            __typename\n            id\n          }\n          pageInfo {\n            __typename\n            hasNextPage\n            endCursor\n          }\n        }\n      }\n    `;\n\n    const store = new Store({\n      resolvers: {\n        Query: {\n          items: relayPagination(),\n        },\n      },\n    });\n\n    const pageOne = {\n      __typename: 'Query',\n      items: {\n        __typename: 'ItemsConnection',\n        edges: [itemEdge(1)],\n        nodes: [itemNode(1)],\n        pageInfo: {\n          __typename: 'PageInfo',\n          hasNextPage: true,\n          endCursor: '1',\n        },\n      },\n    };\n\n    const pageTwo = {\n      __typename: 'Query',\n      items: {\n        __typename: 'ItemsConnection',\n        edges: [itemEdge(1), itemEdge(2)],\n        nodes: [itemNode(1), itemNode(2)],\n        pageInfo: {\n          __typename: 'PageInfo',\n          hasNextPage: false,\n          endCursor: '2',\n        },\n      },\n    };\n\n    write(store, { query: Pagination, variables: { first: 1 } }, pageOne);\n    write(store, { query: Pagination, variables: { first: 2 } }, pageTwo);\n\n    const res = query(store, { query: Pagination, variables: { first: 2 } });\n\n    expect(res.partial).toBe(false);\n    expect(res.data).toEqual(pageTwo);\n  });\n\n  it('ignores empty pages when paginating', () => {\n    const PaginationForward = gql`\n      query ($first: Int!, $after: String) {\n        __typename\n        items(first: $first, after: $after) {\n          __typename\n          nodes {\n            __typename\n            id\n          }\n          pageInfo {\n            __typename\n            startCursor\n            endCursor\n          }\n        }\n      }\n    `;\n    const PaginationBackward = gql`\n      query ($last: Int!, $before: String) {\n        __typename\n        items(last: $last, before: $before) {\n          __typename\n          nodes {\n            __typename\n            id\n          }\n          pageInfo {\n            __typename\n            startCursor\n            endCursor\n          }\n        }\n      }\n    `;\n\n    const store = new Store({\n      resolvers: {\n        Query: {\n          items: relayPagination(),\n        },\n      },\n    });\n\n    const forwardOne = {\n      __typename: 'Query',\n      items: {\n        __typename: 'ItemsConnection',\n        nodes: [itemNode(1), itemNode(2)],\n        pageInfo: {\n          __typename: 'PageInfo',\n          startCursor: '1',\n          endCursor: '2',\n        },\n      },\n    };\n    const forwardAfter = {\n      __typename: 'Query',\n      items: {\n        __typename: 'ItemsConnection',\n        nodes: [],\n        pageInfo: {\n          __typename: 'PageInfo',\n          startCursor: null,\n          endCursor: null,\n        },\n      },\n    };\n    const backwardBefore = {\n      __typename: 'Query',\n      items: {\n        __typename: 'ItemsConnection',\n        nodes: [],\n        pageInfo: {\n          __typename: 'PageInfo',\n          startCursor: null,\n          endCursor: null,\n        },\n      },\n    };\n\n    write(\n      store,\n      { query: PaginationForward, variables: { first: 2 } },\n      forwardOne\n    );\n    write(\n      store,\n      { query: PaginationBackward, variables: { last: 1, before: '1' } },\n      backwardBefore\n    );\n\n    const res = query(store, {\n      query: PaginationForward,\n      variables: { first: 2 },\n    });\n\n    expect(res.partial).toBe(false);\n    expect(res.data).toEqual(forwardOne);\n    write(\n      store,\n      { query: PaginationForward, variables: { first: 1, after: '2' } },\n      forwardAfter\n    );\n\n    expect(res.partial).toBe(false);\n    expect(res.data).toEqual(forwardOne);\n  });\n\n  it('allows for an empty page when this is the only result', () => {\n    const Pagination = gql`\n      query ($first: Int!, $after: String) {\n        __typename\n        items(first: $first, after: $after) {\n          __typename\n          nodes {\n            __typename\n            id\n          }\n          pageInfo {\n            __typename\n            startCursor\n            endCursor\n          }\n        }\n      }\n    `;\n\n    const store = new Store({\n      resolvers: {\n        Query: {\n          items: relayPagination(),\n        },\n      },\n    });\n\n    const pageOne = {\n      __typename: 'Query',\n      items: {\n        __typename: 'ItemsConnection',\n        nodes: [],\n        pageInfo: {\n          __typename: 'PageInfo',\n          startCursor: null,\n          endCursor: null,\n        },\n      },\n    };\n\n    write(store, { query: Pagination, variables: { first: 2 } }, pageOne);\n    const res = query(store, {\n      query: Pagination,\n      variables: { first: 2 },\n    });\n\n    expect(res.partial).toBe(false);\n    expect(res.data).toEqual(pageOne);\n  });\n});\n\ndescribe('as directive', () => {\n  it('works with forward pagination', () => {\n    const Pagination = gql`\n      query ($cursor: String) {\n        __typename\n        items(first: 1, after: $cursor) @_relayPagination {\n          __typename\n          edges {\n            __typename\n            node {\n              __typename\n              id\n            }\n          }\n          nodes {\n            __typename\n            id\n          }\n          pageInfo {\n            __typename\n            hasNextPage\n            endCursor\n          }\n        }\n      }\n    `;\n\n    const store = new Store({\n      directives: {\n        relayPagination: () => relayPagination(),\n      },\n    });\n\n    const pageOne = {\n      __typename: 'Query',\n      items: {\n        __typename: 'ItemsConnection',\n        edges: [itemEdge(1)],\n        nodes: [itemNode(1)],\n        pageInfo: {\n          __typename: 'PageInfo',\n          hasNextPage: true,\n          endCursor: '1',\n        },\n      },\n    };\n\n    const pageTwo = {\n      __typename: 'Query',\n      items: {\n        __typename: 'ItemsConnection',\n        edges: [itemEdge(2)],\n        nodes: [itemNode(2)],\n        pageInfo: {\n          __typename: 'PageInfo',\n          hasNextPage: false,\n          endCursor: null,\n        },\n      },\n    };\n\n    write(store, { query: Pagination, variables: { cursor: null } }, pageOne);\n    write(store, { query: Pagination, variables: { cursor: '1' } }, pageTwo);\n\n    const res = query(store, { query: Pagination });\n\n    expect(res.partial).toBe(false);\n    expect(res.data).toEqual({\n      ...pageTwo,\n      items: {\n        ...pageTwo.items,\n        edges: [pageOne.items.edges[0], pageTwo.items.edges[0]],\n        nodes: [pageOne.items.nodes[0], pageTwo.items.nodes[0]],\n      },\n    });\n  });\n});\n"
  },
  {
    "path": "exchanges/graphcache/src/extras/relayPagination.ts",
    "content": "import { stringifyVariables } from '@urql/core';\nimport type { Cache, Resolver, Variables, NullArray } from '../types';\n\nexport type MergeMode = 'outwards' | 'inwards';\n\n/** Input parameters for the {@link relayPagination} factory. */\nexport interface PaginationParams {\n  /** Flip between inwards and outwards pagination.\n   *\n   * @remarks\n   * This is only relevant if you’re querying pages using forwards and\n   * backwards pagination at the same time.\n   * When set to `'inwards'`, its default, pages that have been queried\n   * forward are placed in front of all pages that were queried backwards.\n   * When set to `'outwards'`, the two sets are merged in reverse.\n   */\n  mergeMode?: MergeMode;\n}\n\ninterface PageInfo {\n  __typename: string;\n  endCursor: null | string;\n  startCursor: null | string;\n  hasNextPage: boolean;\n  hasPreviousPage: boolean;\n}\n\ninterface Page {\n  __typename: string;\n  edges: NullArray<string>;\n  nodes: NullArray<string>;\n  pageInfo: PageInfo;\n}\n\nconst defaultPageInfo: PageInfo = {\n  __typename: 'PageInfo',\n  endCursor: null,\n  startCursor: null,\n  hasNextPage: false,\n  hasPreviousPage: false,\n};\n\nconst ensureKey = (x: any): string | null => (typeof x === 'string' ? x : null);\n\nconst concatEdges = (\n  cache: Cache,\n  leftEdges: NullArray<string>,\n  rightEdges: NullArray<string>\n) => {\n  const ids = new Set<string>();\n  for (let i = 0, l = leftEdges.length; i < l; i++) {\n    const edge = leftEdges[i] as string | null;\n    const node = cache.resolve(edge, 'node');\n    if (typeof node === 'string') ids.add(node);\n  }\n\n  const newEdges = leftEdges.slice();\n  for (let i = 0, l = rightEdges.length; i < l; i++) {\n    const edge = rightEdges[i] as string | null;\n    const node = cache.resolve(edge, 'node');\n    if (typeof node === 'string' && !ids.has(node)) {\n      ids.add(node);\n      newEdges.push(edge);\n    }\n  }\n\n  return newEdges;\n};\n\nconst concatNodes = (\n  leftNodes: NullArray<string>,\n  rightNodes: NullArray<string>\n) => {\n  const ids = new Set<string>();\n  for (let i = 0, l = leftNodes.length; i < l; i++) {\n    const node = leftNodes[i];\n    if (typeof node === 'string') ids.add(node);\n  }\n\n  const newNodes = leftNodes.slice();\n  for (let i = 0, l = rightNodes.length; i < l; i++) {\n    const node = rightNodes[i];\n    if (typeof node === 'string' && !ids.has(node)) {\n      ids.add(node);\n      newNodes.push(node);\n    }\n  }\n\n  return newNodes;\n};\n\nconst compareArgs = (\n  fieldArgs: Variables,\n  connectionArgs: Variables\n): boolean => {\n  for (const key in connectionArgs) {\n    if (\n      key === 'first' ||\n      key === 'last' ||\n      key === 'after' ||\n      key === 'before'\n    ) {\n      continue;\n    } else if (!(key in fieldArgs)) {\n      return false;\n    }\n\n    const argA = fieldArgs[key];\n    const argB = connectionArgs[key];\n\n    if (\n      typeof argA !== typeof argB || typeof argA !== 'object'\n        ? argA !== argB\n        : stringifyVariables(argA) !== stringifyVariables(argB)\n    ) {\n      return false;\n    }\n  }\n\n  for (const key in fieldArgs) {\n    if (\n      key === 'first' ||\n      key === 'last' ||\n      key === 'after' ||\n      key === 'before'\n    ) {\n      continue;\n    }\n\n    if (!(key in connectionArgs)) return false;\n  }\n\n  return true;\n};\n\nconst getPage = (\n  cache: Cache,\n  entityKey: string,\n  fieldKey: string\n): Page | null => {\n  const link = ensureKey(cache.resolve(entityKey, fieldKey));\n  if (!link) return null;\n\n  const typename = cache.resolve(link, '__typename') as string;\n  const edges = (cache.resolve(link, 'edges') || []) as NullArray<string>;\n  const nodes = (cache.resolve(link, 'nodes') || []) as NullArray<string>;\n  if (typeof typename !== 'string') {\n    return null;\n  }\n\n  const page: Page = {\n    __typename: typename,\n    edges,\n    nodes,\n    pageInfo: defaultPageInfo,\n  };\n\n  const pageInfoKey = cache.resolve(link, 'pageInfo');\n  if (typeof pageInfoKey === 'string') {\n    const pageInfoType = ensureKey(cache.resolve(pageInfoKey, '__typename'));\n    const endCursor = ensureKey(cache.resolve(pageInfoKey, 'endCursor'));\n    const startCursor = ensureKey(cache.resolve(pageInfoKey, 'startCursor'));\n    const hasNextPage = cache.resolve(pageInfoKey, 'hasNextPage');\n    const hasPreviousPage = cache.resolve(pageInfoKey, 'hasPreviousPage');\n\n    const pageInfo: PageInfo = (page.pageInfo = {\n      __typename: typeof pageInfoType === 'string' ? pageInfoType : 'PageInfo',\n      hasNextPage: typeof hasNextPage === 'boolean' ? hasNextPage : !!endCursor,\n      hasPreviousPage:\n        typeof hasPreviousPage === 'boolean' ? hasPreviousPage : !!startCursor,\n      endCursor,\n      startCursor,\n    });\n\n    if (pageInfo.endCursor === null) {\n      const edge = edges[edges.length - 1] as string | null;\n      if (edge) {\n        const endCursor = cache.resolve(edge, 'cursor');\n        pageInfo.endCursor = ensureKey(endCursor);\n      }\n    }\n\n    if (pageInfo.startCursor === null) {\n      const edge = edges[0] as string | null;\n      if (edge) {\n        const startCursor = cache.resolve(edge, 'cursor');\n        pageInfo.startCursor = ensureKey(startCursor);\n      }\n    }\n  }\n\n  return page;\n};\n\n/** Creates a {@link Resolver} that combines pages that comply to the Relay pagination spec.\n *\n * @param params - A {@link PaginationParams} configuration object.\n * @returns the created Relay pagination {@link Resolver}.\n *\n * @remarks\n * `relayPagination` is a factory that creates a {@link Resolver} that can combine\n * multiple pages on a field that complies to the Relay pagination spec into a single,\n * combined list for infinite scrolling.\n *\n * This resolver will only work on fields that return a `Connection` GraphQL object\n * type, according to the Relay pagination spec.\n *\n * Hint: It's not recommended to use this when you can handle infinite scrolling\n * in your UI code instead.\n *\n * @see {@link https://urql.dev/goto/docs/graphcache/local-resolvers#relay-pagination} for more information.\n * @see {@link https://urql.dev/goto/docs/basics/ui-patterns/#infinite-scrolling} for an alternate approach.\n */\nexport const relayPagination = (\n  params: PaginationParams = {}\n): Resolver<any, any, any> => {\n  const mergeMode = params.mergeMode || 'inwards';\n\n  return (_parent, fieldArgs, cache, info) => {\n    const { parentKey: entityKey, fieldName } = info;\n\n    const allFields = cache.inspectFields(entityKey);\n    const fieldInfos = allFields.filter(info => info.fieldName === fieldName);\n    const size = fieldInfos.length;\n    if (size === 0) {\n      return undefined;\n    }\n\n    let typename: string | null = null;\n    let startEdges: NullArray<string> = [];\n    let endEdges: NullArray<string> = [];\n    let startNodes: NullArray<string> = [];\n    let endNodes: NullArray<string> = [];\n    let pageInfo: PageInfo = { ...defaultPageInfo };\n\n    for (let i = 0; i < size; i++) {\n      const { fieldKey, arguments: args } = fieldInfos[i];\n      if (args === null || !compareArgs(fieldArgs, args)) {\n        continue;\n      }\n\n      const page = getPage(cache, entityKey, fieldKey);\n      if (page === null) {\n        continue;\n      }\n      if (page.nodes.length === 0 && page.edges.length === 0 && typename) {\n        continue;\n      }\n\n      if (\n        mergeMode === 'inwards' &&\n        typeof args.last === 'number' &&\n        typeof args.first === 'number'\n      ) {\n        const firstEdges = page.edges.slice(0, args.first + 1);\n        const lastEdges = page.edges.slice(-args.last);\n        const firstNodes = page.nodes.slice(0, args.first + 1);\n        const lastNodes = page.nodes.slice(-args.last);\n\n        startEdges = concatEdges(cache, startEdges, firstEdges);\n        endEdges = concatEdges(cache, lastEdges, endEdges);\n        startNodes = concatNodes(startNodes, firstNodes);\n        endNodes = concatNodes(lastNodes, endNodes);\n\n        pageInfo = page.pageInfo;\n      } else if (args.after) {\n        startEdges = concatEdges(cache, startEdges, page.edges);\n        startNodes = concatNodes(startNodes, page.nodes);\n        pageInfo.endCursor = page.pageInfo.endCursor;\n        pageInfo.hasNextPage = page.pageInfo.hasNextPage;\n      } else if (args.before) {\n        endEdges = concatEdges(cache, page.edges, endEdges);\n        endNodes = concatNodes(page.nodes, endNodes);\n        pageInfo.startCursor = page.pageInfo.startCursor;\n        pageInfo.hasPreviousPage = page.pageInfo.hasPreviousPage;\n      } else if (typeof args.last === 'number') {\n        endEdges = concatEdges(cache, page.edges, endEdges);\n        endNodes = concatNodes(page.nodes, endNodes);\n        pageInfo = page.pageInfo;\n      } else {\n        startEdges = concatEdges(cache, startEdges, page.edges);\n        startNodes = concatNodes(startNodes, page.nodes);\n        pageInfo = page.pageInfo;\n      }\n\n      if (page.pageInfo.__typename !== pageInfo.__typename)\n        pageInfo.__typename = page.pageInfo.__typename;\n      if (typename !== page.__typename) typename = page.__typename;\n    }\n\n    if (typeof typename !== 'string') {\n      return undefined;\n    }\n\n    const hasCurrentPage = !!ensureKey(\n      cache.resolve(entityKey, fieldName, fieldArgs)\n    );\n    if (!hasCurrentPage) {\n      if (!(info as any).store.schema) {\n        return undefined;\n      } else {\n        info.partial = true;\n      }\n    }\n\n    return {\n      __typename: typename,\n      edges:\n        mergeMode === 'inwards'\n          ? concatEdges(cache, startEdges, endEdges)\n          : concatEdges(cache, endEdges, startEdges),\n      nodes:\n        mergeMode === 'inwards'\n          ? concatNodes(startNodes, endNodes)\n          : concatNodes(endNodes, startNodes),\n      pageInfo: {\n        __typename: pageInfo.__typename,\n        endCursor: pageInfo.endCursor,\n        startCursor: pageInfo.startCursor,\n        hasNextPage: pageInfo.hasNextPage,\n        hasPreviousPage: pageInfo.hasPreviousPage,\n      },\n    };\n  };\n};\n"
  },
  {
    "path": "exchanges/graphcache/src/extras/simplePagination.test.ts",
    "content": "import { gql } from '@urql/core';\nimport { it, expect, describe } from 'vitest';\nimport { __initAnd_query as query } from '../operations/query';\nimport { __initAnd_write as write } from '../operations/write';\nimport { Store } from '../store/store';\nimport { MergeMode, simplePagination } from './simplePagination';\n\ndescribe('as resolver', () => {\n  it('works with forward pagination', () => {\n    const Pagination = gql`\n      query ($skip: Number, $limit: Number) {\n        __typename\n        persons(skip: $skip, limit: $limit) {\n          __typename\n          id\n          name\n        }\n      }\n    `;\n\n    const store = new Store({\n      resolvers: {\n        Query: {\n          persons: simplePagination(),\n        },\n      },\n    });\n\n    const pageOne = {\n      __typename: 'Query',\n      persons: [\n        { id: 1, name: 'Jovi', __typename: 'Person' },\n        { id: 2, name: 'Phil', __typename: 'Person' },\n        { id: 3, name: 'Andy', __typename: 'Person' },\n      ],\n    };\n\n    const pageTwo = {\n      __typename: 'Query',\n      persons: [\n        { id: 4, name: 'Kadi', __typename: 'Person' },\n        { id: 5, name: 'Dom', __typename: 'Person' },\n        { id: 6, name: 'Sofia', __typename: 'Person' },\n      ],\n    };\n\n    write(\n      store,\n      { query: Pagination, variables: { skip: 0, limit: 3 } },\n      pageOne\n    );\n    const pageOneResult = query(store, {\n      query: Pagination,\n      variables: { skip: 0, limit: 3 },\n    });\n    expect(pageOneResult.data).toEqual(pageOne);\n\n    write(\n      store,\n      { query: Pagination, variables: { skip: 3, limit: 3 } },\n      pageTwo\n    );\n\n    const pageTwoResult = query(store, {\n      query: Pagination,\n      variables: { skip: 3, limit: 3 },\n    });\n    expect((pageTwoResult.data as any).persons).toEqual([\n      ...pageOne.persons,\n      ...pageTwo.persons,\n    ]);\n\n    const pageThreeResult = query(store, {\n      query: Pagination,\n      variables: { skip: 6, limit: 3 },\n    });\n    expect(pageThreeResult.data).toEqual(null);\n  });\n\n  it('works with backwards pagination', () => {\n    const Pagination = gql`\n      query ($skip: Number, $limit: Number) {\n        __typename\n        persons(skip: $skip, limit: $limit) {\n          __typename\n          id\n          name\n        }\n      }\n    `;\n\n    const store = new Store({\n      resolvers: {\n        Query: {\n          persons: simplePagination({ mergeMode: 'before' }),\n        },\n      },\n    });\n\n    const pageOne = {\n      __typename: 'Query',\n      persons: [\n        { id: 7, name: 'Jovi', __typename: 'Person' },\n        { id: 8, name: 'Phil', __typename: 'Person' },\n        { id: 9, name: 'Andy', __typename: 'Person' },\n      ],\n    };\n\n    const pageTwo = {\n      __typename: 'Query',\n      persons: [\n        { id: 4, name: 'Kadi', __typename: 'Person' },\n        { id: 5, name: 'Dom', __typename: 'Person' },\n        { id: 6, name: 'Sofia', __typename: 'Person' },\n      ],\n    };\n\n    write(\n      store,\n      { query: Pagination, variables: { skip: 0, limit: 3 } },\n      pageOne\n    );\n    const pageOneResult = query(store, {\n      query: Pagination,\n      variables: { skip: 0, limit: 3 },\n    });\n    expect(pageOneResult.data).toEqual(pageOne);\n\n    write(\n      store,\n      { query: Pagination, variables: { skip: 3, limit: 3 } },\n      pageTwo\n    );\n\n    const pageTwoResult = query(store, {\n      query: Pagination,\n      variables: { skip: 3, limit: 3 },\n    });\n    expect((pageTwoResult.data as any).persons).toEqual([\n      ...pageTwo.persons,\n      ...pageOne.persons,\n    ]);\n\n    const pageThreeResult = query(store, {\n      query: Pagination,\n      variables: { skip: 6, limit: 3 },\n    });\n    expect(pageThreeResult.data).toEqual(null);\n  });\n\n  it('handles duplicates', () => {\n    const Pagination = gql`\n      query ($skip: Number, $limit: Number) {\n        __typename\n        persons(skip: $skip, limit: $limit) {\n          __typename\n          id\n          name\n        }\n      }\n    `;\n\n    const store = new Store({\n      resolvers: {\n        Query: {\n          persons: simplePagination(),\n        },\n      },\n    });\n\n    const pageOne = {\n      __typename: 'Query',\n      persons: [\n        { id: 1, name: 'Jovi', __typename: 'Person' },\n        { id: 2, name: 'Phil', __typename: 'Person' },\n        { id: 3, name: 'Andy', __typename: 'Person' },\n      ],\n    };\n\n    const pageTwo = {\n      __typename: 'Query',\n      persons: [\n        { id: 3, name: 'Andy', __typename: 'Person' },\n        { id: 4, name: 'Kadi', __typename: 'Person' },\n        { id: 5, name: 'Dom', __typename: 'Person' },\n      ],\n    };\n\n    write(\n      store,\n      { query: Pagination, variables: { skip: 0, limit: 3 } },\n      pageOne\n    );\n    write(\n      store,\n      { query: Pagination, variables: { skip: 2, limit: 3 } },\n      pageTwo\n    );\n\n    const result = query(store, {\n      query: Pagination,\n      variables: { skip: 2, limit: 3 },\n    });\n    expect(result.data).toEqual({\n      __typename: 'Query',\n      persons: [...pageOne.persons, pageTwo.persons[1], pageTwo.persons[2]],\n    });\n  });\n\n  it('should not return previous result when adding a parameter', () => {\n    const Pagination = gql`\n      query ($skip: Number, $limit: Number, $filter: String) {\n        __typename\n        persons(skip: $skip, limit: $limit, filter: $filter) {\n          __typename\n          id\n          name\n        }\n      }\n    `;\n\n    const store = new Store({\n      resolvers: {\n        Query: {\n          persons: simplePagination(),\n        },\n      },\n    });\n\n    const pageOne = {\n      __typename: 'Query',\n      persons: [\n        { id: 1, name: 'Jovi', __typename: 'Person' },\n        { id: 2, name: 'Phil', __typename: 'Person' },\n        { id: 3, name: 'Andy', __typename: 'Person' },\n      ],\n    };\n\n    const emptyPage = {\n      __typename: 'Query',\n      persons: [],\n    };\n\n    write(\n      store,\n      { query: Pagination, variables: { skip: 0, limit: 3 } },\n      pageOne\n    );\n    write(\n      store,\n      { query: Pagination, variables: { skip: 0, limit: 3, filter: 'b' } },\n      emptyPage\n    );\n\n    const res = query(store, {\n      query: Pagination,\n      variables: { skip: 0, limit: 3, filter: 'b' },\n    });\n    expect(res.data).toEqual({ __typename: 'Query', persons: [] });\n  });\n\n  it('should preserve the correct order in forward pagination', () => {\n    const Pagination = gql`\n      query ($skip: Number, $limit: Number) {\n        __typename\n        persons(skip: $skip, limit: $limit) {\n          __typename\n          id\n          name\n        }\n      }\n    `;\n\n    const store = new Store({\n      resolvers: {\n        Query: {\n          persons: simplePagination({ mergeMode: 'after' }),\n        },\n      },\n    });\n\n    const pageOne = {\n      __typename: 'Query',\n      persons: [\n        { id: 1, name: 'Jovi', __typename: 'Person' },\n        { id: 2, name: 'Phil', __typename: 'Person' },\n        { id: 3, name: 'Andy', __typename: 'Person' },\n      ],\n    };\n\n    const pageTwo = {\n      __typename: 'Query',\n      persons: [\n        { id: 4, name: 'Kadi', __typename: 'Person' },\n        { id: 5, name: 'Dom', __typename: 'Person' },\n        { id: 6, name: 'Sofia', __typename: 'Person' },\n      ],\n    };\n\n    write(\n      store,\n      { query: Pagination, variables: { skip: 3, limit: 3 } },\n      pageTwo\n    );\n    write(\n      store,\n      { query: Pagination, variables: { skip: 0, limit: 3 } },\n      pageOne\n    );\n\n    const result = query(store, {\n      query: Pagination,\n      variables: { skip: 3, limit: 3 },\n    });\n    expect(result.data).toEqual({\n      __typename: 'Query',\n      persons: [...pageOne.persons, ...pageTwo.persons],\n    });\n  });\n\n  it('should preserve the correct order in backward pagination', () => {\n    const Pagination = gql`\n      query ($skip: Number, $limit: Number) {\n        __typename\n        persons(skip: $skip, limit: $limit) {\n          __typename\n          id\n          name\n        }\n      }\n    `;\n\n    const store = new Store({\n      resolvers: {\n        Query: {\n          persons: simplePagination({ mergeMode: 'before' }),\n        },\n      },\n    });\n\n    const pageOne = {\n      __typename: 'Query',\n      persons: [\n        { id: 7, name: 'Jovi', __typename: 'Person' },\n        { id: 8, name: 'Phil', __typename: 'Person' },\n        { id: 9, name: 'Andy', __typename: 'Person' },\n      ],\n    };\n\n    const pageTwo = {\n      __typename: 'Query',\n      persons: [\n        { id: 4, name: 'Kadi', __typename: 'Person' },\n        { id: 5, name: 'Dom', __typename: 'Person' },\n        { id: 6, name: 'Sofia', __typename: 'Person' },\n      ],\n    };\n\n    write(\n      store,\n      { query: Pagination, variables: { skip: 3, limit: 3 } },\n      pageTwo\n    );\n    write(\n      store,\n      { query: Pagination, variables: { skip: 0, limit: 3 } },\n      pageOne\n    );\n\n    const result = query(store, {\n      query: Pagination,\n      variables: { skip: 3, limit: 3 },\n    });\n\n    expect(result.data).toEqual({\n      __typename: 'Query',\n      persons: [...pageTwo.persons, ...pageOne.persons],\n    });\n  });\n\n  it('prevents overlapping of pagination on different arguments', () => {\n    const Pagination = gql`\n      query ($skip: Number, $limit: Number, $filter: string) {\n        __typename\n        persons(skip: $skip, limit: $limit, filter: $filter) {\n          __typename\n          id\n          name\n        }\n      }\n    `;\n\n    const store = new Store({\n      resolvers: {\n        Query: {\n          persons: simplePagination(),\n        },\n      },\n    });\n\n    const page = withId => ({\n      __typename: 'Query',\n      persons: [{ id: withId, name: withId, __typename: 'Person' }],\n    });\n\n    write(\n      store,\n      { query: Pagination, variables: { filter: 'one', skip: 0, limit: 1 } },\n      page('one')\n    );\n\n    write(\n      store,\n      { query: Pagination, variables: { filter: 'two', skip: 1, limit: 1 } },\n      page('two')\n    );\n\n    const resOne = query(store, {\n      query: Pagination,\n      variables: { filter: 'one', skip: 0, limit: 1 },\n    });\n    const resTwo = query(store, {\n      query: Pagination,\n      variables: { filter: 'two', skip: 1, limit: 1 },\n    });\n    const resThree = query(store, {\n      query: Pagination,\n      variables: { filter: 'three', skip: 2, limit: 1 },\n    });\n\n    expect(resOne.data).toHaveProperty('persons[0].id', 'one');\n    expect(resOne.data).toHaveProperty('persons.length', 1);\n\n    expect(resTwo.data).toHaveProperty('persons[0].id', 'two');\n    expect(resTwo.data).toHaveProperty('persons.length', 1);\n\n    expect(resThree.data).toEqual(null);\n  });\n});\n\ndescribe('as directive', () => {\n  it('works with forward pagination', () => {\n    const Pagination = gql`\n      query ($skip: Number, $limit: Number) {\n        __typename\n        persons(skip: $skip, limit: $limit) @_simplePagination {\n          __typename\n          id\n          name\n        }\n      }\n    `;\n\n    const store = new Store({\n      directives: {\n        simplePagination: () => simplePagination(),\n      },\n    });\n\n    const pageOne = {\n      __typename: 'Query',\n      persons: [\n        { id: 1, name: 'Jovi', __typename: 'Person' },\n        { id: 2, name: 'Phil', __typename: 'Person' },\n        { id: 3, name: 'Andy', __typename: 'Person' },\n      ],\n    };\n\n    const pageTwo = {\n      __typename: 'Query',\n      persons: [\n        { id: 4, name: 'Kadi', __typename: 'Person' },\n        { id: 5, name: 'Dom', __typename: 'Person' },\n        { id: 6, name: 'Sofia', __typename: 'Person' },\n      ],\n    };\n\n    write(\n      store,\n      { query: Pagination, variables: { skip: 0, limit: 3 } },\n      pageOne\n    );\n    const pageOneResult = query(store, {\n      query: Pagination,\n      variables: { skip: 0, limit: 3 },\n    });\n    expect(pageOneResult.data).toEqual(pageOne);\n\n    write(\n      store,\n      { query: Pagination, variables: { skip: 3, limit: 3 } },\n      pageTwo\n    );\n\n    const pageTwoResult = query(store, {\n      query: Pagination,\n      variables: { skip: 3, limit: 3 },\n    });\n\n    expect((pageTwoResult.data as any).persons).toEqual([\n      ...pageOne.persons,\n      ...pageTwo.persons,\n    ]);\n\n    const pageThreeResult = query(store, {\n      query: Pagination,\n      variables: { skip: 6, limit: 3 },\n    });\n    expect(pageThreeResult.data).toEqual(null);\n  });\n\n  it('works with backwards pagination', () => {\n    const Pagination = gql`\n      query ($skip: Number, $limit: Number) {\n        __typename\n        persons(skip: $skip, limit: $limit)\n          @_simplePagination(mergeMode: \"before\") {\n          __typename\n          id\n          name\n        }\n      }\n    `;\n\n    const store = new Store({\n      directives: {\n        simplePagination: directiveArguments =>\n          simplePagination({\n            mergeMode: directiveArguments!.mergeMode as MergeMode,\n          }),\n      },\n    });\n\n    const pageOne = {\n      __typename: 'Query',\n      persons: [\n        { id: 7, name: 'Jovi', __typename: 'Person' },\n        { id: 8, name: 'Phil', __typename: 'Person' },\n        { id: 9, name: 'Andy', __typename: 'Person' },\n      ],\n    };\n\n    const pageTwo = {\n      __typename: 'Query',\n      persons: [\n        { id: 4, name: 'Kadi', __typename: 'Person' },\n        { id: 5, name: 'Dom', __typename: 'Person' },\n        { id: 6, name: 'Sofia', __typename: 'Person' },\n      ],\n    };\n\n    write(\n      store,\n      { query: Pagination, variables: { skip: 0, limit: 3 } },\n      pageOne\n    );\n    const pageOneResult = query(store, {\n      query: Pagination,\n      variables: { skip: 0, limit: 3 },\n    });\n    expect(pageOneResult.data).toEqual(pageOne);\n\n    write(\n      store,\n      { query: Pagination, variables: { skip: 3, limit: 3 } },\n      pageTwo\n    );\n\n    const pageTwoResult = query(store, {\n      query: Pagination,\n      variables: { skip: 3, limit: 3 },\n    });\n    expect((pageTwoResult.data as any).persons).toEqual([\n      ...pageTwo.persons,\n      ...pageOne.persons,\n    ]);\n\n    const pageThreeResult = query(store, {\n      query: Pagination,\n      variables: { skip: 6, limit: 3 },\n    });\n    expect(pageThreeResult.data).toEqual(null);\n  });\n});\n"
  },
  {
    "path": "exchanges/graphcache/src/extras/simplePagination.ts",
    "content": "import { stringifyVariables } from '@urql/core';\nimport type { Resolver, Variables, NullArray } from '../types';\n\nexport type MergeMode = 'before' | 'after';\n\n/** Input parameters for the {@link simplePagination} factory. */\nexport interface PaginationParams {\n  /** The name of the field argument used to define the page’s offset. */\n  offsetArgument?: string;\n  /** The name of the field argument used to define the page’s length. */\n  limitArgument?: string;\n  /** Flip between forward and backwards pagination.\n   *\n   * @remarks\n   * When set to `'after'`, its default, pages are merged forwards and in order.\n   * When set to `'before'`, pages are merged in reverse, putting later pages\n   * in front of earlier ones.\n   */\n  mergeMode?: MergeMode;\n}\n\n/** Creates a {@link Resolver} that combines pages of a primitive pagination field.\n *\n * @param options - A {@link PaginationParams} configuration object.\n * @returns the created pagination {@link Resolver}.\n *\n * @remarks\n * `simplePagination` is a factory that creates a {@link Resolver} that can combine\n * multiple lists on a paginated field into a single, combined list for infinite\n * scrolling.\n *\n * Hint: It's not recommended to use this when you can handle infinite scrolling\n * in your UI code instead.\n *\n * @see {@link https://urql.dev/goto/docs/graphcache/local-resolvers#simple-pagination} for more information.\n * @see {@link https://urql.dev/goto/docs/basics/ui-patterns/#infinite-scrolling} for an alternate approach.\n */\nexport const simplePagination = ({\n  offsetArgument = 'skip',\n  limitArgument = 'limit',\n  mergeMode = 'after',\n}: PaginationParams = {}): Resolver<any, any, any> => {\n  const compareArgs = (\n    fieldArgs: Variables,\n    connectionArgs: Variables\n  ): boolean => {\n    for (const key in connectionArgs) {\n      if (key === offsetArgument || key === limitArgument) {\n        continue;\n      } else if (!(key in fieldArgs)) {\n        return false;\n      }\n\n      const argA = fieldArgs[key];\n      const argB = connectionArgs[key];\n\n      if (\n        typeof argA !== typeof argB || typeof argA !== 'object'\n          ? argA !== argB\n          : stringifyVariables(argA) !== stringifyVariables(argB)\n      ) {\n        return false;\n      }\n    }\n\n    for (const key in fieldArgs) {\n      if (key === offsetArgument || key === limitArgument) {\n        continue;\n      }\n      if (!(key in connectionArgs)) return false;\n    }\n\n    return true;\n  };\n\n  return (_parent, fieldArgs, cache, info) => {\n    const { parentKey: entityKey, fieldName } = info;\n\n    const allFields = cache.inspectFields(entityKey);\n    const fieldInfos = allFields.filter(info => info.fieldName === fieldName);\n    const size = fieldInfos.length;\n    if (size === 0) {\n      return undefined;\n    }\n\n    const visited = new Set();\n    let result: NullArray<string> = [];\n    let prevOffset: number | null = null;\n\n    for (let i = 0; i < size; i++) {\n      const { fieldKey, arguments: args } = fieldInfos[i];\n      if (args === null || !compareArgs(fieldArgs, args)) {\n        continue;\n      }\n\n      const links = cache.resolve(entityKey, fieldKey) as string[];\n      const currentOffset = args[offsetArgument];\n\n      if (\n        links === null ||\n        links.length === 0 ||\n        typeof currentOffset !== 'number'\n      ) {\n        continue;\n      }\n\n      const tempResult: NullArray<string> = [];\n\n      for (let j = 0; j < links.length; j++) {\n        const link = links[j];\n        if (visited.has(link)) continue;\n        tempResult.push(link);\n        visited.add(link);\n      }\n\n      if (\n        (!prevOffset || currentOffset > prevOffset) ===\n        (mergeMode === 'after')\n      ) {\n        result = [...result, ...tempResult];\n      } else {\n        result = [...tempResult, ...result];\n      }\n\n      prevOffset = currentOffset;\n    }\n\n    const hasCurrentPage = cache.resolve(entityKey, fieldName, fieldArgs);\n    if (hasCurrentPage) {\n      return result;\n    } else if (!(info as any).store.schema) {\n      return undefined;\n    } else {\n      info.partial = true;\n      return result;\n    }\n  };\n};\n"
  },
  {
    "path": "exchanges/graphcache/src/helpers/help.ts",
    "content": "// These are guards that are used throughout the codebase to warn or error on\n// unexpected behaviour or conditions.\n// Every warning and error comes with a number that uniquely identifies them.\n// You can read more about the messages themselves in `docs/graphcache/errors.md`\n\nimport type {\n  ExecutableDefinitionNode,\n  InlineFragmentNode,\n} from '@0no-co/graphql.web';\nimport type { Logger } from '../types';\nimport { Kind } from '@0no-co/graphql.web';\n\nexport type ErrorCode =\n  | 1\n  | 2\n  | 3\n  | 4\n  | 5\n  | 6\n  | 7\n  | 8\n  | 9\n  | 10\n  | 11\n  | 12\n  | 13\n  | 14\n  | 15\n  | 16\n  | 17\n  | 18\n  | 19\n  | 20\n  | 21\n  | 22\n  | 23\n  | 24\n  | 25\n  | 26\n  | 27\n  | 28;\n\ntype DebugNode = ExecutableDefinitionNode | InlineFragmentNode;\n\n// URL unfurls to https://formidable.com/open-source/urql/docs/graphcache/errors/\nconst helpUrl = '\\nhttps://bit.ly/2XbVrpR#';\nconst cache = new Set<string>();\n\nexport const currentDebugStack: string[] = [];\n\nexport const popDebugNode = () => currentDebugStack.pop();\n\nexport const pushDebugNode = (typename: void | string, node: DebugNode) => {\n  let identifier = '';\n  if (node.kind === Kind.INLINE_FRAGMENT) {\n    identifier = typename\n      ? `Inline Fragment on \"${typename}\"`\n      : 'Inline Fragment';\n  } else if (node.kind === Kind.OPERATION_DEFINITION) {\n    const name = node.name ? `\"${node.name.value}\"` : 'Unnamed';\n    identifier = `${name} ${node.operation}`;\n  } else if (node.kind === Kind.FRAGMENT_DEFINITION) {\n    identifier = `\"${node.name.value}\" Fragment`;\n  }\n\n  if (identifier) {\n    currentDebugStack.push(identifier);\n  }\n};\n\nconst getDebugOutput = (): string =>\n  currentDebugStack.length\n    ? '\\n(Caused At: ' + currentDebugStack.join(', ') + ')'\n    : '';\n\nexport function invariant(\n  condition: any,\n  message: string,\n  code: ErrorCode\n): asserts condition {\n  if (!condition) {\n    let errorMessage = message || 'Minfied Error #' + code + '\\n';\n    if (process.env.NODE_ENV !== 'production') {\n      errorMessage += getDebugOutput();\n    }\n\n    const error = new Error(errorMessage + helpUrl + code);\n    error.name = 'Graphcache Error';\n    throw error;\n  }\n}\n\nexport function warn(\n  message: string,\n  code: ErrorCode,\n  logger: Logger | undefined\n) {\n  if (!cache.has(message)) {\n    if (logger) {\n      logger('warn', message + getDebugOutput() + helpUrl + code);\n    } else {\n      console.warn(message + getDebugOutput() + helpUrl + code);\n    }\n    cache.add(message);\n  }\n}\n"
  },
  {
    "path": "exchanges/graphcache/src/helpers/operation.ts",
    "content": "import type { Operation, RequestPolicy, OperationDebugMeta } from '@urql/core';\nimport { makeOperation } from '@urql/core';\n\n// Returns the given operation result with added cacheOutcome meta field\nexport const addMetadata = (\n  operation: Operation,\n  meta: OperationDebugMeta\n): Operation =>\n  makeOperation(operation.kind, operation, {\n    ...operation.context,\n    meta: {\n      ...operation.context.meta,\n      ...meta,\n    },\n  });\n\n// Copy an operation and change the requestPolicy to skip the cache\nexport const toRequestPolicy = (\n  operation: Operation,\n  requestPolicy: RequestPolicy\n): Operation => {\n  return makeOperation(operation.kind, operation, {\n    ...operation.context,\n    requestPolicy,\n  });\n};\n"
  },
  {
    "path": "exchanges/graphcache/src/index.ts",
    "content": "export * from './types';\nexport { Store } from './store/store';\nexport { cacheExchange } from './cacheExchange';\nexport { offlineExchange } from './offlineExchange';\n"
  },
  {
    "path": "exchanges/graphcache/src/offlineExchange.test.ts",
    "content": "import {\n  gql,\n  createClient,\n  ExchangeIO,\n  Operation,\n  OperationResult,\n} from '@urql/core';\nimport { vi, expect, it, describe, beforeAll, afterAll } from 'vitest';\n\nimport { pipe, share, map, makeSubject, tap, publish } from 'wonka';\nimport { queryResponse } from '../../../packages/core/src/test-utils';\nimport { offlineExchange } from './offlineExchange';\n\nconst mutationOne = gql`\n  mutation {\n    updateAuthor {\n      id\n      name\n    }\n  }\n`;\n\nconst mutationOneData = {\n  __typename: 'Mutation',\n  updateAuthor: {\n    __typename: 'Author',\n    id: '123',\n    name: 'Author',\n  },\n};\n\nconst queryOne = gql`\n  query {\n    authors {\n      id\n      name\n      __typename\n    }\n  }\n`;\n\nconst queryOneData = {\n  __typename: 'Query',\n  authors: [\n    {\n      id: '123',\n      name: 'Me',\n      __typename: 'Author',\n    },\n  ],\n};\n\nconst dispatchDebug = vi.fn();\n\nconst storage = {\n  onOnline: vi.fn(),\n  writeData: vi.fn(() => Promise.resolve(undefined)),\n  writeMetadata: vi.fn(() => Promise.resolve(undefined)),\n  readData: vi.fn(() => Promise.resolve({})),\n  readMetadata: vi.fn(() => Promise.resolve([])),\n};\n\ndescribe('storage', () => {\n  it('should read the metadata and dispatch operations on initialization', () => {\n    const client = createClient({\n      url: 'http://0.0.0.0',\n      exchanges: [],\n    });\n\n    const reexecuteOperation = vi\n      .spyOn(client, 'reexecuteOperation')\n      .mockImplementation(() => undefined);\n    const op = client.createRequestOperation('mutation', {\n      key: 1,\n      query: mutationOne,\n      variables: {},\n    });\n\n    const response = vi.fn((forwardOp: Operation): OperationResult => {\n      expect(forwardOp.key).toBe(op.key);\n      return {\n        ...queryResponse,\n        operation: forwardOp,\n        data: mutationOneData,\n      };\n    });\n\n    const { source: ops$ } = makeSubject<Operation>();\n    const result = vi.fn();\n    const forward: ExchangeIO = ops$ => pipe(ops$, map(response), share);\n\n    vi.useFakeTimers();\n    pipe(\n      offlineExchange({ storage })({ forward, client, dispatchDebug })(ops$),\n      tap(result),\n      publish\n    );\n    vi.runAllTimers();\n\n    expect(storage.readMetadata).toBeCalledTimes(1);\n    expect(reexecuteOperation).toBeCalledTimes(0);\n  });\n});\n\ndescribe('offline', () => {\n  beforeAll(() => {\n    vi.resetAllMocks();\n    vi.stubGlobal('navigator', { onLine: true });\n  });\n\n  afterAll(() => {\n    vi.unstubAllGlobals();\n  });\n\n  it('should intercept errored mutations', () => {\n    const onlineSpy = vi.spyOn(globalThis.navigator, 'onLine', 'get');\n\n    const client = createClient({\n      url: 'http://0.0.0.0',\n      exchanges: [],\n    });\n\n    const queryOp = client.createRequestOperation('query', {\n      key: 1,\n      query: queryOne,\n      variables: {},\n    });\n\n    const mutationOp = client.createRequestOperation('mutation', {\n      key: 2,\n      query: mutationOne,\n      variables: {},\n    });\n\n    const response = vi.fn((forwardOp: Operation): OperationResult => {\n      if (forwardOp.key === queryOp.key) {\n        onlineSpy.mockReturnValueOnce(true);\n        return { ...queryResponse, operation: forwardOp, data: queryOneData };\n      } else {\n        onlineSpy.mockReturnValueOnce(false);\n        return {\n          ...queryResponse,\n          operation: forwardOp,\n          // @ts-ignore\n          error: { networkError: new Error('failed to fetch') },\n        };\n      }\n    });\n\n    const { source: ops$, next } = makeSubject<Operation>();\n    const result = vi.fn();\n    const forward: ExchangeIO = ops$ => pipe(ops$, map(response), share);\n\n    pipe(\n      offlineExchange({\n        storage,\n        optimistic: {\n          updateAuthor: () => ({\n            id: '123',\n            name: 'URQL',\n            __typename: 'Author',\n          }),\n        },\n      })({ forward, client, dispatchDebug })(ops$),\n      tap(result),\n      publish\n    );\n\n    next(queryOp);\n    expect(result).toBeCalledTimes(1);\n    expect(queryOneData).toMatchObject(result.mock.calls[0][0].data);\n\n    next(mutationOp);\n    expect(result).toBeCalledTimes(2);\n\n    next(queryOp);\n    expect(result).toBeCalledTimes(3);\n  });\n\n  it('should intercept errored queries', async () => {\n    const client = createClient({\n      url: 'http://0.0.0.0',\n      exchanges: [],\n    });\n    const onlineSpy = vi\n      .spyOn(navigator, 'onLine', 'get')\n      .mockReturnValueOnce(false);\n\n    const queryOp = client.createRequestOperation('query', {\n      key: 1,\n      query: queryOne,\n      variables: undefined,\n    });\n\n    const response = vi.fn((forwardOp: Operation): OperationResult => {\n      onlineSpy.mockReturnValueOnce(false);\n      return {\n        operation: forwardOp,\n        // @ts-ignore\n        error: { networkError: new Error('failed to fetch') },\n      };\n    });\n\n    const { source: ops$, next } = makeSubject<Operation>();\n    const result = vi.fn();\n    const forward: ExchangeIO = ops$ => pipe(ops$, map(response));\n\n    pipe(\n      offlineExchange({ storage })({ forward, client, dispatchDebug })(ops$),\n      tap(result),\n      publish\n    );\n\n    next(queryOp);\n\n    expect(result).toBeCalledTimes(1);\n    expect(response).toBeCalledTimes(1);\n\n    expect(result.mock.calls[0][0]).toEqual({\n      data: null,\n      error: undefined,\n      extensions: undefined,\n      operation: expect.any(Object),\n      hasNext: false,\n      stale: false,\n    });\n\n    expect(result.mock.calls[0][0]).toHaveProperty(\n      'operation.context.meta.cacheOutcome',\n      'miss'\n    );\n  });\n\n  it('should flush the queue when we become online', async () => {\n    let resolveOnOnlineCalled: () => void;\n    const onOnlineCalled = new Promise<void>(\n      resolve => (resolveOnOnlineCalled = resolve)\n    );\n\n    let flush: () => {};\n    storage.onOnline.mockImplementation(cb => {\n      flush = cb;\n      resolveOnOnlineCalled!();\n    });\n\n    const onlineSpy = vi.spyOn(navigator, 'onLine', 'get');\n\n    const client = createClient({\n      url: 'http://0.0.0.0',\n      exchanges: [],\n    });\n\n    const mutationOp = client.createRequestOperation('mutation', {\n      key: 1,\n      query: mutationOne,\n      variables: {},\n    });\n\n    const response = vi.fn((forwardOp: Operation): OperationResult => {\n      onlineSpy.mockReturnValueOnce(false);\n      return {\n        operation: forwardOp,\n        // @ts-ignore\n        error: { networkError: new Error('failed to fetch') },\n      };\n    });\n\n    const { source: ops$, next } = makeSubject<Operation>();\n    const result = vi.fn();\n    const forward: ExchangeIO = ops$ => pipe(ops$, map(response), share);\n\n    pipe(\n      offlineExchange({\n        storage,\n        optimistic: {\n          updateAuthor: () => ({\n            id: '123',\n            name: 'URQL',\n            __typename: 'Author',\n          }),\n        },\n      })({ forward, client, dispatchDebug })(ops$),\n      tap(result),\n      publish\n    );\n\n    next(mutationOp);\n\n    await onOnlineCalled;\n\n    flush!();\n  });\n});\n"
  },
  {
    "path": "exchanges/graphcache/src/offlineExchange.ts",
    "content": "import { pipe, share, merge, makeSubject, filter, onPush } from 'wonka';\n\nimport type {\n  Operation,\n  OperationResult,\n  Exchange,\n  ExchangeIO,\n  CombinedError,\n  RequestPolicy,\n} from '@urql/core';\nimport { stringifyDocument, createRequest, makeOperation } from '@urql/core';\n\nimport type {\n  SerializedRequest,\n  CacheExchangeOpts,\n  StorageAdapter,\n} from './types';\nimport { cacheExchange } from './cacheExchange';\nimport { toRequestPolicy } from './helpers/operation';\n\nconst policyLevel = {\n  'cache-only': 0,\n  'cache-first': 1,\n  'network-only': 2,\n  'cache-and-network': 3,\n} as const;\n\n/** Input parameters for the {@link offlineExchange}.\n * @remarks\n * This configuration object extends the {@link CacheExchangeOpts}\n * as the `offlineExchange` extends the regular {@link cacheExchange}.\n */\nexport interface OfflineExchangeOpts extends CacheExchangeOpts {\n  /** Configures an offline storage adapter for Graphcache.\n   *\n   * @remarks\n   * A {@link StorageAdapter} allows Graphcache to write data to an external,\n   * asynchronous storage, and hydrate data from it when it first loads.\n   * This allows you to preserve normalized data between restarts/reloads.\n   *\n   * @see {@link https://urql.dev/goto/docs/graphcache/offline} for the full Offline Support docs.\n   */\n  storage: StorageAdapter;\n  /** Predicate function to determine whether a {@link CombinedError} hints at a network error.\n   *\n   * @remarks\n   * Not ever {@link CombinedError} means that the device is offline and by default\n   * the `offlineExchange` will check for common network error messages and check\n   * `navigator.onLine`. However, when `isOfflineError` is passed it can replace\n   * the default offline detection.\n   */\n  isOfflineError?(\n    error: undefined | CombinedError,\n    result: OperationResult\n  ): boolean;\n}\n\n/** Exchange factory that creates a normalized cache exchange in Offline Support mode.\n *\n * @param opts - A {@link OfflineExchangeOpts} configuration object.\n * @returns the created normalized, offline cache {@link Exchange}.\n *\n * @remarks\n * The `offlineExchange` is a wrapper around the regular {@link cacheExchange}\n * which adds logic via the {@link OfflineExchangeOpts.storage} adapter to\n * recognize when it’s offline, when to retry failed mutations, and how\n * to handle longer periods of being offline.\n *\n * @see {@link https://urql.dev/goto/docs/graphcache/offline} for the full Offline Support docs.\n */\nexport const offlineExchange =\n  <C extends OfflineExchangeOpts>(opts: C): Exchange =>\n  input => {\n    const { storage } = opts;\n\n    const isOfflineError =\n      opts.isOfflineError ||\n      ((error: undefined | CombinedError) =>\n        error &&\n        error.networkError &&\n        !error.response &&\n        ((typeof navigator !== 'undefined' && navigator.onLine === false) ||\n          /request failed|failed to fetch|network\\s?error/i.test(\n            error.networkError.message\n          )));\n\n    if (\n      storage &&\n      storage.onOnline &&\n      storage.readMetadata &&\n      storage.writeMetadata\n    ) {\n      const { forward: outerForward, client, dispatchDebug } = input;\n      const { source: reboundOps$, next } = makeSubject<Operation>();\n      const failedQueue: Operation[] = [];\n      let hasRehydrated = false;\n      let isFlushingQueue = false;\n\n      const updateMetadata = () => {\n        if (hasRehydrated) {\n          const requests: SerializedRequest[] = [];\n          for (let i = 0; i < failedQueue.length; i++) {\n            const operation = failedQueue[i];\n            if (operation.kind === 'mutation') {\n              requests.push({\n                query: stringifyDocument(operation.query),\n                variables: operation.variables,\n                extensions: operation.extensions,\n              });\n            }\n          }\n          storage.writeMetadata!(requests);\n        }\n      };\n\n      const filterQueue = (key: number) => {\n        for (let i = failedQueue.length - 1; i >= 0; i--)\n          if (failedQueue[i].key === key) failedQueue.splice(i, 1);\n      };\n\n      const flushQueue = () => {\n        if (!isFlushingQueue) {\n          const sent = new Set<number>();\n          isFlushingQueue = true;\n          for (let i = 0; i < failedQueue.length; i++) {\n            const operation = failedQueue[i];\n            if (operation.kind === 'mutation' || !sent.has(operation.key)) {\n              sent.add(operation.key);\n              if (operation.kind !== 'subscription') {\n                next(makeOperation('teardown', operation));\n                let overridePolicy: RequestPolicy = 'cache-first';\n                for (let i = 0; i < failedQueue.length; i++) {\n                  const { requestPolicy } = failedQueue[i].context;\n                  if (policyLevel[requestPolicy] > policyLevel[overridePolicy])\n                    overridePolicy = requestPolicy;\n                }\n                next(toRequestPolicy(operation, overridePolicy));\n              } else {\n                next(toRequestPolicy(operation, 'cache-first'));\n              }\n            }\n          }\n          isFlushingQueue = false;\n          failedQueue.length = 0;\n          updateMetadata();\n        }\n      };\n\n      const forward: ExchangeIO = ops$ => {\n        return pipe(\n          outerForward(ops$),\n          filter(res => {\n            if (\n              hasRehydrated &&\n              res.operation.kind === 'mutation' &&\n              res.operation.context.optimistic &&\n              isOfflineError(res.error, res)\n            ) {\n              failedQueue.push(res.operation);\n              updateMetadata();\n              return false;\n            }\n\n            return true;\n          }),\n          share\n        );\n      };\n\n      const cacheResults$ = cacheExchange({\n        ...opts,\n        storage: {\n          ...storage,\n          readData() {\n            const hydrate = storage.readData();\n            return {\n              async then(onEntries) {\n                const mutations = await storage.readMetadata!();\n                for (let i = 0; mutations && i < mutations.length; i++) {\n                  failedQueue.push(\n                    client.createRequestOperation(\n                      'mutation',\n                      createRequest(mutations[i].query, mutations[i].variables),\n                      mutations[i].extensions\n                    )\n                  );\n                }\n                onEntries!(await hydrate);\n                storage.onOnline!(flushQueue);\n                hasRehydrated = true;\n                flushQueue();\n              },\n            };\n          },\n        },\n      })({\n        client,\n        dispatchDebug,\n        forward,\n      });\n\n      return operations$ => {\n        const opsAndRebound$ = merge([\n          reboundOps$,\n          pipe(\n            operations$,\n            onPush(operation => {\n              if (operation.kind === 'query' && !hasRehydrated) {\n                failedQueue.push(operation);\n              } else if (operation.kind === 'teardown') {\n                filterQueue(operation.key);\n              }\n            })\n          ),\n        ]);\n\n        return pipe(\n          cacheResults$(opsAndRebound$),\n          filter(res => {\n            if (res.operation.kind === 'query') {\n              if (isOfflineError(res.error, res)) {\n                next(toRequestPolicy(res.operation, 'cache-only'));\n                failedQueue.push(res.operation);\n                return false;\n              } else if (!hasRehydrated) {\n                filterQueue(res.operation.key);\n              }\n            }\n            return true;\n          })\n        );\n      };\n    }\n\n    return cacheExchange(opts)(input);\n  };\n"
  },
  {
    "path": "exchanges/graphcache/src/operations/invalidate.ts",
    "content": "import * as InMemoryData from '../store/data';\nimport { keyOfField } from '../store/keys';\nimport type { FieldArgs } from '../types';\n\ninterface PartialFieldInfo {\n  fieldKey: string;\n}\n\nexport const invalidateEntity = (\n  entityKey: string,\n  field?: string,\n  args?: FieldArgs\n) => {\n  const fields: PartialFieldInfo[] = field\n    ? [{ fieldKey: keyOfField(field, args) }]\n    : InMemoryData.inspectFields(entityKey);\n\n  for (let i = 0, l = fields.length; i < l; i++) {\n    const { fieldKey } = fields[i];\n    if (InMemoryData.readLink(entityKey, fieldKey) !== undefined) {\n      InMemoryData.writeLink(entityKey, fieldKey, undefined);\n    } else {\n      InMemoryData.writeRecord(entityKey, fieldKey, undefined);\n    }\n  }\n};\n\nexport const invalidateType = (\n  typename: string,\n  excludedEntities: string[]\n) => {\n  const types = InMemoryData.getEntitiesForType(typename);\n  for (const entity of types) {\n    if (excludedEntities.includes(entity)) continue;\n    invalidateEntity(entity);\n  }\n};\n"
  },
  {
    "path": "exchanges/graphcache/src/operations/query.test.ts",
    "content": "/* eslint-disable @typescript-eslint/no-var-requires */\n\nimport { gql } from '@urql/core';\nimport { minifyIntrospectionQuery } from '@urql/introspection';\nimport { describe, it, beforeEach, beforeAll, expect } from 'vitest';\n\nimport { Store } from '../store/store';\nimport { __initAnd_write as write } from './write';\nimport { __initAnd_query as query } from './query';\n\nconst TODO_QUERY = gql`\n  query Todos {\n    todos {\n      id\n      text\n      complete\n      author {\n        id\n        name\n        known\n        __typename\n      }\n      __typename\n    }\n  }\n`;\n\ndescribe('Query', () => {\n  let schema, store, alteredRoot;\n\n  beforeAll(() => {\n    schema = minifyIntrospectionQuery(\n      require('../test-utils/simple_schema.json')\n    );\n    alteredRoot = minifyIntrospectionQuery(\n      require('../test-utils/altered_root_schema.json')\n    );\n  });\n\n  beforeEach(() => {\n    store = new Store({ schema });\n    write(\n      store,\n      { query: TODO_QUERY },\n      {\n        __typename: 'Query',\n        todos: [\n          { id: '0', text: 'Teach', __typename: 'Todo' },\n          { id: '1', text: 'Learn', __typename: 'Todo' },\n        ],\n      }\n    );\n  });\n\n  it('test partial results', () => {\n    const result = query(store, { query: TODO_QUERY });\n    expect(result.partial).toBe(true);\n    expect(result.data).toEqual({\n      todos: [\n        {\n          id: '0',\n          text: 'Teach',\n          __typename: 'Todo',\n          author: null,\n          complete: null,\n        },\n        {\n          id: '1',\n          text: 'Learn',\n          __typename: 'Todo',\n          author: null,\n          complete: null,\n        },\n      ],\n    });\n  });\n\n  it('should warn once for invalid fields on an entity', () => {\n    const INVALID_TODO_QUERY = gql`\n      query InvalidTodo {\n        todos {\n          id\n          text\n          incomplete\n        }\n      }\n    `;\n\n    query(store, { query: INVALID_TODO_QUERY });\n    expect(console.warn).toHaveBeenCalledTimes(1);\n    expect((console.warn as any).mock.calls[0][0]).toMatch(\n      /Caused At: \"InvalidTodo\" query/\n    );\n\n    query(store, { query: INVALID_TODO_QUERY });\n    expect(console.warn).toHaveBeenCalledTimes(1);\n\n    expect((console.warn as any).mock.calls[0][0]).toMatch(/incomplete/);\n  });\n\n  it('should warn once for invalid sub-entities on an entity at the right stack', () => {\n    const INVALID_TODO_QUERY = gql`\n      query InvalidTodo {\n        todos {\n          ...ValidTodo\n          ...InvalidFields\n        }\n      }\n\n      fragment ValidTodo on Todo {\n        id\n        text\n      }\n\n      fragment InvalidFields on Todo {\n        id\n        writer {\n          id\n        }\n      }\n    `;\n\n    query(store, { query: INVALID_TODO_QUERY });\n    expect(console.warn).toHaveBeenCalledTimes(1);\n    expect((console.warn as any).mock.calls[0][0]).toMatch(\n      /Caused At: \"InvalidTodo\" query, \"InvalidFields\" Fragment/\n    );\n\n    query(store, { query: INVALID_TODO_QUERY });\n    expect(console.warn).toHaveBeenCalledTimes(1);\n    expect((console.warn as any).mock.calls[0][0]).toMatch(/writer/);\n  });\n\n  // Issue#64\n  it('should not crash for valid queries', () => {\n    const VALID_QUERY = gql`\n      query getTodos {\n        __typename\n        todos {\n          __typename\n          id\n          text\n        }\n      }\n    `;\n    // Use new store to ensure bug reproduction\n    const store = new Store({ schema });\n\n    let { data } = query(store, { query: VALID_QUERY });\n    expect(data).toEqual(null);\n\n    write(\n      store,\n      { query: VALID_QUERY },\n      // @ts-ignore\n      {\n        // Removing typename here would formerly crash this.\n        todos: [{ __typename: 'Todo', id: '0', text: 'Solve bug' }],\n      }\n    );\n    ({ data } = query(store, { query: VALID_QUERY }));\n    expect(data).toEqual({\n      __typename: 'Query',\n      todos: [{ __typename: 'Todo', id: '0', text: 'Solve bug' }],\n    });\n\n    expect(console.error).not.toHaveBeenCalled();\n  });\n\n  it('should respect altered root types', () => {\n    const QUERY = gql`\n      query getTodos {\n        __typename\n        todos {\n          __typename\n          id\n          text\n        }\n      }\n    `;\n\n    const store = new Store({ schema: alteredRoot });\n\n    let { data } = query(store, { query: QUERY });\n    expect(data).toEqual(null);\n\n    write(\n      store,\n      { query: QUERY },\n      {\n        todos: [{ __typename: 'Todo', id: '0', text: 'Solve bug' }],\n        __typename: 'query_root',\n      }\n    );\n\n    ({ data } = query(store, { query: QUERY }));\n    expect(data).toEqual({\n      __typename: 'query_root',\n      todos: [{ __typename: 'Todo', id: '0', text: 'Solve bug' }],\n    });\n\n    expect(console.warn).not.toHaveBeenCalled();\n    expect(console.error).not.toHaveBeenCalled();\n  });\n\n  it('should not allow subsequent reads when first result was null', () => {\n    const QUERY_WRITE = gql`\n      query writeTodos {\n        __typename\n        todos {\n          __typename\n          ...ValidRead\n        }\n      }\n\n      fragment ValidRead on Todo {\n        id\n      }\n    `;\n\n    const QUERY_READ = gql`\n      query getTodos {\n        __typename\n        todos {\n          __typename\n          ...MissingRead\n        }\n        todos {\n          __typename\n          id\n        }\n      }\n\n      fragment MissingRead on Todo {\n        id\n        text\n      }\n    `;\n\n    const store = new Store({\n      schema: alteredRoot,\n    });\n\n    let { data } = query(store, { query: QUERY_READ });\n    expect(data).toEqual(null);\n\n    write(\n      store,\n      { query: QUERY_WRITE },\n      {\n        todos: [\n          {\n            __typename: 'Todo',\n            id: '0',\n          },\n        ],\n        __typename: 'Query',\n      }\n    );\n\n    ({ data } = query(store, { query: QUERY_READ }));\n    expect(data).toEqual({\n      __typename: 'query_root',\n      todos: [null],\n    });\n\n    expect(console.warn).not.toHaveBeenCalled();\n    expect(console.error).not.toHaveBeenCalled();\n  });\n\n  it('should not allow subsequent reads when first result was null (with resolvers)', () => {\n    const QUERY_WRITE = gql`\n      query writeTodos {\n        __typename\n        todos {\n          __typename\n          ...ValidRead\n        }\n      }\n\n      fragment ValidRead on Todo {\n        id\n      }\n    `;\n\n    const QUERY_READ = gql`\n      query getTodos {\n        __typename\n        todos {\n          __typename\n          ...MissingRead\n        }\n        todos {\n          __typename\n          id\n        }\n      }\n\n      fragment MissingRead on Todo {\n        id\n        text\n      }\n    `;\n\n    const store = new Store({\n      schema,\n      resolvers: {\n        Query: {\n          todos: (_parent, _args, cache) => cache.resolve('Query', 'todos'),\n        },\n      },\n    });\n\n    let { data } = query(store, { query: QUERY_READ });\n    expect(data).toEqual(null);\n\n    write(\n      store,\n      { query: QUERY_WRITE },\n      {\n        todos: [\n          {\n            __typename: 'Todo',\n            id: '0',\n          },\n        ],\n        __typename: 'Query',\n      }\n    );\n\n    ({ data } = query(store, { query: QUERY_READ }));\n    expect(data).toEqual({\n      __typename: 'Query',\n      todos: [null],\n    });\n\n    expect(console.warn).not.toHaveBeenCalled();\n    expect(console.error).not.toHaveBeenCalled();\n  });\n\n  it('should not mix references', () => {\n    const QUERY_WRITE = gql`\n      query writeTodos {\n        __typename\n        todos {\n          __typename\n          id\n          textA\n          textB\n        }\n      }\n    `;\n\n    const QUERY_READ = gql`\n      query getTodos {\n        __typename\n        todos {\n          __typename\n          id\n          textA\n        }\n        todos {\n          __typename\n          textB\n        }\n      }\n    `;\n\n    const store = new Store({\n      schema: alteredRoot,\n    });\n\n    write(\n      store,\n      { query: QUERY_WRITE },\n      {\n        todos: [\n          {\n            __typename: 'Todo',\n            id: '0',\n            textA: 'a',\n            textB: 'b',\n          },\n        ],\n        __typename: 'Query',\n      }\n    );\n\n    let data: any;\n    data = query(store, { query: QUERY_READ }).data;\n\n    expect(data).toEqual({\n      __typename: 'query_root',\n      todos: [\n        {\n          __typename: 'Todo',\n          id: '0',\n          textA: 'a',\n          textB: 'b',\n        },\n      ],\n    });\n\n    const previousData = {\n      __typename: 'query_root',\n      todos: [\n        {\n          __typename: 'Todo',\n          id: '0',\n          textA: 'a',\n          textB: 'old',\n        },\n      ],\n    };\n\n    data = query(store, { query: QUERY_READ }, previousData).data;\n\n    expect(data).toEqual({\n      __typename: 'query_root',\n      todos: [\n        {\n          __typename: 'Todo',\n          id: '0',\n          textA: 'a',\n          textB: 'b',\n        },\n      ],\n    });\n\n    expect(previousData).toHaveProperty('todos.0.textA', 'a');\n    expect(previousData).toHaveProperty('todos.0.textB', 'old');\n  });\n\n  it('should keep references stable (1)', () => {\n    const QUERY = gql`\n      query todos {\n        __typename\n        todos {\n          __typename\n          test\n        }\n        todos {\n          __typename\n          id\n        }\n      }\n    `;\n\n    const store = new Store({\n      schema: alteredRoot,\n    });\n\n    const expected = {\n      todos: [\n        {\n          __typename: 'Todo',\n          id: '0',\n          test: '0',\n        },\n        {\n          __typename: 'Todo',\n          id: '1',\n          test: '1',\n        },\n        {\n          __typename: 'Todo',\n          id: '2',\n          test: '2',\n        },\n      ],\n      __typename: 'query_root',\n    };\n\n    write(store, { query: QUERY }, expected);\n\n    const prevData = query(\n      store,\n      { query: QUERY },\n      {\n        todos: [\n          {\n            __typename: 'Todo',\n            id: '0',\n            test: 'prev-0',\n          },\n          {\n            __typename: 'Todo',\n            id: '1',\n            test: '1',\n          },\n          {\n            __typename: 'Todo',\n            id: '2',\n            test: '2',\n          },\n        ],\n        __typename: 'query_root',\n      }\n    ).data as any;\n\n    const data = query(store, { query: QUERY }, prevData).data as any;\n    expect(data).toEqual(expected);\n\n    expect(prevData.todos[0]).toBe(data.todos[0]);\n    expect(prevData.todos[1]).toBe(data.todos[1]);\n    expect(prevData.todos[2]).toBe(data.todos[2]);\n    expect(prevData.todos).toBe(data.todos);\n    expect(prevData).toBe(data);\n  });\n\n  it('should keep references stable (negative test)', () => {\n    const QUERY = gql`\n      query todos {\n        __typename\n        todos {\n          __typename\n          id\n        }\n        todos {\n          __typename\n          test\n        }\n      }\n    `;\n\n    const store = new Store({\n      schema: alteredRoot,\n    });\n\n    const expected = {\n      todos: [\n        {\n          __typename: 'Todo',\n          id: '0',\n          test: '0',\n        },\n        {\n          __typename: 'Todo',\n          id: '1',\n          test: '1',\n        },\n        {\n          __typename: 'Todo',\n          id: '2',\n          test: '2',\n        },\n      ],\n      __typename: 'query_root',\n    };\n\n    write(store, { query: QUERY }, expected);\n\n    const prevData = query(\n      store,\n      { query: QUERY },\n      {\n        todos: [\n          {\n            __typename: 'Todo',\n            id: '0',\n            test: 'prev-0',\n          },\n          {\n            __typename: 'Todo',\n            id: '1',\n            test: '1',\n          },\n          {\n            __typename: 'Todo',\n            id: '2',\n            test: '2',\n          },\n        ],\n        __typename: 'query_root',\n      }\n    ).data as any;\n\n    expected.todos[0].test = 'x';\n    write(store, { query: QUERY }, expected);\n\n    const data = query(store, { query: QUERY }, prevData).data as any;\n    expect(data).toEqual(expected);\n\n    expect(prevData.todos[1]).toBe(data.todos[1]);\n    expect(prevData.todos[2]).toBe(data.todos[2]);\n    expect(prevData.todos[0]).not.toBe(data.todos[0]);\n    expect(prevData.todos).not.toBe(data.todos);\n    expect(prevData).not.toBe(data);\n  });\n});\n"
  },
  {
    "path": "exchanges/graphcache/src/operations/query.ts",
    "content": "import type { FormattedNode, CombinedError } from '@urql/core';\nimport { formatDocument } from '@urql/core';\n\nimport type {\n  FieldNode,\n  DocumentNode,\n  FragmentDefinitionNode,\n} from '@0no-co/graphql.web';\n\nimport type { SelectionSet } from '../ast';\nimport {\n  getSelectionSet,\n  getName,\n  getFragmentTypeName,\n  getFieldAlias,\n  getFragments,\n  getMainOperation,\n  normalizeVariables,\n  getFieldArguments,\n  getDirectives,\n} from '../ast';\n\nimport type {\n  Variables,\n  Data,\n  DataField,\n  Link,\n  OperationRequest,\n  Dependencies,\n  Resolver,\n} from '../types';\n\nimport { joinKeys, keyOfField } from '../store/keys';\nimport type { Store } from '../store/store';\nimport * as InMemoryData from '../store/data';\nimport { warn, pushDebugNode, popDebugNode } from '../helpers/help';\n\nimport type { Context } from './shared';\nimport {\n  SelectionIterator,\n  ensureData,\n  makeContext,\n  updateContext,\n  getFieldError,\n  deferRef,\n  optionalRef,\n} from './shared';\n\nimport {\n  isFieldAvailableOnType,\n  isFieldNullable,\n  isListNullable,\n} from '../ast';\n\nexport interface QueryResult {\n  dependencies: Dependencies;\n  partial: boolean;\n  hasNext: boolean;\n  data: null | Data;\n}\n\n/** Reads a GraphQL query from the cache.\n * @internal\n */\nexport const __initAnd_query = (\n  store: Store,\n  request: OperationRequest,\n  data?: Data | null | undefined,\n  error?: CombinedError | undefined,\n  key?: number\n): QueryResult => {\n  InMemoryData.initDataState('read', store.data, key);\n  const result = _query(store, request, data, error);\n  InMemoryData.clearDataState();\n  return result;\n};\n\n/** Reads a GraphQL query from the cache.\n * @internal\n */\nexport const _query = (\n  store: Store,\n  request: OperationRequest,\n  input?: Data | null | undefined,\n  error?: CombinedError | undefined\n): QueryResult => {\n  const query = formatDocument(request.query);\n  const operation = getMainOperation(query);\n  const rootKey = store.rootFields[operation.operation];\n  const rootSelect = getSelectionSet(operation);\n\n  const ctx = makeContext(\n    store,\n    normalizeVariables(operation, request.variables),\n    getFragments(query),\n    rootKey,\n    rootKey,\n    error\n  );\n\n  if (process.env.NODE_ENV !== 'production') {\n    pushDebugNode(rootKey, operation);\n  }\n\n  // NOTE: This may reuse \"previous result data\" as indicated by the\n  // `originalData` argument in readRoot(). This behaviour isn't used\n  // for readSelection() however, which always produces results from\n  // scratch\n  const data =\n    rootKey !== ctx.store.rootFields['query']\n      ? readRoot(ctx, rootKey, rootSelect, input || InMemoryData.makeData())\n      : readSelection(\n          ctx,\n          rootKey,\n          rootSelect,\n          input || InMemoryData.makeData()\n        );\n\n  if (process.env.NODE_ENV !== 'production') {\n    popDebugNode();\n    InMemoryData.getCurrentDependencies();\n  }\n\n  return {\n    dependencies: InMemoryData.currentDependencies!,\n    partial: ctx.partial || !data,\n    hasNext: ctx.hasNext,\n    data: data || null,\n  };\n};\n\nconst readRoot = (\n  ctx: Context,\n  entityKey: string,\n  select: FormattedNode<SelectionSet>,\n  input: Data\n): Data => {\n  const typename = ctx.store.rootNames[entityKey]\n    ? entityKey\n    : input.__typename;\n  if (typeof typename !== 'string') {\n    return input;\n  }\n\n  const selection = new SelectionIterator(\n    entityKey,\n    entityKey,\n    false,\n    undefined,\n    select,\n    ctx\n  );\n\n  let node: FormattedNode<FieldNode> | void;\n  let hasChanged = InMemoryData.currentForeignData;\n  const output = InMemoryData.makeData(input);\n  while ((node = selection.next())) {\n    const fieldAlias = getFieldAlias(node);\n    const fieldValue = input[fieldAlias];\n    // Add the current alias to the walked path before processing the field's value\n    ctx.__internal.path.push(fieldAlias);\n    // We temporarily store the data field in here, but undefined\n    // means that the value is missing from the cache\n    let dataFieldValue: void | DataField;\n    if (node.selectionSet && fieldValue !== null) {\n      dataFieldValue = readRootField(\n        ctx,\n        getSelectionSet(node),\n        ensureData(fieldValue)\n      );\n    } else {\n      dataFieldValue = fieldValue;\n    }\n\n    // Check for any referential changes in the field's value\n    hasChanged = hasChanged || dataFieldValue !== fieldValue;\n    if (dataFieldValue !== undefined) output[fieldAlias] = dataFieldValue!;\n\n    // After processing the field, remove the current alias from the path again\n    ctx.__internal.path.pop();\n  }\n\n  return hasChanged ? output : input;\n};\n\nconst readRootField = (\n  ctx: Context,\n  select: FormattedNode<SelectionSet>,\n  originalData: Link<Data>\n): Link<Data> => {\n  if (Array.isArray(originalData)) {\n    const newData = new Array(originalData.length);\n    let hasChanged = InMemoryData.currentForeignData;\n    for (let i = 0, l = originalData.length; i < l; i++) {\n      // Add the current index to the walked path before reading the field's value\n      ctx.__internal.path.push(i);\n      // Recursively read the root field's value\n      newData[i] = readRootField(ctx, select, originalData[i]);\n      hasChanged = hasChanged || newData[i] !== originalData[i];\n      // After processing the field, remove the current index from the path\n      ctx.__internal.path.pop();\n    }\n\n    return hasChanged ? newData : originalData;\n  } else if (originalData === null) {\n    return null;\n  }\n\n  // Write entity to key that falls back to the given parentFieldKey\n  const entityKey = ctx.store.keyOfEntity(originalData);\n  if (entityKey !== null) {\n    // We assume that since this is used for result data this can never be undefined,\n    // since the result data has already been written to the cache\n    return readSelection(ctx, entityKey, select, originalData) || null;\n  } else {\n    return readRoot(ctx, originalData.__typename, select, originalData);\n  }\n};\n\nexport const _queryFragment = (\n  store: Store,\n  query: FormattedNode<DocumentNode>,\n  entity: Partial<Data> | string,\n  variables?: Variables,\n  fragmentName?: string\n): Data | null => {\n  const fragments = getFragments(query);\n\n  let fragment: FormattedNode<FragmentDefinitionNode>;\n  if (fragmentName) {\n    fragment = fragments[fragmentName]!;\n    if (!fragment) {\n      warn(\n        'readFragment(...) was called with a fragment name that does not exist.\\n' +\n          'You provided ' +\n          fragmentName +\n          ' but could only find ' +\n          Object.keys(fragments).join(', ') +\n          '.',\n        6,\n        store.logger\n      );\n\n      return null;\n    }\n  } else {\n    const names = Object.keys(fragments);\n    fragment = fragments[names[0]]!;\n    if (!fragment) {\n      warn(\n        'readFragment(...) was called with an empty fragment.\\n' +\n          'You have to call it with at least one fragment in your GraphQL document.',\n        6,\n        store.logger\n      );\n\n      return null;\n    }\n  }\n\n  const typename = getFragmentTypeName(fragment);\n  if (typeof entity !== 'string' && !entity.__typename)\n    entity.__typename = typename;\n  const entityKey = store.keyOfEntity(entity as Data);\n  if (!entityKey) {\n    warn(\n      \"Can't generate a key for readFragment(...).\\n\" +\n        'You have to pass an `id` or `_id` field or create a custom `keys` config for `' +\n        typename +\n        '`.',\n      7,\n      store.logger\n    );\n\n    return null;\n  }\n\n  if (process.env.NODE_ENV !== 'production') {\n    pushDebugNode(typename, fragment);\n  }\n\n  const ctx = makeContext(\n    store,\n    variables || {},\n    fragments,\n    typename,\n    entityKey,\n    undefined\n  );\n\n  const result =\n    readSelection(\n      ctx,\n      entityKey,\n      getSelectionSet(fragment),\n      InMemoryData.makeData()\n    ) || null;\n\n  if (process.env.NODE_ENV !== 'production') {\n    popDebugNode();\n  }\n\n  return result;\n};\n\nfunction getFieldResolver(\n  directives: ReturnType<typeof getDirectives>,\n  typename: string,\n  fieldName: string,\n  ctx: Context\n): Resolver | void {\n  const resolvers = ctx.store.resolvers[typename];\n  const fieldResolver = resolvers && resolvers[fieldName];\n\n  let directiveResolver: Resolver | undefined;\n  for (const name in directives) {\n    const directiveNode = directives[name];\n    if (\n      directiveNode &&\n      name !== 'include' &&\n      name !== 'skip' &&\n      ctx.store.directives[name]\n    ) {\n      directiveResolver = ctx.store.directives[name](\n        getFieldArguments(directiveNode, ctx.variables)\n      );\n      if (process.env.NODE_ENV === 'production') return directiveResolver;\n      break;\n    }\n  }\n\n  if (fieldResolver && directiveResolver) {\n    warn(\n      `A resolver and directive is being used at \"${typename}.${fieldName}\" simultaneously. Only the directive will apply.`,\n      28,\n      ctx.store.logger\n    );\n  }\n\n  return directiveResolver || fieldResolver;\n}\n\nconst readSelection = (\n  ctx: Context,\n  key: string,\n  select: FormattedNode<SelectionSet>,\n  input: Data,\n  result?: Data\n): Data | undefined => {\n  const { store } = ctx;\n  const isQuery = key === store.rootFields.query;\n\n  const entityKey = (result && store.keyOfEntity(result)) || key;\n  if (!isQuery && !!ctx.store.rootNames[entityKey]) {\n    warn(\n      'Invalid root traversal: A selection was being read on `' +\n        entityKey +\n        '` which is an uncached root type.\\n' +\n        'The `' +\n        ctx.store.rootFields.mutation +\n        '` and `' +\n        ctx.store.rootFields.subscription +\n        '` types are special ' +\n        'Operation Root Types and cannot be read back from the cache.',\n      25,\n      store.logger\n    );\n  }\n\n  const typename = !isQuery\n    ? InMemoryData.readRecord(entityKey, '__typename') ||\n      (result && result.__typename)\n    : key;\n\n  if (typeof typename !== 'string') {\n    return;\n  } else if (result && typename !== result.__typename) {\n    warn(\n      'Invalid resolver data: The resolver at `' +\n        entityKey +\n        '` returned an ' +\n        'invalid typename that could not be reconciled with the cache.',\n      8,\n      store.logger\n    );\n\n    return;\n  }\n\n  const selection = new SelectionIterator(\n    typename,\n    entityKey,\n    false,\n    undefined,\n    select,\n    ctx\n  );\n\n  let hasFields = false;\n  let hasNext = false;\n  let hasChanged = InMemoryData.currentForeignData;\n  let node: FormattedNode<FieldNode> | void;\n  const hasPartials = ctx.partial;\n  const output = InMemoryData.makeData(input);\n  while ((node = selection.next()) !== undefined) {\n    // Derive the needed data from our node.\n    const fieldName = getName(node);\n    const fieldArgs = getFieldArguments(node, ctx.variables);\n    const fieldAlias = getFieldAlias(node);\n    const directives = getDirectives(node);\n    const resolver = getFieldResolver(directives, typename, fieldName, ctx);\n    const fieldKey = keyOfField(fieldName, fieldArgs);\n    const key = joinKeys(entityKey, fieldKey);\n    const fieldValue = InMemoryData.readRecord(entityKey, fieldKey);\n    const resultValue = result ? result[fieldName] : undefined;\n\n    if (process.env.NODE_ENV !== 'production' && store.schema && typename) {\n      isFieldAvailableOnType(\n        store.schema,\n        typename,\n        fieldName,\n        ctx.store.logger\n      );\n    }\n\n    // Add the current alias to the walked path before processing the field's value\n    ctx.__internal.path.push(fieldAlias);\n    // We temporarily store the data field in here, but undefined\n    // means that the value is missing from the cache\n    let dataFieldValue: void | DataField = undefined;\n\n    if (fieldName === '__typename') {\n      // We directly assign the typename as it's already available\n      dataFieldValue = typename;\n    } else if (resultValue !== undefined && node.selectionSet === undefined) {\n      // The field is a scalar and can be retrieved directly from the result\n      dataFieldValue = resultValue;\n    } else if (InMemoryData.currentOperation === 'read' && resolver) {\n      // We have a resolver for this field.\n      // Prepare the actual fieldValue, so that the resolver can use it,\n      // as to avoid the user having to do `cache.resolve(parent, info.fieldKey)`\n      // only to get a scalar value.\n      let parent = output;\n      if (node.selectionSet === undefined && fieldValue !== undefined) {\n        parent = {\n          ...output,\n          [fieldAlias]: fieldValue,\n          [fieldName]: fieldValue,\n        };\n      }\n\n      // We have to update the information in context to reflect the info\n      // that the resolver will receive\n      updateContext(ctx, parent, typename, entityKey, fieldKey, fieldName);\n\n      dataFieldValue = resolver(\n        parent,\n        fieldArgs || ({} as Variables),\n        store,\n        ctx\n      );\n\n      if (node.selectionSet) {\n        // When it has a selection set we are resolving an entity with a\n        // subselection. This can either be a list or an object.\n        dataFieldValue = resolveResolverResult(\n          ctx,\n          typename,\n          fieldName,\n          key,\n          getSelectionSet(node),\n          (output[fieldAlias] !== undefined\n            ? output[fieldAlias]\n            : input[fieldAlias]) as Data,\n          dataFieldValue,\n          InMemoryData.ownsData(input)\n        );\n      }\n\n      if (\n        store.schema &&\n        dataFieldValue === null &&\n        !isFieldNullable(store.schema, typename, fieldName, ctx.store.logger)\n      ) {\n        // Special case for when null is not a valid value for the\n        // current field\n        return undefined;\n      }\n    } else if (!node.selectionSet) {\n      // The field is a scalar but isn't on the result, so it's retrieved from the cache\n      dataFieldValue = fieldValue;\n    } else if (resultValue !== undefined) {\n      // We start walking the nested resolver result here\n      dataFieldValue = resolveResolverResult(\n        ctx,\n        typename,\n        fieldName,\n        key,\n        getSelectionSet(node),\n        (output[fieldAlias] !== undefined\n          ? output[fieldAlias]\n          : input[fieldAlias]) as Data,\n        resultValue,\n        InMemoryData.ownsData(input)\n      );\n    } else {\n      // Otherwise we attempt to get the missing field from the cache\n      const link = InMemoryData.readLink(entityKey, fieldKey);\n\n      if (link !== undefined) {\n        dataFieldValue = resolveLink(\n          ctx,\n          link,\n          typename,\n          fieldName,\n          getSelectionSet(node),\n          (output[fieldAlias] !== undefined\n            ? output[fieldAlias]\n            : input[fieldAlias]) as Data,\n          InMemoryData.ownsData(input)\n        );\n      } else if (typeof fieldValue === 'object' && fieldValue !== null) {\n        // The entity on the field was invalid but can still be recovered\n        dataFieldValue = fieldValue;\n      }\n    }\n\n    // Now that dataFieldValue has been retrieved it'll be set on data\n    // If it's uncached (undefined) but nullable we can continue assembling\n    // a partial query result\n    if (\n      !deferRef &&\n      dataFieldValue === undefined &&\n      (directives.optional ||\n        (optionalRef && !directives.required) ||\n        !!getFieldError(ctx) ||\n        (!directives.required &&\n          store.schema &&\n          isFieldNullable(store.schema, typename, fieldName, ctx.store.logger)))\n    ) {\n      // The field is uncached or has errored, so it'll be set to null and skipped\n      ctx.partial = true;\n      dataFieldValue = null;\n    } else if (\n      dataFieldValue === null &&\n      (directives.required || optionalRef === false)\n    ) {\n      if (\n        ctx.store.logger &&\n        process.env.NODE_ENV !== 'production' &&\n        InMemoryData.currentOperation === 'read'\n      ) {\n        ctx.store.logger(\n          'debug',\n          `Got value \"null\" for required field \"${fieldName}\"${\n            fieldArgs ? ` with args ${JSON.stringify(fieldArgs)}` : ''\n          } on entity \"${entityKey}\"`\n        );\n      }\n      dataFieldValue = undefined;\n    } else {\n      hasFields = hasFields || fieldName !== '__typename';\n    }\n\n    // After processing the field, remove the current alias from the path again\n    ctx.__internal.path.pop();\n    // Check for any referential changes in the field's value\n    hasChanged = hasChanged || dataFieldValue !== input[fieldAlias];\n    if (dataFieldValue !== undefined) {\n      output[fieldAlias] = dataFieldValue;\n    } else if (deferRef) {\n      hasNext = true;\n    } else {\n      if (\n        ctx.store.logger &&\n        process.env.NODE_ENV !== 'production' &&\n        InMemoryData.currentOperation === 'read'\n      ) {\n        ctx.store.logger(\n          'debug',\n          `No value for field \"${fieldName}\"${\n            fieldArgs ? ` with args ${JSON.stringify(fieldArgs)}` : ''\n          } on entity \"${entityKey}\"`\n        );\n      }\n      // If the field isn't deferred or partial then we have to abort and also reset\n      // the partial field\n      ctx.partial = hasPartials;\n      return undefined;\n    }\n  }\n\n  ctx.partial = ctx.partial || hasPartials;\n  ctx.hasNext = ctx.hasNext || hasNext;\n  return isQuery && ctx.partial && !hasFields\n    ? undefined\n    : hasChanged\n      ? output\n      : input;\n};\n\nconst resolveResolverResult = (\n  ctx: Context,\n  typename: string,\n  fieldName: string,\n  key: string,\n  select: FormattedNode<SelectionSet>,\n  prevData: void | null | Data | Data[],\n  result: void | DataField,\n  isOwnedData: boolean\n): DataField | void => {\n  if (Array.isArray(result)) {\n    const { store } = ctx;\n    // Check whether values of the list may be null; for resolvers we assume\n    // that they can be, since it's user-provided data\n    const _isListNullable = store.schema\n      ? isListNullable(store.schema, typename, fieldName, ctx.store.logger)\n      : false;\n    const hasPartials = ctx.partial;\n    const data = InMemoryData.makeData(prevData, true);\n    let hasChanged =\n      InMemoryData.currentForeignData ||\n      !Array.isArray(prevData) ||\n      result.length !== prevData.length;\n    for (let i = 0, l = result.length; i < l; i++) {\n      // Add the current index to the walked path before reading the field's value\n      ctx.__internal.path.push(i);\n      // Recursively read resolver result\n      const childResult = resolveResolverResult(\n        ctx,\n        typename,\n        fieldName,\n        joinKeys(key, `${i}`),\n        select,\n        prevData != null ? prevData[i] : undefined,\n        result[i],\n        isOwnedData\n      );\n      // After processing the field, remove the current index from the path\n      ctx.__internal.path.pop();\n      // Check the result for cache-missed values\n      if (childResult === undefined && !_isListNullable) {\n        ctx.partial = hasPartials;\n        return undefined;\n      } else {\n        ctx.partial =\n          ctx.partial || (childResult === undefined && _isListNullable);\n        data[i] = childResult != null ? childResult : null;\n        hasChanged = hasChanged || data[i] !== prevData![i];\n      }\n    }\n\n    return hasChanged ? data : prevData;\n  } else if (result === null || result === undefined) {\n    return result;\n  } else if (isOwnedData && prevData === null) {\n    return null;\n  } else if (isDataOrKey(result)) {\n    const data = (prevData || InMemoryData.makeData(prevData)) as Data;\n    return typeof result === 'string'\n      ? readSelection(ctx, result, select, data)\n      : readSelection(ctx, key, select, data, result);\n  } else {\n    warn(\n      'Invalid resolver value: The field at `' +\n        key +\n        '` is a scalar (number, boolean, etc)' +\n        ', but the GraphQL query expects a selection set for this field.',\n      9,\n      ctx.store.logger\n    );\n\n    return undefined;\n  }\n};\n\nconst resolveLink = (\n  ctx: Context,\n  link: Link | Link[],\n  typename: string,\n  fieldName: string,\n  select: FormattedNode<SelectionSet>,\n  prevData: void | null | Data | Data[],\n  isOwnedData: boolean\n): DataField | undefined => {\n  if (Array.isArray(link)) {\n    const { store } = ctx;\n    const _isListNullable = store.schema\n      ? isListNullable(store.schema, typename, fieldName, ctx.store.logger)\n      : false;\n    const newLink = InMemoryData.makeData(prevData, true);\n    const hasPartials = ctx.partial;\n    let hasChanged =\n      InMemoryData.currentForeignData ||\n      !Array.isArray(prevData) ||\n      link.length !== prevData.length;\n    for (let i = 0, l = link.length; i < l; i++) {\n      // Add the current index to the walked path before reading the field's value\n      ctx.__internal.path.push(i);\n      // Recursively read the link\n      const childLink = resolveLink(\n        ctx,\n        link[i],\n        typename,\n        fieldName,\n        select,\n        prevData != null ? prevData[i] : undefined,\n        isOwnedData\n      );\n      // After processing the field, remove the current index from the path\n      ctx.__internal.path.pop();\n      // Check the result for cache-missed values\n      if (childLink === undefined && !_isListNullable) {\n        ctx.partial = hasPartials;\n        return undefined;\n      } else {\n        ctx.partial =\n          ctx.partial || (childLink === undefined && _isListNullable);\n        newLink[i] = childLink || null;\n        hasChanged = hasChanged || newLink[i] !== prevData![i];\n      }\n    }\n\n    return hasChanged ? newLink : (prevData as Data[]);\n  } else if (link === null || (prevData === null && isOwnedData)) {\n    return null;\n  }\n\n  return readSelection(\n    ctx,\n    link,\n    select,\n    (prevData || InMemoryData.makeData(prevData)) as Data\n  );\n};\n\nconst isDataOrKey = (x: any): x is string | Data =>\n  typeof x === 'string' ||\n  (typeof x === 'object' && typeof (x as any).__typename === 'string');\n"
  },
  {
    "path": "exchanges/graphcache/src/operations/shared.test.ts",
    "content": "import { describe, it, expect } from 'vitest';\nimport {\n  TypedDocumentNode,\n  FormattedNode,\n  formatDocument,\n  gql,\n} from '@urql/core';\nimport { FieldNode } from '@0no-co/graphql.web';\n\nimport { SelectionIterator, deferRef } from './shared';\nimport { SelectionSet } from '../ast';\n\nconst selectionOfDocument = (\n  doc: TypedDocumentNode\n): FormattedNode<SelectionSet> => {\n  for (const definition of formatDocument(doc).definitions)\n    if (definition.kind === 'OperationDefinition')\n      return definition.selectionSet.selections as FormattedNode<SelectionSet>;\n  return [];\n};\n\nconst ctx = {} as any;\n\ndescribe('SelectionIterator', () => {\n  it('emits all fields', () => {\n    const selection = selectionOfDocument(gql`\n      {\n        a\n        b\n        c\n      }\n    `);\n    const iterate = new SelectionIterator(\n      'Query',\n      'Query',\n      false,\n      undefined,\n      selection,\n      ctx\n    );\n    const result: FieldNode[] = [];\n\n    let node: FieldNode | void;\n    while ((node = iterate.next())) result.push(node);\n\n    expect(result).toMatchInlineSnapshot(`\n      [\n        {\n          \"alias\": undefined,\n          \"arguments\": undefined,\n          \"directives\": undefined,\n          \"kind\": \"Field\",\n          \"name\": {\n            \"kind\": \"Name\",\n            \"value\": \"a\",\n          },\n          \"selectionSet\": undefined,\n        },\n        {\n          \"alias\": undefined,\n          \"arguments\": undefined,\n          \"directives\": undefined,\n          \"kind\": \"Field\",\n          \"name\": {\n            \"kind\": \"Name\",\n            \"value\": \"b\",\n          },\n          \"selectionSet\": undefined,\n        },\n        {\n          \"alias\": undefined,\n          \"arguments\": undefined,\n          \"directives\": undefined,\n          \"kind\": \"Field\",\n          \"name\": {\n            \"kind\": \"Name\",\n            \"value\": \"c\",\n          },\n          \"selectionSet\": undefined,\n        },\n      ]\n    `);\n  });\n\n  it('skips fields that are skipped or not included', () => {\n    const selection = selectionOfDocument(gql`\n      {\n        a @skip(if: true)\n        b @include(if: false)\n      }\n    `);\n\n    const iterate = new SelectionIterator(\n      'Query',\n      'Query',\n      false,\n      undefined,\n      selection,\n      ctx\n    );\n    const result: FieldNode[] = [];\n\n    let node: FieldNode | void;\n    while ((node = iterate.next())) result.push(node);\n\n    expect(result).toMatchInlineSnapshot('[]');\n  });\n\n  it('processes fragments', () => {\n    const selection = selectionOfDocument(gql`\n      {\n        a\n        ... {\n          b\n        }\n        ... {\n          ... {\n            c\n          }\n        }\n      }\n    `);\n\n    const iterate = new SelectionIterator(\n      'Query',\n      'Query',\n      false,\n      undefined,\n      selection,\n      ctx\n    );\n    const result: FieldNode[] = [];\n\n    let node: FieldNode | void;\n    while ((node = iterate.next())) result.push(node);\n\n    expect(result).toMatchInlineSnapshot(`\n      [\n        {\n          \"alias\": undefined,\n          \"arguments\": undefined,\n          \"directives\": undefined,\n          \"kind\": \"Field\",\n          \"name\": {\n            \"kind\": \"Name\",\n            \"value\": \"a\",\n          },\n          \"selectionSet\": undefined,\n        },\n        {\n          \"alias\": undefined,\n          \"arguments\": undefined,\n          \"directives\": undefined,\n          \"kind\": \"Field\",\n          \"name\": {\n            \"kind\": \"Name\",\n            \"value\": \"b\",\n          },\n          \"selectionSet\": undefined,\n        },\n        {\n          \"alias\": undefined,\n          \"arguments\": undefined,\n          \"directives\": undefined,\n          \"kind\": \"Field\",\n          \"name\": {\n            \"kind\": \"Name\",\n            \"value\": \"c\",\n          },\n          \"selectionSet\": undefined,\n        },\n      ]\n    `);\n  });\n\n  it('updates deferred state as needed', () => {\n    const selection = selectionOfDocument(gql`\n      {\n        a\n        ... @defer {\n          b\n        }\n        ... {\n          ... @defer {\n            c\n          }\n        }\n        ... {\n          ... {\n            d\n          }\n        }\n        ... @defer {\n          ... {\n            e\n          }\n        }\n        ... {\n          ... {\n            f\n          }\n        }\n        ... {\n          g\n        }\n        h\n      }\n    `);\n\n    const iterate = new SelectionIterator(\n      'Query',\n      'Query',\n      false,\n      undefined,\n      selection,\n      ctx\n    );\n\n    const deferred: boolean[] = [];\n    while (iterate.next()) deferred.push(deferRef);\n    expect(deferred).toEqual([\n      false, // a\n      true, // b\n      true, // c\n      false, // d\n      true, // e\n      false, // f\n      false, // g\n      false, // h\n    ]);\n  });\n\n  it('applies the parent’s defer state if needed', () => {\n    const selection = selectionOfDocument(gql`\n      {\n        a\n        ... @defer {\n          b\n        }\n        ... {\n          c\n        }\n      }\n    `);\n\n    const iterate = new SelectionIterator(\n      'Query',\n      'Query',\n      true,\n      undefined,\n      selection,\n      ctx\n    );\n\n    const deferred: boolean[] = [];\n    while (iterate.next()) deferred.push(deferRef);\n    expect(deferred).toEqual([true, true, true]);\n  });\n});\n"
  },
  {
    "path": "exchanges/graphcache/src/operations/shared.ts",
    "content": "import type { CombinedError, ErrorLike, FormattedNode } from '@urql/core';\n\nimport type {\n  InlineFragmentNode,\n  FragmentDefinitionNode,\n  FieldNode,\n} from '@0no-co/graphql.web';\nimport { Kind } from '@0no-co/graphql.web';\n\nimport type { SelectionSet } from '../ast';\nimport {\n  isDeferred,\n  getTypeCondition,\n  getSelectionSet,\n  getName,\n  isOptional,\n} from '../ast';\n\nimport { warn, pushDebugNode, popDebugNode } from '../helpers/help';\nimport {\n  hasField,\n  currentOperation,\n  currentOptimistic,\n  writeConcreteType,\n  getConcreteTypes,\n  isSeenConcreteType,\n} from '../store/data';\nimport { keyOfField } from '../store/keys';\nimport type { Store } from '../store/store';\n\nimport { getFieldArguments, shouldInclude, isInterfaceOfType } from '../ast';\n\nimport type {\n  Fragments,\n  Variables,\n  DataField,\n  NullArray,\n  Link,\n  Entity,\n  Data,\n  Logger,\n} from '../types';\n\nexport interface Context {\n  store: Store;\n  variables: Variables;\n  fragments: Fragments;\n  parentTypeName: string;\n  parentKey: string;\n  parentFieldKey: string;\n  parent: Data;\n  fieldName: string;\n  error: ErrorLike | undefined;\n  partial: boolean;\n  hasNext: boolean;\n  optimistic: boolean;\n  __internal: {\n    path: Array<string | number>;\n    errorMap: { [path: string]: ErrorLike } | undefined;\n  };\n}\n\nexport let contextRef: Context | null = null;\nexport let deferRef = false;\nexport let optionalRef: boolean | undefined = undefined;\n\n// Checks whether the current data field is a cache miss because of a GraphQLError\nexport const getFieldError = (ctx: Context): ErrorLike | undefined =>\n  ctx.__internal.path.length > 0 && ctx.__internal.errorMap\n    ? ctx.__internal.errorMap[ctx.__internal.path.join('.')]\n    : undefined;\n\nexport const makeContext = (\n  store: Store,\n  variables: Variables,\n  fragments: Fragments,\n  typename: string,\n  entityKey: string,\n  error: CombinedError | undefined\n): Context => {\n  const ctx: Context = {\n    store,\n    variables,\n    fragments,\n    parent: { __typename: typename },\n    parentTypeName: typename,\n    parentKey: entityKey,\n    parentFieldKey: '',\n    fieldName: '',\n    error: undefined,\n    partial: false,\n    hasNext: false,\n    optimistic: currentOptimistic,\n    __internal: {\n      path: [],\n      errorMap: undefined,\n    },\n  };\n\n  if (error && error.graphQLErrors) {\n    for (let i = 0; i < error.graphQLErrors.length; i++) {\n      const graphQLError = error.graphQLErrors[i];\n      if (graphQLError.path && graphQLError.path.length) {\n        if (!ctx.__internal.errorMap)\n          ctx.__internal.errorMap = Object.create(null);\n        ctx.__internal.errorMap![graphQLError.path.join('.')] = graphQLError;\n      }\n    }\n  }\n\n  return ctx;\n};\n\nexport const updateContext = (\n  ctx: Context,\n  data: Data,\n  typename: string,\n  entityKey: string,\n  fieldKey: string,\n  fieldName: string\n) => {\n  contextRef = ctx;\n  ctx.parent = data;\n  ctx.parentTypeName = typename;\n  ctx.parentKey = entityKey;\n  ctx.parentFieldKey = fieldKey;\n  ctx.fieldName = fieldName;\n  ctx.error = getFieldError(ctx);\n};\n\nconst isFragmentHeuristicallyMatching = (\n  node: FormattedNode<InlineFragmentNode | FragmentDefinitionNode>,\n  typename: void | string,\n  entityKey: string,\n  vars: Variables,\n  logger?: Logger\n) => {\n  if (!typename) return false;\n  const typeCondition = getTypeCondition(node);\n  if (!typeCondition || typename === typeCondition) return true;\n\n  warn(\n    'Heuristic Fragment Matching: A fragment is trying to match against the `' +\n      typename +\n      '` type, ' +\n      'but the type condition is `' +\n      typeCondition +\n      '`. Since GraphQL allows for interfaces `' +\n      typeCondition +\n      '` may be an ' +\n      'interface.\\nA schema needs to be defined for this match to be deterministic, ' +\n      'otherwise the fragment will be matched heuristically!',\n    16,\n    logger\n  );\n\n  return !getSelectionSet(node).some(node => {\n    if (node.kind !== Kind.FIELD) return false;\n    const fieldKey = keyOfField(getName(node), getFieldArguments(node, vars));\n    return !hasField(entityKey, fieldKey);\n  });\n};\n\nexport class SelectionIterator {\n  typename: undefined | string;\n  entityKey: string;\n  ctx: Context;\n  stack: {\n    selectionSet: FormattedNode<SelectionSet>;\n    index: number;\n    defer: boolean;\n    optional: boolean | undefined;\n  }[];\n\n  // NOTE: Outside of this file, we expect `_defer` to always be reset to `false`\n  constructor(\n    typename: undefined | string,\n    entityKey: string,\n    _defer: false,\n    _optional: undefined,\n    selectionSet: FormattedNode<SelectionSet>,\n    ctx: Context\n  );\n  // NOTE: Inside this file we expect the state to be recursively passed on\n  constructor(\n    typename: undefined | string,\n    entityKey: string,\n    _defer: boolean,\n    _optional: undefined | boolean,\n    selectionSet: FormattedNode<SelectionSet>,\n    ctx: Context\n  );\n\n  constructor(\n    typename: undefined | string,\n    entityKey: string,\n    _defer: boolean,\n    _optional: boolean | undefined,\n    selectionSet: FormattedNode<SelectionSet>,\n    ctx: Context\n  ) {\n    this.typename = typename;\n    this.entityKey = entityKey;\n    this.ctx = ctx;\n    this.stack = [\n      {\n        selectionSet,\n        index: 0,\n        defer: _defer,\n        optional: _optional,\n      },\n    ];\n  }\n\n  next(): FormattedNode<FieldNode> | undefined {\n    while (this.stack.length > 0) {\n      let state = this.stack[this.stack.length - 1];\n      while (state.index < state.selectionSet.length) {\n        const select = state.selectionSet[state.index++];\n        if (!shouldInclude(select, this.ctx.variables)) {\n          /*noop*/\n        } else if (select.kind !== Kind.FIELD) {\n          // A fragment is either referred to by FragmentSpread or inline\n          const fragment =\n            select.kind !== Kind.INLINE_FRAGMENT\n              ? this.ctx.fragments[getName(select)]\n              : select;\n          if (fragment) {\n            const isMatching =\n              !fragment.typeCondition ||\n              (this.ctx.store.schema\n                ? isInterfaceOfType(\n                    this.ctx.store.schema,\n                    fragment,\n                    this.typename\n                  )\n                : this.ctx.store.possibleTypeMap\n                  ? isSuperType(\n                      this.ctx.store.possibleTypeMap,\n                      fragment.typeCondition.name.value,\n                      this.typename\n                    )\n                  : (currentOperation === 'read' &&\n                      isFragmentMatching(\n                        fragment.typeCondition.name.value,\n                        this.typename\n                      )) ||\n                    isFragmentHeuristicallyMatching(\n                      fragment,\n                      this.typename,\n                      this.entityKey,\n                      this.ctx.variables,\n                      this.ctx.store.logger\n                    ));\n            if (\n              isMatching ||\n              (currentOperation === 'write' && !this.ctx.store.schema)\n            ) {\n              if (process.env.NODE_ENV !== 'production')\n                pushDebugNode(this.typename, fragment);\n              const isFragmentOptional = isOptional(select);\n              if (\n                isMatching &&\n                fragment.typeCondition &&\n                this.typename !== fragment.typeCondition.name.value\n              ) {\n                writeConcreteType(\n                  fragment.typeCondition.name.value,\n                  this.typename!\n                );\n              }\n\n              this.stack.push(\n                (state = {\n                  selectionSet: getSelectionSet(fragment),\n                  index: 0,\n                  defer: state.defer || isDeferred(select, this.ctx.variables),\n                  optional:\n                    isFragmentOptional !== undefined\n                      ? isFragmentOptional\n                      : state.optional,\n                })\n              );\n            }\n          }\n        } else if (currentOperation === 'write' || !select._generated) {\n          deferRef = state.defer;\n          optionalRef = state.optional;\n          return select;\n        }\n      }\n      this.stack.pop();\n      if (process.env.NODE_ENV !== 'production') popDebugNode();\n    }\n    return undefined;\n  }\n}\n\nconst isSuperType = (\n  possibleTypeMap: Map<string, Set<string>>,\n  typeCondition: string,\n  typename: string | void\n) => {\n  if (!typename) return false;\n  if (typeCondition === typename) return true;\n\n  const concreteTypes = possibleTypeMap.get(typeCondition);\n\n  return concreteTypes && concreteTypes.has(typename);\n};\n\nconst isFragmentMatching = (typeCondition: string, typename: string | void) => {\n  if (!typename) return false;\n  if (typeCondition === typename) return true;\n\n  const isProbableAbstractType = !isSeenConcreteType(typeCondition);\n  if (!isProbableAbstractType) return false;\n\n  const types = getConcreteTypes(typeCondition);\n  return types.size && types.has(typename);\n};\n\nexport const ensureData = (x: DataField): Data | NullArray<Data> | null =>\n  x == null ? null : (x as Data | NullArray<Data>);\n\nexport const ensureLink = (store: Store, ref: Link<Entity>): Link => {\n  if (!ref) {\n    return ref || null;\n  } else if (Array.isArray(ref)) {\n    const link = new Array(ref.length);\n    for (let i = 0, l = link.length; i < l; i++)\n      link[i] = ensureLink(store, ref[i]);\n    return link;\n  }\n\n  const link = store.keyOfEntity(ref);\n  if (!link && ref && typeof ref === 'object') {\n    warn(\n      \"Can't generate a key for link(...) item.\" +\n        '\\nYou have to pass an `id` or `_id` field or create a custom `keys` config for `' +\n        ref.__typename +\n        '`.',\n      12,\n      store.logger\n    );\n  }\n\n  return link;\n};\n"
  },
  {
    "path": "exchanges/graphcache/src/operations/write.test.ts",
    "content": "/* eslint-disable @typescript-eslint/no-var-requires */\n\nimport { gql, CombinedError } from '@urql/core';\nimport { minifyIntrospectionQuery } from '@urql/introspection';\nimport { vi, expect, it, beforeEach, describe, beforeAll } from 'vitest';\n\nimport { __initAnd_write as write } from './write';\nimport * as InMemoryData from '../store/data';\nimport { Store } from '../store/store';\n\nconst TODO_QUERY = gql`\n  query todos {\n    todos {\n      id\n      text\n      complete\n      author {\n        id\n        name\n        known\n        __typename\n      }\n      __typename\n    }\n  }\n`;\n\ndescribe('Query', () => {\n  let schema, store;\n\n  beforeAll(() => {\n    schema = minifyIntrospectionQuery(\n      require('../test-utils/simple_schema.json')\n    );\n  });\n\n  beforeEach(() => {\n    store = new Store({ schema });\n    write(\n      store,\n      { query: TODO_QUERY },\n      {\n        __typename: 'Query',\n        todos: [\n          { id: '0', text: 'Teach', __typename: 'Todo' },\n          { id: '1', text: 'Learn', __typename: 'Todo' },\n        ],\n      }\n    );\n\n    vi.clearAllMocks();\n  });\n\n  it('should not crash for valid writes', async () => {\n    const VALID_TODO_QUERY = gql`\n      mutation {\n        toggleTodo {\n          id\n          text\n          complete\n        }\n      }\n    `;\n    write(\n      store,\n      { query: VALID_TODO_QUERY },\n      {\n        __typename: 'Mutation',\n        toggleTodo: {\n          __typename: 'Todo',\n          id: '0',\n          text: 'Teach',\n          complete: true,\n        },\n      }\n    );\n    expect(console.warn).not.toHaveBeenCalled();\n    expect(console.error).not.toHaveBeenCalled();\n  });\n\n  it('should warn once for invalid fields on an entity', () => {\n    const INVALID_TODO_QUERY = gql`\n      mutation {\n        toggleTodo {\n          id\n          text\n          incomplete\n        }\n      }\n    `;\n    write(\n      store,\n      { query: INVALID_TODO_QUERY },\n      {\n        __typename: 'Mutation',\n        toggleTodo: {\n          __typename: 'Todo',\n          id: '0',\n          text: 'Teach',\n          incomplete: false,\n        },\n      }\n    );\n    expect(console.warn).toHaveBeenCalledTimes(1);\n    write(\n      store,\n      { query: INVALID_TODO_QUERY },\n      {\n        __typename: 'Mutation',\n        toggleTodo: {\n          __typename: 'Todo',\n          id: '0',\n          text: 'Teach',\n          incomplete: false,\n        },\n      }\n    );\n    expect(console.warn).toHaveBeenCalledTimes(1);\n    expect((console.warn as any).mock.calls[0][0]).toMatch(\n      /The field `incomplete` does not exist on `Todo`/\n    );\n  });\n\n  it('should warn once for invalid link fields on an entity', () => {\n    const INVALID_TODO_QUERY = gql`\n      mutation {\n        toggleTodo {\n          id\n          text\n          writer {\n            id\n          }\n        }\n      }\n    `;\n    write(\n      store,\n      { query: INVALID_TODO_QUERY },\n      {\n        __typename: 'Mutation',\n        toggleTodo: {\n          __typename: 'Todo',\n          id: '0',\n          text: 'Teach',\n          writer: {\n            id: '0',\n          },\n        },\n      }\n    );\n    // Because of us indicating Todo:Writer as a scalar\n    expect(console.warn).toHaveBeenCalledTimes(2);\n    expect((console.warn as any).mock.calls[0][0]).toMatch(\n      /The field `writer` does not exist on `Todo`/\n    );\n  });\n\n  it('should skip undefined values that are expected', () => {\n    const query = gql`\n      {\n        field\n      }\n    `;\n\n    // This should not overwrite the field\n    write(store, { query }, { field: undefined } as any);\n    // Because of us writing an undefined field\n    expect(console.warn).toHaveBeenCalledTimes(2);\n\n    expect((console.warn as any).mock.calls[1][0]).toMatch(\n      /Invalid undefined: The field at `field`/\n    );\n\n    write(store, { query }, { field: 'test' } as any);\n    write(store, { query }, { field: undefined } as any);\n    InMemoryData.initDataState('read', store.data, null);\n    // The field must still be `'test'`\n    expect(InMemoryData.readRecord('Query', 'field')).toBe('test');\n  });\n\n  it('should write errored records as undefined rather than null', () => {\n    const query = gql`\n      {\n        missingField\n        setField\n      }\n    `;\n\n    write(\n      store,\n      { query },\n      { missingField: null, setField: 'test' } as any,\n      new CombinedError({\n        graphQLErrors: [\n          {\n            message: 'Test',\n            path: ['missingField'],\n          },\n        ],\n      })\n    );\n\n    InMemoryData.initDataState('read', store.data, null);\n\n    // The setField must still be `'test'`\n    expect(InMemoryData.readRecord('Query', 'setField')).toBe('test');\n    // The missingField must still be `undefined`\n    expect(InMemoryData.readRecord('Query', 'missingField')).toBe(undefined);\n  });\n\n  it('should write errored links as undefined rather than null', () => {\n    const query = gql`\n      {\n        missingTodoItem: todos {\n          id\n          text\n        }\n        missingTodo: todo {\n          id\n          text\n        }\n      }\n    `;\n\n    write(\n      store,\n      { query },\n      {\n        missingTodoItem: [null, { __typename: 'Todo', id: 1, text: 'Learn' }],\n        missingTodo: null,\n      } as any,\n      new CombinedError({\n        graphQLErrors: [\n          {\n            message: 'Test',\n            path: ['missingTodoItem', 0],\n          },\n          {\n            message: 'Test',\n            path: ['missingTodo'],\n          },\n        ],\n      })\n    );\n\n    InMemoryData.initDataState('read', store.data, null);\n    expect(InMemoryData.readLink('Query', 'todos')).toEqual([\n      undefined,\n      'Todo:1',\n    ]);\n    expect(InMemoryData.readLink('Query', 'todo')).toEqual(undefined);\n  });\n});\n"
  },
  {
    "path": "exchanges/graphcache/src/operations/write.ts",
    "content": "import type { FormattedNode, CombinedError } from '@urql/core';\nimport { formatDocument } from '@urql/core';\n\nimport type {\n  FieldNode,\n  DocumentNode,\n  FragmentDefinitionNode,\n} from '@0no-co/graphql.web';\n\nimport type { SelectionSet } from '../ast';\nimport {\n  getFragments,\n  getMainOperation,\n  normalizeVariables,\n  getFieldArguments,\n  isFieldAvailableOnType,\n  getSelectionSet,\n  getName,\n  getFragmentTypeName,\n  getFieldAlias,\n} from '../ast';\n\nimport { invariant, warn, pushDebugNode, popDebugNode } from '../helpers/help';\n\nimport type {\n  NullArray,\n  Variables,\n  Data,\n  Link,\n  OperationRequest,\n  Dependencies,\n  EntityField,\n  OptimisticMutationResolver,\n} from '../types';\n\nimport { joinKeys, keyOfField } from '../store/keys';\nimport type { Store } from '../store/store';\nimport * as InMemoryData from '../store/data';\n\nimport type { Context } from './shared';\nimport {\n  SelectionIterator,\n  ensureData,\n  makeContext,\n  updateContext,\n  getFieldError,\n  deferRef,\n} from './shared';\nimport { invalidateType } from './invalidate';\n\nexport interface WriteResult {\n  data: null | Data;\n  dependencies: Dependencies;\n}\n\n/** Writes a GraphQL response to the cache.\n * @internal\n */\nexport const __initAnd_write = (\n  store: Store,\n  request: OperationRequest,\n  data: Data,\n  error?: CombinedError | undefined,\n  key?: number\n): WriteResult => {\n  InMemoryData.initDataState('write', store.data, key || null);\n  const result = _write(store, request, data, error);\n  InMemoryData.clearDataState();\n  return result;\n};\n\nexport const __initAnd_writeOptimistic = (\n  store: Store,\n  request: OperationRequest,\n  key: number\n): WriteResult => {\n  if (process.env.NODE_ENV !== 'production') {\n    invariant(\n      getMainOperation(request.query).operation === 'mutation',\n      'writeOptimistic(...) was called with an operation that is not a mutation.\\n' +\n        'This case is unsupported and should never occur.',\n      10\n    );\n  }\n\n  InMemoryData.initDataState('write', store.data, key, true);\n  const result = _write(store, request, {} as Data, undefined);\n  InMemoryData.clearDataState();\n  return result;\n};\n\nexport const _write = (\n  store: Store,\n  request: OperationRequest,\n  data?: Data,\n  error?: CombinedError | undefined\n) => {\n  if (process.env.NODE_ENV !== 'production') {\n    InMemoryData.getCurrentDependencies();\n  }\n\n  const query = formatDocument(request.query);\n  const operation = getMainOperation(query);\n  const result: WriteResult = {\n    data: data || InMemoryData.makeData(),\n    dependencies: InMemoryData.currentDependencies!,\n  };\n  const kind = store.rootFields[operation.operation];\n\n  const ctx = makeContext(\n    store,\n    normalizeVariables(operation, request.variables),\n    getFragments(query),\n    kind,\n    kind,\n    error\n  );\n\n  if (process.env.NODE_ENV !== 'production') {\n    pushDebugNode(kind, operation);\n  }\n\n  writeSelection(ctx, kind, getSelectionSet(operation), result.data!);\n\n  if (process.env.NODE_ENV !== 'production') {\n    popDebugNode();\n  }\n\n  return result;\n};\n\nexport const _writeFragment = (\n  store: Store,\n  query: FormattedNode<DocumentNode>,\n  data: Partial<Data>,\n  variables?: Variables,\n  fragmentName?: string\n) => {\n  const fragments = getFragments(query);\n  let fragment: FormattedNode<FragmentDefinitionNode>;\n  if (fragmentName) {\n    fragment = fragments[fragmentName]!;\n    if (!fragment) {\n      warn(\n        'writeFragment(...) was called with a fragment name that does not exist.\\n' +\n          'You provided ' +\n          fragmentName +\n          ' but could only find ' +\n          Object.keys(fragments).join(', ') +\n          '.',\n        11,\n        store.logger\n      );\n\n      return null;\n    }\n  } else {\n    const names = Object.keys(fragments);\n    fragment = fragments[names[0]]!;\n    if (!fragment) {\n      warn(\n        'writeFragment(...) was called with an empty fragment.\\n' +\n          'You have to call it with at least one fragment in your GraphQL document.',\n        11,\n        store.logger\n      );\n\n      return null;\n    }\n  }\n\n  const typename = getFragmentTypeName(fragment);\n  const dataToWrite = { __typename: typename, ...data } as Data;\n  const entityKey = store.keyOfEntity(dataToWrite);\n  if (!entityKey) {\n    return warn(\n      \"Can't generate a key for writeFragment(...) data.\\n\" +\n        'You have to pass an `id` or `_id` field or create a custom `keys` config for `' +\n        typename +\n        '`.',\n      12,\n      store.logger\n    );\n  }\n\n  if (process.env.NODE_ENV !== 'production') {\n    pushDebugNode(typename, fragment);\n  }\n\n  const ctx = makeContext(\n    store,\n    variables || {},\n    fragments,\n    typename,\n    entityKey,\n    undefined\n  );\n\n  writeSelection(ctx, entityKey, getSelectionSet(fragment), dataToWrite);\n\n  if (process.env.NODE_ENV !== 'production') {\n    popDebugNode();\n  }\n};\n\nconst writeSelection = (\n  ctx: Context,\n  entityKey: undefined | string,\n  select: FormattedNode<SelectionSet>,\n  data: Data\n) => {\n  // These fields determine how we write. The `Query` root type is written\n  // like a normal entity, hence, we use `rootField` with a default to determine\n  // this. All other root names (Subscription & Mutation) are in a different\n  // write mode\n  const rootField = ctx.store.rootNames[entityKey!] || 'query';\n  const isRoot = !!ctx.store.rootNames[entityKey!];\n\n  let typename = isRoot ? entityKey : data.__typename;\n  if (!typename && entityKey && ctx.optimistic) {\n    typename = InMemoryData.readRecord(entityKey, '__typename') as\n      | string\n      | undefined;\n  }\n\n  if (!typename) {\n    warn(\n      \"Couldn't find __typename when writing.\\n\" +\n        \"If you're writing to the cache manually have to pass a `__typename` property on each entity in your data.\",\n      14,\n      ctx.store.logger\n    );\n    return;\n  } else if (!isRoot && entityKey) {\n    InMemoryData.writeRecord(entityKey, '__typename', typename);\n    InMemoryData.writeType(typename, entityKey);\n  }\n\n  const updates = ctx.store.updates[typename];\n  const selection = new SelectionIterator(\n    typename,\n    entityKey || typename,\n    false,\n    undefined,\n    select,\n    ctx\n  );\n\n  let node: FormattedNode<FieldNode> | void;\n  while ((node = selection.next())) {\n    const fieldName = getName(node);\n    const fieldArgs = getFieldArguments(node, ctx.variables);\n    const fieldKey = keyOfField(fieldName, fieldArgs);\n    const fieldAlias = getFieldAlias(node);\n    let fieldValue = data[ctx.optimistic ? fieldName : fieldAlias];\n\n    if (\n      // Skip typename fields and assume they've already been written above\n      fieldName === '__typename' ||\n      // Fields marked as deferred that aren't defined must be skipped\n      // Otherwise, we also ignore undefined values in optimistic updaters\n      (fieldValue === undefined &&\n        (deferRef || (ctx.optimistic && rootField === 'query')))\n    ) {\n      continue;\n    }\n\n    if (process.env.NODE_ENV !== 'production') {\n      if (ctx.store.schema && typename && fieldName !== '__typename') {\n        isFieldAvailableOnType(\n          ctx.store.schema,\n          typename,\n          fieldName,\n          ctx.store.logger\n        );\n      }\n    }\n\n    // Add the current alias to the walked path before processing the field's value\n    ctx.__internal.path.push(fieldAlias);\n\n    // Execute optimistic mutation functions on root fields, or execute recursive functions\n    // that have been returned on optimistic objects\n    let resolver: OptimisticMutationResolver | undefined;\n    if (ctx.optimistic && rootField === 'mutation') {\n      resolver = ctx.store.optimisticMutations[fieldName];\n      if (!resolver) continue;\n    } else if (ctx.optimistic && typeof fieldValue === 'function') {\n      resolver = fieldValue as any;\n    }\n\n    // Execute the field-level resolver to retrieve its data\n    if (resolver) {\n      // We have to update the context to reflect up-to-date ResolveInfo\n      updateContext(\n        ctx,\n        data,\n        typename,\n        entityKey || typename,\n        fieldKey,\n        fieldName\n      );\n      fieldValue = ensureData(resolver(fieldArgs || {}, ctx.store, ctx));\n    }\n\n    if (fieldValue === undefined) {\n      if (process.env.NODE_ENV !== 'production') {\n        if (\n          !entityKey ||\n          !InMemoryData.hasField(entityKey, fieldKey) ||\n          (ctx.optimistic && !InMemoryData.readRecord(entityKey, '__typename'))\n        ) {\n          const expected =\n            node.selectionSet === undefined\n              ? 'scalar (number, boolean, etc)'\n              : 'selection set';\n\n          warn(\n            'Invalid undefined: The field at `' +\n              fieldKey +\n              '` is `undefined`, but the GraphQL query expects a ' +\n              expected +\n              ' for this field.',\n            13,\n            ctx.store.logger\n          );\n        }\n      }\n\n      continue; // Skip this field\n    }\n\n    if (node.selectionSet) {\n      // Process the field and write links for the child entities that have been written\n      if (entityKey && rootField === 'query') {\n        const key = joinKeys(entityKey, fieldKey);\n        const link = writeField(\n          ctx,\n          getSelectionSet(node),\n          ensureData(fieldValue),\n          key,\n          ctx.optimistic\n            ? InMemoryData.readLink(entityKey || typename, fieldKey)\n            : undefined\n        );\n\n        InMemoryData.writeLink(entityKey || typename, fieldKey, link);\n      } else {\n        writeField(ctx, getSelectionSet(node), ensureData(fieldValue));\n      }\n    } else if (entityKey && rootField === 'query') {\n      // This is a leaf node, so we're setting the field's value directly\n      InMemoryData.writeRecord(\n        entityKey || typename,\n        fieldKey,\n        (fieldValue !== null || !getFieldError(ctx)\n          ? fieldValue\n          : undefined) as EntityField\n      );\n    }\n\n    // We run side-effect updates after the default, normalized updates\n    // so that the data is already available in-store if necessary\n    const updater = updates && updates[fieldName];\n    if (updater) {\n      // We have to update the context to reflect up-to-date ResolveInfo\n      updateContext(\n        ctx,\n        data,\n        typename,\n        entityKey || typename,\n        fieldKey,\n        fieldName\n      );\n\n      data[fieldName] = fieldValue;\n      updater(data, fieldArgs || {}, ctx.store, ctx);\n    } else if (\n      typename === ctx.store.rootFields['mutation'] &&\n      !ctx.optimistic\n    ) {\n      // If we're on a mutation that doesn't have an updater, we'll see\n      // whether we can find the entity returned by the mutation in the cache.\n      // if we don't we'll assume this is a create mutation and invalidate\n      // the found __typename.\n      if (fieldValue && Array.isArray(fieldValue)) {\n        const excludedEntities: string[] = fieldValue.map(\n          entity => ctx.store.keyOfEntity(entity) || ''\n        );\n        for (let i = 0, l = fieldValue.length; i < l; i++) {\n          const key = excludedEntities[i];\n          if (key && fieldValue[i].__typename) {\n            const resolved = InMemoryData.readRecord(key, '__typename');\n            const count = InMemoryData!.getRefCount(key);\n            if (resolved && !count) {\n              invalidateType(fieldValue[i].__typename, excludedEntities);\n            }\n          }\n        }\n      } else if (fieldValue && typeof fieldValue === 'object') {\n        const key = ctx.store.keyOfEntity(fieldValue as any);\n        if (key) {\n          const resolved = InMemoryData.readRecord(key, '__typename');\n          const count = InMemoryData.getRefCount(key);\n          if ((!resolved || !count) && fieldValue.__typename) {\n            invalidateType(fieldValue.__typename, [key]);\n          }\n        }\n      }\n    }\n\n    // After processing the field, remove the current alias from the path again\n    ctx.__internal.path.pop();\n  }\n};\n\n// A pattern to match typenames of types that are likely never keyable\nconst KEYLESS_TYPE_RE = /^__|PageInfo|(Connection|Edge)$/;\n\nconst writeField = (\n  ctx: Context,\n  select: FormattedNode<SelectionSet>,\n  data: null | Data | NullArray<Data>,\n  parentFieldKey?: string,\n  prevLink?: Link\n): Link | undefined => {\n  if (Array.isArray(data)) {\n    const newData = new Array(data.length);\n    for (let i = 0, l = data.length; i < l; i++) {\n      // Add the current index to the walked path before processing the link\n      ctx.__internal.path.push(i);\n      // Append the current index to the parentFieldKey fallback\n      const indexKey = parentFieldKey\n        ? joinKeys(parentFieldKey, `${i}`)\n        : undefined;\n      // Recursively write array data\n      const prevIndex = prevLink != null ? prevLink[i] : undefined;\n      const links = writeField(ctx, select, data[i], indexKey, prevIndex);\n      // Link cannot be expressed as a recursive type\n      newData[i] = links as string | null;\n      // After processing the field, remove the current index from the path\n      ctx.__internal.path.pop();\n    }\n\n    return newData;\n  } else if (data === null) {\n    return getFieldError(ctx) ? undefined : null;\n  }\n\n  const entityKey =\n    ctx.store.keyOfEntity(data) ||\n    (typeof prevLink === 'string' ? prevLink : null);\n  const typename = data.__typename;\n\n  if (\n    parentFieldKey &&\n    !ctx.store.keys[data.__typename] &&\n    entityKey === null &&\n    typeof typename === 'string' &&\n    !KEYLESS_TYPE_RE.test(typename)\n  ) {\n    warn(\n      'Invalid key: The GraphQL query at the field at `' +\n        parentFieldKey +\n        '` has a selection set, ' +\n        'but no key could be generated for the data at this field.\\n' +\n        'You have to request `id` or `_id` fields for all selection sets or create ' +\n        'a custom `keys` config for `' +\n        typename +\n        '`.\\n' +\n        'Entities without keys will be embedded directly on the parent entity. ' +\n        'If this is intentional, create a `keys` config for `' +\n        typename +\n        '` that always returns null.',\n      15,\n      ctx.store.logger\n    );\n  }\n\n  const childKey = entityKey || parentFieldKey;\n  writeSelection(ctx, childKey, select, data);\n  return childKey || null;\n};\n"
  },
  {
    "path": "exchanges/graphcache/src/store/__snapshots__/store.test.ts.snap",
    "content": "// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html\n\nexports[`Store with storage > should be able to persist embedded data 1`] = `\n{\n  \"Query%2eappointment({\"id\":\"1\"}).__typename\": \"\"Appointment\"\",\n  \"Query%2eappointment({\"id\":\"1\"}).info\": \"\"urql meeting\"\",\n  \"Query.appointment({\"id\":\"1\"})\": \":\"Query.appointment({\\\\\"id\\\\\":\\\\\"1\\\\\"})\"\",\n}\n`;\n\nexports[`Store with storage > should be able to store and rehydrate data 1`] = `\n{\n  \"Appointment:1.__typename\": \"\"Appointment\"\",\n  \"Appointment:1.id\": \"\"1\"\",\n  \"Appointment:1.info\": \"\"urql meeting\"\",\n  \"Query.appointment({\"id\":\"1\"})\": \":\"Appointment:1\"\",\n}\n`;\n"
  },
  {
    "path": "exchanges/graphcache/src/store/data.test.ts",
    "content": "import { describe, it, beforeEach, expect } from 'vitest';\nimport * as InMemoryData from './data';\nimport { keyOfField } from './keys';\n\nlet data: InMemoryData.InMemoryData;\n\nbeforeEach(() => {\n  data = InMemoryData.make('Query');\n  InMemoryData.initDataState('write', data, null);\n});\n\ndescribe('garbage collection', () => {\n  it('erases orphaned entities', () => {\n    InMemoryData.writeRecord('Todo:1', '__typename', 'Todo');\n    InMemoryData.writeRecord('Todo:1', 'id', '1');\n    InMemoryData.writeRecord('Todo:2', '__typename', 'Todo');\n    InMemoryData.writeRecord('Query', '__typename', 'Query');\n    InMemoryData.writeLink('Query', 'todo', 'Todo:1');\n    InMemoryData.writeType('Todo', 'Todo:1');\n\n    InMemoryData.gc();\n\n    expect(InMemoryData.readLink('Query', 'todo')).toBe('Todo:1');\n    expect(InMemoryData.getEntitiesForType('Todo')).toEqual(\n      new Set(['Todo:1'])\n    );\n\n    InMemoryData.writeLink('Query', 'todo', undefined);\n    InMemoryData.gc();\n\n    expect(InMemoryData.readLink('Query', 'todo')).toBe(undefined);\n    expect(InMemoryData.readRecord('Todo:1', 'id')).toBe(undefined);\n    expect(InMemoryData.getEntitiesForType('Todo')).toEqual(new Set());\n\n    expect(InMemoryData.getCurrentDependencies()).toEqual(\n      new Set(['Todo:1', 'Todo:2', 'Query.todo'])\n    );\n  });\n\n  it('keeps readopted entities', () => {\n    InMemoryData.writeRecord('Todo:1', '__typename', 'Todo');\n    InMemoryData.writeRecord('Todo:1', 'id', '1');\n    InMemoryData.writeRecord('Query', '__typename', 'Query');\n    InMemoryData.writeLink('Query', 'todo', 'Todo:1');\n    InMemoryData.writeLink('Query', 'todo', undefined);\n    InMemoryData.writeLink('Query', 'newTodo', 'Todo:1');\n    InMemoryData.writeType('Todo', 'Todo:1');\n\n    InMemoryData.gc();\n\n    expect(InMemoryData.readLink('Query', 'newTodo')).toBe('Todo:1');\n    expect(InMemoryData.readLink('Query', 'todo')).toBe(undefined);\n    expect(InMemoryData.readRecord('Todo:1', 'id')).toBe('1');\n    expect(InMemoryData.getEntitiesForType('Todo')).toEqual(\n      new Set(['Todo:1'])\n    );\n\n    expect(InMemoryData.getCurrentDependencies()).toEqual(\n      new Set(['Todo:1', 'Query.todo', 'Query.newTodo'])\n    );\n  });\n\n  it('keeps entities with multiple owners', () => {\n    InMemoryData.writeRecord('Todo:1', '__typename', 'Todo');\n    InMemoryData.writeRecord('Todo:1', 'id', '1');\n    InMemoryData.writeRecord('Query', '__typename', 'Query');\n    InMemoryData.writeLink('Query', 'todoA', 'Todo:1');\n    InMemoryData.writeLink('Query', 'todoB', 'Todo:1');\n    InMemoryData.writeLink('Query', 'todoA', undefined);\n\n    InMemoryData.gc();\n\n    expect(InMemoryData.readLink('Query', 'todoA')).toBe(undefined);\n    expect(InMemoryData.readLink('Query', 'todoB')).toBe('Todo:1');\n    expect(InMemoryData.readRecord('Todo:1', 'id')).toBe('1');\n\n    expect(InMemoryData.getCurrentDependencies()).toEqual(\n      new Set(['Todo:1', 'Query.todoA', 'Query.todoB'])\n    );\n  });\n\n  it('skips entities with optimistic updates', () => {\n    InMemoryData.writeRecord('Todo:1', '__typename', 'Todo');\n    InMemoryData.writeRecord('Todo:1', 'id', '1');\n    InMemoryData.writeLink('Query', 'todo', 'Todo:1');\n\n    InMemoryData.initDataState('write', data, 1, true);\n    InMemoryData.writeLink('Query', 'temp', 'Todo:1');\n\n    InMemoryData.initDataState('write', data, 0, true);\n    InMemoryData.writeLink('Query', 'todo', undefined);\n\n    InMemoryData.gc();\n\n    expect(InMemoryData.readRecord('Todo:1', 'id')).toBe('1');\n\n    InMemoryData.reserveLayer(data, 1);\n    InMemoryData.gc();\n\n    expect(InMemoryData.readRecord('Todo:1', 'id')).toBe('1');\n    // TODO: is it a problem that this fails, we are reading from Todo\n    // but we are not updating anything\n    expect(InMemoryData.getCurrentDependencies()).toEqual(\n      new Set(['Query.todo'])\n    );\n  });\n\n  it('erases child entities that are orphaned', () => {\n    InMemoryData.writeRecord('Author:1', '__typename', 'Author');\n    InMemoryData.writeRecord('Author:1', 'id', '1');\n    InMemoryData.writeLink('Todo:1', 'author', 'Author:1');\n    InMemoryData.writeRecord('Todo:1', '__typename', 'Todo');\n    InMemoryData.writeRecord('Todo:1', 'id', '1');\n    InMemoryData.writeLink('Query', 'todo', 'Todo:1');\n    InMemoryData.writeType('Todo', 'Todo:1');\n    InMemoryData.writeType('Author', 'Author:1');\n\n    InMemoryData.writeLink('Query', 'todo', undefined);\n    expect(InMemoryData.getEntitiesForType('Todo')).toEqual(\n      new Set(['Todo:1'])\n    );\n    expect(InMemoryData.getEntitiesForType('Author')).toEqual(\n      new Set(['Author:1'])\n    );\n    InMemoryData.gc();\n\n    expect(InMemoryData.readRecord('Todo:1', 'id')).toBe(undefined);\n    expect(InMemoryData.readRecord('Author:1', 'id')).toBe(undefined);\n    expect(InMemoryData.getEntitiesForType('Todo')).toEqual(new Set());\n    expect(InMemoryData.getEntitiesForType('Author')).toEqual(new Set());\n\n    expect(InMemoryData.getCurrentDependencies()).toEqual(\n      new Set(['Author:1', 'Todo:1', 'Query.todo'])\n    );\n  });\n});\n\ndescribe('inspectFields', () => {\n  it('returns field infos for all links and records', () => {\n    InMemoryData.writeRecord('Query', '__typename', 'Query');\n    InMemoryData.writeLink('Query', keyOfField('todo', { id: '1' }), 'Todo:1');\n    InMemoryData.writeRecord('Query', keyOfField('hasTodo', { id: '1' }), true);\n\n    InMemoryData.writeLink('Query', 'randomTodo', 'Todo:1');\n\n    expect(InMemoryData.inspectFields('Query')).toMatchInlineSnapshot(`\n      [\n        {\n          \"arguments\": {\n            \"id\": \"1\",\n          },\n          \"fieldKey\": \"todo({\"id\":\"1\"})\",\n          \"fieldName\": \"todo\",\n        },\n        {\n          \"arguments\": null,\n          \"fieldKey\": \"randomTodo\",\n          \"fieldName\": \"randomTodo\",\n        },\n        {\n          \"arguments\": null,\n          \"fieldKey\": \"__typename\",\n          \"fieldName\": \"__typename\",\n        },\n        {\n          \"arguments\": {\n            \"id\": \"1\",\n          },\n          \"fieldKey\": \"hasTodo({\"id\":\"1\"})\",\n          \"fieldName\": \"hasTodo\",\n        },\n      ]\n    `);\n\n    expect(InMemoryData.getCurrentDependencies()).toEqual(\n      new Set([\n        'Query.todo({\"id\":\"1\"})',\n        'Query.hasTodo({\"id\":\"1\"})',\n        'Query.randomTodo',\n      ])\n    );\n  });\n\n  it('returns an empty array when an entity is unknown', () => {\n    expect(InMemoryData.inspectFields('Random')).toEqual([]);\n\n    expect(InMemoryData.getCurrentDependencies()).toEqual(new Set(['Random']));\n  });\n\n  it('returns field infos for all optimistic updates', () => {\n    InMemoryData.initDataState('write', data, 1, true);\n    InMemoryData.writeLink('Query', 'todo', 'Todo:1');\n\n    expect(InMemoryData.inspectFields('Random')).toMatchInlineSnapshot('[]');\n  });\n\n  it('avoids duplicate field infos', () => {\n    InMemoryData.writeLink('Query', 'todo', 'Todo:1');\n\n    InMemoryData.initDataState('write', data, 1, true);\n    InMemoryData.writeLink('Query', 'todo', 'Todo:2');\n\n    expect(InMemoryData.inspectFields('Query')).toMatchInlineSnapshot(`\n      [\n        {\n          \"arguments\": null,\n          \"fieldKey\": \"todo\",\n          \"fieldName\": \"todo\",\n        },\n      ]\n    `);\n  });\n});\n\ndescribe('commutative changes', () => {\n  it('always applies out-of-order updates in-order', () => {\n    InMemoryData.reserveLayer(data, 1);\n    InMemoryData.reserveLayer(data, 2);\n\n    InMemoryData.initDataState('write', data, 2);\n    InMemoryData.writeRecord('Query', 'index', 2);\n    expect(InMemoryData.readRecord('Query', 'index')).toBe(2);\n    InMemoryData.clearDataState();\n\n    InMemoryData.initDataState('read', data, null);\n    expect(InMemoryData.readRecord('Query', 'index')).toBe(2);\n\n    InMemoryData.initDataState('write', data, 1);\n    InMemoryData.writeRecord('Query', 'index', 1);\n    expect(InMemoryData.readRecord('Query', 'index')).toBe(2);\n    InMemoryData.clearDataState();\n\n    InMemoryData.initDataState('read', data, null);\n    expect(InMemoryData.readRecord('Query', 'index')).toBe(2);\n\n    expect(data.optimisticOrder).toEqual([]);\n  });\n\n  it('creates optimistic layers that may be removed later', () => {\n    InMemoryData.reserveLayer(data, 1);\n\n    InMemoryData.initDataState('write', data, 2, true);\n    InMemoryData.writeRecord('Query', 'index', 2);\n    InMemoryData.clearDataState();\n\n    InMemoryData.initDataState('read', data, null);\n    expect(InMemoryData.readRecord('Query', 'index')).toBe(2);\n\n    // Actively clearing out layer 2\n    InMemoryData.noopDataState(data, 2);\n\n    InMemoryData.initDataState('read', data, null);\n    expect(InMemoryData.readRecord('Query', 'index')).toBe(undefined);\n\n    InMemoryData.initDataState('write', data, 1);\n    InMemoryData.writeRecord('Query', 'index', 1);\n    InMemoryData.clearDataState();\n\n    InMemoryData.initDataState('write', data, null);\n    expect(InMemoryData.readRecord('Query', 'index')).toBe(1);\n    InMemoryData.clearDataState();\n\n    expect(data.optimisticOrder).toEqual([]);\n  });\n\n  it('discards optimistic order when concrete data is written', () => {\n    InMemoryData.reserveLayer(data, 1);\n    InMemoryData.reserveLayer(data, 2);\n    InMemoryData.reserveLayer(data, 3);\n\n    InMemoryData.initDataState('write', data, 2, true);\n    InMemoryData.writeRecord('Query', 'index', 2);\n    InMemoryData.writeRecord('Query', 'optimistic', true);\n    InMemoryData.clearDataState();\n\n    InMemoryData.initDataState('write', data, 3);\n    InMemoryData.writeRecord('Query', 'index', 3);\n    InMemoryData.clearDataState();\n\n    // Expect Layer 3\n    expect(data.optimisticOrder).toEqual([3, 2, 1]);\n    InMemoryData.initDataState('read', data, null);\n    expect(InMemoryData.readRecord('Query', 'index')).toBe(3);\n    expect(InMemoryData.readRecord('Query', 'optimistic')).toBe(true);\n\n    // Write 2 again\n    InMemoryData.initDataState('write', data, 2);\n    InMemoryData.writeRecord('Query', 'index', 2);\n    InMemoryData.clearDataState();\n\n    // 2 has moved in front of 3\n    expect(data.optimisticOrder).toEqual([2, 3, 1]);\n    InMemoryData.initDataState('read', data, null);\n    expect(InMemoryData.readRecord('Query', 'index')).toBe(2);\n    expect(InMemoryData.readRecord('Query', 'optimistic')).toBe(undefined);\n  });\n\n  it('overrides data using optimistic layers', () => {\n    InMemoryData.reserveLayer(data, 1);\n    InMemoryData.reserveLayer(data, 2);\n    InMemoryData.reserveLayer(data, 3);\n\n    InMemoryData.initDataState('write', data, 2);\n    InMemoryData.writeRecord('Query', 'index', 2);\n    InMemoryData.clearDataState();\n\n    InMemoryData.initDataState('write', data, 3);\n    InMemoryData.writeRecord('Query', 'index', 3);\n    InMemoryData.clearDataState();\n\n    // Regular write that isn't optimistic\n    InMemoryData.initDataState('write', data, null);\n    InMemoryData.writeRecord('Query', 'index', 1);\n    InMemoryData.clearDataState();\n\n    InMemoryData.initDataState('read', data, null);\n    expect(InMemoryData.readRecord('Query', 'index')).toBe(3);\n\n    expect(data.optimisticOrder).toEqual([3, 2, 1]);\n  });\n\n  it('avoids optimistic layers when only one layer is pending', () => {\n    InMemoryData.reserveLayer(data, 1);\n\n    InMemoryData.initDataState('write', data, 1);\n    InMemoryData.writeRecord('Query', 'index', 2);\n    InMemoryData.clearDataState();\n\n    // This will be applied and visible since the above write isn't optimistic\n    InMemoryData.initDataState('write', data, null);\n    InMemoryData.writeRecord('Query', 'index', 1);\n    InMemoryData.clearDataState();\n\n    InMemoryData.initDataState('read', data, null);\n    expect(InMemoryData.readRecord('Query', 'index')).toBe(1);\n\n    expect(data.optimisticOrder).toEqual([]);\n  });\n\n  it('continues applying optimistic layers even if the first one completes', () => {\n    InMemoryData.reserveLayer(data, 1);\n    InMemoryData.reserveLayer(data, 2);\n    InMemoryData.reserveLayer(data, 3);\n    InMemoryData.reserveLayer(data, 4);\n\n    InMemoryData.initDataState('write', data, 1);\n    InMemoryData.writeRecord('Query', 'index', 1);\n    InMemoryData.clearDataState();\n\n    InMemoryData.initDataState('read', data, null);\n    expect(InMemoryData.readRecord('Query', 'index')).toBe(1);\n\n    InMemoryData.initDataState('write', data, 3);\n    InMemoryData.writeRecord('Query', 'index', 3);\n    InMemoryData.clearDataState();\n\n    InMemoryData.initDataState('read', data, null);\n    expect(InMemoryData.readRecord('Query', 'index')).toBe(3);\n\n    InMemoryData.initDataState('write', data, 4);\n    InMemoryData.writeRecord('Query', 'index', 4);\n    InMemoryData.clearDataState();\n\n    InMemoryData.initDataState('read', data, null);\n    expect(InMemoryData.readRecord('Query', 'index')).toBe(4);\n\n    InMemoryData.initDataState('write', data, 2);\n    InMemoryData.writeRecord('Query', 'index', 2);\n    InMemoryData.clearDataState();\n\n    InMemoryData.initDataState('read', data, null);\n    expect(InMemoryData.readRecord('Query', 'index')).toBe(4);\n\n    expect(data.optimisticOrder).toEqual([]);\n  });\n\n  it('allows noopDataState to clear layers only if necessary', () => {\n    InMemoryData.reserveLayer(data, 1);\n    InMemoryData.reserveLayer(data, 2);\n\n    InMemoryData.noopDataState(data, 2);\n    expect(data.optimisticOrder).toEqual([2, 1]);\n\n    InMemoryData.noopDataState(data, 1);\n    expect(data.optimisticOrder).toEqual([]);\n  });\n\n  it('respects non-reserved optimistic layers', () => {\n    InMemoryData.reserveLayer(data, 1);\n\n    InMemoryData.initDataState('write', data, 2, true);\n    InMemoryData.writeRecord('Query', 'index', 2);\n    InMemoryData.clearDataState();\n\n    InMemoryData.reserveLayer(data, 3);\n\n    expect(data.optimisticOrder).toEqual([3, 2, 1]);\n    expect([...data.commutativeKeys]).toEqual([1, 3]);\n\n    InMemoryData.initDataState('write', data, 1);\n    InMemoryData.writeRecord('Query', 'index', 1);\n    InMemoryData.clearDataState();\n    expect(data.optimisticOrder).toEqual([3, 2]);\n\n    InMemoryData.initDataState('read', data, null);\n    expect(InMemoryData.readRecord('Query', 'index')).toBe(2);\n\n    InMemoryData.initDataState('write', data, 3);\n    InMemoryData.writeRecord('Query', 'index', 3);\n    InMemoryData.clearDataState();\n    expect(data.optimisticOrder).toEqual([3, 2]);\n\n    InMemoryData.initDataState('read', data, null);\n    expect(InMemoryData.readRecord('Query', 'index')).toBe(3);\n  });\n\n  it('squashes when optimistic layers are completed', () => {\n    InMemoryData.reserveLayer(data, 1);\n\n    InMemoryData.initDataState('write', data, 2, true);\n    InMemoryData.writeRecord('Query', 'index', 2);\n    InMemoryData.clearDataState();\n    expect(data.optimisticOrder).toEqual([2, 1]);\n\n    InMemoryData.initDataState('write', data, 1);\n    InMemoryData.writeRecord('Query', 'index', 1);\n    InMemoryData.clearDataState();\n    expect(data.optimisticOrder).toEqual([2]);\n\n    // Delete optimistic layer\n    InMemoryData.noopDataState(data, 2);\n    expect(data.optimisticOrder).toEqual([]);\n\n    InMemoryData.initDataState('read', data, null);\n    expect(InMemoryData.readRecord('Query', 'index')).toBe(1);\n  });\n\n  it('squashes when optimistic layers are replaced with actual data', () => {\n    InMemoryData.reserveLayer(data, 1);\n\n    InMemoryData.initDataState('write', data, 2, true);\n    InMemoryData.writeRecord('Query', 'index', 2);\n    InMemoryData.clearDataState();\n    expect(data.optimisticOrder).toEqual([2, 1]);\n\n    InMemoryData.initDataState('write', data, 1);\n    InMemoryData.writeRecord('Query', 'index', 1);\n    InMemoryData.clearDataState();\n    expect(data.optimisticOrder).toEqual([2]);\n\n    // Convert optimistic layer to commutative layer\n    InMemoryData.initDataState('write', data, 2);\n    InMemoryData.writeRecord('Query', 'index', 2);\n    InMemoryData.clearDataState();\n    expect(data.optimisticOrder).toEqual([]);\n\n    InMemoryData.initDataState('read', data, null);\n    expect(InMemoryData.readRecord('Query', 'index')).toBe(2);\n  });\n\n  it('prevents inspectFields from failing for uninitialised layers', () => {\n    InMemoryData.initDataState('write', data, null);\n    InMemoryData.writeRecord('Query', 'test', true);\n    InMemoryData.clearDataState();\n\n    InMemoryData.reserveLayer(data, 1);\n\n    InMemoryData.initDataState('read', data, null);\n    expect(InMemoryData.inspectFields('Query')).toEqual([\n      {\n        arguments: null,\n        fieldKey: 'test',\n        fieldName: 'test',\n      },\n    ]);\n  });\n\n  it('allows reserveLayer to be called repeatedly', () => {\n    InMemoryData.reserveLayer(data, 1);\n    InMemoryData.reserveLayer(data, 1);\n    expect(data.optimisticOrder).toEqual([1]);\n    expect([...data.commutativeKeys]).toEqual([1]);\n  });\n\n  it('allows reserveLayer to be called after registering an optimistc layer', () => {\n    InMemoryData.noopDataState(data, 1, true);\n    expect(data.optimisticOrder).toEqual([1]);\n    expect(data.commutativeKeys.size).toBe(0);\n\n    InMemoryData.reserveLayer(data, 1);\n    expect(data.optimisticOrder).toEqual([1]);\n    expect([...data.commutativeKeys]).toEqual([1]);\n  });\n});\n\ndescribe('deferred changes', () => {\n  it('keeps a deferred layer around until completion', () => {\n    // initially it's unknown whether a layer is deferred\n    InMemoryData.reserveLayer(data, 1, true);\n    InMemoryData.reserveLayer(data, 2);\n\n    InMemoryData.reserveLayer(data, 2);\n    InMemoryData.initDataState('write', data, 2);\n    InMemoryData.writeRecord('Query', 'index', 2);\n    InMemoryData.clearDataState();\n\n    InMemoryData.initDataState('read', data, null);\n    expect(InMemoryData.readRecord('Query', 'index')).toBe(2);\n\n    // The layers must not be squashed\n    expect(data.optimisticOrder).toEqual([2, 1]);\n\n    // A future response may then clear the layer\n    InMemoryData.reserveLayer(data, 1, false);\n    InMemoryData.initDataState('write', data, 1);\n    InMemoryData.writeRecord('Query', 'index', 1);\n    InMemoryData.clearDataState();\n\n    // The layers must then be squashed\n    expect(data.optimisticOrder).toEqual([]);\n  });\n\n  it('does not erase data from a prior deferred layer when updating it', () => {\n    // initially it's unknown whether a layer is deferred\n    InMemoryData.reserveLayer(data, 1, true);\n    InMemoryData.reserveLayer(data, 2, true);\n\n    InMemoryData.initDataState('write', data, 2);\n    InMemoryData.writeRecord('Query', 'index', 2);\n    InMemoryData.clearDataState();\n\n    InMemoryData.initDataState('read', data, null);\n    expect(InMemoryData.readRecord('Query', 'index')).toBe(2);\n\n    // A subsequent reserve layer call should not erase the layer\n    InMemoryData.reserveLayer(data, 2, true);\n    InMemoryData.initDataState('read', data, null);\n    expect(InMemoryData.readRecord('Query', 'index')).toBe(2);\n\n    // The layers must not be squashed\n    expect(data.optimisticOrder).toEqual([2, 1]);\n  });\n\n  it('keeps a deferred layer around even if it is the lowest', () => {\n    // initially it's unknown whether a layer is deferred\n    InMemoryData.reserveLayer(data, 1);\n    InMemoryData.reserveLayer(data, 2);\n    InMemoryData.reserveLayer(data, 3);\n\n    InMemoryData.initDataState('write', data, 2);\n    InMemoryData.writeRecord('Query', 'index', 2);\n    InMemoryData.clearDataState();\n\n    // Mark layer 3 as deferred\n    InMemoryData.reserveLayer(data, 3, true);\n\n    // The value is unchanged\n    InMemoryData.initDataState('read', data, null);\n    expect(InMemoryData.readRecord('Query', 'index')).toBe(2);\n\n    // The layers must not be squashed\n    expect(data.optimisticOrder).toEqual([3, 2, 1]);\n\n    // A future response may not clear the layer\n    InMemoryData.initDataState('write', data, 1);\n    InMemoryData.writeRecord('Query', 'index', 1);\n    InMemoryData.clearDataState();\n    expect(data.optimisticOrder).toEqual([3]);\n\n    // The layers must then be squashed\n    InMemoryData.noopDataState(data, 3, false);\n    expect(data.optimisticOrder).toEqual([]);\n  });\n\n  it('unmarks deferred layers when they receive a noop write', () => {\n    // initially it's unknown whether a layer is deferred\n    InMemoryData.reserveLayer(data, 1);\n    InMemoryData.reserveLayer(data, 2);\n\n    InMemoryData.reserveLayer(data, 2);\n    InMemoryData.initDataState('write', data, 2);\n    InMemoryData.writeRecord('Query', 'index', 2);\n    InMemoryData.clearDataState();\n\n    // The layer is marked as deferred via re-reserving it\n    InMemoryData.reserveLayer(data, 1, true);\n    InMemoryData.initDataState('write', data, 1);\n    InMemoryData.clearDataState();\n\n    // The layer is then receiving a noop write\n    InMemoryData.noopDataState(data, 1, false);\n    expect(data.optimisticOrder).toEqual([]);\n  });\n});\n"
  },
  {
    "path": "exchanges/graphcache/src/store/data.ts",
    "content": "import { stringifyVariables } from '@urql/core';\n\nimport type {\n  Link,\n  EntityField,\n  FieldInfo,\n  StorageAdapter,\n  SerializedEntries,\n  Dependencies,\n  OperationType,\n  DataField,\n  Data,\n} from '../types';\n\nimport {\n  serializeKeys,\n  deserializeKeyInfo,\n  fieldInfoOfKey,\n  joinKeys,\n} from './keys';\n\nimport { invariant, currentDebugStack } from '../helpers/help';\n\ntype Dict<T> = Record<string, T>;\ntype KeyMap<T> = Map<string, T>;\ntype OperationMap<T> = Map<number, T>;\n\ninterface NodeMap<T> {\n  optimistic: OperationMap<KeyMap<Dict<T | undefined>>>;\n  base: KeyMap<Dict<T>>;\n}\n\nexport interface InMemoryData {\n  /** Flag for whether the data is waiting for hydration */\n  hydrating: boolean;\n  /** Flag for whether deferred tasks have been scheduled yet */\n  defer: boolean;\n  /** A list of entities that have been flagged for gargabe collection since no references to them are left */\n  gc: Set<string>;\n  /** A list of entity+field keys that will be persisted */\n  persist: Set<string>;\n  /** The API's \"Query\" typename which is needed to filter dependencies */\n  queryRootKey: string;\n  /** Number of references to each entity (except \"Query\") */\n  refCount: KeyMap<number>;\n  /** A map of entity fields (key-value entries per entity) */\n  records: NodeMap<EntityField>;\n  /** A map of entity links which are connections from one entity to another (key-value entries per entity) */\n  links: NodeMap<Link>;\n  /** A map of typename to a list of entity-keys belonging to said type */\n  types: Map<string, Set<string>>;\n  /** A set of Query operation keys that are in-flight and deferred/streamed */\n  deferredKeys: Set<number>;\n  /** A set of Query operation keys that are in-flight and awaiting a result */\n  commutativeKeys: Set<number>;\n  /** A set of Query operation keys that have been written to */\n  dirtyKeys: Set<number>;\n  /** The order of optimistic layers */\n  optimisticOrder: number[];\n  /** This may be a persistence adapter that will receive changes in a batch */\n  storage: StorageAdapter | null;\n  /** A map of all the types we have encountered that did not map directly to a concrete type */\n  abstractToConcreteMap: Map<string, Set<string>>;\n}\n\nlet currentOwnership: null | WeakSet<any> = null;\nlet currentDataMapping: null | WeakMap<any, any> = null;\nlet currentData: null | InMemoryData = null;\nlet currentOptimisticKey: null | number = null;\nexport let currentOperation: null | OperationType = null;\nexport let currentDependencies: null | Dependencies = null;\nexport let currentForeignData = false;\nexport let currentOptimistic = false;\n\nexport function makeData(data: DataField | void, isArray?: false): Data;\nexport function makeData(data: DataField | void, isArray: true): DataField[];\n\n/** Creates a new data object unless it's been created in this data run */\nexport function makeData(data?: DataField | void, isArray?: boolean) {\n  let newData: Data | Data[] | undefined;\n  if (data) {\n    if (currentOwnership!.has(data)) return data;\n    newData = currentDataMapping!.get(data) as any;\n  }\n\n  if (newData == null) {\n    newData = (isArray ? [] : {}) as any;\n  }\n\n  if (data) {\n    currentDataMapping!.set(data, newData);\n  }\n\n  currentOwnership!.add(newData);\n  return newData;\n}\n\nexport const ownsData = (data?: Data): boolean =>\n  !!data && currentOwnership!.has(data);\n\n/** Before reading or writing the global state needs to be initialised */\nexport const initDataState = (\n  operationType: OperationType,\n  data: InMemoryData,\n  layerKey?: number | null,\n  isOptimistic?: boolean,\n  isForeignData?: boolean\n) => {\n  currentOwnership = new WeakSet();\n  currentDataMapping = new WeakMap();\n  currentOperation = operationType;\n  currentData = data;\n  currentDependencies = new Set();\n  currentOptimistic = !!isOptimistic;\n  currentForeignData = !!isForeignData;\n  if (process.env.NODE_ENV !== 'production') {\n    currentDebugStack.length = 0;\n  }\n\n  if (!layerKey) {\n    currentOptimisticKey = null;\n  } else if (currentOperation === 'read') {\n    // We don't create new layers for read operations and instead simply\n    // apply the currently available layer, if any\n    currentOptimisticKey = layerKey;\n  } else if (\n    isOptimistic ||\n    data.hydrating ||\n    data.optimisticOrder.length > 1\n  ) {\n    // If this operation isn't optimistic and we see it for the first time,\n    // then it must've been optimistic in the past, so we can proactively\n    // clear the optimistic data before writing\n    if (!isOptimistic && !data.commutativeKeys.has(layerKey)) {\n      reserveLayer(data, layerKey);\n    } else if (isOptimistic) {\n      if (\n        data.optimisticOrder.indexOf(layerKey) !== -1 &&\n        !data.commutativeKeys.has(layerKey)\n      ) {\n        data.optimisticOrder.splice(data.optimisticOrder.indexOf(layerKey), 1);\n      }\n      // NOTE: This optimally shouldn't happen as it implies that an optimistic\n      // write is being performed after a concrete write.\n      data.commutativeKeys.delete(layerKey);\n    }\n\n    // An optimistic update of a mutation may force an optimistic layer,\n    // or this Query update may be applied optimistically since it's part\n    // of a commutative chain\n    currentOptimisticKey = layerKey;\n    createLayer(data, layerKey);\n  } else {\n    // Otherwise we don't create an optimistic layer and clear the\n    // operation's one if it already exists\n    // We also do this when only one layer exists to avoid having to squash\n    // any layers at the end of writing this layer\n    currentOptimisticKey = null;\n    deleteLayer(data, layerKey);\n  }\n};\n\n/** Reset the data state after read/write is complete */\nexport const clearDataState = () => {\n  // NOTE: This is only called to check for the invariant to pass\n  if (process.env.NODE_ENV !== 'production') {\n    getCurrentDependencies();\n  }\n\n  const data = currentData!;\n  const layerKey = currentOptimisticKey;\n  currentOptimistic = false;\n  currentOptimisticKey = null;\n\n  // Determine whether the current operation has been a commutative layer\n  if (\n    !data.hydrating &&\n    layerKey &&\n    data.optimisticOrder.indexOf(layerKey) > -1\n  ) {\n    // Squash all layers in reverse order (low priority upwards) that have\n    // been written already\n    let i = data.optimisticOrder.length;\n    while (\n      --i >= 0 &&\n      data.dirtyKeys.has(data.optimisticOrder[i]) &&\n      data.commutativeKeys.has(data.optimisticOrder[i])\n    )\n      squashLayer(data.optimisticOrder[i]);\n  }\n\n  currentOwnership = null;\n  currentDataMapping = null;\n  currentOperation = null;\n  currentData = null;\n  currentDependencies = null;\n  if (process.env.NODE_ENV !== 'production') {\n    currentDebugStack.length = 0;\n  }\n\n  if (process.env.NODE_ENV !== 'test') {\n    // Schedule deferred tasks if we haven't already, and if either a persist or GC run\n    // are likely to be needed\n    if (!data.defer && (data.storage || !data.optimisticOrder.length)) {\n      data.defer = true;\n      setTimeout(() => {\n        initDataState('read', data, null);\n        gc();\n        persistData();\n        clearDataState();\n        data.defer = false;\n      });\n    }\n  }\n};\n\n/** Initialises then resets the data state, which may squash this layer if necessary */\nexport const noopDataState = (\n  data: InMemoryData,\n  layerKey: number | null,\n  isOptimistic?: boolean\n) => {\n  if (layerKey && !isOptimistic) data.deferredKeys.delete(layerKey);\n  initDataState('write', data, layerKey, isOptimistic);\n  clearDataState();\n};\n\n/** As we're writing, we keep around all the records and links we've read or have written to */\nexport const getCurrentDependencies = (): Dependencies => {\n  invariant(\n    currentDependencies !== null,\n    'Invalid Cache call: The cache may only be accessed or mutated during' +\n      'operations like write or query, or as part of its resolvers, updaters, ' +\n      'or optimistic configs.',\n    2\n  );\n\n  return currentDependencies;\n};\n\nconst DEFAULT_EMPTY_SET = new Set<string>();\nexport const make = (queryRootKey: string): InMemoryData => ({\n  hydrating: false,\n  defer: false,\n  gc: new Set(),\n  types: new Map(),\n  persist: new Set(),\n  queryRootKey,\n  refCount: new Map(),\n  links: {\n    optimistic: new Map(),\n    base: new Map(),\n  },\n  abstractToConcreteMap: new Map(),\n  records: {\n    optimistic: new Map(),\n    base: new Map(),\n  },\n  deferredKeys: new Set(),\n  commutativeKeys: new Set(),\n  dirtyKeys: new Set(),\n  optimisticOrder: [],\n  storage: null,\n});\n\n/** Adds a node value to a NodeMap (taking optimistic values into account */\nconst setNode = <T>(\n  map: NodeMap<T>,\n  entityKey: string,\n  fieldKey: string,\n  value: T\n) => {\n  if (process.env.NODE_ENV !== 'production') {\n    invariant(\n      currentOperation !== 'read',\n      'Invalid Cache write: You may not write to the cache during cache reads. ' +\n        ' Accesses to `cache.writeFragment`, `cache.updateQuery`, and `cache.link` may ' +\n        ' not be made inside `resolvers` for instance.',\n      27\n    );\n  }\n\n  // Optimistic values are written to a map in the optimistic dict\n  // All other values are written to the base map\n  const keymap: KeyMap<Dict<T | undefined>> = currentOptimisticKey\n    ? map.optimistic.get(currentOptimisticKey)!\n    : map.base;\n\n  // On the map itself we get or create the entity as a dict\n  let entity = keymap.get(entityKey) as Dict<T | undefined>;\n  if (entity === undefined) {\n    keymap.set(entityKey, (entity = Object.create(null)));\n  }\n\n  // If we're setting undefined we delete the node's entry\n  // On optimistic layers we actually set undefined so it can\n  // override the base value\n  if (value === undefined && !currentOptimisticKey) {\n    delete entity[fieldKey];\n  } else {\n    entity[fieldKey] = value;\n  }\n};\n\n/** Gets a node value from a NodeMap (taking optimistic values into account */\nconst getNode = <T>(\n  map: NodeMap<T>,\n  entityKey: string,\n  fieldKey: string\n): T | undefined => {\n  let node: Dict<T | undefined> | undefined;\n  // A read may be initialised to skip layers until its own, which is useful for\n  // reading back written data. It won't skip over optimistic layers however\n  let skip =\n    !currentOptimistic &&\n    currentOperation === 'read' &&\n    currentOptimisticKey &&\n    currentData!.commutativeKeys.has(currentOptimisticKey);\n  // This first iterates over optimistic layers (in order)\n  for (let i = 0, l = currentData!.optimisticOrder.length; i < l; i++) {\n    const layerKey = currentData!.optimisticOrder[i];\n    const optimistic = map.optimistic.get(layerKey);\n    // If we're reading starting from a specific layer, we skip until a match\n    skip = skip && layerKey !== currentOptimisticKey;\n    // If the node and node value exists it is returned, including undefined\n    if (\n      optimistic &&\n      (!skip || !currentData!.commutativeKeys.has(layerKey)) &&\n      (!currentOptimistic ||\n        currentOperation === 'write' ||\n        currentData!.commutativeKeys.has(layerKey)) &&\n      (node = optimistic.get(entityKey)) !== undefined &&\n      fieldKey in node\n    ) {\n      return node[fieldKey];\n    }\n  }\n\n  // Otherwise we read the non-optimistic base value\n  node = map.base.get(entityKey);\n  return node !== undefined ? node[fieldKey] : undefined;\n};\n\nexport function getRefCount(entityKey: string): number {\n  return currentData!.refCount.get(entityKey) || 0;\n}\n\n/** Adjusts the reference count of an entity on a refCount dict by \"by\" and updates the gc */\nconst updateRCForEntity = (entityKey: string, by: number): void => {\n  // Retrieve the reference count and adjust it by \"by\"\n  const count = getRefCount(entityKey);\n  const newCount = count + by > 0 ? count + by : 0;\n  currentData!.refCount.set(entityKey, newCount);\n  // Add it to the garbage collection batch if it needs to be deleted or remove it\n  // from the batch if it needs to be kept\n  if (!newCount) currentData!.gc.add(entityKey);\n  else if (!count && newCount) currentData!.gc.delete(entityKey);\n};\n\n/** Adjusts the reference counts of all entities of a link on a refCount dict by \"by\" and updates the gc */\nconst updateRCForLink = (link: Link | undefined, by: number): void => {\n  if (Array.isArray(link)) {\n    for (let i = 0, l = link.length; i < l; i++) updateRCForLink(link[i], by);\n  } else if (typeof link === 'string') {\n    updateRCForEntity(link, by);\n  }\n};\n\n/** Writes all parsed FieldInfo objects of a given node dict to a given array if it hasn't been seen */\nconst extractNodeFields = <T>(\n  fieldInfos: FieldInfo[],\n  seenFieldKeys: Set<string>,\n  node: Dict<T> | undefined\n): void => {\n  if (node !== undefined) {\n    for (const fieldKey in node) {\n      if (!seenFieldKeys.has(fieldKey)) {\n        // If the node hasn't been seen the serialized fieldKey is turnt back into\n        // a rich FieldInfo object that also contains the field's name and arguments\n        fieldInfos.push(fieldInfoOfKey(fieldKey));\n        seenFieldKeys.add(fieldKey);\n      }\n    }\n  }\n};\n\n/** Writes all parsed FieldInfo objects of all nodes in a NodeMap to a given array */\nconst extractNodeMapFields = <T>(\n  fieldInfos: FieldInfo[],\n  seenFieldKeys: Set<string>,\n  entityKey: string,\n  map: NodeMap<T>\n) => {\n  // Extracts FieldInfo for the entity in the base map\n  extractNodeFields(fieldInfos, seenFieldKeys, map.base.get(entityKey));\n\n  // Then extracts FieldInfo for the entity from the optimistic maps\n  for (let i = 0, l = currentData!.optimisticOrder.length; i < l; i++) {\n    const optimistic = map.optimistic.get(currentData!.optimisticOrder[i]);\n    if (optimistic !== undefined) {\n      extractNodeFields(fieldInfos, seenFieldKeys, optimistic.get(entityKey));\n    }\n  }\n};\n\n/** Garbage collects all entities that have been marked as having no references */\nexport const gc = () => {\n  // If we're currently awaiting deferred results, abort GC run\n  if (currentData!.optimisticOrder.length) return;\n\n  // Iterate over all entities that have been marked for deletion\n  // Entities have been marked for deletion in `updateRCForEntity` if\n  // their reference count dropped to 0\n  for (const entityKey of currentData!.gc.keys()) {\n    // Remove the current key from the GC batch\n    currentData!.gc.delete(entityKey);\n\n    // Check first whether the entity has any references,\n    // if so, we skip it from the GC run\n    const rc = getRefCount(entityKey);\n    if (rc > 0) continue;\n\n    const record = currentData!.records.base.get(entityKey);\n    // Delete the reference count, and delete the entity from the GC batch\n    currentData!.refCount.delete(entityKey);\n    currentData!.records.base.delete(entityKey);\n\n    const typename = (record && record.__typename) as string | undefined;\n    if (typename) {\n      const type = currentData!.types.get(typename);\n      if (type) type.delete(entityKey);\n    }\n\n    const linkNode = currentData!.links.base.get(entityKey);\n    if (linkNode) {\n      currentData!.links.base.delete(entityKey);\n      for (const fieldKey in linkNode) updateRCForLink(linkNode[fieldKey], -1);\n    }\n  }\n};\n\nconst updateDependencies = (entityKey: string, fieldKey?: string) => {\n  if (entityKey !== currentData!.queryRootKey) {\n    currentDependencies!.add(entityKey);\n  } else if (fieldKey !== undefined && fieldKey !== '__typename') {\n    currentDependencies!.add(joinKeys(entityKey, fieldKey));\n  }\n};\n\nconst updatePersist = (entityKey: string, fieldKey: string) => {\n  if (!currentOptimistic && currentData!.storage) {\n    currentData!.persist.add(serializeKeys(entityKey, fieldKey));\n  }\n};\n\n/** Reads an entity's field (a \"record\") from data */\nexport const readRecord = (\n  entityKey: string,\n  fieldKey: string\n): EntityField => {\n  if (currentOperation === 'read') {\n    updateDependencies(entityKey, fieldKey);\n  }\n  return getNode(currentData!.records, entityKey, fieldKey);\n};\n\n/** Reads an entity's link from data */\nexport const readLink = (\n  entityKey: string,\n  fieldKey: string\n): Link | undefined => {\n  if (currentOperation === 'read') {\n    updateDependencies(entityKey, fieldKey);\n  }\n  return getNode(currentData!.links, entityKey, fieldKey);\n};\n\nexport const getEntitiesForType = (typename: string): Set<string> =>\n  currentData!.types.get(typename) || DEFAULT_EMPTY_SET;\n\nexport const writeType = (typename: string, entityKey: string) => {\n  const existingTypes = currentData!.types.get(typename);\n  if (!existingTypes) {\n    const typeSet = new Set<string>();\n    typeSet.add(entityKey);\n    currentData!.types.set(typename, typeSet);\n  } else {\n    existingTypes.add(entityKey);\n  }\n};\n\nexport const getConcreteTypes = (typename: string): Set<string> =>\n  currentData!.abstractToConcreteMap.get(typename) || DEFAULT_EMPTY_SET;\n\nexport const isSeenConcreteType = (typename: string): boolean =>\n  currentData!.types.has(typename);\n\nexport const writeConcreteType = (\n  abstractType: string,\n  concreteType: string\n) => {\n  const existingTypes = currentData!.abstractToConcreteMap.get(abstractType);\n  if (!existingTypes) {\n    const typeSet = new Set<string>();\n    typeSet.add(concreteType);\n    currentData!.abstractToConcreteMap.set(abstractType, typeSet);\n  } else {\n    existingTypes.add(concreteType);\n  }\n};\n\n/** Writes an entity's field (a \"record\") to data */\nexport const writeRecord = (\n  entityKey: string,\n  fieldKey: string,\n  value?: EntityField\n) => {\n  const existing = getNode(currentData!.records, entityKey, fieldKey);\n  if (!isEqualLinkOrScalar(existing, value)) {\n    updateDependencies(entityKey, fieldKey);\n    updatePersist(entityKey, fieldKey);\n  }\n\n  setNode(currentData!.records, entityKey, fieldKey, value);\n};\n\nexport const hasField = (entityKey: string, fieldKey: string): boolean =>\n  readRecord(entityKey, fieldKey) !== undefined ||\n  readLink(entityKey, fieldKey) !== undefined;\n\n/** Writes an entity's link to data */\nexport const writeLink = (\n  entityKey: string,\n  fieldKey: string,\n  link?: Link | undefined\n) => {\n  // Retrieve the link NodeMap from either an optimistic or the base layer\n  const links = currentOptimisticKey\n    ? currentData!.links.optimistic.get(currentOptimisticKey)\n    : currentData!.links.base;\n  // Update the reference count for the link\n  if (!currentOptimisticKey) {\n    const entityLinks = links && links.get(entityKey);\n    updateRCForLink(entityLinks && entityLinks[fieldKey], -1);\n    updateRCForLink(link, 1);\n  }\n  const existing = getNode(currentData!.links, entityKey, fieldKey);\n  if (!isEqualLinkOrScalar(existing, link)) {\n    updateDependencies(entityKey, fieldKey);\n    updatePersist(entityKey, fieldKey);\n  }\n\n  // Update the link\n  setNode(currentData!.links, entityKey, fieldKey, link);\n};\n\n/** Reserves an optimistic layer and preorders it */\nexport const reserveLayer = (\n  data: InMemoryData,\n  layerKey: number,\n  hasNext?: boolean\n) => {\n  // Find the current index for the layer, and remove it from\n  // the order if it exists already\n  let index = data.optimisticOrder.indexOf(layerKey);\n  if (index > -1) data.optimisticOrder.splice(index, 1);\n\n  if (hasNext) {\n    data.deferredKeys.add(layerKey);\n    // If the layer has future results then we'll move it past any layer that's\n    // still empty, so currently pending operations will take precedence over it\n    for (\n      index = index > -1 ? index : 0;\n      index < data.optimisticOrder.length &&\n      !data.deferredKeys.has(data.optimisticOrder[index]) &&\n      (!data.dirtyKeys.has(data.optimisticOrder[index]) ||\n        !data.commutativeKeys.has(data.optimisticOrder[index]));\n      index++\n    );\n  } else {\n    data.deferredKeys.delete(layerKey);\n    // Protect optimistic layers from being turned into non-optimistic layers\n    // while preserving optimistic data\n    if (index > -1 && !data.commutativeKeys.has(layerKey))\n      clearLayer(data, layerKey);\n    index = 0;\n  }\n\n  // Register the layer with the deferred or \"top\" index and\n  // mark it as commutative\n  data.optimisticOrder.splice(index, 0, layerKey);\n  data.commutativeKeys.add(layerKey);\n};\n\n/** Checks whether a given layer exists */\nexport const hasLayer = (data: InMemoryData, layerKey: number) =>\n  data.commutativeKeys.has(layerKey) ||\n  data.optimisticOrder.indexOf(layerKey) > -1;\n\n/** Creates an optimistic layer of links and records */\nconst createLayer = (data: InMemoryData, layerKey: number) => {\n  if (data.optimisticOrder.indexOf(layerKey) === -1) {\n    data.optimisticOrder.unshift(layerKey);\n  }\n\n  if (!data.dirtyKeys.has(layerKey)) {\n    data.dirtyKeys.add(layerKey);\n    data.links.optimistic.set(layerKey, new Map());\n    data.records.optimistic.set(layerKey, new Map());\n  }\n};\n\n/** Clears all links and records of an optimistic layer */\nconst clearLayer = (data: InMemoryData, layerKey: number) => {\n  if (data.dirtyKeys.has(layerKey)) {\n    data.dirtyKeys.delete(layerKey);\n    data.records.optimistic.delete(layerKey);\n    data.links.optimistic.delete(layerKey);\n    data.deferredKeys.delete(layerKey);\n  }\n};\n\n/** Deletes links and records of an optimistic layer, and the layer itself */\nconst deleteLayer = (data: InMemoryData, layerKey: number) => {\n  const index = data.optimisticOrder.indexOf(layerKey);\n  if (index > -1) {\n    data.optimisticOrder.splice(index, 1);\n    data.commutativeKeys.delete(layerKey);\n  }\n\n  clearLayer(data, layerKey);\n};\n\n/** Merges an optimistic layer of links and records into the base data */\nconst squashLayer = (layerKey: number) => {\n  // Hide current dependencies from squashing operations\n  const previousDependencies = currentDependencies;\n  currentDependencies = new Set();\n  currentOperation = 'write';\n\n  const links = currentData!.links.optimistic.get(layerKey);\n  if (links) {\n    for (const entry of links.entries()) {\n      const entityKey = entry[0];\n      const keyMap = entry[1];\n      for (const fieldKey in keyMap) {\n        writeLink(entityKey, fieldKey, keyMap[fieldKey]);\n      }\n    }\n  }\n\n  const records = currentData!.records.optimistic.get(layerKey);\n  if (records) {\n    for (const entry of records.entries()) {\n      const entityKey = entry[0];\n      const keyMap = entry[1];\n      for (const fieldKey in keyMap) {\n        writeRecord(entityKey, fieldKey, keyMap[fieldKey]);\n      }\n    }\n  }\n\n  currentDependencies = previousDependencies;\n  deleteLayer(currentData!, layerKey);\n};\n\n/** Return an array of FieldInfo (info on all the fields and their arguments) for a given entity */\nexport const inspectFields = (entityKey: string): FieldInfo[] => {\n  const { links, records } = currentData!;\n  const fieldInfos: FieldInfo[] = [];\n  const seenFieldKeys: Set<string> = new Set();\n  // Update dependencies\n  updateDependencies(entityKey);\n  // Extract FieldInfos to the fieldInfos array for links and records\n  // This also deduplicates by keeping track of fieldKeys in the seenFieldKeys Set\n  extractNodeMapFields(fieldInfos, seenFieldKeys, entityKey, links);\n  extractNodeMapFields(fieldInfos, seenFieldKeys, entityKey, records);\n  return fieldInfos;\n};\n\nexport const persistData = () => {\n  if (currentData!.storage) {\n    currentOptimistic = true;\n    currentOperation = 'read';\n    const entries: SerializedEntries = {};\n    for (const key of currentData!.persist.keys()) {\n      const { entityKey, fieldKey } = deserializeKeyInfo(key);\n      let x: void | Link | EntityField;\n      if ((x = readLink(entityKey, fieldKey)) !== undefined) {\n        entries[key] = `:${stringifyVariables(x)}`;\n      } else if ((x = readRecord(entityKey, fieldKey)) !== undefined) {\n        entries[key] = stringifyVariables(x);\n      } else {\n        entries[key] = undefined;\n      }\n    }\n\n    currentOptimistic = false;\n    currentData!.storage.writeData(entries);\n    currentData!.persist.clear();\n  }\n};\n\nexport const hydrateData = (\n  data: InMemoryData,\n  storage: StorageAdapter,\n  entries: SerializedEntries\n) => {\n  initDataState('write', data, null);\n\n  for (const key in entries) {\n    const value = entries[key];\n    if (value !== undefined) {\n      const { entityKey, fieldKey } = deserializeKeyInfo(key);\n      if (value[0] === ':') {\n        if (readLink(entityKey, fieldKey) === undefined)\n          writeLink(entityKey, fieldKey, JSON.parse(value.slice(1)));\n      } else {\n        if (readRecord(entityKey, fieldKey) === undefined)\n          writeRecord(entityKey, fieldKey, JSON.parse(value));\n      }\n    }\n  }\n\n  data.storage = storage;\n  data.hydrating = false;\n  clearDataState();\n};\n\nfunction isEqualLinkOrScalar(\n  a: Link | EntityField | undefined,\n  b: Link | EntityField | undefined\n) {\n  if (typeof a !== typeof b) return false;\n  if (a !== b) return false;\n  if (Array.isArray(a) && Array.isArray(b)) {\n    if (a.length !== b.length) return false;\n    return !a.some((el, index) => el !== b[index]);\n  }\n\n  return true;\n}\n"
  },
  {
    "path": "exchanges/graphcache/src/store/keys.ts",
    "content": "import { stringifyVariables } from '@urql/core';\nimport type { FieldArgs, FieldInfo, KeyInfo } from '../types';\n\nexport const keyOfField = (fieldName: string, args?: FieldArgs) =>\n  args ? `${fieldName}(${stringifyVariables(args)})` : fieldName;\n\nexport const joinKeys = (parentKey: string, key: string) =>\n  `${parentKey}.${key}`;\n\nexport const fieldInfoOfKey = (fieldKey: string): FieldInfo => {\n  const parenIndex = fieldKey.indexOf('(');\n  if (parenIndex > -1) {\n    return {\n      fieldKey,\n      fieldName: fieldKey.slice(0, parenIndex),\n      arguments: JSON.parse(fieldKey.slice(parenIndex + 1, -1)),\n    };\n  } else {\n    return {\n      fieldKey,\n      fieldName: fieldKey,\n      arguments: null,\n    };\n  }\n};\n\nexport const serializeKeys = (entityKey: string, fieldKey: string) =>\n  `${entityKey.replace(/\\./g, '%2e')}.${fieldKey}`;\n\nexport const deserializeKeyInfo = (key: string): KeyInfo => {\n  const dotIndex = key.indexOf('.');\n  const entityKey = key.slice(0, dotIndex).replace(/%2e/g, '.');\n  const fieldKey = key.slice(dotIndex + 1);\n  return { entityKey, fieldKey };\n};\n"
  },
  {
    "path": "exchanges/graphcache/src/store/store.test.ts",
    "content": "/* eslint-disable @typescript-eslint/no-var-requires */\nimport { minifyIntrospectionQuery } from '@urql/introspection';\nimport { formatDocument, gql } from '@urql/core';\nimport { vi, expect, it, beforeEach, describe } from 'vitest';\n\nimport {\n  executeSync,\n  getIntrospectionQuery,\n  buildClientSchema,\n  parse,\n} from 'graphql';\n\nimport { Data, StorageAdapter } from '../types';\nimport { makeContext, updateContext } from '../operations/shared';\nimport * as InMemoryData from './data';\nimport { Store } from './store';\nimport { noop } from '../test-utils/utils';\n\nimport { __initAnd_query as query } from '../operations/query';\nimport {\n  __initAnd_write as write,\n  __initAnd_writeOptimistic as writeOptimistic,\n} from '../operations/write';\n\nconst mocked = (x: any): any => x;\n\nconst Appointment = gql`\n  query appointment($id: String) {\n    __typename\n    appointment(id: $id) {\n      __typename\n      id\n      info\n    }\n  }\n`;\n\nconst Todos = gql`\n  query {\n    __typename\n    todos {\n      __typename\n      id\n      text\n      complete\n      author {\n        __typename\n        id\n        name\n      }\n    }\n  }\n`;\n\nconst TodosWithoutTypename = gql`\n  query {\n    __typename\n    todos {\n      id\n      text\n      complete\n      author {\n        id\n        name\n      }\n    }\n  }\n`;\n\nconst todosData = {\n  __typename: 'Query',\n  todos: [\n    {\n      id: '0',\n      text: 'Go to the shops',\n      complete: false,\n      __typename: 'Todo',\n      author: { id: '0', name: 'Jovi', __typename: 'Author' },\n    },\n    {\n      id: '1',\n      text: 'Pick up the kids',\n      complete: true,\n      __typename: 'Todo',\n      author: { id: '1', name: 'Phil', __typename: 'Author' },\n    },\n    {\n      id: '2',\n      text: 'Install urql',\n      complete: false,\n      __typename: 'Todo',\n      author: { id: '0', name: 'Jovi', __typename: 'Author' },\n    },\n  ],\n} as any;\n\ndescribe('Store', () => {\n  it('supports unformatted query documents', () => {\n    const store = new Store();\n\n    // NOTE: This is the query without __typename annotations\n    write(store, { query: TodosWithoutTypename }, todosData);\n    const result = query(store, { query: TodosWithoutTypename });\n    expect(result.data).toEqual({\n      todos: [\n        {\n          id: '0',\n          text: 'Go to the shops',\n          complete: false,\n          author: { id: '0', name: 'Jovi' },\n        },\n        {\n          id: '1',\n          text: 'Pick up the kids',\n          complete: true,\n          author: { id: '1', name: 'Phil' },\n        },\n        {\n          id: '2',\n          text: 'Install urql',\n          complete: false,\n          author: { id: '0', name: 'Jovi' },\n        },\n      ],\n      __typename: 'Query',\n    });\n  });\n});\n\ndescribe('Store with UpdatesConfig', () => {\n  it(\"sets the store's updates field to the given argument\", () => {\n    const updatesOption = {\n      Mutation: {\n        toggleTodo: noop,\n      },\n      Subscription: {\n        newTodo: noop,\n      },\n    };\n\n    const store = new Store({\n      updates: updatesOption,\n    });\n\n    expect(store.updates.Mutation).toBe(updatesOption.Mutation);\n    expect(store.updates.Subscription).toBe(updatesOption.Subscription);\n  });\n\n  it('should not warn if Mutation/Subscription operations do exist in the schema', function () {\n    new Store({\n      schema: minifyIntrospectionQuery(\n        require('../test-utils/simple_schema.json')\n      ),\n      updates: {\n        Mutation: {\n          toggleTodo: noop,\n        },\n        Subscription: {\n          newTodo: noop,\n        },\n      },\n    });\n\n    expect(console.warn).not.toBeCalled();\n  });\n\n  it(\"should warn if Mutation operations don't exist in the schema\", function () {\n    new Store({\n      schema: minifyIntrospectionQuery(\n        require('../test-utils/simple_schema.json')\n      ),\n      updates: {\n        Mutation: {\n          doTheChaChaSlide: noop,\n        },\n      },\n    });\n\n    expect(console.warn).toBeCalledTimes(1);\n    const warnMessage = mocked(console.warn).mock.calls[0][0];\n    expect(warnMessage).toContain(\n      'Invalid updates field: `doTheChaChaSlide` on `Mutation` is not in the defined schema'\n    );\n    expect(warnMessage).toContain('https://bit.ly/2XbVrpR#22');\n  });\n\n  it(\"should warn if Subscription operations don't exist in the schema\", function () {\n    new Store({\n      schema: minifyIntrospectionQuery(\n        require('../test-utils/simple_schema.json')\n      ),\n      updates: {\n        Subscription: {\n          someoneDidTheChaChaSlide: noop,\n        },\n      },\n    });\n\n    expect(console.warn).toBeCalledTimes(1);\n    const warnMessage = mocked(console.warn).mock.calls[0][0];\n    expect(warnMessage).toContain(\n      'Invalid updates field: `someoneDidTheChaChaSlide` on `Subscription` is not in the defined schema'\n    );\n    expect(warnMessage).toContain('https://bit.ly/2XbVrpR#22');\n  });\n});\n\ndescribe('Store with KeyingConfig', () => {\n  it('generates keys from custom keying function', () => {\n    const store = new Store({\n      keys: {\n        User: () => 'me',\n        None: () => null,\n      },\n    });\n\n    expect(store.keyOfEntity({ __typename: 'Any', id: '123' })).toBe('Any:123');\n    expect(store.keyOfEntity({ __typename: 'Any', _id: '123' })).toBe(\n      'Any:123'\n    );\n    expect(store.keyOfEntity({ __typename: 'Any' })).toBe(null);\n    expect(store.keyOfEntity({ __typename: 'User' })).toBe('User:me');\n    expect(store.keyOfEntity({ __typename: 'None' })).toBe(null);\n  });\n\n  it('should not warn if keys do exist in the schema', function () {\n    new Store({\n      schema: minifyIntrospectionQuery(\n        require('../test-utils/simple_schema.json')\n      ),\n      keys: {\n        Todo: () => 'Todo',\n      },\n    });\n\n    expect(console.warn).not.toBeCalled();\n  });\n\n  it(\"should warn if a key doesn't exist in the schema\", function () {\n    new Store({\n      schema: minifyIntrospectionQuery(\n        require('../test-utils/simple_schema.json')\n      ),\n      keys: {\n        Todo: () => 'todo',\n        NotInSchema: () => 'foo',\n      },\n    });\n\n    expect(console.warn).toBeCalledTimes(1);\n    const warnMessage = mocked(console.warn).mock.calls[0][0];\n    expect(warnMessage).toContain(\n      'The type `NotInSchema` is not an object in the defined schema, but the `keys` option is referencing it'\n    );\n    expect(warnMessage).toContain('https://bit.ly/2XbVrpR#20');\n  });\n});\n\ndescribe('Store with Global IDs', () => {\n  it('generates keys without typenames when set to true', () => {\n    const store = new Store({ globalIDs: true });\n    expect(store.keyOfEntity({ __typename: 'Any', id: '123' })).toBe('123');\n    expect(store.keyOfEntity({ __typename: 'None', id: '123' })).toBe('123');\n  });\n\n  it('generates keys without typenames when matching an input set', () => {\n    const store = new Store({ globalIDs: ['User'] });\n    expect(store.keyOfEntity({ __typename: 'Any', id: '123' })).toBe('Any:123');\n    expect(store.keyOfEntity({ __typename: 'User', id: '123' })).toBe('123');\n  });\n});\n\ndescribe('Store with ResolverConfig', () => {\n  it(\"sets the store's resolvers field to the given argument\", () => {\n    const resolversOption = {\n      Query: {\n        latestTodo: () => 'todo',\n      },\n    };\n\n    const store = new Store({\n      resolvers: resolversOption,\n    });\n\n    expect(store.resolvers).toBe(resolversOption);\n  });\n\n  it(\"sets the store's resolvers field to an empty default if not provided\", () => {\n    const store = new Store({});\n\n    expect(store.resolvers).toEqual({});\n  });\n\n  it('should not warn if resolvers do exist in the schema', function () {\n    new Store({\n      schema: minifyIntrospectionQuery(\n        require('../test-utils/simple_schema.json')\n      ),\n      resolvers: {\n        Query: {\n          latestTodo: () => 'todo',\n          todos: () => ['todo 1', 'todo 2'],\n        },\n        Todo: {\n          text: todo => (todo.text as string).toUpperCase(),\n          author: todo => (todo.author as string).toUpperCase(),\n        },\n      },\n    });\n\n    expect(console.warn).not.toBeCalled();\n  });\n\n  it(\"should warn if a Query doesn't exist in the schema\", function () {\n    new Store({\n      schema: minifyIntrospectionQuery(\n        require('../test-utils/simple_schema.json')\n      ),\n      resolvers: {\n        Query: {\n          todos: () => ['todo 1', 'todo 2'],\n          // This query should be warned about.\n          findDeletedTodos: () => ['todo 1', 'todo 2'],\n        },\n      },\n    });\n\n    expect(console.warn).toBeCalledTimes(1);\n    const warnMessage = mocked(console.warn).mock.calls[0][0];\n    expect(warnMessage).toContain(\n      'Invalid resolver: `Query.findDeletedTodos` is not in the defined schema, but the `resolvers` option is referencing it'\n    );\n    expect(warnMessage).toContain('https://bit.ly/2XbVrpR#23');\n  });\n\n  it(\"should warn if a type doesn't exist in the schema\", function () {\n    new Store({\n      schema: minifyIntrospectionQuery(\n        require('../test-utils/simple_schema.json')\n      ),\n      resolvers: {\n        Todo: {\n          complete: () => true,\n        },\n        // This type should be warned about.\n        Dinosaur: {\n          isExtinct: () => true,\n        },\n      },\n    });\n\n    expect(console.warn).toBeCalledTimes(1);\n    const warnMessage = mocked(console.warn).mock.calls[0][0];\n    expect(warnMessage).toContain(\n      'Invalid resolver: `Dinosaur` is not in the defined schema, but the `resolvers` option is referencing it'\n    );\n    expect(warnMessage).toContain('https://bit.ly/2XbVrpR#23');\n  });\n\n  it('should warn when we use an interface type', function () {\n    new Store({\n      schema: minifyIntrospectionQuery(\n        require('../test-utils/simple_schema.json')\n      ),\n      resolvers: {\n        ITodo: {\n          complete: () => true,\n        },\n      },\n    });\n\n    expect(console.warn).toBeCalledTimes(1);\n    const warnMessage = mocked(console.warn).mock.calls[0][0];\n    expect(warnMessage).toContain(\n      'Invalid resolver: `ITodo` does not match to a concrete type in the schema, but the `resolvers` option is referencing it. Implement the resolver for the types that implement the interface instead.'\n    );\n    expect(warnMessage).toContain('https://bit.ly/2XbVrpR#26');\n  });\n\n  it(\"should warn if a type's property doesn't exist in the schema\", function () {\n    new Store({\n      schema: minifyIntrospectionQuery(\n        require('../test-utils/simple_schema.json')\n      ),\n      resolvers: {\n        Todo: {\n          complete: () => true,\n          // This property should be warned about.\n          isAboutDinosaurs: () => true,\n        },\n      },\n    });\n\n    expect(console.warn).toBeCalledTimes(1);\n    const warnMessage = mocked(console.warn).mock.calls[0][0];\n    expect(warnMessage).toContain(\n      'Invalid resolver: `Todo.isAboutDinosaurs` is not in the defined schema, but the `resolvers` option is referencing it'\n    );\n    expect(warnMessage).toContain('https://bit.ly/2XbVrpR#23');\n  });\n});\n\ndescribe('Store with OptimisticMutationConfig', () => {\n  let store;\n  let context;\n\n  beforeEach(() => {\n    store = new Store({\n      optimistic: {\n        addTodo: variables => {\n          return {\n            ...variables,\n          } as Data;\n        },\n      },\n    });\n\n    context = makeContext(store, {}, {}, 'Query', 'Query', undefined);\n    write(store, { query: Todos }, todosData);\n    InMemoryData.initDataState('read', store.data, null);\n  });\n\n  it('should resolve a property', () => {\n    const todoResult = store.resolve({ __typename: 'Todo', id: '0' }, 'text');\n    expect(todoResult).toEqual('Go to the shops');\n    const authorResult = store.resolve(\n      { __typename: 'Author', id: '0' },\n      'name'\n    );\n    expect(authorResult).toBe('Jovi');\n    const result = store.resolve({ id: 0, __typename: 'Todo' }, 'text');\n    expect(result).toEqual('Go to the shops');\n    // TODO: we have no way of asserting this to really be the case.\n    const deps = InMemoryData.getCurrentDependencies();\n    expect(deps).toEqual(new Set(['Todo:0', 'Author:0']));\n    InMemoryData.clearDataState();\n  });\n\n  it('should resolve current parent argument fields', () => {\n    const randomData = { __typename: 'Todo', id: 1, createdAt: '2020-12-09' };\n\n    updateContext(\n      context,\n      randomData,\n      'Todo',\n      'Todo:1',\n      'createdAt',\n      'createdAt'\n    );\n\n    expect(store.keyOfEntity(randomData)).toBe(context.parentKey);\n    expect(store.keyOfEntity({})).not.toBe(context.parentKey);\n\n    // Should work without a __typename field\n    delete (randomData as any).__typename;\n    expect(store.keyOfEntity(randomData)).toBe(context.parentKey);\n  });\n\n  it('should resolve with a key as first argument', () => {\n    const authorResult = store.resolve('Author:0', 'name');\n    expect(authorResult).toBe('Jovi');\n    const deps = InMemoryData.getCurrentDependencies();\n    expect(deps).toEqual(new Set(['Author:0']));\n    InMemoryData.clearDataState();\n  });\n\n  it('should resolve a link property', () => {\n    const parent = {\n      id: '0',\n      text: 'test',\n      author: undefined,\n      __typename: 'Todo',\n    };\n    const result = store.resolve(parent, 'author');\n    expect(result).toEqual('Author:0');\n    const deps = InMemoryData.getCurrentDependencies();\n    expect(deps).toEqual(new Set(['Todo:0']));\n    InMemoryData.clearDataState();\n  });\n\n  it('should invalidate null keys correctly', () => {\n    const connection = gql`\n      query test {\n        exercisesConnection(page: { after: null, first: 10 }) {\n          id\n        }\n      }\n    `;\n\n    write(\n      store,\n      {\n        query: connection,\n      },\n      {\n        exercisesConnection: null,\n      } as any\n    );\n    let { data } = query(store, { query: connection });\n\n    InMemoryData.initDataState('write', store.data, null);\n    expect((data as any).exercisesConnection).toEqual(null);\n    const fields = store.inspectFields({ __typename: 'Query' });\n    fields.forEach(({ fieldName, arguments: args }) => {\n      if (fieldName === 'exercisesConnection') {\n        store.invalidate('Query', fieldName, args);\n      }\n    });\n    InMemoryData.clearDataState();\n\n    ({ data } = query(store, { query: connection }));\n    expect(data).toBe(null);\n  });\n\n  it('should be able to write a fragment', () => {\n    InMemoryData.initDataState('write', store.data, null);\n\n    store.writeFragment(\n      gql`\n        fragment _ on Todo {\n          id\n          text\n          complete\n        }\n      `,\n      {\n        id: '0',\n        text: 'update',\n        complete: true,\n      }\n    );\n\n    const deps = InMemoryData.getCurrentDependencies();\n    expect(deps).toEqual(new Set(['Todo:0']));\n\n    const { data } = query(store, { query: Todos });\n\n    expect(data).toEqual({\n      __typename: 'Query',\n      todos: [\n        {\n          ...todosData.todos[0],\n          text: 'update',\n          complete: true,\n        },\n        todosData.todos[1],\n        todosData.todos[2],\n      ],\n    });\n  });\n\n  it('should be able to write a fragment by name', () => {\n    InMemoryData.initDataState('write', store.data, null);\n\n    store.writeFragment(\n      gql`\n        fragment authorFields on Author {\n          id\n        }\n\n        fragment todoFields on Todo {\n          id\n          text\n          complete\n        }\n      `,\n      {\n        id: '0',\n        text: 'update',\n        complete: true,\n      },\n      undefined,\n      'todoFields'\n    );\n\n    const deps = InMemoryData.getCurrentDependencies();\n    expect(deps).toEqual(new Set(['Todo:0']));\n\n    const { data } = query(store, { query: Todos });\n\n    expect(data).toEqual({\n      __typename: 'Query',\n      todos: [\n        {\n          ...todosData.todos[0],\n          text: 'update',\n          complete: true,\n        },\n        todosData.todos[1],\n        todosData.todos[2],\n      ],\n    });\n  });\n\n  it('should be able to read a fragment', () => {\n    InMemoryData.initDataState('read', store.data, null);\n    const result = store.readFragment(\n      gql`\n        fragment _ on Todo {\n          id\n          text\n          complete\n          __typename\n        }\n      `,\n      { id: '0' }\n    );\n\n    const deps = InMemoryData.getCurrentDependencies();\n    expect(deps).toEqual(new Set(['Todo:0']));\n\n    expect(result).toEqual({\n      id: '0',\n      text: 'Go to the shops',\n      complete: false,\n      __typename: 'Todo',\n    });\n\n    InMemoryData.clearDataState();\n  });\n\n  it('should be able to read a fragment by name', () => {\n    InMemoryData.initDataState('read', store.data, null);\n    const result = store.readFragment(\n      gql`\n        fragment authorFields on Author {\n          id\n          text\n          complete\n          __typename\n        }\n\n        fragment todoFields on Todo {\n          id\n          text\n          complete\n          __typename\n        }\n      `,\n      { id: '0' },\n      undefined,\n      'todoFields'\n    );\n\n    const deps = InMemoryData.getCurrentDependencies();\n    expect(deps).toEqual(new Set(['Todo:0']));\n\n    expect(result).toEqual({\n      id: '0',\n      text: 'Go to the shops',\n      complete: false,\n      __typename: 'Todo',\n    });\n\n    InMemoryData.clearDataState();\n  });\n\n  it('should be able to update a query', () => {\n    InMemoryData.initDataState('write', store.data, null);\n    store.updateQuery({ query: Todos }, data => ({\n      ...data,\n      todos: [\n        ...data.todos,\n        {\n          __typename: 'Todo',\n          id: '4',\n          text: 'Test updateQuery',\n          complete: false,\n          author: {\n            __typename: 'Author',\n            id: '3',\n            name: 'Andy',\n          },\n        },\n      ],\n    }));\n    InMemoryData.clearDataState();\n\n    const { data: result } = query(store, {\n      query: Todos,\n    });\n\n    expect(result).toEqual({\n      __typename: 'Query',\n      todos: [\n        ...todosData.todos,\n        {\n          __typename: 'Todo',\n          id: '4',\n          text: 'Test updateQuery',\n          complete: false,\n          author: {\n            __typename: 'Author',\n            id: '3',\n            name: 'Andy',\n          },\n        },\n      ],\n    });\n  });\n\n  it('should be able to update a query with variables', () => {\n    write(\n      store,\n      {\n        query: Appointment,\n        variables: { id: '1' },\n      },\n      {\n        __typename: 'Query',\n        appointment: {\n          __typename: 'Appointment',\n          id: '1',\n          info: 'urql meeting',\n        },\n      }\n    );\n\n    InMemoryData.initDataState('write', store.data, null);\n    store.updateQuery({ query: Appointment, variables: { id: '1' } }, data => ({\n      ...data,\n      appointment: {\n        ...data.appointment,\n        info: 'urql meeting revisited',\n      },\n    }));\n    InMemoryData.clearDataState();\n\n    const { data: result } = query(store, {\n      query: Appointment,\n      variables: { id: '1' },\n    });\n    expect(result).toEqual({\n      __typename: 'Query',\n      appointment: {\n        id: '1',\n        info: 'urql meeting revisited',\n        __typename: 'Appointment',\n      },\n    });\n  });\n\n  it('should be able to read a query', () => {\n    InMemoryData.initDataState('read', store.data, null);\n    const result = store.readQuery({ query: Todos });\n\n    const deps = InMemoryData.getCurrentDependencies();\n    expect(deps).toEqual(\n      new Set([\n        'Query.todos',\n        'Todo:0',\n        'Todo:1',\n        'Todo:2',\n        'Author:0',\n        'Author:1',\n      ])\n    );\n\n    expect(result).toEqual({\n      __typename: 'Query',\n      todos: todosData.todos,\n    });\n    InMemoryData.clearDataState();\n  });\n\n  it('should be able to optimistically mutate', () => {\n    const { dependencies } = writeOptimistic(\n      store,\n      {\n        query: gql`\n          mutation {\n            addTodo(\n              id: \"1\"\n              text: \"I'm optimistic about this feature\"\n              complete: true\n              __typename: \"Todo\"\n            ) {\n              id\n              text\n              complete\n              __typename\n            }\n          }\n        `,\n      },\n      1\n    );\n    expect(dependencies).toEqual(new Set(['Todo:1']));\n    let { data } = query(store, { query: Todos });\n    expect(data).toEqual({\n      __typename: 'Query',\n      todos: [\n        todosData.todos[0],\n        {\n          id: '1',\n          text: \"I'm optimistic about this feature\",\n          complete: true,\n          __typename: 'Todo',\n          author: {\n            __typename: 'Author',\n            id: '1',\n            name: 'Phil',\n          },\n        },\n        todosData.todos[2],\n      ],\n    });\n\n    InMemoryData.noopDataState(store.data, 1);\n\n    ({ data } = query(store, { query: Todos }));\n    expect(data).toEqual({\n      __typename: 'Query',\n      todos: todosData.todos,\n    });\n  });\n\n  it('should be able to optimistically mutate with partial data', () => {\n    const { dependencies } = writeOptimistic(\n      store,\n      {\n        query: gql`\n          mutation {\n            addTodo(id: \"0\", complete: true, __typename: \"Todo\") {\n              id\n              text\n              complete\n              __typename\n            }\n          }\n        `,\n      },\n      1\n    );\n    expect(dependencies).toEqual(new Set(['Todo:0']));\n    let { data } = query(store, { query: Todos });\n    expect(data).toEqual({\n      __typename: 'Query',\n      todos: [\n        {\n          ...todosData.todos[0],\n          complete: true,\n        },\n        todosData.todos[1],\n        todosData.todos[2],\n      ],\n    });\n\n    InMemoryData.noopDataState(store.data, 1);\n\n    ({ data } = query(store, { query: Todos }));\n    expect(data).toEqual({\n      __typename: 'Query',\n      todos: todosData.todos,\n    });\n  });\n\n  describe('Invalidating an entity', () => {\n    it('removes an entity from a list by object-key.', () => {\n      InMemoryData.initDataState('write', store.data, null);\n      store.invalidate(todosData.todos[1]);\n      const { data } = query(store, { query: Todos });\n      expect(data).toBe(null);\n    });\n\n    it('removes an entity from a list by string-key.', () => {\n      InMemoryData.initDataState('write', store.data, null);\n      store.invalidate(store.keyOfEntity(todosData.todos[1]));\n      const { data } = query(store, { query: Todos });\n      expect(data).toBe(null);\n    });\n  });\n\n  describe('Invalidating a type', () => {\n    it('removes an entity from a list.', () => {\n      InMemoryData.initDataState('write', store.data, null);\n      store.invalidate('Todo');\n      const { data } = query(store, { query: Todos });\n      expect(data).toBe(null);\n    });\n  });\n});\n\ndescribe('Store with storage', () => {\n  let store: Store;\n\n  const expectedData = {\n    __typename: 'Query',\n    appointment: {\n      __typename: 'Appointment',\n      id: '1',\n      info: 'urql meeting',\n    },\n  };\n\n  beforeEach(() => {\n    store = new Store();\n  });\n\n  it('should be able to store and rehydrate data', () => {\n    const storage: StorageAdapter = {\n      readData: vi.fn(),\n      writeData: vi.fn(),\n    };\n\n    store.data.storage = storage;\n\n    write(\n      store,\n      {\n        query: Appointment,\n        variables: { id: '1' },\n      },\n      expectedData\n    );\n\n    InMemoryData.initDataState('write', store.data, null);\n    InMemoryData.persistData();\n    InMemoryData.clearDataState();\n\n    expect(storage.writeData).toHaveBeenCalled();\n\n    const serialisedStore = (storage.writeData as any).mock.calls[0][0];\n    expect(serialisedStore).toMatchSnapshot();\n\n    store = new Store();\n    InMemoryData.hydrateData(store.data, storage, serialisedStore);\n\n    const { data } = query(store, {\n      query: Appointment,\n      variables: { id: '1' },\n    });\n\n    expect(data).toEqual(expectedData);\n  });\n\n  it('should be able to persist embedded data', () => {\n    const EmbeddedAppointment = gql`\n      query appointment($id: String) {\n        __typename\n        appointment(id: $id) {\n          __typename\n          info\n        }\n      }\n    `;\n\n    const embeddedData = {\n      ...expectedData,\n      appointment: {\n        ...expectedData.appointment,\n        id: undefined,\n      },\n    } as any;\n\n    const storage: StorageAdapter = {\n      readData: vi.fn(),\n      writeData: vi.fn(),\n    };\n\n    store.data.storage = storage;\n\n    write(\n      store,\n      {\n        query: EmbeddedAppointment,\n        variables: { id: '1' },\n      },\n      embeddedData\n    );\n\n    InMemoryData.initDataState('write', store.data, null);\n    InMemoryData.persistData();\n    InMemoryData.clearDataState();\n\n    expect(storage.writeData).toHaveBeenCalled();\n\n    const serialisedStore = (storage.writeData as any).mock.calls[0][0];\n    expect(serialisedStore).toMatchSnapshot();\n\n    store = new Store();\n    InMemoryData.hydrateData(store.data, storage, serialisedStore);\n\n    const { data } = query(store, {\n      query: EmbeddedAppointment,\n      variables: { id: '1' },\n    });\n\n    expect(data).toEqual(embeddedData);\n  });\n\n  it('persists commutative layers and ignores optimistic layers', () => {\n    const storage: StorageAdapter = {\n      readData: vi.fn(),\n      writeData: vi.fn(),\n    };\n\n    store.data.storage = storage;\n\n    InMemoryData.reserveLayer(store.data, 1);\n\n    InMemoryData.initDataState('write', store.data, 1);\n    InMemoryData.writeRecord('Query', 'base', true);\n    InMemoryData.clearDataState();\n\n    InMemoryData.initDataState('write', store.data, 2, true);\n    InMemoryData.writeRecord('Query', 'base', false);\n    InMemoryData.clearDataState();\n\n    InMemoryData.initDataState('read', store.data, null);\n    expect(InMemoryData.readRecord('Query', 'base')).toBe(false);\n    InMemoryData.persistData();\n    InMemoryData.clearDataState();\n\n    expect(storage.writeData).toHaveBeenCalled();\n    const serialisedStore = (storage.writeData as any).mock.calls[0][0];\n\n    expect(serialisedStore).toEqual({\n      'Query.base': 'true',\n    });\n\n    store = new Store();\n    InMemoryData.hydrateData(store.data, storage, serialisedStore);\n\n    InMemoryData.initDataState('write', store.data, null);\n    expect(InMemoryData.readRecord('Query', 'base')).toBe(true);\n    InMemoryData.clearDataState();\n  });\n\n  it(\"should warn if an optimistic field doesn't exist in the schema's mutations\", () => {\n    new Store({\n      schema: minifyIntrospectionQuery(\n        require('../test-utils/simple_schema.json')\n      ),\n      updates: {\n        Mutation: {\n          toggleTodo: noop,\n        },\n      },\n      optimistic: {\n        toggleTodo: () => null,\n        // This field should be warned about.\n        deleteTodo: () => null,\n      },\n    });\n\n    expect(console.warn).toBeCalledTimes(1);\n    const warnMessage = mocked(console.warn).mock.calls[0][0];\n    expect(warnMessage).toContain(\n      'Invalid optimistic mutation field: `deleteTodo` is not a mutation field in the defined schema, but the `optimistic` option is referencing it.'\n    );\n    expect(warnMessage).toContain('https://bit.ly/2XbVrpR#24');\n  });\n\n  it('should use different rootConfigs', () => {\n    const fakeUpdater = vi.fn();\n\n    const store = new Store({\n      schema: {\n        __schema: {\n          queryType: {\n            name: 'query_root',\n          },\n          mutationType: {\n            name: 'mutation_root',\n          },\n          subscriptionType: {\n            name: 'subscription_root',\n          },\n        },\n      },\n      updates: {\n        mutation_root: {\n          toggleTodo: fakeUpdater,\n        },\n      },\n    });\n\n    const mutationData = {\n      toggleTodo: {\n        __typename: 'Todo',\n        id: 1,\n      },\n    };\n    write(store, { query: Todos }, todosData);\n    write(\n      store,\n      {\n        query: gql`\n          mutation {\n            toggleTodo(id: 1) {\n              id\n            }\n          }\n        `,\n      },\n      mutationData as any\n    );\n\n    expect(fakeUpdater).toBeCalledTimes(1);\n  });\n\n  it('should warn when __typename is missing when store.writeFragment is called', () => {\n    InMemoryData.initDataState('write', store.data, null);\n\n    store.writeFragment(\n      parse(`\n        fragment _ on Test {\n          __typename\n          id\n          sub {\n            id\n          }\n        }\n      `),\n      {\n        id: 'test',\n        sub: {\n          id: 'test',\n        },\n      }\n    );\n\n    InMemoryData.clearDataState();\n\n    expect(console.warn).toBeCalledTimes(1);\n    const warnMessage = mocked(console.warn).mock.calls[0][0];\n    expect(warnMessage).toContain(\n      \"Couldn't find __typename when writing.\\nIf you're writing to the cache manually have to pass a `__typename` property on each entity in your data.\"\n    );\n    expect(warnMessage).toContain('https://bit.ly/2XbVrpR#14');\n  });\n});\n\ndescribe('Store introspection', () => {\n  it('should not warn for an introspection result root (of an unminified schema)', function () {\n    // NOTE: Do not wrap this require in `minifyIntrospectionQuery`!\n    // eslint-disable-next-line\n    const schema = require('../test-utils/simple_schema.json');\n    const store = new Store({ schema });\n\n    const introspectionQuery = formatDocument(parse(getIntrospectionQuery()));\n\n    query(store, { query: introspectionQuery }, schema);\n    expect(console.warn).toBeCalledTimes(0);\n  });\n\n  it('should not warn for an introspection result root (of a minified schema)', function () {\n    // NOTE: Do not wrap this require in `minifyIntrospectionQuery`!\n    // eslint-disable-next-line\n    const schema = require('../test-utils/simple_schema.json');\n    const store = new Store({ schema: minifyIntrospectionQuery(schema) });\n\n    const introspectionQuery = formatDocument(parse(getIntrospectionQuery()));\n\n    query(store, { query: introspectionQuery }, schema);\n    expect(console.warn).toBeCalledTimes(0);\n  });\n\n  it('should not warn for an introspection result with typenames', function () {\n    const schema = buildClientSchema(\n      require('../test-utils/simple_schema.json')\n    );\n    const introspectionQuery = formatDocument(parse(getIntrospectionQuery()));\n\n    const introspectionResult = executeSync({\n      document: introspectionQuery,\n      schema,\n    }).data as any;\n\n    const store = new Store({\n      schema: minifyIntrospectionQuery(introspectionResult),\n    });\n\n    write(store, { query: introspectionQuery }, introspectionResult);\n    query(store, { query: introspectionQuery });\n    expect(console.warn).toBeCalledTimes(0);\n  });\n});\n\nit('should link up entities', () => {\n  const store = new Store();\n  const todo = gql`\n    query test {\n      todo(id: \"1\") {\n        id\n        title\n        __typename\n      }\n    }\n  `;\n  const author = gql`\n    query testAuthor {\n      author(id: \"1\") {\n        id\n        name\n        __typename\n      }\n    }\n  `;\n  write(\n    store,\n    {\n      query: todo,\n    },\n    {\n      todo: {\n        id: '1',\n        title: 'learn urql',\n        __typename: 'Todo',\n      },\n      __typename: 'Query',\n    } as any\n  );\n  let { data } = query(store, { query: todo });\n  expect((data as any).todo).toEqual({\n    id: '1',\n    title: 'learn urql',\n    __typename: 'Todo',\n  });\n  write(\n    store,\n    {\n      query: author,\n    },\n    {\n      author: { __typename: 'Author', id: '1', name: 'Formidable' },\n      __typename: 'Query',\n    } as any\n  );\n  InMemoryData.initDataState('write', store.data, null);\n  store.link((data as any).todo, 'author', {\n    __typename: 'Author',\n    id: '1',\n    name: 'Formidable',\n  });\n  InMemoryData.clearDataState();\n  const todoWithAuthor = gql`\n    query test {\n      todo(id: \"1\") {\n        id\n        title\n        __typename\n        author {\n          id\n          name\n          __typename\n        }\n      }\n    }\n  `;\n  ({ data } = query(store, { query: todoWithAuthor }));\n  expect((data as any).todo).toEqual({\n    id: '1',\n    title: 'learn urql',\n    __typename: 'Todo',\n    author: {\n      __typename: 'Author',\n      id: '1',\n      name: 'Formidable',\n    },\n  });\n});\n"
  },
  {
    "path": "exchanges/graphcache/src/store/store.ts",
    "content": "import type { TypedDocumentNode } from '@urql/core';\nimport { formatDocument, createRequest } from '@urql/core';\n\nimport type {\n  Cache,\n  FieldInfo,\n  ResolverConfig,\n  DataField,\n  Variables,\n  FieldArgs,\n  Link,\n  Data,\n  QueryInput,\n  UpdatesConfig,\n  OptimisticMutationConfig,\n  KeyingConfig,\n  Entity,\n  CacheExchangeOpts,\n  DirectivesConfig,\n  Logger,\n} from '../types';\n\nimport { invariant } from '../helpers/help';\nimport { contextRef, ensureLink } from '../operations/shared';\nimport { _query, _queryFragment } from '../operations/query';\nimport { _write, _writeFragment } from '../operations/write';\nimport { invalidateEntity, invalidateType } from '../operations/invalidate';\nimport { keyOfField } from './keys';\nimport * as InMemoryData from './data';\n\nimport type { SchemaIntrospector } from '../ast';\nimport {\n  buildClientSchema,\n  expectValidKeyingConfig,\n  expectValidUpdatesConfig,\n  expectValidResolversConfig,\n  expectValidOptimisticMutationsConfig,\n} from '../ast';\n\ntype DocumentNode = TypedDocumentNode<any, any>;\ntype RootField = 'query' | 'mutation' | 'subscription';\n\n/** Implementation of the {@link Cache} interface as created internally by the {@link cacheExchange}.\n * @internal\n */\nexport class Store<\n  C extends Partial<CacheExchangeOpts> = Partial<CacheExchangeOpts>,\n> implements Cache\n{\n  data: InMemoryData.InMemoryData;\n\n  logger?: Logger;\n  directives: DirectivesConfig;\n  resolvers: ResolverConfig;\n  updates: UpdatesConfig;\n  optimisticMutations: OptimisticMutationConfig;\n  keys: KeyingConfig;\n  globalIDs: Set<string> | boolean;\n  schema?: SchemaIntrospector;\n  possibleTypeMap?: Map<string, Set<string>>;\n\n  rootFields: { query: string; mutation: string; subscription: string };\n  rootNames: { [name: string]: RootField | void };\n\n  constructor(opts?: C) {\n    if (!opts) opts = {} as C;\n\n    this.logger = opts.logger;\n    this.resolvers = opts.resolvers || {};\n    this.directives = opts.directives || {};\n    this.optimisticMutations = opts.optimistic || {};\n    this.keys = opts.keys || {};\n\n    this.globalIDs = Array.isArray(opts.globalIDs)\n      ? new Set(opts.globalIDs)\n      : !!opts.globalIDs;\n\n    let queryName = 'Query';\n    let mutationName = 'Mutation';\n    let subscriptionName = 'Subscription';\n    if (opts.schema) {\n      const schema = buildClientSchema(opts.schema);\n      queryName = schema.query || queryName;\n      mutationName = schema.mutation || mutationName;\n      subscriptionName = schema.subscription || subscriptionName;\n      // Only add schema introspector if it has types info\n      if (schema.types) this.schema = schema;\n    }\n\n    if (!this.schema && opts.possibleTypes) {\n      this.possibleTypeMap = new Map();\n      for (const entry of Object.entries(opts.possibleTypes)) {\n        const [abstractType, concreteTypes] = entry;\n        this.possibleTypeMap.set(abstractType, new Set(concreteTypes));\n      }\n    }\n\n    this.updates = opts.updates || {};\n\n    this.rootFields = {\n      query: queryName,\n      mutation: mutationName,\n      subscription: subscriptionName,\n    };\n\n    this.rootNames = {\n      [queryName]: 'query',\n      [mutationName]: 'mutation',\n      [subscriptionName]: 'subscription',\n    };\n\n    this.data = InMemoryData.make(queryName);\n\n    if (this.schema && process.env.NODE_ENV !== 'production') {\n      expectValidKeyingConfig(this.schema, this.keys, this.logger);\n      expectValidUpdatesConfig(this.schema, this.updates, this.logger);\n      expectValidResolversConfig(this.schema, this.resolvers, this.logger);\n      expectValidOptimisticMutationsConfig(\n        this.schema,\n        this.optimisticMutations,\n        this.logger\n      );\n    }\n  }\n\n  keyOfField(fieldName: string, fieldArgs?: FieldArgs) {\n    return keyOfField(fieldName, fieldArgs);\n  }\n\n  keyOfEntity(data: Entity) {\n    // In resolvers and updaters we may have a specific parent\n    // object available that can be used to skip to a specific parent\n    // key directly without looking at its incomplete properties\n    if (contextRef && data === contextRef.parent) {\n      return contextRef.parentKey;\n    } else if (data == null || typeof data === 'string') {\n      return data || null;\n    } else if (!data.__typename) {\n      return null;\n    } else if (this.rootNames[data.__typename]) {\n      return data.__typename;\n    }\n\n    let key: string | null = null;\n    if (this.keys[data.__typename]) {\n      key = this.keys[data.__typename](data) || null;\n    } else if (data.id != null) {\n      key = `${data.id}`;\n    } else if (data._id != null) {\n      key = `${data._id}`;\n    }\n\n    const typename = data.__typename;\n    const globalID =\n      this.globalIDs === true ||\n      (this.globalIDs && this.globalIDs.has(typename));\n    return globalID || !key ? key : `${typename}:${key}`;\n  }\n\n  resolve(\n    entity: Entity,\n    field: string,\n    args?: FieldArgs\n  ): DataField | undefined {\n    const entityKey = this.keyOfEntity(entity);\n    if (entityKey) {\n      const fieldKey = keyOfField(field, args);\n      const fieldValue = InMemoryData.readRecord(entityKey, fieldKey);\n      if (fieldValue !== undefined) return fieldValue;\n      let fieldLink = InMemoryData.readLink(entityKey, fieldKey);\n      if (fieldLink !== undefined) fieldLink = ensureLink(this, fieldLink);\n      return fieldLink;\n    }\n  }\n\n  invalidate(entity: Entity, field?: string, args?: FieldArgs) {\n    const entityKey = this.keyOfEntity(entity);\n    const shouldInvalidateType =\n      entity &&\n      typeof entity === 'string' &&\n      !field &&\n      !args &&\n      !this.resolve(entity, '__typename');\n\n    if (shouldInvalidateType) {\n      invalidateType(entity, []);\n    } else {\n      invariant(\n        entityKey,\n        \"Can't generate a key for invalidate(...).\\n\" +\n          'You have to pass an id or _id field or create a custom `keys` field for `' +\n          (typeof entity === 'object'\n            ? (entity as Data).__typename\n            : entity + '`.'),\n        19\n      );\n\n      invalidateEntity(entityKey, field, args);\n    }\n  }\n\n  inspectFields(entity: Entity): FieldInfo[] {\n    const entityKey = this.keyOfEntity(entity);\n    return entityKey ? InMemoryData.inspectFields(entityKey) : [];\n  }\n\n  updateQuery<T = Data, V = Variables>(\n    input: QueryInput<T, V>,\n    updater: (data: T | null) => T | null\n  ): void {\n    const request = createRequest(input.query, input.variables!);\n    const output = updater(this.readQuery(request));\n    if (output !== null) {\n      _write(this, request, output as any, undefined);\n    }\n  }\n\n  readQuery<T = Data, V = Variables>(input: QueryInput<T, V>): T | null {\n    const request = createRequest(input.query, input.variables!);\n    return _query(this, request, undefined, undefined).data as T | null;\n  }\n\n  readFragment<T = Data, V = Variables>(\n    fragment: DocumentNode | TypedDocumentNode<T, V>,\n    entity: string | Data | T,\n    variables?: V,\n    fragmentName?: string\n  ): T | null {\n    return _queryFragment(\n      this,\n      formatDocument(fragment),\n      entity as Data,\n      variables as any,\n      fragmentName\n    ) as T | null;\n  }\n\n  writeFragment<T = Data, V = Variables>(\n    fragment: DocumentNode | TypedDocumentNode<T, V>,\n    data: T,\n    variables?: V,\n    fragmentName?: string\n  ): void {\n    _writeFragment(\n      this,\n      formatDocument(fragment),\n      data as Data,\n      variables as any,\n      fragmentName\n    );\n  }\n\n  link(\n    entity: Entity,\n    field: string,\n    args: FieldArgs,\n    link: Link<Entity>\n  ): void;\n\n  link(entity: Entity, field: string, link: Link<Entity>): void;\n\n  link(\n    entity: Entity,\n    field: string,\n    ...rest: [FieldArgs, Link<Entity>] | [Link<Entity>]\n  ): void {\n    const args = rest.length === 2 ? rest[0] : null;\n    const link = rest.length === 2 ? rest[1] : rest[0];\n    const entityKey = this.keyOfEntity(entity);\n    if (entityKey) {\n      InMemoryData.writeLink(\n        entityKey,\n        keyOfField(field, args),\n        ensureLink(this, link)\n      );\n    }\n  }\n}\n"
  },
  {
    "path": "exchanges/graphcache/src/test-utils/altered_root_schema.json",
    "content": "{\n  \"__schema\": {\n    \"queryType\": {\n      \"name\": \"query_root\",\n      \"__typename\": \"__Type\"\n    },\n    \"mutationType\": {\n      \"name\": \"mutation_root\",\n      \"__typename\": \"__Type\"\n    },\n    \"subscriptionType\": null,\n    \"types\": [\n      {\n        \"kind\": \"OBJECT\",\n        \"name\": \"query_root\",\n        \"fields\": [\n          {\n            \"name\": \"todos\",\n            \"args\": [],\n            \"type\": {\n              \"kind\": \"LIST\",\n              \"name\": null,\n              \"ofType\": {\n                \"kind\": \"OBJECT\",\n                \"name\": \"Todo\",\n                \"ofType\": null\n              }\n            }\n          }\n        ],\n        \"inputFields\": null,\n        \"interfaces\": [],\n        \"enumValues\": null,\n        \"possibleTypes\": null\n      },\n      {\n        \"kind\": \"OBJECT\",\n        \"name\": \"Todo\",\n        \"fields\": [\n          {\n            \"name\": \"id\",\n            \"args\": [],\n            \"type\": {\n              \"kind\": \"NON_NULL\",\n              \"name\": null,\n              \"ofType\": {\n                \"kind\": \"SCALAR\",\n                \"name\": \"ID\",\n                \"ofType\": null\n              }\n            }\n          },\n          {\n            \"name\": \"text\",\n            \"args\": [],\n            \"type\": {\n              \"kind\": \"NON_NULL\",\n              \"name\": null,\n              \"ofType\": {\n                \"kind\": \"SCALAR\",\n                \"name\": \"String\",\n                \"ofType\": null\n              }\n            }\n          },\n          {\n            \"name\": \"complete\",\n            \"args\": [],\n            \"type\": {\n              \"kind\": \"SCALAR\",\n              \"name\": \"Boolean\",\n              \"ofType\": null\n            }\n          },\n          {\n            \"name\": \"author\",\n            \"args\": [],\n            \"type\": {\n              \"kind\": \"OBJECT\",\n              \"name\": \"Author\",\n              \"ofType\": null\n            }\n          }\n        ],\n        \"inputFields\": null,\n        \"interfaces\": [],\n        \"enumValues\": null,\n        \"possibleTypes\": null\n      },\n      {\n        \"kind\": \"SCALAR\",\n        \"name\": \"ID\",\n        \"fields\": null,\n        \"inputFields\": null,\n        \"interfaces\": null,\n        \"enumValues\": null,\n        \"possibleTypes\": null\n      },\n      {\n        \"kind\": \"SCALAR\",\n        \"name\": \"String\",\n        \"fields\": null,\n        \"inputFields\": null,\n        \"interfaces\": null,\n        \"enumValues\": null,\n        \"possibleTypes\": null\n      },\n      {\n        \"kind\": \"SCALAR\",\n        \"name\": \"Boolean\",\n        \"fields\": null,\n        \"inputFields\": null,\n        \"interfaces\": null,\n        \"enumValues\": null,\n        \"possibleTypes\": null\n      },\n      {\n        \"kind\": \"OBJECT\",\n        \"name\": \"Author\",\n        \"fields\": [\n          {\n            \"name\": \"id\",\n            \"args\": [],\n            \"type\": {\n              \"kind\": \"NON_NULL\",\n              \"name\": null,\n              \"ofType\": {\n                \"kind\": \"SCALAR\",\n                \"name\": \"ID\",\n                \"ofType\": null\n              }\n            }\n          },\n          {\n            \"name\": \"name\",\n            \"args\": [],\n            \"type\": {\n              \"kind\": \"NON_NULL\",\n              \"name\": null,\n              \"ofType\": {\n                \"kind\": \"SCALAR\",\n                \"name\": \"String\",\n                \"ofType\": null\n              }\n            }\n          },\n          {\n            \"name\": \"known\",\n            \"args\": [],\n            \"type\": {\n              \"kind\": \"SCALAR\",\n              \"name\": \"Boolean\",\n              \"ofType\": null\n            }\n          }\n        ],\n        \"inputFields\": null,\n        \"interfaces\": [],\n        \"enumValues\": null,\n        \"possibleTypes\": null\n      },\n      {\n        \"kind\": \"OBJECT\",\n        \"name\": \"mutation_root\",\n        \"fields\": [\n          {\n            \"name\": \"toggleTodo\",\n            \"args\": [\n              {\n                \"name\": \"id\",\n                \"type\": {\n                  \"kind\": \"NON_NULL\",\n                  \"name\": null,\n                  \"ofType\": {\n                    \"kind\": \"SCALAR\",\n                    \"name\": \"ID\",\n                    \"ofType\": null\n                  }\n                }\n              }\n            ],\n            \"type\": {\n              \"kind\": \"OBJECT\",\n              \"name\": \"Todo\",\n              \"ofType\": null\n            }\n          }\n        ],\n        \"inputFields\": null,\n        \"interfaces\": [],\n        \"enumValues\": null,\n        \"possibleTypes\": null\n      },\n      {\n        \"kind\": \"OBJECT\",\n        \"name\": \"__Schema\",\n        \"fields\": [\n          {\n            \"name\": \"types\",\n            \"args\": [],\n            \"type\": {\n              \"kind\": \"NON_NULL\",\n              \"name\": null,\n              \"ofType\": {\n                \"kind\": \"LIST\",\n                \"name\": null,\n                \"ofType\": {\n                  \"kind\": \"NON_NULL\",\n                  \"name\": null,\n                  \"ofType\": {\n                    \"kind\": \"OBJECT\",\n                    \"name\": \"__Type\",\n                    \"ofType\": null\n                  }\n                }\n              }\n            }\n          },\n          {\n            \"name\": \"queryType\",\n            \"args\": [],\n            \"type\": {\n              \"kind\": \"NON_NULL\",\n              \"name\": null,\n              \"ofType\": {\n                \"kind\": \"OBJECT\",\n                \"name\": \"__Type\",\n                \"ofType\": null\n              }\n            }\n          },\n          {\n            \"name\": \"mutationType\",\n            \"args\": [],\n            \"type\": {\n              \"kind\": \"OBJECT\",\n              \"name\": \"__Type\",\n              \"ofType\": null\n            }\n          },\n          {\n            \"name\": \"subscriptionType\",\n            \"args\": [],\n            \"type\": {\n              \"kind\": \"OBJECT\",\n              \"name\": \"__Type\",\n              \"ofType\": null\n            }\n          },\n          {\n            \"name\": \"directives\",\n            \"args\": [],\n            \"type\": {\n              \"kind\": \"NON_NULL\",\n              \"name\": null,\n              \"ofType\": {\n                \"kind\": \"LIST\",\n                \"name\": null,\n                \"ofType\": {\n                  \"kind\": \"NON_NULL\",\n                  \"name\": null,\n                  \"ofType\": {\n                    \"kind\": \"OBJECT\",\n                    \"name\": \"__Directive\",\n                    \"ofType\": null\n                  }\n                }\n              }\n            }\n          }\n        ],\n        \"inputFields\": null,\n        \"interfaces\": [],\n        \"enumValues\": null,\n        \"possibleTypes\": null\n      },\n      {\n        \"kind\": \"OBJECT\",\n        \"name\": \"__Type\",\n        \"fields\": [\n          {\n            \"name\": \"kind\",\n            \"args\": [],\n            \"type\": {\n              \"kind\": \"NON_NULL\",\n              \"name\": null,\n              \"ofType\": {\n                \"kind\": \"ENUM\",\n                \"name\": \"__TypeKind\",\n                \"ofType\": null\n              }\n            }\n          },\n          {\n            \"name\": \"name\",\n            \"args\": [],\n            \"type\": {\n              \"kind\": \"SCALAR\",\n              \"name\": \"String\",\n              \"ofType\": null\n            }\n          },\n          {\n            \"name\": \"description\",\n            \"args\": [],\n            \"type\": {\n              \"kind\": \"SCALAR\",\n              \"name\": \"String\",\n              \"ofType\": null\n            }\n          },\n          {\n            \"name\": \"fields\",\n            \"args\": [\n              {\n                \"name\": \"includeDeprecated\",\n                \"type\": {\n                  \"kind\": \"SCALAR\",\n                  \"name\": \"Boolean\",\n                  \"ofType\": null\n                }\n              }\n            ],\n            \"type\": {\n              \"kind\": \"LIST\",\n              \"name\": null,\n              \"ofType\": {\n                \"kind\": \"NON_NULL\",\n                \"name\": null,\n                \"ofType\": {\n                  \"kind\": \"OBJECT\",\n                  \"name\": \"__Field\",\n                  \"ofType\": null\n                }\n              }\n            }\n          },\n          {\n            \"name\": \"interfaces\",\n            \"args\": [],\n            \"type\": {\n              \"kind\": \"LIST\",\n              \"name\": null,\n              \"ofType\": {\n                \"kind\": \"NON_NULL\",\n                \"name\": null,\n                \"ofType\": {\n                  \"kind\": \"OBJECT\",\n                  \"name\": \"__Type\",\n                  \"ofType\": null\n                }\n              }\n            }\n          },\n          {\n            \"name\": \"possibleTypes\",\n            \"args\": [],\n            \"type\": {\n              \"kind\": \"LIST\",\n              \"name\": null,\n              \"ofType\": {\n                \"kind\": \"NON_NULL\",\n                \"name\": null,\n                \"ofType\": {\n                  \"kind\": \"OBJECT\",\n                  \"name\": \"__Type\",\n                  \"ofType\": null\n                }\n              }\n            }\n          },\n          {\n            \"name\": \"enumValues\",\n            \"args\": [\n              {\n                \"name\": \"includeDeprecated\",\n                \"type\": {\n                  \"kind\": \"SCALAR\",\n                  \"name\": \"Boolean\",\n                  \"ofType\": null\n                }\n              }\n            ],\n            \"type\": {\n              \"kind\": \"LIST\",\n              \"name\": null,\n              \"ofType\": {\n                \"kind\": \"NON_NULL\",\n                \"name\": null,\n                \"ofType\": {\n                  \"kind\": \"OBJECT\",\n                  \"name\": \"__EnumValue\",\n                  \"ofType\": null\n                }\n              }\n            }\n          },\n          {\n            \"name\": \"inputFields\",\n            \"args\": [],\n            \"type\": {\n              \"kind\": \"LIST\",\n              \"name\": null,\n              \"ofType\": {\n                \"kind\": \"NON_NULL\",\n                \"name\": null,\n                \"ofType\": {\n                  \"kind\": \"OBJECT\",\n                  \"name\": \"__InputValue\",\n                  \"ofType\": null\n                }\n              }\n            }\n          },\n          {\n            \"name\": \"ofType\",\n            \"args\": [],\n            \"type\": {\n              \"kind\": \"OBJECT\",\n              \"name\": \"__Type\",\n              \"ofType\": null\n            }\n          }\n        ],\n        \"inputFields\": null,\n        \"interfaces\": [],\n        \"enumValues\": null,\n        \"possibleTypes\": null\n      },\n      {\n        \"kind\": \"ENUM\",\n        \"name\": \"__TypeKind\",\n        \"fields\": null,\n        \"inputFields\": null,\n        \"interfaces\": null,\n        \"enumValues\": [\n          {\n            \"name\": \"SCALAR\"\n          },\n          {\n            \"name\": \"OBJECT\"\n          },\n          {\n            \"name\": \"INTERFACE\"\n          },\n          {\n            \"name\": \"UNION\"\n          },\n          {\n            \"name\": \"ENUM\"\n          },\n          {\n            \"name\": \"INPUT_OBJECT\"\n          },\n          {\n            \"name\": \"LIST\"\n          },\n          {\n            \"name\": \"NON_NULL\"\n          }\n        ],\n        \"possibleTypes\": null\n      },\n      {\n        \"kind\": \"OBJECT\",\n        \"name\": \"__Field\",\n        \"fields\": [\n          {\n            \"name\": \"name\",\n            \"args\": [],\n            \"type\": {\n              \"kind\": \"NON_NULL\",\n              \"name\": null,\n              \"ofType\": {\n                \"kind\": \"SCALAR\",\n                \"name\": \"String\",\n                \"ofType\": null\n              }\n            }\n          },\n          {\n            \"name\": \"description\",\n            \"args\": [],\n            \"type\": {\n              \"kind\": \"SCALAR\",\n              \"name\": \"String\",\n              \"ofType\": null\n            }\n          },\n          {\n            \"name\": \"args\",\n            \"args\": [],\n            \"type\": {\n              \"kind\": \"NON_NULL\",\n              \"name\": null,\n              \"ofType\": {\n                \"kind\": \"LIST\",\n                \"name\": null,\n                \"ofType\": {\n                  \"kind\": \"NON_NULL\",\n                  \"name\": null,\n                  \"ofType\": {\n                    \"kind\": \"OBJECT\",\n                    \"name\": \"__InputValue\",\n                    \"ofType\": null\n                  }\n                }\n              }\n            }\n          },\n          {\n            \"name\": \"type\",\n            \"args\": [],\n            \"type\": {\n              \"kind\": \"NON_NULL\",\n              \"name\": null,\n              \"ofType\": {\n                \"kind\": \"OBJECT\",\n                \"name\": \"__Type\",\n                \"ofType\": null\n              }\n            }\n          },\n          {\n            \"name\": \"isDeprecated\",\n            \"args\": [],\n            \"type\": {\n              \"kind\": \"NON_NULL\",\n              \"name\": null,\n              \"ofType\": {\n                \"kind\": \"SCALAR\",\n                \"name\": \"Boolean\",\n                \"ofType\": null\n              }\n            }\n          },\n          {\n            \"name\": \"deprecationReason\",\n            \"args\": [],\n            \"type\": {\n              \"kind\": \"SCALAR\",\n              \"name\": \"String\",\n              \"ofType\": null\n            }\n          }\n        ],\n        \"inputFields\": null,\n        \"interfaces\": [],\n        \"enumValues\": null,\n        \"possibleTypes\": null\n      },\n      {\n        \"kind\": \"OBJECT\",\n        \"name\": \"__InputValue\",\n        \"fields\": [\n          {\n            \"name\": \"name\",\n            \"args\": [],\n            \"type\": {\n              \"kind\": \"NON_NULL\",\n              \"name\": null,\n              \"ofType\": {\n                \"kind\": \"SCALAR\",\n                \"name\": \"String\",\n                \"ofType\": null\n              }\n            }\n          },\n          {\n            \"name\": \"description\",\n            \"args\": [],\n            \"type\": {\n              \"kind\": \"SCALAR\",\n              \"name\": \"String\",\n              \"ofType\": null\n            }\n          },\n          {\n            \"name\": \"type\",\n            \"args\": [],\n            \"type\": {\n              \"kind\": \"NON_NULL\",\n              \"name\": null,\n              \"ofType\": {\n                \"kind\": \"OBJECT\",\n                \"name\": \"__Type\",\n                \"ofType\": null\n              }\n            }\n          },\n          {\n            \"name\": \"defaultValue\",\n            \"args\": [],\n            \"type\": {\n              \"kind\": \"SCALAR\",\n              \"name\": \"String\",\n              \"ofType\": null\n            }\n          }\n        ],\n        \"inputFields\": null,\n        \"interfaces\": [],\n        \"enumValues\": null,\n        \"possibleTypes\": null\n      },\n      {\n        \"kind\": \"OBJECT\",\n        \"name\": \"__EnumValue\",\n        \"fields\": [\n          {\n            \"name\": \"name\",\n            \"args\": [],\n            \"type\": {\n              \"kind\": \"NON_NULL\",\n              \"name\": null,\n              \"ofType\": {\n                \"kind\": \"SCALAR\",\n                \"name\": \"String\",\n                \"ofType\": null\n              }\n            }\n          },\n          {\n            \"name\": \"description\",\n            \"args\": [],\n            \"type\": {\n              \"kind\": \"SCALAR\",\n              \"name\": \"String\",\n              \"ofType\": null\n            }\n          },\n          {\n            \"name\": \"isDeprecated\",\n            \"args\": [],\n            \"type\": {\n              \"kind\": \"NON_NULL\",\n              \"name\": null,\n              \"ofType\": {\n                \"kind\": \"SCALAR\",\n                \"name\": \"Boolean\",\n                \"ofType\": null\n              }\n            }\n          },\n          {\n            \"name\": \"deprecationReason\",\n            \"args\": [],\n            \"type\": {\n              \"kind\": \"SCALAR\",\n              \"name\": \"String\",\n              \"ofType\": null\n            }\n          }\n        ],\n        \"inputFields\": null,\n        \"interfaces\": [],\n        \"enumValues\": null,\n        \"possibleTypes\": null\n      },\n      {\n        \"kind\": \"OBJECT\",\n        \"name\": \"__Directive\",\n        \"fields\": [\n          {\n            \"name\": \"name\",\n            \"args\": [],\n            \"type\": {\n              \"kind\": \"NON_NULL\",\n              \"name\": null,\n              \"ofType\": {\n                \"kind\": \"SCALAR\",\n                \"name\": \"String\",\n                \"ofType\": null\n              }\n            }\n          },\n          {\n            \"name\": \"description\",\n            \"args\": [],\n            \"type\": {\n              \"kind\": \"SCALAR\",\n              \"name\": \"String\",\n              \"ofType\": null\n            }\n          },\n          {\n            \"name\": \"locations\",\n            \"args\": [],\n            \"type\": {\n              \"kind\": \"NON_NULL\",\n              \"name\": null,\n              \"ofType\": {\n                \"kind\": \"LIST\",\n                \"name\": null,\n                \"ofType\": {\n                  \"kind\": \"NON_NULL\",\n                  \"name\": null,\n                  \"ofType\": {\n                    \"kind\": \"ENUM\",\n                    \"name\": \"__DirectiveLocation\",\n                    \"ofType\": null\n                  }\n                }\n              }\n            }\n          },\n          {\n            \"name\": \"args\",\n            \"args\": [],\n            \"type\": {\n              \"kind\": \"NON_NULL\",\n              \"name\": null,\n              \"ofType\": {\n                \"kind\": \"LIST\",\n                \"name\": null,\n                \"ofType\": {\n                  \"kind\": \"NON_NULL\",\n                  \"name\": null,\n                  \"ofType\": {\n                    \"kind\": \"OBJECT\",\n                    \"name\": \"__InputValue\",\n                    \"ofType\": null\n                  }\n                }\n              }\n            }\n          }\n        ],\n        \"inputFields\": null,\n        \"interfaces\": [],\n        \"enumValues\": null,\n        \"possibleTypes\": null\n      },\n      {\n        \"kind\": \"ENUM\",\n        \"name\": \"__DirectiveLocation\",\n        \"fields\": null,\n        \"inputFields\": null,\n        \"interfaces\": null,\n        \"enumValues\": [\n          {\n            \"name\": \"QUERY\"\n          },\n          {\n            \"name\": \"MUTATION\"\n          },\n          {\n            \"name\": \"SUBSCRIPTION\"\n          },\n          {\n            \"name\": \"FIELD\"\n          },\n          {\n            \"name\": \"FRAGMENT_DEFINITION\"\n          },\n          {\n            \"name\": \"FRAGMENT_SPREAD\"\n          },\n          {\n            \"name\": \"INLINE_FRAGMENT\"\n          },\n          {\n            \"name\": \"VARIABLE_DEFINITION\"\n          },\n          {\n            \"name\": \"SCHEMA\"\n          },\n          {\n            \"name\": \"SCALAR\"\n          },\n          {\n            \"name\": \"OBJECT\"\n          },\n          {\n            \"name\": \"FIELD_DEFINITION\"\n          },\n          {\n            \"name\": \"ARGUMENT_DEFINITION\"\n          },\n          {\n            \"name\": \"INTERFACE\"\n          },\n          {\n            \"name\": \"UNION\"\n          },\n          {\n            \"name\": \"ENUM\"\n          },\n          {\n            \"name\": \"ENUM_VALUE\"\n          },\n          {\n            \"name\": \"INPUT_OBJECT\"\n          },\n          {\n            \"name\": \"INPUT_FIELD_DEFINITION\"\n          }\n        ],\n        \"possibleTypes\": null\n      },\n      {\n        \"kind\": \"INTERFACE\",\n        \"name\": \"ITodo\",\n        \"fields\": [\n          {\n            \"name\": \"id\",\n            \"args\": [],\n            \"type\": {\n              \"kind\": \"NON_NULL\",\n              \"name\": null,\n              \"ofType\": {\n                \"kind\": \"SCALAR\",\n                \"name\": \"ID\",\n                \"ofType\": null\n              }\n            }\n          },\n          {\n            \"name\": \"text\",\n            \"args\": [],\n            \"type\": {\n              \"kind\": \"NON_NULL\",\n              \"name\": null,\n              \"ofType\": {\n                \"kind\": \"SCALAR\",\n                \"name\": \"String\",\n                \"ofType\": null\n              }\n            }\n          },\n          {\n            \"name\": \"complete\",\n            \"args\": [],\n            \"type\": {\n              \"kind\": \"SCALAR\",\n              \"name\": \"Boolean\",\n              \"ofType\": null\n            }\n          },\n          {\n            \"name\": \"author\",\n            \"args\": [],\n            \"type\": {\n              \"kind\": \"OBJECT\",\n              \"name\": \"Author\",\n              \"ofType\": null\n            }\n          }\n        ],\n        \"inputFields\": null,\n        \"interfaces\": null,\n        \"enumValues\": null,\n        \"possibleTypes\": [\n          {\n            \"kind\": \"OBJECT\",\n            \"name\": \"BigTodo\",\n            \"ofType\": null\n          },\n          {\n            \"kind\": \"OBJECT\",\n            \"name\": \"SmallTodo\",\n            \"ofType\": null\n          }\n        ]\n      },\n      {\n        \"kind\": \"OBJECT\",\n        \"name\": \"BigTodo\",\n        \"fields\": [\n          {\n            \"name\": \"id\",\n            \"args\": [],\n            \"type\": {\n              \"kind\": \"NON_NULL\",\n              \"name\": null,\n              \"ofType\": {\n                \"kind\": \"SCALAR\",\n                \"name\": \"ID\",\n                \"ofType\": null\n              }\n            }\n          },\n          {\n            \"name\": \"text\",\n            \"args\": [],\n            \"type\": {\n              \"kind\": \"NON_NULL\",\n              \"name\": null,\n              \"ofType\": {\n                \"kind\": \"SCALAR\",\n                \"name\": \"String\",\n                \"ofType\": null\n              }\n            }\n          },\n          {\n            \"name\": \"complete\",\n            \"args\": [],\n            \"type\": {\n              \"kind\": \"SCALAR\",\n              \"name\": \"Boolean\",\n              \"ofType\": null\n            }\n          },\n          {\n            \"name\": \"author\",\n            \"args\": [],\n            \"type\": {\n              \"kind\": \"OBJECT\",\n              \"name\": \"Author\",\n              \"ofType\": null\n            }\n          },\n          {\n            \"name\": \"wallOfText\",\n            \"args\": [],\n            \"type\": {\n              \"kind\": \"SCALAR\",\n              \"name\": \"String\",\n              \"ofType\": null\n            }\n          }\n        ],\n        \"inputFields\": null,\n        \"interfaces\": [\n          {\n            \"kind\": \"INTERFACE\",\n            \"name\": \"ITodo\",\n            \"ofType\": null\n          }\n        ],\n        \"enumValues\": null,\n        \"possibleTypes\": null\n      },\n      {\n        \"kind\": \"OBJECT\",\n        \"name\": \"SmallTodo\",\n        \"fields\": [\n          {\n            \"name\": \"id\",\n            \"args\": [],\n            \"type\": {\n              \"kind\": \"NON_NULL\",\n              \"name\": null,\n              \"ofType\": {\n                \"kind\": \"SCALAR\",\n                \"name\": \"ID\",\n                \"ofType\": null\n              }\n            }\n          },\n          {\n            \"name\": \"text\",\n            \"args\": [],\n            \"type\": {\n              \"kind\": \"NON_NULL\",\n              \"name\": null,\n              \"ofType\": {\n                \"kind\": \"SCALAR\",\n                \"name\": \"String\",\n                \"ofType\": null\n              }\n            }\n          },\n          {\n            \"name\": \"complete\",\n            \"args\": [],\n            \"type\": {\n              \"kind\": \"SCALAR\",\n              \"name\": \"Boolean\",\n              \"ofType\": null\n            }\n          },\n          {\n            \"name\": \"author\",\n            \"args\": [],\n            \"type\": {\n              \"kind\": \"OBJECT\",\n              \"name\": \"Author\",\n              \"ofType\": null\n            }\n          },\n          {\n            \"name\": \"maxLength\",\n            \"args\": [],\n            \"type\": {\n              \"kind\": \"SCALAR\",\n              \"name\": \"Int\",\n              \"ofType\": null\n            }\n          }\n        ],\n        \"inputFields\": null,\n        \"interfaces\": [\n          {\n            \"kind\": \"INTERFACE\",\n            \"name\": \"ITodo\",\n            \"ofType\": null\n          }\n        ],\n        \"enumValues\": null,\n        \"possibleTypes\": null\n      },\n      {\n        \"kind\": \"SCALAR\",\n        \"name\": \"Int\",\n        \"fields\": null,\n        \"inputFields\": null,\n        \"interfaces\": null,\n        \"enumValues\": null,\n        \"possibleTypes\": null\n      },\n      {\n        \"kind\": \"ENUM\",\n        \"name\": \"Todos\",\n        \"fields\": null,\n        \"inputFields\": null,\n        \"interfaces\": null,\n        \"enumValues\": [\n          {\n            \"name\": \"SmallTodo\"\n          },\n          {\n            \"name\": \"BigTodo\"\n          }\n        ],\n        \"possibleTypes\": null\n      },\n      {\n        \"kind\": \"UNION\",\n        \"name\": \"Search\",\n        \"fields\": null,\n        \"inputFields\": null,\n        \"interfaces\": null,\n        \"enumValues\": null,\n        \"possibleTypes\": [\n          {\n            \"kind\": \"OBJECT\",\n            \"name\": \"SmallTodo\",\n            \"ofType\": null\n          },\n          {\n            \"kind\": \"OBJECT\",\n            \"name\": \"BigTodo\",\n            \"ofType\": null\n          }\n        ]\n      },\n      {\n        \"kind\": \"ENUM\",\n        \"name\": \"CacheControlScope\",\n        \"fields\": null,\n        \"inputFields\": null,\n        \"interfaces\": null,\n        \"enumValues\": [\n          {\n            \"name\": \"PUBLIC\"\n          },\n          {\n            \"name\": \"PRIVATE\"\n          }\n        ],\n        \"possibleTypes\": null\n      },\n      {\n        \"kind\": \"SCALAR\",\n        \"name\": \"Upload\",\n        \"fields\": null,\n        \"inputFields\": null,\n        \"interfaces\": null,\n        \"enumValues\": null,\n        \"possibleTypes\": null\n      }\n    ]\n  }\n}\n"
  },
  {
    "path": "exchanges/graphcache/src/test-utils/examples-1.test.ts",
    "content": "import { gql } from '@urql/core';\nimport { it, expect, afterEach } from 'vitest';\nimport { __initAnd_query as query } from '../operations/query';\nimport {\n  __initAnd_write as write,\n  __initAnd_writeOptimistic as writeOptimistic,\n} from '../operations/write';\nimport * as InMemoryData from '../store/data';\nimport { Store } from '../store/store';\nimport { Data } from '../types';\n\nconst Todos = gql`\n  query {\n    __typename\n    todos {\n      __typename\n      id\n      complete\n      text\n    }\n  }\n`;\n\nconst TodoFragment = gql`\n  fragment _ on Todo {\n    __typename\n    id\n    text\n    complete\n  }\n`;\n\nconst Todo = gql`\n  query ($id: ID!) {\n    __typename\n    todo(id: $id) {\n      id\n      text\n      complete\n    }\n  }\n`;\n\nconst ToggleTodo = gql`\n  mutation ($id: ID!) {\n    __typename\n    toggleTodo(id: $id) {\n      __typename\n      id\n      text\n      complete\n    }\n  }\n`;\n\nconst NestedClearNameTodo = gql`\n  mutation ($id: ID!) {\n    __typename\n    clearName(id: $id) {\n      __typename\n      todo {\n        __typename\n        id\n        text\n        complete\n      }\n    }\n  }\n`;\n\nafterEach(() => {\n  expect(console.warn).not.toHaveBeenCalled();\n});\n\nit('passes the \"getting-started\" example', () => {\n  const store = new Store();\n  const todosData = {\n    __typename: 'Query',\n    todos: [\n      { id: '0', text: 'Go to the shops', complete: false, __typename: 'Todo' },\n      { id: '1', text: 'Pick up the kids', complete: true, __typename: 'Todo' },\n      { id: '2', text: 'Install urql', complete: false, __typename: 'Todo' },\n    ],\n  };\n\n  const writeRes = write(store, { query: Todos }, todosData);\n\n  expect(writeRes.dependencies).toEqual(\n    new Set(['Query.todos', 'Todo:0', 'Todo:1', 'Todo:2'])\n  );\n\n  let queryRes = query(store, { query: Todos });\n\n  expect(queryRes.data).toEqual(todosData);\n  expect(queryRes.dependencies).toEqual(writeRes.dependencies);\n  expect(queryRes.partial).toBe(false);\n\n  const mutatedTodo = {\n    ...todosData.todos[2],\n    complete: true,\n  };\n\n  const mutationRes = write(\n    store,\n    { query: ToggleTodo, variables: { id: '2' } },\n    {\n      __typename: 'Mutation',\n      toggleTodo: mutatedTodo,\n    }\n  );\n\n  expect(mutationRes.dependencies).toEqual(new Set(['Todo:2']));\n\n  queryRes = query(store, { query: Todos });\n\n  expect(queryRes.partial).toBe(false);\n  expect(queryRes.data).toEqual({\n    ...todosData,\n    todos: [...todosData.todos.slice(0, 2), mutatedTodo],\n  });\n\n  const newMutatedTodo = {\n    ...mutatedTodo,\n    text: '',\n  };\n\n  const newMutationRes = write(\n    store,\n    { query: NestedClearNameTodo, variables: { id: '2' } },\n    {\n      __typename: 'Mutation',\n      clearName: {\n        __typename: 'ClearName',\n        todo: newMutatedTodo,\n      },\n    }\n  );\n\n  expect(newMutationRes.dependencies).toEqual(new Set(['Todo:2']));\n\n  queryRes = query(store, { query: Todos });\n\n  expect(queryRes.partial).toBe(false);\n  expect(queryRes.data).toEqual({\n    ...todosData,\n    todos: [...todosData.todos.slice(0, 2), newMutatedTodo],\n  });\n});\n\nit('resolves missing, nullable arguments on fields', () => {\n  const store = new Store();\n\n  const GetWithVariables = gql`\n    query {\n      __typename\n      todo(first: null) {\n        __typename\n        id\n      }\n    }\n  `;\n\n  const GetWithoutVariables = gql`\n    query {\n      __typename\n      todo {\n        __typename\n        id\n      }\n    }\n  `;\n\n  const dataToWrite = {\n    __typename: 'Query',\n    todo: {\n      __typename: 'Todo',\n      id: '123',\n    },\n  };\n\n  write(store, { query: GetWithVariables }, dataToWrite);\n  const { data } = query(store, { query: GetWithoutVariables });\n  expect(data).toEqual(dataToWrite);\n});\n\nit('should link entities', () => {\n  const store = new Store({\n    resolvers: {\n      Query: {\n        todo: (_parent, args) => {\n          return { __typename: 'Todo', ...args };\n        },\n      },\n    },\n  });\n\n  const todosData = {\n    __typename: 'Query',\n    todos: [\n      { id: '0', text: 'Go to the shops', complete: false, __typename: 'Todo' },\n      { id: '1', text: 'Pick up the kids', complete: true, __typename: 'Todo' },\n      { id: '2', text: 'Install urql', complete: false, __typename: 'Todo' },\n    ],\n  };\n\n  write(store, { query: Todos }, todosData);\n  const res = query(store, { query: Todo, variables: { id: '0' } });\n  expect(res.data).toEqual({\n    __typename: 'Query',\n    todo: {\n      id: '0',\n      text: 'Go to the shops',\n      complete: false,\n    },\n  });\n});\n\nit('should not link entities when writing', () => {\n  const store = new Store({\n    resolvers: {\n      Todo: {\n        text: () => '[redacted]',\n      },\n    },\n  });\n\n  const todosData = {\n    __typename: 'Query',\n    todos: [\n      { id: '0', text: 'Go to the shops', complete: false, __typename: 'Todo' },\n      { id: '1', text: 'Pick up the kids', complete: true, __typename: 'Todo' },\n      { id: '2', text: 'Install urql', complete: false, __typename: 'Todo' },\n    ],\n  };\n\n  write(store, { query: Todos }, todosData);\n\n  InMemoryData.initDataState('write', store.data, null);\n  let data = store.readFragment(TodoFragment, { __typename: 'Todo', id: '0' });\n\n  expect(data).toEqual({\n    id: '0',\n    text: 'Go to the shops',\n    complete: false,\n    __typename: 'Todo',\n  });\n\n  InMemoryData.initDataState('read', store.data, null);\n  data = store.readFragment(TodoFragment, { __typename: 'Todo', id: '0' });\n\n  expect(data).toEqual({\n    id: '0',\n    text: '[redacted]',\n    complete: false,\n    __typename: 'Todo',\n  });\n});\n\nit('respects property-level resolvers when given', () => {\n  const store = new Store({\n    resolvers: {\n      Todo: { text: () => 'hi' },\n    },\n  });\n  const todosData = {\n    __typename: 'Query',\n    todos: [\n      { id: '0', text: 'Go to the shops', complete: false, __typename: 'Todo' },\n      { id: '1', text: 'Pick up the kids', complete: true, __typename: 'Todo' },\n      { id: '2', text: 'Install urql', complete: false, __typename: 'Todo' },\n    ],\n  };\n\n  const writeRes = write(store, { query: Todos }, todosData);\n\n  expect(writeRes.dependencies).toEqual(\n    new Set(['Query.todos', 'Todo:0', 'Todo:1', 'Todo:2'])\n  );\n\n  let queryRes = query(store, { query: Todos });\n\n  expect(queryRes.data).toEqual({\n    __typename: 'Query',\n    todos: [\n      { id: '0', text: 'hi', complete: false, __typename: 'Todo' },\n      { id: '1', text: 'hi', complete: true, __typename: 'Todo' },\n      { id: '2', text: 'hi', complete: false, __typename: 'Todo' },\n    ],\n  });\n  expect(queryRes.dependencies).toEqual(writeRes.dependencies);\n  expect(queryRes.partial).toBe(false);\n\n  const mutatedTodo = {\n    ...todosData.todos[2],\n    complete: true,\n  };\n\n  const mutationRes = write(\n    store,\n    { query: ToggleTodo, variables: { id: '2' } },\n    {\n      __typename: 'Mutation',\n      toggleTodo: mutatedTodo,\n    }\n  );\n\n  expect(mutationRes.dependencies).toEqual(new Set(['Todo:2']));\n\n  queryRes = query(store, { query: Todos });\n\n  expect(queryRes.partial).toBe(false);\n  expect(queryRes.data).toEqual({\n    ...todosData,\n    todos: [\n      { id: '0', text: 'hi', complete: false, __typename: 'Todo' },\n      { id: '1', text: 'hi', complete: true, __typename: 'Todo' },\n      { id: '2', text: 'hi', complete: true, __typename: 'Todo' },\n    ],\n  });\n});\n\nit('respects Mutation update functions', () => {\n  const store = new Store({\n    updates: {\n      Mutation: {\n        toggleTodo: function toggleTodo(result, _, cache) {\n          cache.updateQuery({ query: Todos }, data => {\n            if (\n              data &&\n              data.todos &&\n              result &&\n              result.toggleTodo &&\n              (result.toggleTodo as any).id === '1'\n            ) {\n              data.todos[1] = {\n                id: '1',\n                text: `${data.todos[1].text} (Updated)`,\n                complete: (result.toggleTodo as any).complete,\n                __typename: 'Todo',\n              };\n            } else if (data && data.todos) {\n              data.todos[Number((result.toggleTodo as any).id)] = {\n                ...data.todos[Number((result.toggleTodo as any).id)],\n                complete: (result.toggleTodo as any).complete,\n              };\n            }\n            return data as Data;\n          });\n        },\n      },\n    },\n  });\n\n  const todosData = {\n    __typename: 'Query',\n    todos: [\n      { id: '0', text: 'Go to the shops', complete: false, __typename: 'Todo' },\n      {\n        id: '1',\n        text: 'Pick up the kids',\n        complete: false,\n        __typename: 'Todo',\n      },\n      { id: '2', text: 'Install urql', complete: false, __typename: 'Todo' },\n    ],\n  };\n\n  write(store, { query: Todos }, todosData);\n\n  write(\n    store,\n    { query: ToggleTodo, variables: { id: '1' } },\n    {\n      __typename: 'Mutation',\n      toggleTodo: {\n        ...todosData.todos[1],\n        complete: true,\n      },\n    }\n  );\n\n  write(\n    store,\n    { query: ToggleTodo, variables: { id: '2' } },\n    {\n      __typename: 'Mutation',\n      toggleTodo: {\n        ...todosData.todos[2],\n        complete: true,\n      },\n    }\n  );\n\n  const queryRes = query(store, { query: Todos });\n\n  expect(queryRes.partial).toBe(false);\n  expect(queryRes.data).toEqual({\n    ...todosData,\n    todos: [\n      todosData.todos[0],\n      {\n        id: '1',\n        text: 'Pick up the kids (Updated)',\n        complete: true,\n        __typename: 'Todo',\n      },\n      { id: '2', text: 'Install urql', complete: true, __typename: 'Todo' },\n    ],\n  });\n});\n\nit('respects arbitrary type update functions', () => {\n  const store = new Store({\n    updates: {\n      Todo: {\n        text(result, _, cache) {\n          const fragment = gql`\n            fragment _ on Todo {\n              id\n              complete\n            }\n          `;\n\n          cache.writeFragment(fragment, {\n            id: result.id,\n            complete: true,\n          });\n        },\n      },\n    },\n  });\n\n  const todosData = {\n    __typename: 'Query',\n    todos: [\n      { id: '1', text: 'First', complete: false, __typename: 'Todo' },\n      { id: '2', text: 'Second', complete: false, __typename: 'Todo' },\n    ],\n  };\n\n  write(store, { query: Todos }, todosData);\n  const queryRes = query(store, { query: Todos });\n\n  expect(queryRes.partial).toBe(false);\n  expect(queryRes.data).toEqual({\n    ...todosData,\n    todos: [\n      {\n        ...todosData.todos[0],\n        complete: true,\n      },\n      {\n        ...todosData.todos[1],\n        complete: true,\n      },\n    ],\n  });\n});\n\nit('correctly resolves optimistic updates on Relay schemas', () => {\n  const store = new Store({\n    optimistic: {\n      updateItem: variables => ({\n        __typename: 'UpdateItemPayload',\n        item: {\n          __typename: 'Item',\n          id: variables.id as string,\n          name: 'Offline',\n        },\n      }),\n    },\n  });\n\n  const queryData = {\n    __typename: 'Query',\n    root: {\n      __typename: 'Root',\n      id: 'root',\n      items: {\n        __typename: 'ItemConnection',\n        edges: [\n          {\n            __typename: 'ItemEdge',\n            node: {\n              __typename: 'Item',\n              id: '1',\n              name: 'Number One',\n            },\n          },\n          {\n            __typename: 'ItemEdge',\n            node: {\n              __typename: 'Item',\n              id: '2',\n              name: 'Number Two',\n            },\n          },\n        ],\n      },\n    },\n  };\n\n  const getRoot = gql`\n    query GetRoot {\n      root {\n        __typename\n        id\n        items {\n          __typename\n          edges {\n            __typename\n            node {\n              __typename\n              id\n              name\n            }\n          }\n        }\n      }\n    }\n  `;\n\n  const updateItem = gql`\n    mutation UpdateItem($id: ID!) {\n      updateItem(id: $id) {\n        __typename\n        item {\n          __typename\n          id\n          name\n        }\n      }\n    }\n  `;\n\n  write(store, { query: getRoot }, queryData);\n  const { dependencies } = writeOptimistic(\n    store,\n    { query: updateItem, variables: { id: '2' } },\n    1\n  );\n  expect(dependencies.size).not.toBe(0);\n  InMemoryData.noopDataState(store.data, 1);\n  const queryRes = query(store, { query: getRoot });\n\n  expect(queryRes.partial).toBe(false);\n  expect(queryRes.data).not.toBe(null);\n});\n\nit('skips non-optimistic mutation fields on writes', () => {\n  const store = new Store();\n\n  const updateItem = gql`\n    mutation UpdateItem($id: ID!) {\n      updateItem(id: $id) {\n        __typename\n        item {\n          __typename\n          id\n          name\n        }\n      }\n    }\n  `;\n\n  const { dependencies } = writeOptimistic(\n    store,\n    { query: updateItem, variables: { id: '2' } },\n    1\n  );\n  expect(dependencies.size).toBe(0);\n});\n\nit('allows cumulative optimistic updates', () => {\n  let counter = 1;\n\n  const store = new Store({\n    updates: {\n      Mutation: {\n        addTodo: (result, _, cache) => {\n          cache.updateQuery({ query: Todos }, data => {\n            (data as any).todos.push(result.addTodo);\n            return data as Data;\n          });\n        },\n      },\n    },\n    optimistic: {\n      addTodo: () => ({\n        __typename: 'Todo',\n        id: 'optimistic_' + ++counter,\n        text: '',\n        complete: false,\n      }),\n    },\n  });\n\n  const todosData = {\n    __typename: 'Query',\n    todos: [\n      { id: '0', complete: true, text: '0', __typename: 'Todo' },\n      { id: '1', complete: true, text: '1', __typename: 'Todo' },\n    ],\n  };\n\n  write(store, { query: Todos }, todosData);\n\n  const AddTodo = gql`\n    mutation {\n      __typename\n      addTodo {\n        __typename\n        complete\n        text\n        id\n      }\n    }\n  `;\n\n  writeOptimistic(store, { query: AddTodo }, 1);\n  writeOptimistic(store, { query: AddTodo }, 2);\n\n  const queryRes = query(store, { query: Todos });\n\n  expect(queryRes.partial).toBe(false);\n  expect(queryRes.data).toEqual({\n    ...todosData,\n    todos: [\n      todosData.todos[0],\n      todosData.todos[1],\n      { __typename: 'Todo', text: '', complete: false, id: 'optimistic_2' },\n      { __typename: 'Todo', text: '', complete: false, id: 'optimistic_3' },\n    ],\n  });\n});\n\nit('supports clearing a layer then reapplying optimistic updates', () => {\n  let counter = 1;\n\n  const store = new Store({\n    updates: {\n      Mutation: {\n        addTodo: (result, _, cache) => {\n          cache.updateQuery({ query: Todos }, data => {\n            (data as any).todos.push(result.addTodo);\n            return data as Data;\n          });\n        },\n      },\n    },\n    optimistic: {\n      addTodo: () => ({\n        __typename: 'Todo',\n        id: 'optimistic_' + ++counter,\n        text: '',\n        complete: false,\n      }),\n    },\n  });\n\n  const todosData = {\n    __typename: 'Query',\n    todos: [\n      { id: '0', complete: true, text: '0', __typename: 'Todo' },\n      { id: '1', complete: true, text: '1', __typename: 'Todo' },\n    ],\n  };\n\n  write(store, { query: Todos }, todosData);\n\n  const AddTodo = gql`\n    mutation {\n      __typename\n      addTodo {\n        __typename\n        complete\n        text\n        id\n      }\n    }\n  `;\n\n  writeOptimistic(store, { query: AddTodo }, 1);\n  writeOptimistic(store, { query: AddTodo }, 1);\n\n  InMemoryData.noopDataState(store.data, 1);\n\n  writeOptimistic(store, { query: AddTodo }, 1);\n  writeOptimistic(store, { query: AddTodo }, 1);\n\n  const queryRes = query(store, { query: Todos });\n\n  expect(queryRes.partial).toBe(false);\n  expect(queryRes.data).toEqual({\n    ...todosData,\n    todos: [\n      todosData.todos[0],\n      todosData.todos[1],\n      { __typename: 'Todo', text: '', complete: false, id: 'optimistic_4' },\n      { __typename: 'Todo', text: '', complete: false, id: 'optimistic_5' },\n    ],\n  });\n});\n\nit('supports seeing the same optimistic key multiple times (correctly reorders)', () => {\n  const store = new Store({\n    optimistic: {\n      updateTodo: (args: any) => ({\n        __typename: 'Todo',\n        id: args.id,\n        complete: args.completed,\n      }),\n    },\n  });\n\n  const todosData = {\n    __typename: 'Query',\n    todos: [\n      { id: '0', complete: false, text: '0', __typename: 'Todo' },\n      { id: '1', complete: false, text: '1', __typename: 'Todo' },\n    ],\n  };\n\n  write(store, { query: Todos }, todosData);\n\n  const updateTodo = gql`\n    mutation ($id: ID!, $completed: Boolean!) {\n      __typename\n      updateTodo(id: $id, completed: $completed) {\n        __typename\n        complete\n        id\n      }\n    }\n  `;\n\n  writeOptimistic(\n    store,\n    { query: updateTodo, variables: { id: '0', completed: true } },\n    1\n  );\n\n  let queryRes = query(store, { query: Todos });\n  expect(queryRes.partial).toBe(false);\n  expect(queryRes.data?.todos?.[0]?.complete).toEqual(true);\n\n  writeOptimistic(\n    store,\n    { query: updateTodo, variables: { id: '0', completed: false } },\n    2\n  );\n\n  queryRes = query(store, { query: Todos });\n\n  expect(queryRes.partial).toBe(false);\n  expect(queryRes.data?.todos?.[0]?.complete).toEqual(false);\n\n  writeOptimistic(\n    store,\n    { query: updateTodo, variables: { id: '0', completed: true } },\n    1\n  );\n  queryRes = query(store, { query: Todos });\n  expect(queryRes.partial).toBe(false);\n  expect(queryRes.data?.todos?.[0]?.complete).toEqual(true);\n\n  writeOptimistic(\n    store,\n    { query: updateTodo, variables: { id: '0', completed: false } },\n    2\n  );\n\n  queryRes = query(store, { query: Todos });\n\n  expect(queryRes.partial).toBe(false);\n  expect(queryRes.data?.todos?.[0]?.complete).toEqual(false);\n});\n"
  },
  {
    "path": "exchanges/graphcache/src/test-utils/examples-2.test.ts",
    "content": "import { gql } from '@urql/core';\nimport { it, afterEach, expect } from 'vitest';\nimport { __initAnd_query as query } from '../operations/query';\nimport { __initAnd_write as write } from '../operations/write';\nimport { Store } from '../store/store';\n\nconst Item = gql`\n  {\n    todo {\n      __typename\n      id\n      complete\n      text\n    }\n  }\n`;\n\nconst ItemDetailed = gql`\n  {\n    todo {\n      __typename\n      id\n      details {\n        __typename\n        authors {\n          __typename\n          id\n        }\n      }\n    }\n  }\n`;\n\nconst Pagination = gql`\n  query {\n    todos {\n      __typename\n      edges {\n        __typename\n        node {\n          __typename\n          id\n          complete\n          text\n        }\n      }\n      pageInfo {\n        __typename\n        hasNextPage\n        endCursor\n      }\n    }\n  }\n`;\n\nafterEach(() => {\n  expect(console.warn).not.toHaveBeenCalled();\n});\n\nit('allows custom resolvers to resolve nested, unkeyed data', () => {\n  const store = new Store({\n    resolvers: {\n      Query: {\n        todos: () => ({\n          __typename: 'TodosConnection',\n          edges: [\n            {\n              __typename: 'TodoEdge',\n              node: {\n                __typename: 'Todo',\n                id: '1',\n                // The `complete` field will be overwritten here, but we're\n                // leaving out the `text` field\n                complete: true,\n              },\n            },\n          ],\n          pageInfo: {\n            __typename: 'PageInfo',\n            hasNextPage: true,\n            endCursor: '1',\n          },\n        }),\n      },\n    },\n  });\n\n  write(\n    store,\n    { query: Item },\n    {\n      __typename: 'Query',\n      todo: {\n        __typename: 'Todo',\n        id: '1',\n        complete: false,\n        text: 'Example',\n      },\n    }\n  );\n\n  const res = query(store, { query: Pagination });\n\n  expect(res.partial).toBe(false);\n\n  expect(res.data).toEqual({\n    todos: {\n      __typename: 'TodosConnection',\n      edges: [\n        {\n          __typename: 'TodoEdge',\n          node: {\n            __typename: 'Todo',\n            id: '1',\n            complete: true, // This is now true and not false!\n            text: 'Example', // This is still present\n          },\n        },\n      ],\n      pageInfo: {\n        __typename: 'PageInfo',\n        hasNextPage: true,\n        endCursor: '1',\n      },\n    },\n  });\n});\n\nit('allows custom resolvers to resolve nested, unkeyed data with embedded links', () => {\n  const store = new Store({\n    resolvers: {\n      Query: {\n        todos: (_, __, cache) => ({\n          __typename: 'TodosConnection',\n          edges: [\n            {\n              __typename: 'TodoEdge',\n              // This is a key instead of the full entity:\n              node: cache.keyOfEntity({ __typename: 'Todo', id: '1' }),\n            },\n          ],\n          pageInfo: {\n            __typename: 'PageInfo',\n            hasNextPage: true,\n            endCursor: '1',\n          },\n        }),\n      },\n    },\n  });\n\n  write(\n    store,\n    { query: Item },\n    {\n      __typename: 'Query',\n      todo: {\n        __typename: 'Todo',\n        id: '1',\n        complete: false,\n        text: 'Example',\n      },\n    }\n  );\n\n  const res = query(store, { query: Pagination });\n  expect(res.partial).toBe(false);\n  expect(res.data).toEqual({\n    todos: {\n      __typename: 'TodosConnection',\n      edges: [\n        {\n          __typename: 'TodoEdge',\n          node: {\n            __typename: 'Todo',\n            id: '1',\n            complete: false,\n            text: 'Example',\n          },\n        },\n      ],\n      pageInfo: {\n        __typename: 'PageInfo',\n        hasNextPage: true,\n        endCursor: '1',\n      },\n    },\n  });\n});\n\nit('allows custom resolvers to resolve mixed data (keyable and unkeyable)', () => {\n  const store = new Store({\n    keys: {\n      TodoDetails: () => null,\n    },\n    resolvers: {\n      Query: {\n        todo: () => ({\n          __typename: 'Todo',\n          id: '1',\n          details: {\n            __typename: 'TodoDetails',\n          },\n        }),\n      },\n    },\n  });\n\n  write(\n    store,\n    { query: ItemDetailed },\n    {\n      __typename: 'Query',\n      todo: {\n        __typename: 'Todo',\n        id: '1',\n        details: {\n          __typename: 'TodoDetails',\n          authors: [\n            {\n              __typename: 'Author',\n              id: 'x',\n            },\n          ],\n        },\n      },\n    }\n  );\n\n  const res = query(store, { query: ItemDetailed });\n  expect(res.partial).toBe(false);\n  expect(res.dependencies.has('Author:x')).toBeTruthy();\n  expect(res.data).toEqual({\n    todo: {\n      __typename: 'Todo',\n      id: '1',\n      details: {\n        __typename: 'TodoDetails',\n        authors: [\n          {\n            __typename: 'Author',\n            id: 'x',\n          },\n        ],\n      },\n    },\n  });\n});\n"
  },
  {
    "path": "exchanges/graphcache/src/test-utils/examples-3.test.ts",
    "content": "import { gql } from '@urql/core';\nimport { it, afterEach, expect } from 'vitest';\nimport { __initAnd_query as query } from '../operations/query';\nimport { __initAnd_write as write } from '../operations/write';\nimport { Store } from '../store/store';\n\nafterEach(() => {\n  expect(console.warn).not.toHaveBeenCalled();\n});\n\nit('allows viewer fields to overwrite the root Query data', () => {\n  const store = new Store();\n  const get = gql`\n    {\n      int\n    }\n  `;\n  const set = gql`\n    mutation {\n      mutate {\n        viewer {\n          int\n        }\n      }\n    }\n  `;\n\n  write(\n    store,\n    { query: get },\n    {\n      __typename: 'Query',\n      int: 42,\n    }\n  );\n\n  write(\n    store,\n    { query: set },\n    {\n      __typename: 'Mutation',\n      mutate: {\n        __typename: 'MutateResult',\n        viewer: {\n          __typename: 'Query',\n          int: 43,\n        },\n      },\n    }\n  );\n\n  const res = query(store, { query: get });\n\n  expect(res.partial).toBe(false);\n  expect(res.data).toEqual({\n    int: 43,\n  });\n});\n"
  },
  {
    "path": "exchanges/graphcache/src/test-utils/relayPagination_schema.json",
    "content": "{\n  \"__schema\": {\n    \"queryType\": {\n      \"name\": \"Query\"\n    },\n    \"mutationType\": null,\n    \"subscriptionType\": null,\n    \"types\": [\n      {\n        \"kind\": \"OBJECT\",\n        \"name\": \"Query\",\n        \"description\": null,\n        \"fields\": [\n          {\n            \"name\": \"items\",\n            \"description\": null,\n            \"args\": [\n              {\n                \"name\": \"after\",\n                \"description\": null,\n                \"type\": {\n                  \"kind\": \"SCALAR\",\n                  \"name\": \"String\",\n                  \"ofType\": null\n                },\n                \"defaultValue\": null\n              },\n              {\n                \"name\": \"before\",\n                \"description\": null,\n                \"type\": {\n                  \"kind\": \"SCALAR\",\n                  \"name\": \"String\",\n                  \"ofType\": null\n                },\n                \"defaultValue\": null\n              },\n              {\n                \"name\": \"first\",\n                \"description\": null,\n                \"type\": {\n                  \"kind\": \"SCALAR\",\n                  \"name\": \"Int\",\n                  \"ofType\": null\n                },\n                \"defaultValue\": null\n              },\n              {\n                \"name\": \"last\",\n                \"description\": null,\n                \"type\": {\n                  \"kind\": \"SCALAR\",\n                  \"name\": \"Int\",\n                  \"ofType\": null\n                },\n                \"defaultValue\": null\n              }\n            ],\n            \"type\": {\n              \"kind\": \"NON_NULL\",\n              \"name\": null,\n              \"ofType\": {\n                \"kind\": \"OBJECT\",\n                \"name\": \"ItemsConnection\",\n                \"ofType\": null\n              }\n            },\n            \"isDeprecated\": false,\n            \"deprecationReason\": null\n          }\n        ],\n        \"inputFields\": null,\n        \"interfaces\": [],\n        \"enumValues\": null,\n        \"possibleTypes\": null\n      },\n      {\n        \"kind\": \"SCALAR\",\n        \"name\": \"String\",\n        \"description\": \"The `String` scalar type represents textual data, represented as UTF-8 character sequences. The String type is most often used by GraphQL to represent free-form human-readable text.\",\n        \"fields\": null,\n        \"inputFields\": null,\n        \"interfaces\": null,\n        \"enumValues\": null,\n        \"possibleTypes\": null\n      },\n      {\n        \"kind\": \"SCALAR\",\n        \"name\": \"Int\",\n        \"description\": \"The `Int` scalar type represents non-fractional signed whole numeric values. Int can represent values between -(2^31) and 2^31 - 1.\",\n        \"fields\": null,\n        \"inputFields\": null,\n        \"interfaces\": null,\n        \"enumValues\": null,\n        \"possibleTypes\": null\n      },\n      {\n        \"kind\": \"OBJECT\",\n        \"name\": \"ItemsConnection\",\n        \"description\": null,\n        \"fields\": [\n          {\n            \"name\": \"edges\",\n            \"description\": null,\n            \"args\": [],\n            \"type\": {\n              \"kind\": \"NON_NULL\",\n              \"name\": null,\n              \"ofType\": {\n                \"kind\": \"LIST\",\n                \"name\": null,\n                \"ofType\": {\n                  \"kind\": \"NON_NULL\",\n                  \"name\": null,\n                  \"ofType\": {\n                    \"kind\": \"OBJECT\",\n                    \"name\": \"ItemEdge\",\n                    \"ofType\": null\n                  }\n                }\n              }\n            },\n            \"isDeprecated\": false,\n            \"deprecationReason\": null\n          },\n          {\n            \"name\": \"totalCount\",\n            \"description\": null,\n            \"args\": [],\n            \"type\": {\n              \"kind\": \"NON_NULL\",\n              \"name\": null,\n              \"ofType\": {\n                \"kind\": \"SCALAR\",\n                \"name\": \"Int\",\n                \"ofType\": null\n              }\n            },\n            \"isDeprecated\": false,\n            \"deprecationReason\": null\n          },\n          {\n            \"name\": \"pageInfo\",\n            \"description\": null,\n            \"args\": [],\n            \"type\": {\n              \"kind\": \"NON_NULL\",\n              \"name\": null,\n              \"ofType\": {\n                \"kind\": \"OBJECT\",\n                \"name\": \"PageInfo\",\n                \"ofType\": null\n              }\n            },\n            \"isDeprecated\": false,\n            \"deprecationReason\": null\n          }\n        ],\n        \"inputFields\": null,\n        \"interfaces\": [],\n        \"enumValues\": null,\n        \"possibleTypes\": null\n      },\n      {\n        \"kind\": \"OBJECT\",\n        \"name\": \"ItemEdge\",\n        \"description\": null,\n        \"fields\": [\n          {\n            \"name\": \"cursor\",\n            \"description\": null,\n            \"args\": [],\n            \"type\": {\n              \"kind\": \"NON_NULL\",\n              \"name\": null,\n              \"ofType\": {\n                \"kind\": \"SCALAR\",\n                \"name\": \"String\",\n                \"ofType\": null\n              }\n            },\n            \"isDeprecated\": false,\n            \"deprecationReason\": null\n          },\n          {\n            \"name\": \"node\",\n            \"description\": null,\n            \"args\": [],\n            \"type\": {\n              \"kind\": \"NON_NULL\",\n              \"name\": null,\n              \"ofType\": {\n                \"kind\": \"OBJECT\",\n                \"name\": \"Item\",\n                \"ofType\": null\n              }\n            },\n            \"isDeprecated\": false,\n            \"deprecationReason\": null\n          }\n        ],\n        \"inputFields\": null,\n        \"interfaces\": [],\n        \"enumValues\": null,\n        \"possibleTypes\": null\n      },\n      {\n        \"kind\": \"OBJECT\",\n        \"name\": \"Item\",\n        \"description\": null,\n        \"fields\": [\n          {\n            \"name\": \"id\",\n            \"description\": null,\n            \"args\": [],\n            \"type\": {\n              \"kind\": \"NON_NULL\",\n              \"name\": null,\n              \"ofType\": {\n                \"kind\": \"SCALAR\",\n                \"name\": \"ID\",\n                \"ofType\": null\n              }\n            },\n            \"isDeprecated\": false,\n            \"deprecationReason\": null\n          },\n          {\n            \"name\": \"name\",\n            \"description\": null,\n            \"args\": [],\n            \"type\": {\n              \"kind\": \"NON_NULL\",\n              \"name\": null,\n              \"ofType\": {\n                \"kind\": \"SCALAR\",\n                \"name\": \"String\",\n                \"ofType\": null\n              }\n            },\n            \"isDeprecated\": false,\n            \"deprecationReason\": null\n          }\n        ],\n        \"inputFields\": null,\n        \"interfaces\": [\n          {\n            \"kind\": \"INTERFACE\",\n            \"name\": \"Node\",\n            \"ofType\": null\n          }\n        ],\n        \"enumValues\": null,\n        \"possibleTypes\": null\n      },\n      {\n        \"kind\": \"INTERFACE\",\n        \"name\": \"Node\",\n        \"description\": null,\n        \"fields\": [\n          {\n            \"name\": \"id\",\n            \"description\": null,\n            \"args\": [],\n            \"type\": {\n              \"kind\": \"NON_NULL\",\n              \"name\": null,\n              \"ofType\": {\n                \"kind\": \"SCALAR\",\n                \"name\": \"ID\",\n                \"ofType\": null\n              }\n            },\n            \"isDeprecated\": false,\n            \"deprecationReason\": null\n          }\n        ],\n        \"inputFields\": null,\n        \"interfaces\": null,\n        \"enumValues\": null,\n        \"possibleTypes\": [\n          {\n            \"kind\": \"OBJECT\",\n            \"name\": \"Item\",\n            \"ofType\": null\n          }\n        ]\n      },\n      {\n        \"kind\": \"SCALAR\",\n        \"name\": \"ID\",\n        \"description\": \"The `ID` scalar type represents a unique identifier, often used to refetch an object or as key for a cache. The ID type appears in a JSON response as a String; however, it is not intended to be human-readable. When expected as an input type, any string (such as `\\\"4\\\"`) or integer (such as `4`) input value will be accepted as an ID.\",\n        \"fields\": null,\n        \"inputFields\": null,\n        \"interfaces\": null,\n        \"enumValues\": null,\n        \"possibleTypes\": null\n      },\n      {\n        \"kind\": \"OBJECT\",\n        \"name\": \"PageInfo\",\n        \"description\": null,\n        \"fields\": [\n          {\n            \"name\": \"endCursor\",\n            \"description\": null,\n            \"args\": [],\n            \"type\": {\n              \"kind\": \"SCALAR\",\n              \"name\": \"String\",\n              \"ofType\": null\n            },\n            \"isDeprecated\": false,\n            \"deprecationReason\": null\n          },\n          {\n            \"name\": \"hasNextPage\",\n            \"description\": null,\n            \"args\": [],\n            \"type\": {\n              \"kind\": \"NON_NULL\",\n              \"name\": null,\n              \"ofType\": {\n                \"kind\": \"SCALAR\",\n                \"name\": \"Boolean\",\n                \"ofType\": null\n              }\n            },\n            \"isDeprecated\": false,\n            \"deprecationReason\": null\n          },\n          {\n            \"name\": \"hasPreviousPage\",\n            \"description\": null,\n            \"args\": [],\n            \"type\": {\n              \"kind\": \"NON_NULL\",\n              \"name\": null,\n              \"ofType\": {\n                \"kind\": \"SCALAR\",\n                \"name\": \"Boolean\",\n                \"ofType\": null\n              }\n            },\n            \"isDeprecated\": false,\n            \"deprecationReason\": null\n          },\n          {\n            \"name\": \"startCursor\",\n            \"description\": null,\n            \"args\": [],\n            \"type\": {\n              \"kind\": \"SCALAR\",\n              \"name\": \"String\",\n              \"ofType\": null\n            },\n            \"isDeprecated\": false,\n            \"deprecationReason\": null\n          }\n        ],\n        \"inputFields\": null,\n        \"interfaces\": [],\n        \"enumValues\": null,\n        \"possibleTypes\": null\n      },\n      {\n        \"kind\": \"SCALAR\",\n        \"name\": \"Boolean\",\n        \"description\": \"The `Boolean` scalar type represents `true` or `false`.\",\n        \"fields\": null,\n        \"inputFields\": null,\n        \"interfaces\": null,\n        \"enumValues\": null,\n        \"possibleTypes\": null\n      },\n      {\n        \"kind\": \"OBJECT\",\n        \"name\": \"__Schema\",\n        \"description\": \"A GraphQL Schema defines the capabilities of a GraphQL server. It exposes all available types and directives on the server, as well as the entry points for query, mutation, and subscription operations.\",\n        \"fields\": [\n          {\n            \"name\": \"types\",\n            \"description\": \"A list of all types supported by this server.\",\n            \"args\": [],\n            \"type\": {\n              \"kind\": \"NON_NULL\",\n              \"name\": null,\n              \"ofType\": {\n                \"kind\": \"LIST\",\n                \"name\": null,\n                \"ofType\": {\n                  \"kind\": \"NON_NULL\",\n                  \"name\": null,\n                  \"ofType\": {\n                    \"kind\": \"OBJECT\",\n                    \"name\": \"__Type\",\n                    \"ofType\": null\n                  }\n                }\n              }\n            },\n            \"isDeprecated\": false,\n            \"deprecationReason\": null\n          },\n          {\n            \"name\": \"queryType\",\n            \"description\": \"The type that query operations will be rooted at.\",\n            \"args\": [],\n            \"type\": {\n              \"kind\": \"NON_NULL\",\n              \"name\": null,\n              \"ofType\": {\n                \"kind\": \"OBJECT\",\n                \"name\": \"__Type\",\n                \"ofType\": null\n              }\n            },\n            \"isDeprecated\": false,\n            \"deprecationReason\": null\n          },\n          {\n            \"name\": \"mutationType\",\n            \"description\": \"If this server supports mutation, the type that mutation operations will be rooted at.\",\n            \"args\": [],\n            \"type\": {\n              \"kind\": \"OBJECT\",\n              \"name\": \"__Type\",\n              \"ofType\": null\n            },\n            \"isDeprecated\": false,\n            \"deprecationReason\": null\n          },\n          {\n            \"name\": \"subscriptionType\",\n            \"description\": \"If this server support subscription, the type that subscription operations will be rooted at.\",\n            \"args\": [],\n            \"type\": {\n              \"kind\": \"OBJECT\",\n              \"name\": \"__Type\",\n              \"ofType\": null\n            },\n            \"isDeprecated\": false,\n            \"deprecationReason\": null\n          },\n          {\n            \"name\": \"directives\",\n            \"description\": \"A list of all directives supported by this server.\",\n            \"args\": [],\n            \"type\": {\n              \"kind\": \"NON_NULL\",\n              \"name\": null,\n              \"ofType\": {\n                \"kind\": \"LIST\",\n                \"name\": null,\n                \"ofType\": {\n                  \"kind\": \"NON_NULL\",\n                  \"name\": null,\n                  \"ofType\": {\n                    \"kind\": \"OBJECT\",\n                    \"name\": \"__Directive\",\n                    \"ofType\": null\n                  }\n                }\n              }\n            },\n            \"isDeprecated\": false,\n            \"deprecationReason\": null\n          }\n        ],\n        \"inputFields\": null,\n        \"interfaces\": [],\n        \"enumValues\": null,\n        \"possibleTypes\": null\n      },\n      {\n        \"kind\": \"OBJECT\",\n        \"name\": \"__Type\",\n        \"description\": \"The fundamental unit of any GraphQL Schema is the type. There are many kinds of types in GraphQL as represented by the `__TypeKind` enum.\\n\\nDepending on the kind of a type, certain fields describe information about that type. Scalar types provide no information beyond a name and description, while Enum types provide their values. Object and Interface types provide the fields they describe. Abstract types, Union and Interface, provide the Object types possible at runtime. List and NonNull types compose other types.\",\n        \"fields\": [\n          {\n            \"name\": \"kind\",\n            \"description\": null,\n            \"args\": [],\n            \"type\": {\n              \"kind\": \"NON_NULL\",\n              \"name\": null,\n              \"ofType\": {\n                \"kind\": \"ENUM\",\n                \"name\": \"__TypeKind\",\n                \"ofType\": null\n              }\n            },\n            \"isDeprecated\": false,\n            \"deprecationReason\": null\n          },\n          {\n            \"name\": \"name\",\n            \"description\": null,\n            \"args\": [],\n            \"type\": {\n              \"kind\": \"SCALAR\",\n              \"name\": \"String\",\n              \"ofType\": null\n            },\n            \"isDeprecated\": false,\n            \"deprecationReason\": null\n          },\n          {\n            \"name\": \"description\",\n            \"description\": null,\n            \"args\": [],\n            \"type\": {\n              \"kind\": \"SCALAR\",\n              \"name\": \"String\",\n              \"ofType\": null\n            },\n            \"isDeprecated\": false,\n            \"deprecationReason\": null\n          },\n          {\n            \"name\": \"fields\",\n            \"description\": null,\n            \"args\": [\n              {\n                \"name\": \"includeDeprecated\",\n                \"description\": null,\n                \"type\": {\n                  \"kind\": \"SCALAR\",\n                  \"name\": \"Boolean\",\n                  \"ofType\": null\n                },\n                \"defaultValue\": \"false\"\n              }\n            ],\n            \"type\": {\n              \"kind\": \"LIST\",\n              \"name\": null,\n              \"ofType\": {\n                \"kind\": \"NON_NULL\",\n                \"name\": null,\n                \"ofType\": {\n                  \"kind\": \"OBJECT\",\n                  \"name\": \"__Field\",\n                  \"ofType\": null\n                }\n              }\n            },\n            \"isDeprecated\": false,\n            \"deprecationReason\": null\n          },\n          {\n            \"name\": \"interfaces\",\n            \"description\": null,\n            \"args\": [],\n            \"type\": {\n              \"kind\": \"LIST\",\n              \"name\": null,\n              \"ofType\": {\n                \"kind\": \"NON_NULL\",\n                \"name\": null,\n                \"ofType\": {\n                  \"kind\": \"OBJECT\",\n                  \"name\": \"__Type\",\n                  \"ofType\": null\n                }\n              }\n            },\n            \"isDeprecated\": false,\n            \"deprecationReason\": null\n          },\n          {\n            \"name\": \"possibleTypes\",\n            \"description\": null,\n            \"args\": [],\n            \"type\": {\n              \"kind\": \"LIST\",\n              \"name\": null,\n              \"ofType\": {\n                \"kind\": \"NON_NULL\",\n                \"name\": null,\n                \"ofType\": {\n                  \"kind\": \"OBJECT\",\n                  \"name\": \"__Type\",\n                  \"ofType\": null\n                }\n              }\n            },\n            \"isDeprecated\": false,\n            \"deprecationReason\": null\n          },\n          {\n            \"name\": \"enumValues\",\n            \"description\": null,\n            \"args\": [\n              {\n                \"name\": \"includeDeprecated\",\n                \"description\": null,\n                \"type\": {\n                  \"kind\": \"SCALAR\",\n                  \"name\": \"Boolean\",\n                  \"ofType\": null\n                },\n                \"defaultValue\": \"false\"\n              }\n            ],\n            \"type\": {\n              \"kind\": \"LIST\",\n              \"name\": null,\n              \"ofType\": {\n                \"kind\": \"NON_NULL\",\n                \"name\": null,\n                \"ofType\": {\n                  \"kind\": \"OBJECT\",\n                  \"name\": \"__EnumValue\",\n                  \"ofType\": null\n                }\n              }\n            },\n            \"isDeprecated\": false,\n            \"deprecationReason\": null\n          },\n          {\n            \"name\": \"inputFields\",\n            \"description\": null,\n            \"args\": [],\n            \"type\": {\n              \"kind\": \"LIST\",\n              \"name\": null,\n              \"ofType\": {\n                \"kind\": \"NON_NULL\",\n                \"name\": null,\n                \"ofType\": {\n                  \"kind\": \"OBJECT\",\n                  \"name\": \"__InputValue\",\n                  \"ofType\": null\n                }\n              }\n            },\n            \"isDeprecated\": false,\n            \"deprecationReason\": null\n          },\n          {\n            \"name\": \"ofType\",\n            \"description\": null,\n            \"args\": [],\n            \"type\": {\n              \"kind\": \"OBJECT\",\n              \"name\": \"__Type\",\n              \"ofType\": null\n            },\n            \"isDeprecated\": false,\n            \"deprecationReason\": null\n          }\n        ],\n        \"inputFields\": null,\n        \"interfaces\": [],\n        \"enumValues\": null,\n        \"possibleTypes\": null\n      },\n      {\n        \"kind\": \"ENUM\",\n        \"name\": \"__TypeKind\",\n        \"description\": \"An enum describing what kind of type a given `__Type` is.\",\n        \"fields\": null,\n        \"inputFields\": null,\n        \"interfaces\": null,\n        \"enumValues\": [\n          {\n            \"name\": \"SCALAR\",\n            \"description\": \"Indicates this type is a scalar.\",\n            \"isDeprecated\": false,\n            \"deprecationReason\": null\n          },\n          {\n            \"name\": \"OBJECT\",\n            \"description\": \"Indicates this type is an object. `fields` and `interfaces` are valid fields.\",\n            \"isDeprecated\": false,\n            \"deprecationReason\": null\n          },\n          {\n            \"name\": \"INTERFACE\",\n            \"description\": \"Indicates this type is an interface. `fields` and `possibleTypes` are valid fields.\",\n            \"isDeprecated\": false,\n            \"deprecationReason\": null\n          },\n          {\n            \"name\": \"UNION\",\n            \"description\": \"Indicates this type is a union. `possibleTypes` is a valid field.\",\n            \"isDeprecated\": false,\n            \"deprecationReason\": null\n          },\n          {\n            \"name\": \"ENUM\",\n            \"description\": \"Indicates this type is an enum. `enumValues` is a valid field.\",\n            \"isDeprecated\": false,\n            \"deprecationReason\": null\n          },\n          {\n            \"name\": \"INPUT_OBJECT\",\n            \"description\": \"Indicates this type is an input object. `inputFields` is a valid field.\",\n            \"isDeprecated\": false,\n            \"deprecationReason\": null\n          },\n          {\n            \"name\": \"LIST\",\n            \"description\": \"Indicates this type is a list. `ofType` is a valid field.\",\n            \"isDeprecated\": false,\n            \"deprecationReason\": null\n          },\n          {\n            \"name\": \"NON_NULL\",\n            \"description\": \"Indicates this type is a non-null. `ofType` is a valid field.\",\n            \"isDeprecated\": false,\n            \"deprecationReason\": null\n          }\n        ],\n        \"possibleTypes\": null\n      },\n      {\n        \"kind\": \"OBJECT\",\n        \"name\": \"__Field\",\n        \"description\": \"Object and Interface types are described by a list of Fields, each of which has a name, potentially a list of arguments, and a return type.\",\n        \"fields\": [\n          {\n            \"name\": \"name\",\n            \"description\": null,\n            \"args\": [],\n            \"type\": {\n              \"kind\": \"NON_NULL\",\n              \"name\": null,\n              \"ofType\": {\n                \"kind\": \"SCALAR\",\n                \"name\": \"String\",\n                \"ofType\": null\n              }\n            },\n            \"isDeprecated\": false,\n            \"deprecationReason\": null\n          },\n          {\n            \"name\": \"description\",\n            \"description\": null,\n            \"args\": [],\n            \"type\": {\n              \"kind\": \"SCALAR\",\n              \"name\": \"String\",\n              \"ofType\": null\n            },\n            \"isDeprecated\": false,\n            \"deprecationReason\": null\n          },\n          {\n            \"name\": \"args\",\n            \"description\": null,\n            \"args\": [],\n            \"type\": {\n              \"kind\": \"NON_NULL\",\n              \"name\": null,\n              \"ofType\": {\n                \"kind\": \"LIST\",\n                \"name\": null,\n                \"ofType\": {\n                  \"kind\": \"NON_NULL\",\n                  \"name\": null,\n                  \"ofType\": {\n                    \"kind\": \"OBJECT\",\n                    \"name\": \"__InputValue\",\n                    \"ofType\": null\n                  }\n                }\n              }\n            },\n            \"isDeprecated\": false,\n            \"deprecationReason\": null\n          },\n          {\n            \"name\": \"type\",\n            \"description\": null,\n            \"args\": [],\n            \"type\": {\n              \"kind\": \"NON_NULL\",\n              \"name\": null,\n              \"ofType\": {\n                \"kind\": \"OBJECT\",\n                \"name\": \"__Type\",\n                \"ofType\": null\n              }\n            },\n            \"isDeprecated\": false,\n            \"deprecationReason\": null\n          },\n          {\n            \"name\": \"isDeprecated\",\n            \"description\": null,\n            \"args\": [],\n            \"type\": {\n              \"kind\": \"NON_NULL\",\n              \"name\": null,\n              \"ofType\": {\n                \"kind\": \"SCALAR\",\n                \"name\": \"Boolean\",\n                \"ofType\": null\n              }\n            },\n            \"isDeprecated\": false,\n            \"deprecationReason\": null\n          },\n          {\n            \"name\": \"deprecationReason\",\n            \"description\": null,\n            \"args\": [],\n            \"type\": {\n              \"kind\": \"SCALAR\",\n              \"name\": \"String\",\n              \"ofType\": null\n            },\n            \"isDeprecated\": false,\n            \"deprecationReason\": null\n          }\n        ],\n        \"inputFields\": null,\n        \"interfaces\": [],\n        \"enumValues\": null,\n        \"possibleTypes\": null\n      },\n      {\n        \"kind\": \"OBJECT\",\n        \"name\": \"__InputValue\",\n        \"description\": \"Arguments provided to Fields or Directives and the input fields of an InputObject are represented as Input Values which describe their type and optionally a default value.\",\n        \"fields\": [\n          {\n            \"name\": \"name\",\n            \"description\": null,\n            \"args\": [],\n            \"type\": {\n              \"kind\": \"NON_NULL\",\n              \"name\": null,\n              \"ofType\": {\n                \"kind\": \"SCALAR\",\n                \"name\": \"String\",\n                \"ofType\": null\n              }\n            },\n            \"isDeprecated\": false,\n            \"deprecationReason\": null\n          },\n          {\n            \"name\": \"description\",\n            \"description\": null,\n            \"args\": [],\n            \"type\": {\n              \"kind\": \"SCALAR\",\n              \"name\": \"String\",\n              \"ofType\": null\n            },\n            \"isDeprecated\": false,\n            \"deprecationReason\": null\n          },\n          {\n            \"name\": \"type\",\n            \"description\": null,\n            \"args\": [],\n            \"type\": {\n              \"kind\": \"NON_NULL\",\n              \"name\": null,\n              \"ofType\": {\n                \"kind\": \"OBJECT\",\n                \"name\": \"__Type\",\n                \"ofType\": null\n              }\n            },\n            \"isDeprecated\": false,\n            \"deprecationReason\": null\n          },\n          {\n            \"name\": \"defaultValue\",\n            \"description\": \"A GraphQL-formatted string representing the default value for this input value.\",\n            \"args\": [],\n            \"type\": {\n              \"kind\": \"SCALAR\",\n              \"name\": \"String\",\n              \"ofType\": null\n            },\n            \"isDeprecated\": false,\n            \"deprecationReason\": null\n          }\n        ],\n        \"inputFields\": null,\n        \"interfaces\": [],\n        \"enumValues\": null,\n        \"possibleTypes\": null\n      },\n      {\n        \"kind\": \"OBJECT\",\n        \"name\": \"__EnumValue\",\n        \"description\": \"One possible value for a given Enum. Enum values are unique values, not a placeholder for a string or numeric value. However an Enum value is returned in a JSON response as a string.\",\n        \"fields\": [\n          {\n            \"name\": \"name\",\n            \"description\": null,\n            \"args\": [],\n            \"type\": {\n              \"kind\": \"NON_NULL\",\n              \"name\": null,\n              \"ofType\": {\n                \"kind\": \"SCALAR\",\n                \"name\": \"String\",\n                \"ofType\": null\n              }\n            },\n            \"isDeprecated\": false,\n            \"deprecationReason\": null\n          },\n          {\n            \"name\": \"description\",\n            \"description\": null,\n            \"args\": [],\n            \"type\": {\n              \"kind\": \"SCALAR\",\n              \"name\": \"String\",\n              \"ofType\": null\n            },\n            \"isDeprecated\": false,\n            \"deprecationReason\": null\n          },\n          {\n            \"name\": \"isDeprecated\",\n            \"description\": null,\n            \"args\": [],\n            \"type\": {\n              \"kind\": \"NON_NULL\",\n              \"name\": null,\n              \"ofType\": {\n                \"kind\": \"SCALAR\",\n                \"name\": \"Boolean\",\n                \"ofType\": null\n              }\n            },\n            \"isDeprecated\": false,\n            \"deprecationReason\": null\n          },\n          {\n            \"name\": \"deprecationReason\",\n            \"description\": null,\n            \"args\": [],\n            \"type\": {\n              \"kind\": \"SCALAR\",\n              \"name\": \"String\",\n              \"ofType\": null\n            },\n            \"isDeprecated\": false,\n            \"deprecationReason\": null\n          }\n        ],\n        \"inputFields\": null,\n        \"interfaces\": [],\n        \"enumValues\": null,\n        \"possibleTypes\": null\n      },\n      {\n        \"kind\": \"OBJECT\",\n        \"name\": \"__Directive\",\n        \"description\": \"A Directive provides a way to describe alternate runtime execution and type validation behavior in a GraphQL document.\\n\\nIn some cases, you need to provide options to alter GraphQL's execution behavior in ways field arguments will not suffice, such as conditionally including or skipping a field. Directives provide this by describing additional information to the executor.\",\n        \"fields\": [\n          {\n            \"name\": \"name\",\n            \"description\": null,\n            \"args\": [],\n            \"type\": {\n              \"kind\": \"NON_NULL\",\n              \"name\": null,\n              \"ofType\": {\n                \"kind\": \"SCALAR\",\n                \"name\": \"String\",\n                \"ofType\": null\n              }\n            },\n            \"isDeprecated\": false,\n            \"deprecationReason\": null\n          },\n          {\n            \"name\": \"description\",\n            \"description\": null,\n            \"args\": [],\n            \"type\": {\n              \"kind\": \"SCALAR\",\n              \"name\": \"String\",\n              \"ofType\": null\n            },\n            \"isDeprecated\": false,\n            \"deprecationReason\": null\n          },\n          {\n            \"name\": \"locations\",\n            \"description\": null,\n            \"args\": [],\n            \"type\": {\n              \"kind\": \"NON_NULL\",\n              \"name\": null,\n              \"ofType\": {\n                \"kind\": \"LIST\",\n                \"name\": null,\n                \"ofType\": {\n                  \"kind\": \"NON_NULL\",\n                  \"name\": null,\n                  \"ofType\": {\n                    \"kind\": \"ENUM\",\n                    \"name\": \"__DirectiveLocation\",\n                    \"ofType\": null\n                  }\n                }\n              }\n            },\n            \"isDeprecated\": false,\n            \"deprecationReason\": null\n          },\n          {\n            \"name\": \"args\",\n            \"description\": null,\n            \"args\": [],\n            \"type\": {\n              \"kind\": \"NON_NULL\",\n              \"name\": null,\n              \"ofType\": {\n                \"kind\": \"LIST\",\n                \"name\": null,\n                \"ofType\": {\n                  \"kind\": \"NON_NULL\",\n                  \"name\": null,\n                  \"ofType\": {\n                    \"kind\": \"OBJECT\",\n                    \"name\": \"__InputValue\",\n                    \"ofType\": null\n                  }\n                }\n              }\n            },\n            \"isDeprecated\": false,\n            \"deprecationReason\": null\n          }\n        ],\n        \"inputFields\": null,\n        \"interfaces\": [],\n        \"enumValues\": null,\n        \"possibleTypes\": null\n      },\n      {\n        \"kind\": \"ENUM\",\n        \"name\": \"__DirectiveLocation\",\n        \"description\": \"A Directive can be adjacent to many parts of the GraphQL language, a __DirectiveLocation describes one such possible adjacencies.\",\n        \"fields\": null,\n        \"inputFields\": null,\n        \"interfaces\": null,\n        \"enumValues\": [\n          {\n            \"name\": \"QUERY\",\n            \"description\": \"Location adjacent to a query operation.\",\n            \"isDeprecated\": false,\n            \"deprecationReason\": null\n          },\n          {\n            \"name\": \"MUTATION\",\n            \"description\": \"Location adjacent to a mutation operation.\",\n            \"isDeprecated\": false,\n            \"deprecationReason\": null\n          },\n          {\n            \"name\": \"SUBSCRIPTION\",\n            \"description\": \"Location adjacent to a subscription operation.\",\n            \"isDeprecated\": false,\n            \"deprecationReason\": null\n          },\n          {\n            \"name\": \"FIELD\",\n            \"description\": \"Location adjacent to a field.\",\n            \"isDeprecated\": false,\n            \"deprecationReason\": null\n          },\n          {\n            \"name\": \"FRAGMENT_DEFINITION\",\n            \"description\": \"Location adjacent to a fragment definition.\",\n            \"isDeprecated\": false,\n            \"deprecationReason\": null\n          },\n          {\n            \"name\": \"FRAGMENT_SPREAD\",\n            \"description\": \"Location adjacent to a fragment spread.\",\n            \"isDeprecated\": false,\n            \"deprecationReason\": null\n          },\n          {\n            \"name\": \"INLINE_FRAGMENT\",\n            \"description\": \"Location adjacent to an inline fragment.\",\n            \"isDeprecated\": false,\n            \"deprecationReason\": null\n          },\n          {\n            \"name\": \"VARIABLE_DEFINITION\",\n            \"description\": \"Location adjacent to a variable definition.\",\n            \"isDeprecated\": false,\n            \"deprecationReason\": null\n          },\n          {\n            \"name\": \"SCHEMA\",\n            \"description\": \"Location adjacent to a schema definition.\",\n            \"isDeprecated\": false,\n            \"deprecationReason\": null\n          },\n          {\n            \"name\": \"SCALAR\",\n            \"description\": \"Location adjacent to a scalar definition.\",\n            \"isDeprecated\": false,\n            \"deprecationReason\": null\n          },\n          {\n            \"name\": \"OBJECT\",\n            \"description\": \"Location adjacent to an object type definition.\",\n            \"isDeprecated\": false,\n            \"deprecationReason\": null\n          },\n          {\n            \"name\": \"FIELD_DEFINITION\",\n            \"description\": \"Location adjacent to a field definition.\",\n            \"isDeprecated\": false,\n            \"deprecationReason\": null\n          },\n          {\n            \"name\": \"ARGUMENT_DEFINITION\",\n            \"description\": \"Location adjacent to an argument definition.\",\n            \"isDeprecated\": false,\n            \"deprecationReason\": null\n          },\n          {\n            \"name\": \"INTERFACE\",\n            \"description\": \"Location adjacent to an interface definition.\",\n            \"isDeprecated\": false,\n            \"deprecationReason\": null\n          },\n          {\n            \"name\": \"UNION\",\n            \"description\": \"Location adjacent to a union definition.\",\n            \"isDeprecated\": false,\n            \"deprecationReason\": null\n          },\n          {\n            \"name\": \"ENUM\",\n            \"description\": \"Location adjacent to an enum definition.\",\n            \"isDeprecated\": false,\n            \"deprecationReason\": null\n          },\n          {\n            \"name\": \"ENUM_VALUE\",\n            \"description\": \"Location adjacent to an enum value definition.\",\n            \"isDeprecated\": false,\n            \"deprecationReason\": null\n          },\n          {\n            \"name\": \"INPUT_OBJECT\",\n            \"description\": \"Location adjacent to an input object type definition.\",\n            \"isDeprecated\": false,\n            \"deprecationReason\": null\n          },\n          {\n            \"name\": \"INPUT_FIELD_DEFINITION\",\n            \"description\": \"Location adjacent to an input object field definition.\",\n            \"isDeprecated\": false,\n            \"deprecationReason\": null\n          }\n        ],\n        \"possibleTypes\": null\n      }\n    ],\n    \"directives\": [\n      {\n        \"name\": \"skip\",\n        \"description\": \"Directs the executor to skip this field or fragment when the `if` argument is true.\",\n        \"locations\": [\"FIELD\", \"FRAGMENT_SPREAD\", \"INLINE_FRAGMENT\"],\n        \"args\": [\n          {\n            \"name\": \"if\",\n            \"description\": \"Skipped when true.\",\n            \"type\": {\n              \"kind\": \"NON_NULL\",\n              \"name\": null,\n              \"ofType\": {\n                \"kind\": \"SCALAR\",\n                \"name\": \"Boolean\",\n                \"ofType\": null\n              }\n            },\n            \"defaultValue\": null\n          }\n        ]\n      },\n      {\n        \"name\": \"include\",\n        \"description\": \"Directs the executor to include this field or fragment only when the `if` argument is true.\",\n        \"locations\": [\"FIELD\", \"FRAGMENT_SPREAD\", \"INLINE_FRAGMENT\"],\n        \"args\": [\n          {\n            \"name\": \"if\",\n            \"description\": \"Included when true.\",\n            \"type\": {\n              \"kind\": \"NON_NULL\",\n              \"name\": null,\n              \"ofType\": {\n                \"kind\": \"SCALAR\",\n                \"name\": \"Boolean\",\n                \"ofType\": null\n              }\n            },\n            \"defaultValue\": null\n          }\n        ]\n      },\n      {\n        \"name\": \"deprecated\",\n        \"description\": \"Marks an element of a GraphQL schema as no longer supported.\",\n        \"locations\": [\"FIELD_DEFINITION\", \"ENUM_VALUE\"],\n        \"args\": [\n          {\n            \"name\": \"reason\",\n            \"description\": \"Explains why this element was deprecated, usually also including a suggestion for how to access supported similar data. Formatted using the Markdown syntax (as specified by [CommonMark](https://commonmark.org/).\",\n            \"type\": {\n              \"kind\": \"SCALAR\",\n              \"name\": \"String\",\n              \"ofType\": null\n            },\n            \"defaultValue\": \"\\\"No longer supported\\\"\"\n          }\n        ]\n      }\n    ]\n  }\n}\n"
  },
  {
    "path": "exchanges/graphcache/src/test-utils/simple_schema.json",
    "content": "{\n  \"__schema\": {\n    \"queryType\": {\n      \"name\": \"Query\"\n    },\n    \"mutationType\": {\n      \"name\": \"Mutation\"\n    },\n    \"subscriptionType\": {\n      \"name\": \"Subscription\"\n    },\n    \"types\": [\n      {\n        \"kind\": \"OBJECT\",\n        \"name\": \"Query\",\n        \"fields\": [\n          {\n            \"name\": \"todos\",\n            \"args\": [],\n            \"type\": {\n              \"kind\": \"LIST\",\n              \"name\": null,\n              \"ofType\": {\n                \"kind\": \"OBJECT\",\n                \"name\": \"Todo\",\n                \"ofType\": null\n              }\n            }\n          },\n          {\n            \"name\": \"latestTodo\",\n            \"args\": [],\n            \"type\": {\n              \"kind\": \"NON_NULL\",\n              \"name\": null,\n              \"ofType\": {\n                \"kind\": \"UNION\",\n                \"name\": \"LatestTodoResult\",\n                \"ofType\": null\n              }\n            }\n          }\n        ],\n        \"inputFields\": null,\n        \"interfaces\": [],\n        \"enumValues\": null,\n        \"possibleTypes\": null\n      },\n      {\n        \"name\": \"LatestTodoResult\",\n        \"kind\": \"UNION\",\n        \"args\": [],\n        \"possibleTypes\": [\n          {\n            \"kind\": \"OBJECT\",\n            \"name\": \"Todo\",\n            \"ofType\": null\n          },\n          {\n            \"kind\": \"OBJECT\",\n            \"name\": \"NoTodosError\",\n            \"ofType\": null\n          }\n        ]\n      },\n      {\n        \"kind\": \"OBJECT\",\n        \"name\": \"NoTodosError\",\n        \"interfaces\": [],\n        \"fields\": [\n          {\n            \"name\": \"message\",\n            \"args\": [],\n            \"type\": {\n              \"kind\": \"NON_NULL\",\n              \"name\": null,\n              \"ofType\": {\n                \"kind\": \"SCALAR\",\n                \"name\": \"String\",\n                \"ofType\": null\n              }\n            },\n            \"isDeprecated\": false,\n            \"deprecationReason\": null\n          }\n        ]\n      },\n      {\n        \"kind\": \"OBJECT\",\n        \"name\": \"Todo\",\n        \"fields\": [\n          {\n            \"name\": \"id\",\n            \"args\": [],\n            \"type\": {\n              \"kind\": \"NON_NULL\",\n              \"name\": null,\n              \"ofType\": {\n                \"kind\": \"SCALAR\",\n                \"name\": \"ID\",\n                \"ofType\": null\n              }\n            }\n          },\n          {\n            \"name\": \"text\",\n            \"args\": [],\n            \"type\": {\n              \"kind\": \"NON_NULL\",\n              \"name\": null,\n              \"ofType\": {\n                \"kind\": \"SCALAR\",\n                \"name\": \"String\",\n                \"ofType\": null\n              }\n            }\n          },\n          {\n            \"name\": \"complete\",\n            \"args\": [],\n            \"type\": {\n              \"kind\": \"SCALAR\",\n              \"name\": \"Boolean\",\n              \"ofType\": null\n            }\n          },\n          {\n            \"name\": \"author\",\n            \"args\": [],\n            \"type\": {\n              \"kind\": \"OBJECT\",\n              \"name\": \"Author\",\n              \"ofType\": null\n            }\n          }\n        ],\n        \"inputFields\": null,\n        \"interfaces\": [],\n        \"enumValues\": null,\n        \"possibleTypes\": null\n      },\n      {\n        \"kind\": \"SCALAR\",\n        \"name\": \"ID\",\n        \"fields\": null,\n        \"inputFields\": null,\n        \"interfaces\": null,\n        \"enumValues\": null,\n        \"possibleTypes\": null\n      },\n      {\n        \"kind\": \"SCALAR\",\n        \"name\": \"String\",\n        \"fields\": null,\n        \"inputFields\": null,\n        \"interfaces\": null,\n        \"enumValues\": null,\n        \"possibleTypes\": null\n      },\n      {\n        \"kind\": \"SCALAR\",\n        \"name\": \"Boolean\",\n        \"fields\": null,\n        \"inputFields\": null,\n        \"interfaces\": null,\n        \"enumValues\": null,\n        \"possibleTypes\": null\n      },\n      {\n        \"kind\": \"OBJECT\",\n        \"name\": \"Author\",\n        \"fields\": [\n          {\n            \"name\": \"id\",\n            \"args\": [],\n            \"type\": {\n              \"kind\": \"NON_NULL\",\n              \"name\": null,\n              \"ofType\": {\n                \"kind\": \"SCALAR\",\n                \"name\": \"ID\",\n                \"ofType\": null\n              }\n            }\n          },\n          {\n            \"name\": \"name\",\n            \"args\": [],\n            \"type\": {\n              \"kind\": \"NON_NULL\",\n              \"name\": null,\n              \"ofType\": {\n                \"kind\": \"SCALAR\",\n                \"name\": \"String\",\n                \"ofType\": null\n              }\n            }\n          },\n          {\n            \"name\": \"known\",\n            \"args\": [],\n            \"type\": {\n              \"kind\": \"SCALAR\",\n              \"name\": \"Boolean\",\n              \"ofType\": null\n            }\n          }\n        ],\n        \"inputFields\": null,\n        \"interfaces\": [],\n        \"enumValues\": null,\n        \"possibleTypes\": null\n      },\n      {\n        \"kind\": \"OBJECT\",\n        \"name\": \"Mutation\",\n        \"fields\": [\n          {\n            \"name\": \"toggleTodo\",\n            \"args\": [\n              {\n                \"name\": \"id\",\n                \"type\": {\n                  \"kind\": \"NON_NULL\",\n                  \"name\": null,\n                  \"ofType\": {\n                    \"kind\": \"SCALAR\",\n                    \"name\": \"ID\",\n                    \"ofType\": null\n                  }\n                }\n              }\n            ],\n            \"type\": {\n              \"kind\": \"OBJECT\",\n              \"name\": \"Todo\",\n              \"ofType\": null\n            }\n          }\n        ],\n        \"inputFields\": null,\n        \"interfaces\": [],\n        \"enumValues\": null,\n        \"possibleTypes\": null\n      },\n      {\n        \"kind\": \"OBJECT\",\n        \"name\": \"Subscription\",\n        \"fields\": [\n          {\n            \"name\": \"newTodo\",\n            \"args\": [],\n            \"type\": {\n              \"kind\": \"OBJECT\",\n              \"name\": \"Todo\",\n              \"ofType\": null\n            },\n            \"isDeprecated\": false,\n            \"deprecationReason\": null\n          }\n        ],\n        \"inputFields\": null,\n        \"interfaces\": [],\n        \"enumValues\": null,\n        \"possibleTypes\": null\n      },\n      {\n        \"kind\": \"OBJECT\",\n        \"name\": \"__Schema\",\n        \"fields\": [\n          {\n            \"name\": \"types\",\n            \"args\": [],\n            \"type\": {\n              \"kind\": \"NON_NULL\",\n              \"name\": null,\n              \"ofType\": {\n                \"kind\": \"LIST\",\n                \"name\": null,\n                \"ofType\": {\n                  \"kind\": \"NON_NULL\",\n                  \"name\": null,\n                  \"ofType\": {\n                    \"kind\": \"OBJECT\",\n                    \"name\": \"__Type\",\n                    \"ofType\": null\n                  }\n                }\n              }\n            }\n          },\n          {\n            \"name\": \"queryType\",\n            \"args\": [],\n            \"type\": {\n              \"kind\": \"NON_NULL\",\n              \"name\": null,\n              \"ofType\": {\n                \"kind\": \"OBJECT\",\n                \"name\": \"__Type\",\n                \"ofType\": null\n              }\n            }\n          },\n          {\n            \"name\": \"mutationType\",\n            \"args\": [],\n            \"type\": {\n              \"kind\": \"OBJECT\",\n              \"name\": \"__Type\",\n              \"ofType\": null\n            }\n          },\n          {\n            \"name\": \"subscriptionType\",\n            \"args\": [],\n            \"type\": {\n              \"kind\": \"OBJECT\",\n              \"name\": \"__Type\",\n              \"ofType\": null\n            }\n          },\n          {\n            \"name\": \"directives\",\n            \"args\": [],\n            \"type\": {\n              \"kind\": \"NON_NULL\",\n              \"name\": null,\n              \"ofType\": {\n                \"kind\": \"LIST\",\n                \"name\": null,\n                \"ofType\": {\n                  \"kind\": \"NON_NULL\",\n                  \"name\": null,\n                  \"ofType\": {\n                    \"kind\": \"OBJECT\",\n                    \"name\": \"__Directive\",\n                    \"ofType\": null\n                  }\n                }\n              }\n            }\n          }\n        ],\n        \"inputFields\": null,\n        \"interfaces\": [],\n        \"enumValues\": null,\n        \"possibleTypes\": null\n      },\n      {\n        \"kind\": \"OBJECT\",\n        \"name\": \"__Type\",\n        \"fields\": [\n          {\n            \"name\": \"kind\",\n            \"args\": [],\n            \"type\": {\n              \"kind\": \"NON_NULL\",\n              \"name\": null,\n              \"ofType\": {\n                \"kind\": \"ENUM\",\n                \"name\": \"__TypeKind\",\n                \"ofType\": null\n              }\n            }\n          },\n          {\n            \"name\": \"name\",\n            \"args\": [],\n            \"type\": {\n              \"kind\": \"SCALAR\",\n              \"name\": \"String\",\n              \"ofType\": null\n            }\n          },\n          {\n            \"name\": \"description\",\n            \"args\": [],\n            \"type\": {\n              \"kind\": \"SCALAR\",\n              \"name\": \"String\",\n              \"ofType\": null\n            }\n          },\n          {\n            \"name\": \"fields\",\n            \"args\": [\n              {\n                \"name\": \"includeDeprecated\",\n                \"type\": {\n                  \"kind\": \"SCALAR\",\n                  \"name\": \"Boolean\",\n                  \"ofType\": null\n                }\n              }\n            ],\n            \"type\": {\n              \"kind\": \"LIST\",\n              \"name\": null,\n              \"ofType\": {\n                \"kind\": \"NON_NULL\",\n                \"name\": null,\n                \"ofType\": {\n                  \"kind\": \"OBJECT\",\n                  \"name\": \"__Field\",\n                  \"ofType\": null\n                }\n              }\n            }\n          },\n          {\n            \"name\": \"interfaces\",\n            \"args\": [],\n            \"type\": {\n              \"kind\": \"LIST\",\n              \"name\": null,\n              \"ofType\": {\n                \"kind\": \"NON_NULL\",\n                \"name\": null,\n                \"ofType\": {\n                  \"kind\": \"OBJECT\",\n                  \"name\": \"__Type\",\n                  \"ofType\": null\n                }\n              }\n            }\n          },\n          {\n            \"name\": \"possibleTypes\",\n            \"args\": [],\n            \"type\": {\n              \"kind\": \"LIST\",\n              \"name\": null,\n              \"ofType\": {\n                \"kind\": \"NON_NULL\",\n                \"name\": null,\n                \"ofType\": {\n                  \"kind\": \"OBJECT\",\n                  \"name\": \"__Type\",\n                  \"ofType\": null\n                }\n              }\n            }\n          },\n          {\n            \"name\": \"enumValues\",\n            \"args\": [\n              {\n                \"name\": \"includeDeprecated\",\n                \"type\": {\n                  \"kind\": \"SCALAR\",\n                  \"name\": \"Boolean\",\n                  \"ofType\": null\n                }\n              }\n            ],\n            \"type\": {\n              \"kind\": \"LIST\",\n              \"name\": null,\n              \"ofType\": {\n                \"kind\": \"NON_NULL\",\n                \"name\": null,\n                \"ofType\": {\n                  \"kind\": \"OBJECT\",\n                  \"name\": \"__EnumValue\",\n                  \"ofType\": null\n                }\n              }\n            }\n          },\n          {\n            \"name\": \"inputFields\",\n            \"args\": [],\n            \"type\": {\n              \"kind\": \"LIST\",\n              \"name\": null,\n              \"ofType\": {\n                \"kind\": \"NON_NULL\",\n                \"name\": null,\n                \"ofType\": {\n                  \"kind\": \"OBJECT\",\n                  \"name\": \"__InputValue\",\n                  \"ofType\": null\n                }\n              }\n            }\n          },\n          {\n            \"name\": \"ofType\",\n            \"args\": [],\n            \"type\": {\n              \"kind\": \"OBJECT\",\n              \"name\": \"__Type\",\n              \"ofType\": null\n            }\n          }\n        ],\n        \"inputFields\": null,\n        \"interfaces\": [],\n        \"enumValues\": null,\n        \"possibleTypes\": null\n      },\n      {\n        \"kind\": \"ENUM\",\n        \"name\": \"__TypeKind\",\n        \"fields\": null,\n        \"inputFields\": null,\n        \"interfaces\": null,\n        \"enumValues\": [\n          {\n            \"name\": \"SCALAR\"\n          },\n          {\n            \"name\": \"OBJECT\"\n          },\n          {\n            \"name\": \"INTERFACE\"\n          },\n          {\n            \"name\": \"UNION\"\n          },\n          {\n            \"name\": \"ENUM\"\n          },\n          {\n            \"name\": \"INPUT_OBJECT\"\n          },\n          {\n            \"name\": \"LIST\"\n          },\n          {\n            \"name\": \"NON_NULL\"\n          }\n        ],\n        \"possibleTypes\": null\n      },\n      {\n        \"kind\": \"OBJECT\",\n        \"name\": \"__Field\",\n        \"fields\": [\n          {\n            \"name\": \"name\",\n            \"args\": [],\n            \"type\": {\n              \"kind\": \"NON_NULL\",\n              \"name\": null,\n              \"ofType\": {\n                \"kind\": \"SCALAR\",\n                \"name\": \"String\",\n                \"ofType\": null\n              }\n            }\n          },\n          {\n            \"name\": \"description\",\n            \"args\": [],\n            \"type\": {\n              \"kind\": \"SCALAR\",\n              \"name\": \"String\",\n              \"ofType\": null\n            }\n          },\n          {\n            \"name\": \"args\",\n            \"args\": [],\n            \"type\": {\n              \"kind\": \"NON_NULL\",\n              \"name\": null,\n              \"ofType\": {\n                \"kind\": \"LIST\",\n                \"name\": null,\n                \"ofType\": {\n                  \"kind\": \"NON_NULL\",\n                  \"name\": null,\n                  \"ofType\": {\n                    \"kind\": \"OBJECT\",\n                    \"name\": \"__InputValue\",\n                    \"ofType\": null\n                  }\n                }\n              }\n            }\n          },\n          {\n            \"name\": \"type\",\n            \"args\": [],\n            \"type\": {\n              \"kind\": \"NON_NULL\",\n              \"name\": null,\n              \"ofType\": {\n                \"kind\": \"OBJECT\",\n                \"name\": \"__Type\",\n                \"ofType\": null\n              }\n            }\n          },\n          {\n            \"name\": \"isDeprecated\",\n            \"args\": [],\n            \"type\": {\n              \"kind\": \"NON_NULL\",\n              \"name\": null,\n              \"ofType\": {\n                \"kind\": \"SCALAR\",\n                \"name\": \"Boolean\",\n                \"ofType\": null\n              }\n            }\n          },\n          {\n            \"name\": \"deprecationReason\",\n            \"args\": [],\n            \"type\": {\n              \"kind\": \"SCALAR\",\n              \"name\": \"String\",\n              \"ofType\": null\n            }\n          }\n        ],\n        \"inputFields\": null,\n        \"interfaces\": [],\n        \"enumValues\": null,\n        \"possibleTypes\": null\n      },\n      {\n        \"kind\": \"OBJECT\",\n        \"name\": \"__InputValue\",\n        \"fields\": [\n          {\n            \"name\": \"name\",\n            \"args\": [],\n            \"type\": {\n              \"kind\": \"NON_NULL\",\n              \"name\": null,\n              \"ofType\": {\n                \"kind\": \"SCALAR\",\n                \"name\": \"String\",\n                \"ofType\": null\n              }\n            }\n          },\n          {\n            \"name\": \"description\",\n            \"args\": [],\n            \"type\": {\n              \"kind\": \"SCALAR\",\n              \"name\": \"String\",\n              \"ofType\": null\n            }\n          },\n          {\n            \"name\": \"type\",\n            \"args\": [],\n            \"type\": {\n              \"kind\": \"NON_NULL\",\n              \"name\": null,\n              \"ofType\": {\n                \"kind\": \"OBJECT\",\n                \"name\": \"__Type\",\n                \"ofType\": null\n              }\n            }\n          },\n          {\n            \"name\": \"defaultValue\",\n            \"args\": [],\n            \"type\": {\n              \"kind\": \"SCALAR\",\n              \"name\": \"String\",\n              \"ofType\": null\n            }\n          }\n        ],\n        \"inputFields\": null,\n        \"interfaces\": [],\n        \"enumValues\": null,\n        \"possibleTypes\": null\n      },\n      {\n        \"kind\": \"OBJECT\",\n        \"name\": \"__EnumValue\",\n        \"fields\": [\n          {\n            \"name\": \"name\",\n            \"args\": [],\n            \"type\": {\n              \"kind\": \"NON_NULL\",\n              \"name\": null,\n              \"ofType\": {\n                \"kind\": \"SCALAR\",\n                \"name\": \"String\",\n                \"ofType\": null\n              }\n            }\n          },\n          {\n            \"name\": \"description\",\n            \"args\": [],\n            \"type\": {\n              \"kind\": \"SCALAR\",\n              \"name\": \"String\",\n              \"ofType\": null\n            }\n          },\n          {\n            \"name\": \"isDeprecated\",\n            \"args\": [],\n            \"type\": {\n              \"kind\": \"NON_NULL\",\n              \"name\": null,\n              \"ofType\": {\n                \"kind\": \"SCALAR\",\n                \"name\": \"Boolean\",\n                \"ofType\": null\n              }\n            }\n          },\n          {\n            \"name\": \"deprecationReason\",\n            \"args\": [],\n            \"type\": {\n              \"kind\": \"SCALAR\",\n              \"name\": \"String\",\n              \"ofType\": null\n            }\n          }\n        ],\n        \"inputFields\": null,\n        \"interfaces\": [],\n        \"enumValues\": null,\n        \"possibleTypes\": null\n      },\n      {\n        \"kind\": \"OBJECT\",\n        \"name\": \"__Directive\",\n        \"fields\": [\n          {\n            \"name\": \"name\",\n            \"args\": [],\n            \"type\": {\n              \"kind\": \"NON_NULL\",\n              \"name\": null,\n              \"ofType\": {\n                \"kind\": \"SCALAR\",\n                \"name\": \"String\",\n                \"ofType\": null\n              }\n            }\n          },\n          {\n            \"name\": \"description\",\n            \"args\": [],\n            \"type\": {\n              \"kind\": \"SCALAR\",\n              \"name\": \"String\",\n              \"ofType\": null\n            }\n          },\n          {\n            \"name\": \"locations\",\n            \"args\": [],\n            \"type\": {\n              \"kind\": \"NON_NULL\",\n              \"name\": null,\n              \"ofType\": {\n                \"kind\": \"LIST\",\n                \"name\": null,\n                \"ofType\": {\n                  \"kind\": \"NON_NULL\",\n                  \"name\": null,\n                  \"ofType\": {\n                    \"kind\": \"ENUM\",\n                    \"name\": \"__DirectiveLocation\",\n                    \"ofType\": null\n                  }\n                }\n              }\n            }\n          },\n          {\n            \"name\": \"args\",\n            \"args\": [],\n            \"type\": {\n              \"kind\": \"NON_NULL\",\n              \"name\": null,\n              \"ofType\": {\n                \"kind\": \"LIST\",\n                \"name\": null,\n                \"ofType\": {\n                  \"kind\": \"NON_NULL\",\n                  \"name\": null,\n                  \"ofType\": {\n                    \"kind\": \"OBJECT\",\n                    \"name\": \"__InputValue\",\n                    \"ofType\": null\n                  }\n                }\n              }\n            }\n          }\n        ],\n        \"inputFields\": null,\n        \"interfaces\": [],\n        \"enumValues\": null,\n        \"possibleTypes\": null\n      },\n      {\n        \"kind\": \"ENUM\",\n        \"name\": \"__DirectiveLocation\",\n        \"fields\": null,\n        \"inputFields\": null,\n        \"interfaces\": null,\n        \"enumValues\": [\n          {\n            \"name\": \"QUERY\"\n          },\n          {\n            \"name\": \"MUTATION\"\n          },\n          {\n            \"name\": \"SUBSCRIPTION\"\n          },\n          {\n            \"name\": \"FIELD\"\n          },\n          {\n            \"name\": \"FRAGMENT_DEFINITION\"\n          },\n          {\n            \"name\": \"FRAGMENT_SPREAD\"\n          },\n          {\n            \"name\": \"INLINE_FRAGMENT\"\n          },\n          {\n            \"name\": \"VARIABLE_DEFINITION\"\n          },\n          {\n            \"name\": \"SCHEMA\"\n          },\n          {\n            \"name\": \"SCALAR\"\n          },\n          {\n            \"name\": \"OBJECT\"\n          },\n          {\n            \"name\": \"FIELD_DEFINITION\"\n          },\n          {\n            \"name\": \"ARGUMENT_DEFINITION\"\n          },\n          {\n            \"name\": \"INTERFACE\"\n          },\n          {\n            \"name\": \"UNION\"\n          },\n          {\n            \"name\": \"ENUM\"\n          },\n          {\n            \"name\": \"ENUM_VALUE\"\n          },\n          {\n            \"name\": \"INPUT_OBJECT\"\n          },\n          {\n            \"name\": \"INPUT_FIELD_DEFINITION\"\n          }\n        ],\n        \"possibleTypes\": null\n      },\n      {\n        \"kind\": \"INTERFACE\",\n        \"name\": \"ITodo\",\n        \"fields\": [\n          {\n            \"name\": \"id\",\n            \"args\": [],\n            \"type\": {\n              \"kind\": \"NON_NULL\",\n              \"name\": null,\n              \"ofType\": {\n                \"kind\": \"SCALAR\",\n                \"name\": \"ID\",\n                \"ofType\": null\n              }\n            }\n          },\n          {\n            \"name\": \"text\",\n            \"args\": [],\n            \"type\": {\n              \"kind\": \"NON_NULL\",\n              \"name\": null,\n              \"ofType\": {\n                \"kind\": \"SCALAR\",\n                \"name\": \"String\",\n                \"ofType\": null\n              }\n            }\n          },\n          {\n            \"name\": \"complete\",\n            \"args\": [],\n            \"type\": {\n              \"kind\": \"SCALAR\",\n              \"name\": \"Boolean\",\n              \"ofType\": null\n            }\n          },\n          {\n            \"name\": \"author\",\n            \"args\": [],\n            \"type\": {\n              \"kind\": \"OBJECT\",\n              \"name\": \"Author\",\n              \"ofType\": null\n            }\n          }\n        ],\n        \"inputFields\": null,\n        \"interfaces\": null,\n        \"enumValues\": null,\n        \"possibleTypes\": [\n          {\n            \"kind\": \"OBJECT\",\n            \"name\": \"BigTodo\",\n            \"ofType\": null\n          },\n          {\n            \"kind\": \"OBJECT\",\n            \"name\": \"SmallTodo\",\n            \"ofType\": null\n          }\n        ]\n      },\n      {\n        \"kind\": \"OBJECT\",\n        \"name\": \"BigTodo\",\n        \"fields\": [\n          {\n            \"name\": \"id\",\n            \"args\": [],\n            \"type\": {\n              \"kind\": \"NON_NULL\",\n              \"name\": null,\n              \"ofType\": {\n                \"kind\": \"SCALAR\",\n                \"name\": \"ID\",\n                \"ofType\": null\n              }\n            }\n          },\n          {\n            \"name\": \"text\",\n            \"args\": [],\n            \"type\": {\n              \"kind\": \"NON_NULL\",\n              \"name\": null,\n              \"ofType\": {\n                \"kind\": \"SCALAR\",\n                \"name\": \"String\",\n                \"ofType\": null\n              }\n            }\n          },\n          {\n            \"name\": \"complete\",\n            \"args\": [],\n            \"type\": {\n              \"kind\": \"SCALAR\",\n              \"name\": \"Boolean\",\n              \"ofType\": null\n            }\n          },\n          {\n            \"name\": \"author\",\n            \"args\": [],\n            \"type\": {\n              \"kind\": \"OBJECT\",\n              \"name\": \"Author\",\n              \"ofType\": null\n            }\n          },\n          {\n            \"name\": \"wallOfText\",\n            \"args\": [],\n            \"type\": {\n              \"kind\": \"SCALAR\",\n              \"name\": \"String\",\n              \"ofType\": null\n            }\n          }\n        ],\n        \"inputFields\": null,\n        \"interfaces\": [\n          {\n            \"kind\": \"INTERFACE\",\n            \"name\": \"ITodo\",\n            \"ofType\": null\n          }\n        ],\n        \"enumValues\": null,\n        \"possibleTypes\": null\n      },\n      {\n        \"kind\": \"OBJECT\",\n        \"name\": \"SmallTodo\",\n        \"fields\": [\n          {\n            \"name\": \"id\",\n            \"args\": [],\n            \"type\": {\n              \"kind\": \"NON_NULL\",\n              \"name\": null,\n              \"ofType\": {\n                \"kind\": \"SCALAR\",\n                \"name\": \"ID\",\n                \"ofType\": null\n              }\n            }\n          },\n          {\n            \"name\": \"text\",\n            \"args\": [],\n            \"type\": {\n              \"kind\": \"NON_NULL\",\n              \"name\": null,\n              \"ofType\": {\n                \"kind\": \"SCALAR\",\n                \"name\": \"String\",\n                \"ofType\": null\n              }\n            }\n          },\n          {\n            \"name\": \"complete\",\n            \"args\": [],\n            \"type\": {\n              \"kind\": \"SCALAR\",\n              \"name\": \"Boolean\",\n              \"ofType\": null\n            }\n          },\n          {\n            \"name\": \"author\",\n            \"args\": [],\n            \"type\": {\n              \"kind\": \"OBJECT\",\n              \"name\": \"Author\",\n              \"ofType\": null\n            }\n          },\n          {\n            \"name\": \"maxLength\",\n            \"args\": [],\n            \"type\": {\n              \"kind\": \"SCALAR\",\n              \"name\": \"Int\",\n              \"ofType\": null\n            }\n          }\n        ],\n        \"inputFields\": null,\n        \"interfaces\": [\n          {\n            \"kind\": \"INTERFACE\",\n            \"name\": \"ITodo\",\n            \"ofType\": null\n          }\n        ],\n        \"enumValues\": null,\n        \"possibleTypes\": null\n      },\n      {\n        \"kind\": \"SCALAR\",\n        \"name\": \"Int\",\n        \"fields\": null,\n        \"inputFields\": null,\n        \"interfaces\": null,\n        \"enumValues\": null,\n        \"possibleTypes\": null\n      },\n      {\n        \"kind\": \"ENUM\",\n        \"name\": \"Todos\",\n        \"fields\": null,\n        \"inputFields\": null,\n        \"interfaces\": null,\n        \"enumValues\": [\n          {\n            \"name\": \"SmallTodo\"\n          },\n          {\n            \"name\": \"BigTodo\"\n          }\n        ],\n        \"possibleTypes\": null\n      },\n      {\n        \"kind\": \"UNION\",\n        \"name\": \"Search\",\n        \"fields\": null,\n        \"inputFields\": null,\n        \"interfaces\": null,\n        \"enumValues\": null,\n        \"possibleTypes\": [\n          {\n            \"kind\": \"OBJECT\",\n            \"name\": \"SmallTodo\",\n            \"ofType\": null\n          },\n          {\n            \"kind\": \"OBJECT\",\n            \"name\": \"BigTodo\",\n            \"ofType\": null\n          }\n        ]\n      },\n      {\n        \"kind\": \"ENUM\",\n        \"name\": \"CacheControlScope\",\n        \"fields\": null,\n        \"inputFields\": null,\n        \"interfaces\": null,\n        \"enumValues\": [\n          {\n            \"name\": \"PUBLIC\"\n          },\n          {\n            \"name\": \"PRIVATE\"\n          }\n        ],\n        \"possibleTypes\": null\n      },\n      {\n        \"kind\": \"SCALAR\",\n        \"name\": \"Upload\",\n        \"fields\": null,\n        \"inputFields\": null,\n        \"interfaces\": null,\n        \"enumValues\": null,\n        \"possibleTypes\": null\n      }\n    ]\n  }\n}\n"
  },
  {
    "path": "exchanges/graphcache/src/test-utils/suite.test.ts",
    "content": "import { DocumentNode } from 'graphql';\nimport { gql } from '@urql/core';\nimport { it, expect } from 'vitest';\nimport { __initAnd_query as query } from '../operations/query';\nimport { __initAnd_write as write } from '../operations/write';\nimport { Store } from '../store/store';\n\ninterface TestCase {\n  query: DocumentNode;\n  variables?: any;\n  data: any;\n}\n\nconst expectCacheIntegrity = (testcase: TestCase) => {\n  const store = new Store();\n  const request = { query: testcase.query, variables: testcase.variables };\n  const writeRes = write(store, request, testcase.data);\n  const queryRes = query(store, request);\n  expect(queryRes.data).not.toBe(null);\n  expect(queryRes.data).toEqual(testcase.data);\n  expect(queryRes.partial).toBe(false);\n  expect(queryRes.dependencies).toEqual(writeRes.dependencies);\n};\n\nit('int on query', () => {\n  expectCacheIntegrity({\n    query: gql`\n      {\n        __typename\n        int\n      }\n    `,\n    data: { __typename: 'Query', int: 42 },\n  });\n});\n\nit('aliased field on query', () => {\n  expectCacheIntegrity({\n    query: gql`\n      {\n        __typename\n        anotherName: int\n      }\n    `,\n    data: { __typename: 'Query', anotherName: 42 },\n  });\n});\n\nit('@skip directive on field on query', () => {\n  expectCacheIntegrity({\n    query: gql`\n      {\n        __typename\n        intA @skip(if: true)\n        intB @skip(if: false)\n      }\n    `,\n    data: { __typename: 'Query', intB: 2 },\n  });\n});\n\nit('@include directive on field on query', () => {\n  expectCacheIntegrity({\n    query: gql`\n      {\n        __typename\n        intA @include(if: true)\n        intB @include(if: false)\n      }\n    `,\n    data: { __typename: 'Query', intA: 2 },\n  });\n});\n\nit('random directive on field on query', () => {\n  expectCacheIntegrity({\n    query: gql`\n      {\n        __typename\n        int @shouldntMatter\n      }\n    `,\n    data: { __typename: 'Query', int: 1 },\n  });\n});\n\nit('json on query', () => {\n  expectCacheIntegrity({\n    query: gql`\n      {\n        __typename\n        json\n      }\n    `,\n    // The `__typename` field should not mislead the cache\n    data: {\n      __typename: 'Query',\n      json: { __typename: 'Misleading', test: true },\n    },\n  });\n});\n\nit('nullable field on query', () => {\n  expectCacheIntegrity({\n    query: gql`\n      {\n        __typename\n        missing\n      }\n    `,\n    data: { __typename: 'Query', missing: null },\n  });\n});\n\nit('int field with arguments on query', () => {\n  expectCacheIntegrity({\n    query: gql`\n      {\n        __typename\n        int(test: true)\n      }\n    `,\n    data: { __typename: 'Query', int: 42 },\n  });\n});\n\nit('non-keyable entity on query', () => {\n  expectCacheIntegrity({\n    query: gql`\n      {\n        __typename\n        item {\n          __typename\n          name\n        }\n      }\n    `,\n    // This entity has no `id` or `_id` field\n    data: { __typename: 'Query', item: { __typename: 'Item', name: 'Test' } },\n  });\n});\n\nit('non-IDable entity on query', () => {\n  expectCacheIntegrity({\n    query: gql`\n      {\n        __typename\n        item {\n          __typename\n          name\n        }\n      }\n    `,\n    // This entity has a `__typename` but no ID fields\n    data: { __typename: 'Query', item: { __typename: 'Item', name: 'Test' } },\n  });\n});\n\nit('entity on query', () => {\n  expectCacheIntegrity({\n    query: gql`\n      {\n        __typename\n        item {\n          __typename\n          id\n          name\n        }\n      }\n    `,\n    data: {\n      __typename: 'Query',\n      item: { __typename: 'Item', id: '1', name: 'Test' },\n    },\n  });\n});\n\nit('entity on aliased field on query', () => {\n  expectCacheIntegrity({\n    query: gql`\n      {\n        __typename\n        anotherName: item {\n          __typename\n          id\n          name\n        }\n      }\n    `,\n    data: {\n      __typename: 'Query',\n      anotherName: { __typename: 'Item', id: '1', name: 'Test' },\n    },\n  });\n});\n\nit('entity with arguments on query', () => {\n  expectCacheIntegrity({\n    query: gql`\n      {\n        __typename\n        item(test: true) {\n          __typename\n          id\n          name\n        }\n      }\n    `,\n    data: {\n      __typename: 'Query',\n      item: { __typename: 'Item', id: '1', name: 'Test' },\n    },\n  });\n});\n\nit('entity with Int-like ID on query', () => {\n  expectCacheIntegrity({\n    query: gql`\n      {\n        __typename\n        item {\n          __typename\n          id\n          name\n        }\n      }\n    `,\n    // This is the same as above, but with a number on `id`\n    data: {\n      __typename: 'Query',\n      item: { __typename: 'Item', id: 1, name: 'Test' },\n    },\n  });\n});\n\nit('entity list on query', () => {\n  expectCacheIntegrity({\n    query: gql`\n      {\n        __typename\n        items {\n          __typename\n          id\n        }\n      }\n    `,\n    data: {\n      __typename: 'Query',\n      items: [\n        { __typename: 'Item', id: 1 },\n        { __typename: 'Item', id: 2 },\n      ],\n    },\n  });\n});\n\nit('nested entity list on query', () => {\n  expectCacheIntegrity({\n    query: gql`\n      {\n        __typename\n        items {\n          __typename\n          id\n        }\n      }\n    `,\n    data: {\n      // This is the same as above, but with a nested array and added null values\n      __typename: 'Query',\n      items: [\n        { __typename: 'Item', id: 1 },\n        [{ __typename: 'Item', id: 2 }, null],\n        null,\n      ],\n    },\n  });\n});\n\nit('entity list on query and inline fragment', () => {\n  expectCacheIntegrity({\n    query: gql`\n      {\n        __typename\n        items {\n          __typename\n          id\n        }\n        ... on Query {\n          items {\n            test\n          }\n        }\n      }\n    `,\n    data: {\n      __typename: 'Query',\n      items: [{ __typename: 'Item', id: 1, test: true }, null],\n    },\n  });\n});\n\nit('conditionless inline fragment', () => {\n  expectCacheIntegrity({\n    query: gql`\n      {\n        __typename\n        ... {\n          test\n        }\n      }\n    `,\n    data: {\n      __typename: 'Query',\n      test: true,\n    },\n  });\n});\n\nit('skipped conditionless inline fragment', () => {\n  expectCacheIntegrity({\n    query: gql`\n      {\n        __typename\n        ... @skip(if: true) {\n          test\n        }\n      }\n    `,\n    data: {\n      __typename: 'Query',\n    },\n  });\n});\n\nit('entity list on query and spread fragment', () => {\n  expectCacheIntegrity({\n    query: gql`\n      query Test {\n        __typename\n        items {\n          __typename\n          id\n        }\n        ...TestFragment\n      }\n\n      fragment TestFragment on Query {\n        items {\n          test\n        }\n      }\n    `,\n    data: {\n      __typename: 'Query',\n      items: [{ __typename: 'Item', id: 1, test: true }, null],\n    },\n  });\n});\n\nit('skipped spread fragment', () => {\n  expectCacheIntegrity({\n    query: gql`\n      query Test {\n        __typename\n        ...TestFragment @skip(if: true)\n      }\n\n      fragment TestFragment on Query {\n        test\n      }\n    `,\n    data: {\n      __typename: 'Query',\n    },\n  });\n});\n\nit('embedded objects on entities', () => {\n  expectCacheIntegrity({\n    query: gql`\n      {\n        __typename\n        user {\n          __typename\n          id\n          posts {\n            __typename\n            edges {\n              __typename\n              node {\n                __typename\n                id\n              }\n            }\n          }\n        }\n      }\n    `,\n    data: {\n      __typename: 'Query',\n      user: {\n        __typename: 'User',\n        id: 1,\n        posts: {\n          __typename: 'PostsConnection',\n          edges: [\n            {\n              __typename: 'PostsEdge',\n              node: {\n                __typename: 'Post',\n                id: 1,\n              },\n            },\n          ],\n        },\n      },\n    },\n  });\n});\n\nit('nested viewer selections', () => {\n  expectCacheIntegrity({\n    query: gql`\n      {\n        __typename\n        int\n        viewer {\n          __typename\n          int\n        }\n      }\n    `,\n    data: {\n      __typename: 'Query',\n      int: 42,\n      viewer: {\n        __typename: 'Query',\n        int: 42,\n      },\n    },\n  });\n});\n"
  },
  {
    "path": "exchanges/graphcache/src/test-utils/utils.ts",
    "content": "// eslint-disable-next-line\nexport const noop = () => {};\n"
  },
  {
    "path": "exchanges/graphcache/src/types.ts",
    "content": "import type {\n  AnyVariables,\n  DocumentInput,\n  RequestExtensions,\n  TypedDocumentNode,\n  FormattedNode,\n  ErrorLike,\n} from '@urql/core';\n\nimport type { DocumentNode, FragmentDefinitionNode } from '@0no-co/graphql.web';\nimport type { IntrospectionData } from './ast';\n\n/** Nullable GraphQL list types of `T`.\n *\n * @remarks\n * Any GraphQL list of a given type `T` that is nullable is\n * expected to contain nullable values. Nested lists are\n * also taken into account in Graphcache.\n */\nexport type NullArray<T> = Array<null | T | NullArray<T>>;\n\n/** Dictionary of GraphQL Fragment definitions by their names.\n *\n * @remarks\n * A map of {@link FragmentDefinitionNode | FragmentDefinitionNodes} by their\n * fragment names from the original GraphQL document that Graphcache is\n * executing.\n */\nexport interface Fragments {\n  [fragmentName: string]: void | FormattedNode<FragmentDefinitionNode>;\n}\n\n/** Non-object JSON values as serialized by a GraphQL API\n * @see {@link https://spec.graphql.org/October2021/#sel-DAPJDHAAEJHAKmzP} for the\n * GraphQL spec’s serialization format.\n */\nexport type Primitive = null | number | boolean | string;\n\n/** Any GraphQL scalar object\n *\n * @remarks\n * A GraphQL schema may define custom scalars that are resolved\n * and serialized as objects. These objects could also be turned\n * on the client-side into a non-JSON object, e.g. a `Date`.\n *\n * @see {@link https://spec.graphql.org/October2021/#sec-Scalars} for the\n * GraphQL spec’s information on custom scalars.\n */\nexport interface ScalarObject {\n  constructor?: Function;\n  [key: string]: any;\n}\n\n/** GraphQL scalar value\n * @see {@link https://spec.graphql.org/October2021/#sec-Scalars} for the GraphQL\n * spec’s definition of scalars\n */\nexport type Scalar = Primitive | ScalarObject;\n\n/** Fields that Graphcache expects on GraphQL object (“entity”) results.\n *\n * @remarks\n * Any object that comes back from a GraphQL API will have\n * a `__typename` field from GraphQL Object types.\n *\n * The `__typename` field must be present as Graphcache updates\n * GraphQL queries with type name introspection.\n * Furthermore, Graphcache always checks for its default key\n * fields, `id` and `_id` to be present.\n */\nexport interface SystemFields {\n  /** GraphQL Object type name as returned by Type Name Introspection.\n   * @see {@link https://spec.graphql.org/October2021/#sec-Type-Name-Introspection} for\n   * more information on GraphQL’s Type Name introspection.\n   */\n  __typename: string;\n  _id?: string | number | null;\n  id?: string | number | null;\n}\n\n/** Scalar values are stored separately from relations between entities.\n * @internal\n */\nexport type EntityField = undefined | Scalar | NullArray<Scalar>;\n\n/** Values on GraphQL object (“entity”) results.\n *\n * @remarks\n * Any field that comes back from a GraphQL API will have\n * values that are scalars, other objects, or arrays\n * of scalars or objects.\n */\nexport type DataField = Scalar | Data | NullArray<Scalar> | NullArray<Data>;\n\n/** Definition of GraphQL object (“entity”) fields.\n *\n * @remarks\n * Any object that comes back from a GraphQL API will have\n * values that are scalars, other objects, or arrays\n * of scalars or objects, i.e. the {@link DataField} type.\n */\nexport interface DataFields {\n  [fieldName: string]: DataField;\n}\n\n/** Definition of GraphQL variables objects.\n * @remarks\n * Variables, as passed to GraphQL queries, can only contain scalar values.\n *\n * @see {@link https://spec.graphql.org/October2021/#sec-Coercing-Variable-Values} for the\n * GraphQL spec’s coercion of GraphQL variables.\n */\nexport interface Variables {\n  [name: string]: Scalar | Scalar[] | Variables | NullArray<Variables>;\n}\n\n/** Definition of GraphQL objects (“entities”).\n *\n * @remarks\n * An entity is expected to consist of a `__typename`\n * fields, optionally the default `id` or `_id` key\n * fields, and scalar values or other entities\n * otherwise.\n */\nexport type Data = SystemFields & DataFields;\n\n/** An entity, a key of an entity, or `null`\n *\n * @remarks\n * When Graphcache accepts a reference to an entity, you may pass it a key of an entity,\n * as retrieved for instance by {@link Cache.keyOfEntity} or a partial GraphQL object\n * (i.e. an object with a `__typename` and key field).\n */\nexport type Entity = undefined | null | Data | string;\n\n/** A key of an entity, or `null`; or a list of keys.\n *\n * @remarks\n * When Graphcache accepts a reference to one or more entities, you may pass it a\n * key, an entity, or a list of entities or keys. This is often passed to {@link Cache.link}\n * to update a field pointing to other GraphQL objects.\n */\nexport type Link<Key = string> = null | Key | NullArray<Key>;\n\n/** Arguments passed to a Graphcache field resolver.\n *\n * @remarks\n * Arguments a field receives are similar to variables and can\n * only contain scalars or other arguments objects. This\n * is equivalent to the {@link Variables} type.\n *\n * @see {@link https://spec.graphql.org/October2021/#sec-Coercing-Field-Arguments} for the\n * GraphQL spec’s coercion of field arguments.\n */\nexport type FieldArgs = Variables | null | undefined;\n\n/** Metadata about an entity’s cached field.\n *\n * @remarks\n * As returned by {@link Cache.inspectFields}, `FieldInfo` specifies an entity’s cached field,\n * split into the field’s key itself and the field’s original name and arguments.\n */\nexport interface FieldInfo {\n  /** The field’s key which combines `fieldName` and `arguments`. */\n  fieldKey: string;\n  /** The field’s name, as defined on a GraphQL Object type. */\n  fieldName: string;\n  /** The arguments passed to the field as found on the cache. */\n  arguments: Variables | null;\n}\n\n/** A key to an entity field split back into the entity’s key and the field’s key part.\n * @internal\n */\nexport interface KeyInfo {\n  entityKey: string;\n  fieldKey: string;\n}\n\n/** Abstract type for GraphQL requests.\n *\n * @remarks\n * Similarly to `@urql/core`’s `GraphQLRequest` type, `OperationRequest`\n * requires the minimum fields that Grapcache requires to execute a\n * GraphQL operation: its query document and variables.\n */\nexport interface OperationRequest {\n  query: FormattedNode<DocumentNode> | DocumentNode;\n  variables?: any;\n}\n\n/** Metadata object passed to all resolver functions.\n *\n * @remarks\n * `ResolveInfo`, similar to GraphQL.js’ `GraphQLResolveInfo` object,\n * gives your resolvers a global state of the current GraphQL\n * document traversal.\n *\n * `parent`, `parenTypeName`, `parentKey`, and `parentFieldKey`\n * are particularly useful to make reusable resolver functions that\n * must know on which field and type they’re being called on.\n */\nexport interface ResolveInfo {\n  /** The parent GraphQL object.\n   *\n   * @remarks\n   * The GraphQL object that the resolver has been called on. Because this is\n   * a reference to raw GraphQL data, this may be incomplete or contain\n   * aliased fields!\n   */\n  parent: Data;\n  /** The parent object’s typename that the resolver has been called on. */\n  parentTypeName: string;\n  /** The parent object’s entity key that the resolver has been called on. */\n  parentKey: string;\n  /** Current field’s key that the resolver has been called on. */\n  parentFieldKey: string;\n  /** Current field that the resolver has been called on. */\n  fieldName: string;\n  /** Map of fragment definitions from the query document. */\n  fragments: Fragments;\n  /** Full original {@link Variables} object on the {@link OperationRequest}. */\n  variables: Variables;\n  /** Error that occurred for the current field, if any.\n   *\n   * @remarks\n   * If a {@link GraphQLError.path} points at the current field, the error\n   * will be set and provided here. This can be useful to recover from an\n   * error on a specific field.\n   */\n  error: ErrorLike | undefined;\n  /** Flag used to indicate whether the current GraphQL query is only partially cached.\n   *\n   * @remarks\n   * When Graphcache has {@link CacheExchangeOpts.schema} introspection information,\n   * it can automatically generate partial results and trigger a full API request\n   * in the background.\n   * Hence, this field indicates whether any data so far has only been partially\n   * resolved from the cache, and is only in use on {@link Resolver | Resolvers}.\n   *\n   * However, you can also flip this flag to `true` manually to indicate to\n   * the {@link cacheExchange} that it should still make a network request.\n   */\n  partial?: boolean;\n  /** Flag used to indicate whether the current GraphQL mutation is optimistically executed.\n   *\n   * @remarks\n   * An {@link UpdateResolver} is called for both API mutation responses and\n   * optimistic mutation reuslts, as generated by {@link OptimisticMutationResolver}.\n   *\n   * Since an update sometimes needs to perform different actions if it’s run\n   * optimistically, this flag is set to `true` during optimisti cupdates.\n   */\n  optimistic?: boolean;\n  /** Internal state used by Graphcache.\n   * @internal\n   */\n  __internal?: unknown;\n}\n\n/** GraphQL document and variables that should be queried against the cache.\n *\n * @remarks\n * `QueryInput` is a generic GraphQL request that should be executed against\n * cached data, as accepted by {@link cache.readQuery}.\n */\nexport interface QueryInput<T = Data, V = Variables> {\n  query: DocumentInput<T, V>;\n  variables?: V;\n}\n\n/** Interface to interact with cached data, which resolvers receive. */\nexport interface Cache {\n  /** Returns the cache key for a given entity or `null` if it’s unkeyable.\n   *\n   * @param entity - the {@link Entity} to generate a key for.\n   * @returns the entity’s key or `null`.\n   *\n   * @remarks\n   * `cache.keyOfEntity` may be called with a partial GraphQL object (“entity”)\n   * and generates a key for it. It uses your {@link KeyingConfig} and otherwise\n   * defaults to `id` and `_id` fields.\n   *\n   * If it’s passed a `string` or `null`, it will simply return what it’s been passed.\n   * Objects that lack a `__typename` field will return `null`.\n   */\n  keyOfEntity(entity: Entity | undefined): string | null;\n\n  /** Returns the cache key for a field.\n   *\n   * @param fieldName - the field’s name.\n   * @param args - the field’s arguments, if any.\n   * @returns the field key\n   *\n   * @remarks\n   * `cache.keyOfField` is used to create a field’s cache key from a given\n   * field name and its arguments. This is used internally by {@link cache.resolve}\n   * to combine an entity key and a field key into a path that normalized data is\n   * accessed on in Graphcache’s internal data structure.\n   */\n  keyOfField(fieldName: string, args?: FieldArgs): string | null;\n\n  /** Returns a cached value on a given entity’s field.\n   *\n   * @param entity - a GraphQL object (“entity”) or an entity key.\n   * @param fieldName - the field’s name.\n   * @param args - the field’s arguments, if any.\n   * @returns the field’s value or the entity key(s) this field is pointing at.\n   *\n   * @remarks\n   * `cache.resolve` is used to retrieve either the cached value of a field, or\n   * to get the relation of the field (“link”). When a cached field points at\n   * another normalized entity, this method will return the related entity key\n   * (or a list, if it’s pointing at a list of entities).\n   *\n   * As such, if you’re accessing a nested field, you may have to call\n   * `cache.resolve` again and chain its calls.\n   *\n   * Hint: If you have a field key from {@link FieldInfo} or {@link cache.keyOfField},\n   * you may pass it as a second argument.\n   *\n   * @example\n   * ```ts\n   * const authorName = cache.resolve(\n   *   cache.resolve({ __typename: 'Book', id }, 'author'),\n   *   'name'\n   * );\n   * ```\n   */\n  resolve(\n    entity: Entity | undefined,\n    fieldName: string,\n    args?: FieldArgs\n  ): DataField | undefined;\n\n  /** Returns a list of cached fields for a given GraphQL object (“entity”).\n   *\n   * @param entity - a GraphQL object (“entity”) or an entity key.\n   * @returns a list of {@link FieldInfo} objects.\n   *\n   * @remarks\n   * `cache.inspectFields` can be used to list out all known fields\n   * of a given entity. This can be useful in an {@link UpdateResolver}\n   * if you have a `Query` field that accepts many different arguments,\n   * for instance a paginated field.\n   *\n   * The returned list of fields are all fields that the cache knows about,\n   * and you may have to filter them by name or arguments to find only which\n   * ones you need.\n   *\n   * Hint: This method is theoretically a slower operation than simple\n   * cache lookups, as it has to decode field keys. It’s only recommended\n   * to be used in updaters.\n   */\n  inspectFields(entity: Entity): FieldInfo[];\n\n  /** Deletes a cached entity or an entity’s field.\n   *\n   * @param entity - a GraphQL object (“entity”) or an entity key.\n   * @param fieldName - optionally, a field name.\n   * @param args - optionally, the field’s arguments, if any.\n   *\n   * @remarks\n   * `cache.invalidate` can be used in updaters to delete data from\n   * the cache. This will cause the {@link cacheExchange} to reexecute\n   * queries that contain the deleted data.\n   *\n   * If you only pass its first argument, the entire entity is deleted.\n   * However, if a field name (and optionally, its arguments) are passed,\n   * only a single field is erased.\n   */\n  invalidate(\n    entity: Entity | undefined,\n    fieldName?: string,\n    args?: FieldArgs\n  ): void;\n\n  /** Updates a GraphQL query‘s cached data.\n   *\n   * @param input - a {@link QueryInput}, which is a GraphQL query request.\n   * @param updater - a function called with the query’s result or `null` in case of a cache miss, which\n   * may return updated data, which is written to the cache using the query.\n   *\n   * @remarks\n   * `cache.updateQuery` can be used to update data for an entire GraphQL query document.\n   * When it's passed a GraphQL query request, it calls the passed `updater` function\n   * with the cached result for this query. You may then modify and update the data and\n   * return it, after which it’s written back to the cache.\n   *\n   * Hint: While this allows for large updates at once, {@link cache.link},\n   * {@link cache.resolve}, and {@link cache.writeFragment} are often better\n   * choices for more granular and compact updater code.\n   *\n   * @example\n   * ```ts\n   * cache.updateQuery({ query: TodoList }, data => {\n   *   data.todos.push(newTodo);\n   *   return data;\n   * });\n   * ```\n   */\n  updateQuery<T = Data, V = Variables>(\n    input: QueryInput<T, V>,\n    updater: (data: T | null) => T | null\n  ): void;\n\n  /** Returns a GraphQL query‘s cached result.\n   *\n   * @param input - a {@link QueryInput}, which is a GraphQL query request.\n   * @returns the cached data result of the query or `null`, in case of a cache miss.\n   *\n   * @remarks\n   * `cache.readQuery` can be used to read an entire query’s data all at once\n   * from the cache.\n   *\n   * This can be useful when typing out many {@link cache.resolve}\n   * calls is too tedious.\n   *\n   * @example\n   * ```ts\n   * const data = cache.readQuery({\n   *   query: TodosQuery,\n   *   variables: { from: 0, limit: 10 }\n   * });\n   * ```\n   */\n  readQuery<T = Data, V = Variables>(input: QueryInput<T, V>): T | null;\n\n  /** Returns a GraphQL fragment‘s cached result.\n   *\n   * @param fragment - a {@link DocumentNode} containing a fragment definition.\n   * @param entity - a GraphQL object (“entity”) or an entity key to read the fragment on.\n   * @param variables - optionally, GraphQL variables, if the fragments use any.\n   * @returns the cached data result of the fragment or `null`, in case of a cache miss.\n   *\n   * @remarks\n   * `cache.readFragment` can be used to read an entire query’s data all at once\n   * from the cache.\n   *\n   * It attempts to read the fragment starting from the `entity` that’s passed to it.\n   * If the entity can’t be resolved or has mismatching types, `null` is returned.\n   *\n   * This can be useful when typing out many {@link cache.resolve}\n   * calls is too tedious.\n   *\n   * @example\n   * ```ts\n   * const data = cache.readFragment(\n   *   gql`fragment _ on Todo { id, text }`,\n   *   { id: '123' }\n   * );\n   * ```\n   */\n  readFragment<T = Data, V = Variables>(\n    fragment: TypedDocumentNode<any, any> | TypedDocumentNode<T, V>,\n    entity: string | Data | T,\n    variables?: V\n  ): T | null;\n\n  /** Writes a GraphQL fragment to the cache.\n   *\n   * @param fragment - a {@link DocumentNode} containing a fragment definition.\n   * @param data - a GraphQL object to be written with the given fragment.\n   * @param variables - optionally, GraphQL variables, if the fragments use any.\n   *\n   * @remarks\n   * `cache.writeFragment` can be used to write an entity to the cache.\n   * The method will generate a key for the `data` it’s passed, and start writing\n   * it using the fragment.\n   *\n   * This method is used when writing scalar values to the cache.\n   * Since it's rare for an updater to write values to the cache, {@link cache.link}\n   * only allows relations (“links”) to be updated, and `cache.writeFragment` is\n   * instead used when writing multiple scalars.\n   *\n   * @example\n   * ```ts\n   * const data = cache.writeFragment(\n   *   gql`fragment _ on Todo { id, text }`,\n   *   { id: '123', text: 'New Text' }\n   * );\n   * ```\n   */\n  writeFragment<T = Data, V = Variables>(\n    fragment: TypedDocumentNode<any, any> | TypedDocumentNode<T, V>,\n    data: T,\n    variables?: V\n  ): void;\n\n  /** Updates the relation (“link”) from an entity’s field to another entity.\n   *\n   * @param entity - a GraphQL object (“entity”) or an entity key.\n   * @param fieldName - the field’s name.\n   * @param args - optionally, the field’s arguments, if any.\n   * @param link - the GraphQL object(s) that should be set on this field.\n   *\n   * @remarks\n   * The normalized cache stores relations between GraphQL objects separately.\n   * As such, a field can be updated using `cache.link` to point to a new entity,\n   * or a list of entities.\n   *\n   * In other words, `cache.link` is used to set a field to point to another\n   * entity or a list of entities.\n   *\n   * @example\n   * ```ts\n   * const todos = cache.resolve('Query', 'todos');\n   * cache.link('Query', 'todos', [...todos, newTodo]);\n   * ```\n   */\n  link(\n    entity: Entity,\n    field: string,\n    args: FieldArgs,\n    link: Link<Entity>\n  ): void;\n  link(entity: Entity, field: string, value: Link<Entity>): void;\n}\n\n/** Values a {@link Resolver} may return.\n *\n * @remarks\n * A resolver may return any value that a GraphQL object may contain.\n *\n * Additionally however, a resolver may return `undefined` to indicate that data\n * isn’t available from the cache, i.e. to trigger a cache miss.\n */\nexport type ResolverResult =\n  | DataField\n  | (DataFields & { __typename?: string })\n  | null\n  | undefined;\n\nexport type Logger = (\n  severity: 'debug' | 'error' | 'warn',\n  message: string\n) => void;\n\n/** Input parameters for the {@link cacheExchange}. */\nexport type CacheExchangeOpts = {\n  /** Configure a custom-logger for graphcache, this function wll be called with a severity and a message.\n   *\n   * @remarks\n   * By default we will invoke `console.warn` for warnings during development, however you might want to opt\n   * out of this because you are re-using urql for a different library. This setting allows you to stub the logger\n   * function or filter to only logs you want.\n   */\n  logger?: Logger;\n  /** Configures update functions which are called when the mapped fields are written to the cache.\n   *\n   * @remarks\n   * `updates` are commonly used to define additional changes to the cache for\n   * mutation or subscription fields. It may commonly be used to invalidate\n   * cached data or to modify lists after mutations.\n   * This is a map of types to fields to {@link UpdateResolver} functions.\n   *\n   * @see {@link https://urql.dev/goto/docs/graphcache/cache-updates} for the full updates docs.\n   */\n  updates?: UpdatesConfig;\n  /** Configures resolvers which replace cached reuslts with custom values.\n   *\n   * @remarks\n   * `resolvers` is a map of types to fields to {@link Resolver} functions.\n   * These functions allow us to replace cached field values with a custom\n   * result, either to replace values on GraphQL results, or to resolve\n   * entities from the cache for queries that haven't been sent to the API\n   * yet.\n   *\n   * @see {@link https://urql.dev/goto/docs/graphcache/local-resolvers} for the full resolvers docs.\n   */\n  resolvers?: ResolverConfig;\n  /** Configures directives which can perform custom logic on fields.\n   *\n   * @remarks\n   * A {@link DirectivesConfig} may be passed to allow local directives to be used. For example, when `@_custom` is placed on a field and the configuration contains `custom` then this directive is executed by Graphcache.\n   *\n   * @see {@link https://urql.dev/goto/docs/graphcache/local-directives} for the full directives docs.\n   */\n  directives?: DirectivesConfig;\n  /** Configures optimistic updates to react to mutations instantly before an API response.\n   *\n   * @remarks\n   * `optimistic` is a map of mutation fields to {@link OptimisticMutationResolver} functions.\n   * These functions allow us to return result data for mutations to optimistically apply them.\n   * Optimistic updates are temporary updates to the cache’s data which allow an app to\n   * instantly reflect changes that a mutation will make.\n   *\n   * @see {@link https://urql.dev/goto/docs/graphcache/cache-updates/#optimistic-updates} for the\n   * full optimistic updates docs.\n   */\n  optimistic?: OptimisticMutationConfig;\n  /** Configures keying functions for GraphQL types.\n   *\n   * @remarks\n   * `keys` is a map of GraphQL object type names to {@link KeyGenerator} functions.\n   * If a type in your API has no key field or a key field that isn't the default\n   * `id` or `_id` fields, you may define a custom key generator for the type.\n   *\n   * Hint: Graphcache will log warnings when it finds objects that have no keyable\n   * fields, which will remind you to define these functions gradually for every\n   * type that needs them.\n   *\n   * @see {@link https://urql.dev/goto/docs/graphcache/normalized-caching/#custom-keys-and-non-keyable-entities} for\n   * the full keys docs.\n   */\n  keys?: KeyingConfig;\n  /** Enables global IDs for keying GraphQL types.\n   *\n   * @remarks\n   * When `globalIDs` are enabled, GraphQL object type names will not contribute\n   * to the keys of entities and instead only their ID fields (or `keys` return\n   * values will be used.\n   *\n   * This is useful to overlap types of differing typenames. While this isn’t recommended\n   * it can be necessary to represent more complex interface relationships.\n   *\n   * If this should only be applied to a limited set of type names, a list of\n   * type names may be passed instead.\n   */\n  globalIDs?: string[] | boolean;\n  /** Configures abstract to concrete types mapping for GraphQL types.\n   *\n   * @remarks\n   * This will disable heuristic fragment matching, allowing Graphcache to match\n   * fragment deterministically.\n   *\n   * When both `possibleTypes` and `schema` is set, `possibleTypes` value will be\n   * ignored.\n   */\n  possibleTypes?: PossibleTypesConfig;\n  /** Configures Graphcache with Schema Introspection data.\n   *\n   * @remarks\n   * Passing a `schema` to Graphcache enables it to do non-heuristic fragment\n   * matching, and be certain when a fragment matches against a union or interface\n   * on your schema.\n   *\n   * It also enables a mode called “Schema Awareness”, which allows Graphcache to\n   * return partial GraphQL results, `null`-ing out fields that aren’t in the cache\n   * that are nullable on your schema, while requesting the full API response in\n   * the background.\n   *\n   * @see {@link https://urql.dev/goto/urql/docs/graphcache/schema-awareness} for\n   * the full keys docs on Schema Awareness.\n   */\n  schema?: IntrospectionData;\n  /** Configures an offline storage adapter for Graphcache.\n   *\n   * @remarks\n   * A {@link StorageAdapter} allows Graphcache to write data to an external,\n   * asynchronous storage, and hydrate data from it when it first loads.\n   * This allows you to preserve normalized data between restarts/reloads.\n   *\n   * Hint: If you’re trying to use Graphcache’s Offline Support, you may\n   * want to swap out the `cacheExchange` with the {@link offlineExchange}.\n   *\n   * @see {@link https://urql.dev/goto/docs/graphcache/offline} for the full Offline Support docs.\n   */\n  storage?: StorageAdapter;\n};\n\n/** Cache Resolver, which may resolve or replace data during cache reads.\n *\n * @param parent - The GraphQL object that is currently being constructed from cache data.\n * @param args - This field’s arguments.\n * @param cache - {@link Cache} interface.\n * @param info - {@link ResolveInfo} interface.\n * @returns a {@link ResolverResult}, which is an updated value, partial entity, or entity key\n *\n * @remarks\n * A `Resolver`, as defined on the {@link ResolverConfig}, is called for\n * a field’s type during cache reads, and can be used to deserialize or replace\n * scalar values, or to resolve an entity from cached data, even if the\n * current field hasn’t been cached from an API response yet.\n *\n * For instance, if you have a `Query.picture(id: ID!)` field, you may define\n * a resolver that returns `{ __typename: 'Picture', id: args.id }`, since you\n * know the key fields of the GraphQL object.\n *\n * @example\n * ```ts\n * cacheExchange({\n *   resolvers: {\n *     Query: {\n *       // resolvers can be used to resolve cached entities without API requests\n *       todo: (_parent, args) => ({ __typename: 'Todo', id: args.id }),\n *     },\n *     Todo: {\n *       // resolvers can also be used to replace/deserialize scalars\n *       updatedAt: parent => new Date(parent.updatedAt),\n *     },\n *   },\n * });\n * ```\n *\n * @see {@link https://urql.dev/goto/docs/graphcache/local-resolvers} for the full resolvers docs.\n */\nexport type Resolver<\n  ParentData = DataFields,\n  Args = Variables,\n  Result = ResolverResult,\n> = {\n  bivarianceHack(\n    parent: ParentData,\n    args: Args,\n    cache: Cache,\n    info: ResolveInfo\n  ): Result;\n}['bivarianceHack'];\n\n/** Configures resolvers which replace cached reuslts with custom values.\n *\n * @remarks\n * A `ResolverConfig` is a map of types to fields to {@link Resolver} functions.\n * These functions allow us to replace cached field values with a custom\n * result, either to replace values on GraphQL results, or to resolve\n * entities from the cache for queries that haven't been sent to the API\n * yet.\n *\n * @see {@link https://urql.dev/goto/docs/graphcache/local-resolvers} for the full resolvers docs.\n */\nexport type ResolverConfig = {\n  [typeName: string]: {\n    [fieldName: string]: Resolver | void;\n  } | void;\n};\n\nexport type Directive = (\n  directiveArguments: Record<string, unknown> | null\n) => Resolver;\n\nexport type DirectivesConfig = {\n  [directiveName: string]: Directive;\n};\n\n/** Cache Updater, which defines additional cache updates after cache writes.\n *\n * @param parent - The GraphQL object that is currently being written to the cache.\n * @param args - This field’s arguments.\n * @param cache - {@link Cache} interface.\n * @param info - {@link ResolveInfo} interface.\n *\n * @remarks\n * An `UpdateResolver` (“updater”), as defined on the {@link UpdatesConfig}, is\n * called for a field’s type during cache writes, and can be used to instruct\n * the {@link Cache} to perform other cache updates at the same time.\n *\n * This is often used, for instance, to update lists or invalidate entities\n * after a mutation response has come back from the API.\n *\n * @example\n * ```ts\n * cacheExchange({\n *   updates: {\n *     Mutation: {\n *       // updaters can invalidate data from the cache\n *       deleteAuthor: (_parent, args, cache) => {\n *         cache.invalidate({ __typename: 'Author', id: args.id });\n *       },\n *     },\n *   },\n * });\n * ```\n *\n * @see {@link https://urql.dev/goto/docs/graphcache/cache-updates} for the\n * full cache updates docs.\n */\nexport type UpdateResolver<ParentData = DataFields, Args = Variables> = {\n  bivarianceHack(\n    parent: ParentData,\n    args: Args,\n    cache: Cache,\n    info: ResolveInfo\n  ): void;\n}['bivarianceHack'];\n\n/** A key functon, which is called to create a cache key for a GraphQL object (“entity”).\n *\n * @param data - The GraphQL object that a key is generated for.\n * @returns a key `string` or `null` or unkeyable objects.\n *\n * @remarks\n * By default, Graphcache will use an object’s `__typename`, and `id` or `_id` fields\n * to generate a key for an object. However, not all GraphQL objects will have a unique\n * field, and some objects don’t have a key at all.\n *\n * When one of your GraphQL object types has a different key field, you may define a\n * function on the {@link KeyingConfig} to return its key field.\n * You may also have objects that don’t have keys, like “Edge” objects, or scalar-like\n * objects. For these, you can define a function that returns `null`, which tells\n * Graphcache that it’s an embedded object, which only occurs on its parent and is\n * globally unique.\n *\n * @see {@link https://urql.dev/goto/docs/graphcache/normalized-caching/#custom-keys-and-non-keyable-entities} for\n * the full keys docs.\n *\n * @example\n * ```ts\n * cacheExchange({\n *   keys: {\n *     Image: data => data.url,\n *     LatLng: () => null,\n *   },\n * });\n * ```\n */\nexport type KeyGenerator = {\n  bivarianceHack(data: Data): string | null;\n}['bivarianceHack'];\n\n/** Configures update functions which are called when the mapped fields are written to the cache.\n *\n * @remarks\n * `UpdatesConfig` is a map of types to fields to {@link UpdateResolver} functions.\n * These update functions are defined to instruct the cache to make additional changes\n * when a field is written to the cache.\n *\n * As changes are often made after a mutation or subscription, the `typeName` is\n * often set to `'Mutation'` or `'Subscription'`.\n *\n * @see {@link https://urql.dev/goto/docs/graphcache/cache-updates} for the full updates docs.\n *\n * @example\n * ```ts\n * const updates = {\n *   Mutation: {\n *     deleteAuthor(_parent, args, cache) {\n *       // Delete the Author from the cache when Mutation.deleteAuthor is sent\n *       cache.invalidate({ __typename: 'Author', id: args.id });\n *     },\n *   },\n * };\n */\nexport type UpdatesConfig = {\n  [typeName: string | 'Query' | 'Mutation' | 'Subscription']: {\n    [fieldName: string]: UpdateResolver | void;\n  } | void;\n};\n\n/** Remaps result type to allow for nested optimistic mutation resolvers.\n *\n * @remarks\n * An {@link OptimisticMutationResolver} can not only return partial, nested\n * mutation result data, but may also contain more optimistic mutation resolvers\n * for nested fields, which allows fields with arguments to optimistically be\n * resolved to dynamic values.\n *\n * @see {@link OptimisticMutationConfig} for more information.\n */\nexport type MakeFunctional<T> = T extends { __typename: string }\n  ? WithTypename<{\n      [P in keyof T]?: MakeFunctional<T[P]>;\n    }>\n  : OptimisticMutationResolver<Variables, T> | T;\n\n/** Optimistic mutation resolver, which may return data that a mutation response will return.\n *\n * @param args - This field’s arguments.\n * @param cache - {@link Cache} interface.\n * @param info - {@link ResolveInfo} interface.\n * @returns the field’s optimistic data\n *\n * @remarks\n * Graphcache can update its cache optimistically via the {@link OptimisticMutationConfig}.\n * An `OptimisticMutationResolver` should return partial data that a mutation will return\n * once it completes and we receive its result.\n *\n * For instance, it could return the data that a deletion mutation may return\n * optimistically, which might allow an updater to run early and your UI to update\n * instantly.\n *\n * The result that this function returns may miss some fields that your mutation may return,\n * especially if it contains GraphQL object that are already cached. It may also contain\n * other, nested resolvers, which allows you to handle fields that accept arguments.\n */\nexport type OptimisticMutationResolver<\n  Args = Variables,\n  Result = Link<Data> | Scalar,\n> = {\n  bivarianceHack(\n    args: Args,\n    cache: Cache,\n    info: ResolveInfo\n  ): MakeFunctional<Result>;\n}['bivarianceHack'];\n\n/** Configures optimistic result functions which are called to get a mutation’s optimistic result.\n *\n * @remarks\n * `OptimisticMutationConfig` is a map of mutation fields to {@link OptimisticMutationResolver}\n * functions, which return result data for mutations to optimistically apply them.\n * Optimistic updates are temporary updates to the cache’s data which allow an app to\n * instantly reflect changes that a mutation will make.\n *\n * Hint: Results returned from optimistic functions may be partial, and may contain functions.\n * If the returned optimistic object contains functions on fields, these are executed as nested\n * optimistic resolver functions.\n *\n * @see {@link https://urql.dev/goto/docs/graphcache/cache-updates/#optimistic-updates} for the\n * full optimistic updates docs.\n *\n * @example\n * ```ts\n * const optimistic = {\n *   updateProfile: (args) => ({\n *     __typename: 'UserProfile',\n *     id: args.id,\n *     name: args.newName,\n *   }),\n * };\n */\nexport type OptimisticMutationConfig = {\n  [mutationFieldName: string]: OptimisticMutationResolver;\n};\n\n/** Configures keying functions for GraphQL types.\n *\n * @remarks\n * `KeyingConfig` is a map of GraphQL object type names to {@link KeyGenerator} functions.\n * If a type in your API has no key field or a key field that isn't the default\n * `id` or `_id` fields, you may define a custom key generator for the type.\n *\n * Keys are important to a normalized cache, because they’re the identity of the object\n * that is shared across the cache, and helps the cache recognize shared/normalized data.\n *\n * Hint: Graphcache will log warnings when it finds objects that have no keyable\n * fields, which will remind you to define these functions gradually for every\n * type that needs them.\n *\n * @see {@link https://urql.dev/goto/docs/graphcache/normalized-caching/#custom-keys-and-non-keyable-entities} for\n * the full keys docs.\n *\n * @example\n * ```ts\n * const keys = {\n *   Image: data => data.url,\n *   LatLng: () => null,\n * };\n * ```\n */\nexport type KeyingConfig = {\n  [typename: string]: KeyGenerator;\n};\n\nexport type PossibleTypesConfig = {\n  [abstractType: string]: string[];\n};\n\n/** Serialized normalized caching data. */\nexport interface SerializedEntries {\n  [key: string]: string | undefined;\n}\n\n/** A serialized GraphQL request for offline storage. */\nexport interface SerializedRequest {\n  query: string;\n  variables: AnyVariables | undefined;\n  extensions?: RequestExtensions | undefined;\n}\n\n/** Interface for a storage adapter, used by the {@link offlineExchange} for Offline Support.\n * @see {@link https://urql.dev/goto/docs/graphcache/offline} for the full Offline Support docs.\n * @see `@urql/exchange-graphcache/default-storage` for an example implementation using IndexedDB.\n */\nexport interface StorageAdapter {\n  /** Called to rehydrate data when the {@link cacheExchange} first loads.\n   * @remarks\n   * `readData` is called when Graphcache first starts up, and loads cache entries\n   * using which it'll repopulate its normalized cache data.\n   */\n  readData(): Promise<SerializedEntries>;\n  /** Called by the {@link cacheExchange} to write new data to the offline storage.\n   * @remarks\n   * `writeData` is called when Graphcache updated its cached data and wishes to\n   * persist this data to the offline storage. The data is a partial object and\n   * Graphcache does not write all its data at once.\n   */\n  writeData(delta: SerializedEntries): Promise<any>;\n  /** Called to rehydrate metadata when the {@link offlineExchange} first loads.\n   * @remarks\n   * `readMetadata` is called when Graphcache first starts up, and loads\n   * metadata informing it of pending mutations that failed while the device\n   * was offline.\n   */\n  readMetadata?(): Promise<null | SerializedRequest[]>;\n  /** Called by the {@link offlineExchange} to persist failed mutations.\n   * @remarks\n   * `writeMetadata` is called when a mutation failed to persist a queue\n   * of failed mutations to the offline storage that must be retried when\n   * the application is reloaded.\n   */\n  writeMetadata?(json: SerializedRequest[]): void;\n  /** Called to register a callback called when the device is back online.\n   * @remarks\n   * `onOnline` is called by the {@link offlineExchange} with a callback.\n   * This callback must be called when the device comes back online and\n   * will cause all failed mutations in the queue to be retried.\n   */\n  onOnline?(cb: () => void): any;\n  /** Called when the cache has been hydrated with the data from `readData` */\n  onCacheHydrated?(): any;\n}\n\n/** Set of keys that have been modified or accessed.\n * @internal\n */\nexport type Dependencies = Set<string>;\n\n/** The type of cache operation being executed.\n * @internal\n */\nexport type OperationType = 'read' | 'write';\n\n/** Casts a given object type to have a required typename field.\n * @internal\n */\nexport type WithTypename<T extends { __typename?: any }> = T & {\n  __typename: NonNullable<T['__typename']>;\n};\n"
  },
  {
    "path": "exchanges/graphcache/tsconfig.json",
    "content": "{\n  \"extends\": \"../../tsconfig.json\",\n  \"include\": [\"src\"]\n}\n"
  },
  {
    "path": "exchanges/graphcache/vitest.config.ts",
    "content": "import { mergeConfig } from 'vitest/config';\nimport baseConfig from '../../vitest.config';\n\nexport default mergeConfig(baseConfig, {});\n"
  },
  {
    "path": "exchanges/persisted/CHANGELOG.md",
    "content": "# @urql/exchange-persisted-fetch\n\n## 5.0.1\n\n### Patch Changes\n\n- Use nullish coalescing for `preferGetMethod` and `preferGetForPersistedQueries` so that `false` is kept if set\n  Submitted by [@dargmuesli](https://github.com/dargmuesli) (See [#3812](https://github.com/urql-graphql/urql/pull/3812))\n- Updated dependencies (See [#3812](https://github.com/urql-graphql/urql/pull/3812))\n  - @urql/core@6.0.1\n\n## 5.0.0\n\n### Major Changes\n\n- By default leverage GET for queries where the query-string + variables comes down to less than 2048 characters.\n  When upgrading it's important to see whether your server supports `GET`, if it doesn't ideally adding support for it\n  or alternatively setting `preferGetMethod` in the `createClient` method as well as `preferGetForPersistedQueries` for\n  the persisted exchange to `false`\n  Submitted by [@JoviDeCroock](https://github.com/JoviDeCroock) (See [#3789](https://github.com/urql-graphql/urql/pull/3789))\n\n### Patch Changes\n\n- Updated dependencies (See [#3789](https://github.com/urql-graphql/urql/pull/3789) and [#3807](https://github.com/urql-graphql/urql/pull/3807))\n  - @urql/core@6.0.0\n\n## 4.3.1\n\n### Patch Changes\n\n- Omit minified files and sourcemaps' `sourcesContent` in published packages\n  Submitted by [@kitten](https://github.com/kitten) (See [#3755](https://github.com/urql-graphql/urql/pull/3755))\n- Updated dependencies (See [#3755](https://github.com/urql-graphql/urql/pull/3755))\n  - @urql/core@5.1.1\n\n## 4.3.0\n\n### Minor Changes\n\n- Mark `@urql/core` as a peer dependency as well as a regular dependency\n  Submitted by [@kitten](https://github.com/kitten) (See [#3579](https://github.com/urql-graphql/urql/pull/3579))\n\n## 4.2.0\n\n### Minor Changes\n\n- Add option to enable persisted-operations for subscriptions\n  Submitted by [@JoviDeCroock](https://github.com/JoviDeCroock) (See [#3549](https://github.com/urql-graphql/urql/pull/3549))\n\n## 4.1.1\n\n### Patch Changes\n\n- Warn about cached persisted-miss results in development, when a `persistedExchange()` sees a persisted-miss error for a result that's already seen a persisted-miss error (i.e. two misses). This shouldn't happen unless something is caching persisted errors and we should warn about this appropriately\n  Submitted by [@kitten](https://github.com/kitten) (See [#3442](https://github.com/urql-graphql/urql/pull/3442))\n\n## 4.1.0\n\n### Minor Changes\n\n- Allow persisted query logic to be skipped by the `persistedExchange` if the passed `generateHash` function resolves to a nullish value. This allows (A)PQ to be selectively disabled for individual operations\n  Submitted by [@kitten](https://github.com/kitten) (See [#3324](https://github.com/urql-graphql/urql/pull/3324))\n\n### Patch Changes\n\n- Updated dependencies (See [#3317](https://github.com/urql-graphql/urql/pull/3317) and [#3308](https://github.com/urql-graphql/urql/pull/3308))\n  - @urql/core@4.1.0\n\n## 4.0.1\n\n### Patch Changes\n\n- ⚠️ Fix `persistedExchange` ignoring teardowns in its initial operation mapping. Since the hash function is promisified, which defers any persisted operation, it needs to respect teardowns\n  Submitted by [@kitten](https://github.com/kitten) (See [#3312](https://github.com/urql-graphql/urql/pull/3312))\n\n## 4.0.0\n\n### Major Changes\n\n- Update the `preferGetForPersistedQueries` option to include the `'force'` and `'within-url-limit'` values from the Client's `preferGetMethod` option. The default value of `true` no longer sets `OperationContext`'s `preferGetMethod` setting to `'force'`. Instead, the value of `preferGetForPersistedQueries` carries through to the `OperationContext`'s `preferGetMethod` setting for persisted queries\n  Submitted by [@NWRichmond](https://github.com/NWRichmond) (See [#3192](https://github.com/urql-graphql/urql/pull/3192))\n\n## 3.0.1\n\n### Patch Changes\n\n- Publish with npm provenance\n  Submitted by [@kitten](https://github.com/kitten) (See [#3180](https://github.com/urql-graphql/urql/pull/3180))\n\n## 3.0.0\n\n### Major Changes\n\n- Remove `persistedFetchExchange` and instead implement `persistedExchange`. This exchange must be placed in front of a terminating exchange (such as the default `fetchExchange` or a `subscriptionExchange` that supports persisted queries), and only modifies incoming operations to contain `extensions.persistedQuery`, which is sent on via the API. If the API expects Automatic Persisted Queries, requests are retried by this exchange internally\n  Submitted by [@kitten](https://github.com/kitten) (See [#3057](https://github.com/urql-graphql/urql/pull/3057))\n- Rename `@urql/exchange-persisted-fetch` to `@urql/exchange-persisted`\n  Submitted by [@kitten](https://github.com/kitten) (See [#3057](https://github.com/urql-graphql/urql/pull/3057))\n\n### Minor Changes\n\n- Update exchanges to drop redundant `share` calls, since `@urql/core`’s `composeExchanges` utility now automatically does so for us\n  Submitted by [@kitten](https://github.com/kitten) (See [#3082](https://github.com/urql-graphql/urql/pull/3082))\n\n### Patch Changes\n\n- Refactor SHA256 logic to save on bundlesize\n  Submitted by [@kitten](https://github.com/kitten) (See [#3052](https://github.com/urql-graphql/urql/pull/3052))\n- Upgrade to `wonka@^6.3.0`\n  Submitted by [@kitten](https://github.com/kitten) (See [#3104](https://github.com/urql-graphql/urql/pull/3104))\n- Add TSDocs for all exchanges, documenting API internals\n  Submitted by [@kitten](https://github.com/kitten) (See [#3072](https://github.com/urql-graphql/urql/pull/3072))\n- Updated dependencies (See [#3101](https://github.com/urql-graphql/urql/pull/3101), [#3033](https://github.com/urql-graphql/urql/pull/3033), [#3054](https://github.com/urql-graphql/urql/pull/3054), [#3053](https://github.com/urql-graphql/urql/pull/3053), [#3060](https://github.com/urql-graphql/urql/pull/3060), [#3081](https://github.com/urql-graphql/urql/pull/3081), [#3039](https://github.com/urql-graphql/urql/pull/3039), [#3104](https://github.com/urql-graphql/urql/pull/3104), [#3082](https://github.com/urql-graphql/urql/pull/3082), [#3097](https://github.com/urql-graphql/urql/pull/3097), [#3061](https://github.com/urql-graphql/urql/pull/3061), [#3055](https://github.com/urql-graphql/urql/pull/3055), [#3085](https://github.com/urql-graphql/urql/pull/3085), [#3079](https://github.com/urql-graphql/urql/pull/3079), [#3087](https://github.com/urql-graphql/urql/pull/3087), [#3059](https://github.com/urql-graphql/urql/pull/3059), [#3055](https://github.com/urql-graphql/urql/pull/3055), [#3057](https://github.com/urql-graphql/urql/pull/3057), [#3050](https://github.com/urql-graphql/urql/pull/3050), [#3062](https://github.com/urql-graphql/urql/pull/3062), [#3051](https://github.com/urql-graphql/urql/pull/3051), [#3043](https://github.com/urql-graphql/urql/pull/3043), [#3063](https://github.com/urql-graphql/urql/pull/3063), [#3054](https://github.com/urql-graphql/urql/pull/3054), [#3102](https://github.com/urql-graphql/urql/pull/3102), [#3097](https://github.com/urql-graphql/urql/pull/3097), [#3106](https://github.com/urql-graphql/urql/pull/3106), [#3058](https://github.com/urql-graphql/urql/pull/3058), and [#3062](https://github.com/urql-graphql/urql/pull/3062))\n  - @urql/core@4.0.0\n\n## 2.1.0\n\n### Minor Changes\n\n- Adds enableForMutation option for exchange-persisted-fetch to enable persisted operations for mutations, by [@geekuillaume](https://github.com/geekuillaume) (See [#2951](https://github.com/urql-graphql/urql/pull/2951))\n\n## 2.0.0\n\n### Major Changes\n\n- **Goodbye IE11!** 👋 This major release removes support for IE11. All code that is shipped will be transpiled much less and will _not_ be ES5-compatible anymore, by [@kitten](https://github.com/kitten) (See [#2504](https://github.com/FormidableLabs/urql/pull/2504))\n- Upgrade to [Wonka v6](https://github.com/0no-co/wonka) (`wonka@^6.0.0`), which has no breaking changes but is built to target ES2015 and comes with other minor improvements.\n  The library has fully been migrated to TypeScript which will hopefully help with making contributions easier!, by [@kitten](https://github.com/kitten) (See [#2504](https://github.com/FormidableLabs/urql/pull/2504))\n\n### Minor Changes\n\n- Remove the `babel-plugin-modular-graphql` helper, this because the graphql package hasn't converted to ESM yet which gives issues in node environments, by [@JoviDeCroock](https://github.com/JoviDeCroock) (See [#2551](https://github.com/FormidableLabs/urql/pull/2551))\n\n### Patch Changes\n\n- Updated dependencies (See [#2551](https://github.com/FormidableLabs/urql/pull/2551), [#2504](https://github.com/FormidableLabs/urql/pull/2504), [#2619](https://github.com/FormidableLabs/urql/pull/2619), [#2607](https://github.com/FormidableLabs/urql/pull/2607), and [#2504](https://github.com/FormidableLabs/urql/pull/2504))\n  - @urql/core@3.0.0\n\n## 1.3.4\n\n### Patch Changes\n\n- Extend peer dependency range of `graphql` to include `^16.0.0`.\n  As always when upgrading across many packages of `urql`, especially including `@urql/core` we recommend you to deduplicate dependencies after upgrading, using `npm dedupe` or `npx yarn-deduplicate`, by [@kitten](https://github.com/kitten) (See [#2133](https://github.com/FormidableLabs/urql/pull/2133))\n- Updated dependencies (See [#2133](https://github.com/FormidableLabs/urql/pull/2133))\n  - @urql/core@2.3.6\n\n## 1.3.3\n\n### Patch Changes\n\n- ⚠️ Fix Crypto API support for Web Workers and Node Crypto in ESM mode. Previously, when Node Crypto was required in Node ESM mode it would result in an error instead, since we didn't try a dynamic import fallback, by [@kitten](https://github.com/kitten) (See [#2123](https://github.com/FormidableLabs/urql/pull/2123))\n\n## 1.3.2\n\n### Patch Changes\n\n- Optimize for minification by avoiding direct eval call, by [@nderscore](https://github.com/nderscore) (See [#1744](https://github.com/FormidableLabs/urql/pull/1744))\n- Updated dependencies (See [#1776](https://github.com/FormidableLabs/urql/pull/1776) and [#1755](https://github.com/FormidableLabs/urql/pull/1755))\n  - @urql/core@2.1.5\n\n## 1.3.1\n\n### Patch Changes\n\n- Remove closure-compiler from the build step (See [#1570](https://github.com/FormidableLabs/urql/pull/1570))\n- Updated dependencies (See [#1570](https://github.com/FormidableLabs/urql/pull/1570), [#1509](https://github.com/FormidableLabs/urql/pull/1509), [#1600](https://github.com/FormidableLabs/urql/pull/1600), and [#1515](https://github.com/FormidableLabs/urql/pull/1515))\n  - @urql/core@2.1.0\n\n## 1.3.0\n\n### Minor Changes\n\n- Add `enforcePersistedQueries` option to `persistedFetchExchange`, which disables automatic persisted queries and retry logic, and instead assumes that persisted queries will be handled like normal GraphQL requests, by [@kitten](https://github.com/kitten) (See [#1358](https://github.com/FormidableLabs/urql/pull/1358))\n\n### Patch Changes\n\n- Updated dependencies (See [#1374](https://github.com/FormidableLabs/urql/pull/1374), [#1357](https://github.com/FormidableLabs/urql/pull/1357), and [#1375](https://github.com/FormidableLabs/urql/pull/1375))\n  - @urql/core@2.0.0\n\n## 1.2.3\n\n### Patch Changes\n\n- ⚠️ Fix the production build overwriting the development build. Specifically in the previous release we mistakenly replaced all development bundles with production bundles. This doesn't have any direct influence on how these packages work, but prevented development warnings from being logged or full errors from being thrown, by [@kitten](https://github.com/kitten) (See [#1097](https://github.com/FormidableLabs/urql/pull/1097))\n- Updated dependencies (See [#1097](https://github.com/FormidableLabs/urql/pull/1097))\n  - @urql/core@1.14.1\n\n## 1.2.2\n\n### Patch Changes\n\n- Deprecate the `Operation.operationName` property in favor of `Operation.kind`. This name was\n  previously confusing as `operationName` was effectively referring to two different things. You can\n  safely upgrade to this new version, however to mute all deprecation warnings you will have to\n  **upgrade** all `urql` packages you use. If you have custom exchanges that spread operations, please\n  use [the new `makeOperation` helper\n  function](https://formidable.com/open-source/urql/docs/api/core/#makeoperation) instead, by [@bkonkle](https://github.com/bkonkle) (See [#1045](https://github.com/FormidableLabs/urql/pull/1045))\n- Updated dependencies (See [#1094](https://github.com/FormidableLabs/urql/pull/1094) and [#1045](https://github.com/FormidableLabs/urql/pull/1045))\n  - @urql/core@1.14.0\n\n## 1.2.1\n\n### Patch Changes\n\n- Omit the `Content-Type: application/json` HTTP header when using GET in the `fetchExchange`, `persistedFetchExchange`, or `multipartFetchExchange`, by [@JoviDeCroock](https://github.com/JoviDeCroock) (See [#957](https://github.com/FormidableLabs/urql/pull/957))\n- Stops sending a persisted query if the hashing function fails, by [@lorenries](https://github.com/lorenries) (See [#934](https://github.com/FormidableLabs/urql/pull/934))\n- Updated dependencies (See [#947](https://github.com/FormidableLabs/urql/pull/947), [#962](https://github.com/FormidableLabs/urql/pull/962), and [#957](https://github.com/FormidableLabs/urql/pull/957))\n  - @urql/core@1.13.0\n\n## 1.2.0\n\n### Minor Changes\n\n- Pass the parsed GraphQL-document as a second argument to the `generateHash` option, by [@JoviDeCroock](https://github.com/JoviDeCroock) (See [#887](https://github.com/FormidableLabs/urql/pull/887))\n\n### Patch Changes\n\n- Updated dependencies (See [#911](https://github.com/FormidableLabs/urql/pull/911) and [#908](https://github.com/FormidableLabs/urql/pull/908))\n  - @urql/core@1.12.3\n\n## 1.1.0\n\n### Minor Changes\n\n- Adds support for custom hash functions by adding a `generateHash` option to the exchange, by [@lorenries](https://github.com/lorenries) (See [#870](https://github.com/FormidableLabs/urql/pull/870))\n\n### Patch Changes\n\n- Updated dependencies (See [#880](https://github.com/FormidableLabs/urql/pull/880) and [#885](https://github.com/FormidableLabs/urql/pull/885))\n  - @urql/core@1.12.2\n\n## 1.0.1\n\n### Patch Changes\n\n- Upgrade to a minimum version of wonka@^4.0.14 to work around issues with React Native's minification builds, which use uglify-es and could lead to broken bundles, by [@kitten](https://github.com/kitten) (See [#842](https://github.com/FormidableLabs/urql/pull/842))\n- Updated dependencies (See [#838](https://github.com/FormidableLabs/urql/pull/838) and [#842](https://github.com/FormidableLabs/urql/pull/842))\n  - @urql/core@1.12.0\n\n## 1.0.0\n\n### Major Changes\n\n- Change the `persistedFetchExchange` to be an exchange factory. The `persistedFetchExchange` now\n  expects to be called with options. An optional option, `preferGetForPersistedQueries`, may now\n  be passed to send persisted queries as a GET request, even when the `Client`'s `preferGetMethod`\n  option is `false`.\n\nTo migrate you will have to update your usage of `persistedFetchExchange` from\n\n```js\nimport { persistedFetchExchange } from '@urql/exchange-persisted-fetch';\n\ncreateClient({\n  exchanges: [persistedFetchExchange],\n});\n```\n\nto the following:\n\n```js\nimport { persistedFetchExchange } from '@urql/exchange-persisted-fetch';\n\ncreateClient({\n  exchanges: [\n    // Call the exchange and pass optional options:\n    persistedFetchExchange(),\n  ],\n});\n```\n\n### Patch Changes\n\n- Replace `js-sha256` polyfill for Node.js support with Node's Native Crypto API, by [@kitten](https://github.com/kitten) (See [#807](https://github.com/FormidableLabs/urql/pull/807))\n- Updated dependencies (See [#798](https://github.com/FormidableLabs/urql/pull/798))\n  - @urql/core@1.11.8\n\n## 0.1.3\n\n### Patch Changes\n\n- Add `source` debug name to all `dispatchDebug` calls during build time to identify events by which exchange dispatched them, by [@JoviDeCroock](https://github.com/JoviDeCroock) (See [#780](https://github.com/FormidableLabs/urql/pull/780))\n- Updated dependencies (See [#780](https://github.com/FormidableLabs/urql/pull/780))\n  - @urql/core@1.11.7\n\n## 0.1.2\n\n### Patch Changes\n\n- Add a `\"./package.json\"` entry to the `package.json`'s `\"exports\"` field for Node 14. This seems to be required by packages like `rollup-plugin-svelte` to function properly, by [@JoviDeCroock](https://github.com/JoviDeCroock) (See [#771](https://github.com/FormidableLabs/urql/pull/771))\n- Updated dependencies (See [#771](https://github.com/FormidableLabs/urql/pull/771))\n  - @urql/core@1.11.6\n\n## 0.1.1\n\n### Patch Changes\n\n- ⚠️ Fix `persistedFetchExchange` not sending the SHA256 hash extension after a cache miss (`PersistedQueryNotFound` error), by [@kitten](https://github.com/kitten) (See [#766](https://github.com/FormidableLabs/urql/pull/766))\n\n## 0.1.0\n\nThis is the initial release of `@urql/exchange-persisted-fetch` which adds Persisted Queries\nsupport, and is an exchange that can be used alongside the default `fetchExchange` or\n`@urql/exchange-multipart-fetch`.\n\nIt's still experimental, just like `@urql/exchange-multipart-fetch`, so please test it with care and\nreport any bugs you find.\n"
  },
  {
    "path": "exchanges/persisted/README.md",
    "content": "# @urql/exchange-persisted\n\nThe `persistedExchange` is an exchange that allows other terminating exchanges to support Persisted Queries, and is as such placed in front of either the default `fetchExchange` or\nother terminating exchanges.\n\n## Quick Start Guide\n\nFirst install `@urql/exchange-persisted` alongside `urql`:\n\n```sh\nyarn add @urql/exchange-persisted\n# or\nnpm install --save @urql/exchange-persisted\n```\n\nYou'll then need to add the `persistedExchange` function, that this package exposes,\nto your `exchanges`.\n\n```js\nimport { createClient, fetchExchange, cacheExchange } from 'urql';\nimport { persistedExchange } from '@urql/exchange-persisted';\n\nconst client = createClient({\n  url: 'http://localhost:1234/graphql',\n  exchanges: [\n    cacheExchange,\n    persistedExchange({\n      /* optional config */\n    }),\n    fetchExchange,\n  ],\n});\n```\n\nThe `persistedExchange` supports three configuration options:\n\n- `preferGetForPersistedQueries`: Enforce `GET` method to be used by the default `fetchExchange` for persisted queries\n- `enforcePersistedQueries`: This disables _automatic persisted queries_ and disables any retry logic for how the API responds to persisted queries. Instead it's assumed that they'll always succeed.\n- `generateHash`: A function that takes a GraphQL query and returns the hashed result. This defaults to the `window.crypto` API in the browser and the `crypto` module in Node.\n- `enableForMutation`: By default, the exchange only handles `query` operations, but enabling this allows it to handle mutations as well.\n\n## Avoid hashing during runtime\n\nIf you want to generate hashes at build-time you can use a [webpack-loader](https://github.com/leoasis/graphql-persisted-document-loader) to achieve this,\nwhen using this all you need to do in this exchange is the following:\n\n```js\nimport { createClient, fetchExchange, cacheExchange } from 'urql';\nimport { persistedExchange } from '@urql/exchange-persisted';\n\nconst client = createClient({\n  url: 'http://localhost:1234/graphql',\n  exchanges: [\n    cacheExchange,\n    persistedExchange({\n      generateHash: (_, document) => document.documentId,\n    }),\n    fetchExchange,\n  ],\n});\n```\n"
  },
  {
    "path": "exchanges/persisted/jsr.json",
    "content": "{\n  \"name\": \"@urql/exchange-persisted\",\n  \"version\": \"5.0.1\",\n  \"exports\": {\n    \".\": \"./src/index.ts\"\n  },\n  \"exclude\": [\n    \"node_modules\",\n    \"cypress\",\n    \"**/*.test.*\",\n    \"**/*.spec.*\",\n    \"**/*.test.*.snap\",\n    \"**/*.spec.*.snap\"\n  ]\n}"
  },
  {
    "path": "exchanges/persisted/package.json",
    "content": "{\n  \"name\": \"@urql/exchange-persisted\",\n  \"version\": \"5.0.1\",\n  \"description\": \"An exchange that allows for persisted queries support when fetching queries\",\n  \"sideEffects\": false,\n  \"homepage\": \"https://formidable.com/open-source/urql/docs/\",\n  \"bugs\": \"https://github.com/urql-graphql/urql/issues\",\n  \"license\": \"MIT\",\n  \"author\": \"urql GraphQL Contributors\",\n  \"repository\": {\n    \"type\": \"git\",\n    \"url\": \"https://github.com/urql-graphql/urql.git\",\n    \"directory\": \"exchanges/persisted\"\n  },\n  \"keywords\": [\n    \"urql\",\n    \"graphql\",\n    \"persisted queries\",\n    \"exchanges\"\n  ],\n  \"main\": \"dist/urql-exchange-persisted\",\n  \"module\": \"dist/urql-exchange-persisted.mjs\",\n  \"types\": \"dist/urql-exchange-persisted.d.ts\",\n  \"source\": \"src/index.ts\",\n  \"exports\": {\n    \".\": {\n      \"types\": \"./dist/urql-exchange-persisted.d.ts\",\n      \"import\": \"./dist/urql-exchange-persisted.mjs\",\n      \"require\": \"./dist/urql-exchange-persisted.js\",\n      \"source\": \"./src/index.ts\"\n    },\n    \"./package.json\": \"./package.json\"\n  },\n  \"files\": [\n    \"LICENSE\",\n    \"CHANGELOG.md\",\n    \"README.md\",\n    \"dist/\"\n  ],\n  \"scripts\": {\n    \"test\": \"vitest\",\n    \"clean\": \"rimraf dist extras\",\n    \"check\": \"tsc --noEmit\",\n    \"lint\": \"eslint --ext=js,jsx,ts,tsx .\",\n    \"build\": \"rollup -c ../../scripts/rollup/config.mjs\",\n    \"prepare\": \"node ../../scripts/prepare/index.js\",\n    \"prepublishOnly\": \"run-s clean build\"\n  },\n  \"peerDependencies\": {\n    \"@urql/core\": \"^6.0.0\"\n  },\n  \"dependencies\": {\n    \"@urql/core\": \"workspace:^6.0.1\",\n    \"wonka\": \"^6.3.2\"\n  },\n  \"devDependencies\": {\n    \"@urql/core\": \"workspace:*\",\n    \"graphql\": \"^16.0.0\"\n  },\n  \"publishConfig\": {\n    \"access\": \"public\",\n    \"provenance\": true\n  }\n}\n"
  },
  {
    "path": "exchanges/persisted/src/index.ts",
    "content": "export * from './persistedExchange';\n"
  },
  {
    "path": "exchanges/persisted/src/persistedExchange.test.ts",
    "content": "import {\n  Source,\n  pipe,\n  fromValue,\n  fromArray,\n  toPromise,\n  delay,\n  take,\n  tap,\n  map,\n} from 'wonka';\n\nimport { Client, Operation, OperationResult, CombinedError } from '@urql/core';\n\nimport { vi, expect, it } from 'vitest';\nimport {\n  queryResponse,\n  queryOperation,\n} from '../../../packages/core/src/test-utils';\nimport { persistedExchange } from './persistedExchange';\n\nconst makeExchangeArgs = () => {\n  const operations: Operation[] = [];\n\n  const result = vi.fn(\n    (operation: Operation): OperationResult => ({ ...queryResponse, operation })\n  );\n\n  return {\n    operations,\n    result,\n    exchangeArgs: {\n      forward: (op$: Source<Operation>) =>\n        pipe(\n          op$,\n          tap(op => operations.push(op)),\n          map(result)\n        ),\n      client: new Client({ url: '/api', exchanges: [] }),\n    } as any,\n  };\n};\n\nit('adds the APQ extensions correctly', async () => {\n  const { exchangeArgs } = makeExchangeArgs();\n\n  const res = await pipe(\n    fromValue(queryOperation),\n    persistedExchange()(exchangeArgs),\n    take(1),\n    toPromise\n  );\n\n  expect(res.operation.context.persistAttempt).toBe(true);\n  expect(res.operation.extensions).toEqual({\n    persistedQuery: {\n      version: 1,\n      sha256Hash: expect.any(String),\n      miss: undefined,\n    },\n  });\n});\n\nit('retries query when persisted query resulted in miss', async () => {\n  const { result, operations, exchangeArgs } = makeExchangeArgs();\n\n  result.mockImplementationOnce(operation => ({\n    ...queryResponse,\n    operation,\n    error: new CombinedError({\n      graphQLErrors: [{ message: 'PersistedQueryNotFound' }],\n    }),\n  }));\n\n  const res = await pipe(\n    fromValue(queryOperation),\n    persistedExchange()(exchangeArgs),\n    take(1),\n    toPromise\n  );\n\n  expect(res.operation.context.persistAttempt).toBe(true);\n  expect(operations.length).toBe(2);\n\n  expect(operations[1].extensions).toEqual({\n    persistedQuery: {\n      version: 1,\n      sha256Hash: expect.any(String),\n      miss: true,\n    },\n  });\n});\n\nit('retries query persisted query resulted in unsupported', async () => {\n  const { result, operations, exchangeArgs } = makeExchangeArgs();\n\n  result.mockImplementationOnce(operation => ({\n    ...queryResponse,\n    operation,\n    error: new CombinedError({\n      graphQLErrors: [{ message: 'PersistedQueryNotSupported' }],\n    }),\n  }));\n\n  await pipe(\n    fromArray([queryOperation, queryOperation]),\n    delay(0),\n    persistedExchange()(exchangeArgs),\n    take(2),\n    toPromise\n  );\n\n  expect(operations.length).toBe(3);\n\n  expect(operations[1].extensions).toEqual({\n    persistedQuery: undefined,\n  });\n\n  expect(operations[2].extensions).toEqual(undefined);\n});\n\nit('fails gracefully when an invalid result with `PersistedQueryNotFound` is always delivered', async () => {\n  const { result, operations, exchangeArgs } = makeExchangeArgs();\n\n  result.mockImplementation(operation => ({\n    ...queryResponse,\n    operation,\n    error: new CombinedError({\n      graphQLErrors: [{ message: 'PersistedQueryNotFound' }],\n    }),\n  }));\n\n  const res = await pipe(\n    fromValue(queryOperation),\n    persistedExchange()(exchangeArgs),\n    take(1),\n    toPromise\n  );\n\n  expect(res.operation.context.persistAttempt).toBe(true);\n  expect(operations.length).toBe(2);\n\n  expect(operations[1].extensions).toEqual({\n    persistedQuery: {\n      version: 1,\n      sha256Hash: expect.any(String),\n      miss: true,\n    },\n  });\n\n  expect(console.warn).toHaveBeenLastCalledWith(\n    expect.stringMatching(/two misses/i)\n  );\n});\n\nit('skips operation when generateHash returns a nullish value', async () => {\n  const { result, operations, exchangeArgs } = makeExchangeArgs();\n\n  result.mockImplementationOnce(operation => ({\n    ...queryResponse,\n    operation,\n    data: null,\n  }));\n\n  const res = await pipe(\n    fromValue(queryOperation),\n    persistedExchange({ generateHash: async () => null })(exchangeArgs),\n    take(1),\n    toPromise\n  );\n\n  expect(res.operation.context.persistAttempt).toBe(true);\n  expect(operations.length).toBe(1);\n  expect(operations[0]).not.toHaveProperty('extensions.persistedQuery');\n});\n\nit.each([true, false, 'force', 'within-url-limit'] as const)(\n  'sets `context.preferGetMethod` to %s when `options.preferGetForPersistedQueries` is %s',\n  async preferGetMethodValue => {\n    const { exchangeArgs } = makeExchangeArgs();\n\n    const res = await pipe(\n      fromValue(queryOperation),\n      persistedExchange({ preferGetForPersistedQueries: preferGetMethodValue })(\n        exchangeArgs\n      ),\n      take(1),\n      toPromise\n    );\n\n    expect(res.operation.context.preferGetMethod).toBe(preferGetMethodValue);\n  }\n);\n"
  },
  {
    "path": "exchanges/persisted/src/persistedExchange.ts",
    "content": "import {\n  map,\n  makeSubject,\n  fromPromise,\n  filter,\n  merge,\n  mergeMap,\n  takeUntil,\n  pipe,\n} from 'wonka';\n\nimport type {\n  PersistedRequestExtensions,\n  TypedDocumentNode,\n  OperationResult,\n  CombinedError,\n  Exchange,\n  Operation,\n  OperationContext,\n} from '@urql/core';\nimport { makeOperation, stringifyDocument } from '@urql/core';\n\nimport { hash } from './sha256';\n\nconst isPersistedMiss = (error: CombinedError): boolean =>\n  error.graphQLErrors.some(x => x.message === 'PersistedQueryNotFound');\n\nconst isPersistedUnsupported = (error: CombinedError): boolean =>\n  error.graphQLErrors.some(x => x.message === 'PersistedQueryNotSupported');\n\n/** Input parameters for the {@link persistedExchange}. */\nexport interface PersistedExchangeOptions {\n  /** Controls whether GET method requests will be made for Persisted Queries.\n   *\n   * @remarks\n   * When set to `true` or `'within-url-limit'`, the `persistedExchange`\n   * will use GET requests on persisted queries when the request URL\n   * doesn't exceed the 2048 character limit.\n   *\n   * When set to `force`, the `persistedExchange` will set\n   * `OperationContext.preferGetMethod` to `'force'` on persisted queries,\n   * which will force requests to be made using a GET request.\n   *\n   * GET requests are frequently used to make GraphQL requests more\n   * cacheable on CDNs.\n   *\n   * @defaultValue `within-url-limit` - Use GET requests for persisted queries within the URL limit.\n   */\n  preferGetForPersistedQueries?: OperationContext['preferGetMethod'];\n  /** Enforces non-automatic persisted queries by ignoring APQ errors.\n   *\n   * @remarks\n   * When enabled, the `persistedExchange` will ignore `PersistedQueryNotFound`\n   * and `PersistedQueryNotSupported` errors and assume that all persisted\n   * queries are already known to the API.\n   *\n   * This is used to switch from Automatic Persisted Queries to\n   * Persisted Queries. This is commonly used to obfuscate GraphQL\n   * APIs.\n   */\n  enforcePersistedQueries?: boolean;\n  /** Custom hashing function for persisted queries.\n   *\n   * @remarks\n   * By default, `persistedExchange` will create a SHA-256 hash for\n   * persisted queries automatically. If you're instead generating\n   * hashes at compile-time, or need to use a custom SHA-256 function,\n   * you may pass one here.\n   *\n   * If `generateHash` returns either `null` or `undefined`, the\n   * operation will not be treated as a persisted operation, which\n   * essentially skips this exchange’s logic for a given operation.\n   *\n   * Hint: The default SHA-256 function uses the WebCrypto API. This\n   * API is unavailable on React Native, which may require you to\n   * pass a custom function here.\n   */\n  generateHash?(\n    query: string,\n    document: TypedDocumentNode<any, any>\n  ): Promise<string | undefined | null>;\n  /** Enables persisted queries to be used for mutations.\n   *\n   * @remarks\n   * When enabled, the `persistedExchange` will also use the persisted queries\n   * logic for mutation operations.\n   *\n   * This is disabled by default, but often used on APIs that obfuscate\n   * their GraphQL APIs.\n   */\n  enableForMutation?: boolean;\n  /** Enables persisted queries to be used for subscriptions.\n   *\n   * @remarks\n   * When enabled, the `persistedExchange` will also use the persisted queries\n   * logic for subscription operations.\n   *\n   * This is disabled by default, but often used on APIs that obfuscate\n   * their GraphQL APIs.\n   */\n  enableForSubscriptions?: boolean;\n}\n\n/** Exchange factory that adds support for Persisted Queries.\n *\n * @param options - A {@link PersistedExchangeOptions} configuration object.\n * @returns the created persisted queries {@link Exchange}.\n *\n * @remarks\n * The `persistedExchange` adds support for (Automatic) Persisted Queries\n * to any `fetchExchange`, `subscriptionExchange`, or other API exchanges\n * following it.\n *\n * It does so by adding the `persistedQuery` extensions field to GraphQL\n * requests and handles `PersistedQueryNotFound` and\n * `PersistedQueryNotSupported` errors.\n *\n * @example\n * ```ts\n * import { Client, cacheExchange, fetchExchange } from '@urql/core';\n * import { persistedExchange } from '@urql/exchange-persisted';\n *\n * const client = new Client({\n *   url: 'URL',\n *   exchanges: [\n *     cacheExchange,\n *     persistedExchange({\n *       preferGetForPersistedQueries: true,\n *     }),\n *     fetchExchange\n *   ],\n * });\n * ```\n */\nexport const persistedExchange =\n  (options?: PersistedExchangeOptions): Exchange =>\n  ({ forward }) => {\n    if (!options) options = {};\n\n    const preferGetForPersistedQueries =\n      options.preferGetForPersistedQueries != null\n        ? options.preferGetForPersistedQueries\n        : 'within-url-limit';\n    const enforcePersistedQueries = !!options.enforcePersistedQueries;\n    const hashFn = options.generateHash || hash;\n    const enableForMutation = !!options.enableForMutation;\n    const enableForSubscriptions = !!options.enableForSubscriptions;\n    let supportsPersistedQueries = true;\n\n    const operationFilter = (operation: Operation) =>\n      supportsPersistedQueries &&\n      !operation.context.persistAttempt &&\n      ((enableForMutation && operation.kind === 'mutation') ||\n        (enableForSubscriptions && operation.kind === 'subscription') ||\n        operation.kind === 'query');\n\n    const getPersistedOperation = async (operation: Operation) => {\n      const persistedOperation = makeOperation(operation.kind, operation, {\n        ...operation.context,\n        persistAttempt: true,\n      });\n\n      const sha256Hash = await hashFn(\n        stringifyDocument(operation.query),\n        operation.query\n      );\n      if (sha256Hash) {\n        persistedOperation.extensions = {\n          ...persistedOperation.extensions,\n          persistedQuery: {\n            version: 1,\n            sha256Hash,\n          },\n        };\n        if (persistedOperation.kind === 'query') {\n          persistedOperation.context.preferGetMethod =\n            preferGetForPersistedQueries;\n        }\n      }\n\n      return persistedOperation;\n    };\n\n    return operations$ => {\n      const retries = makeSubject<Operation>();\n\n      const forwardedOps$ = pipe(\n        operations$,\n        filter(operation => !operationFilter(operation))\n      );\n\n      const persistedOps$ = pipe(\n        operations$,\n        filter(operationFilter),\n        mergeMap(operation => {\n          const persistedOperation$ = getPersistedOperation(operation);\n          return pipe(\n            fromPromise(persistedOperation$),\n            takeUntil(\n              pipe(\n                operations$,\n                filter(op => op.kind === 'teardown' && op.key === operation.key)\n              )\n            )\n          );\n        })\n      );\n\n      return pipe(\n        merge([persistedOps$, forwardedOps$, retries.source]),\n        forward,\n        map(result => {\n          if (\n            !enforcePersistedQueries &&\n            result.operation.extensions &&\n            result.operation.extensions.persistedQuery\n          ) {\n            if (result.error && isPersistedUnsupported(result.error)) {\n              // Disable future persisted queries if they're not enforced\n              supportsPersistedQueries = false;\n              // Update operation with unsupported attempt\n              const followupOperation = makeOperation(\n                result.operation.kind,\n                result.operation\n              );\n              if (followupOperation.extensions)\n                delete followupOperation.extensions.persistedQuery;\n              retries.next(followupOperation);\n              return null;\n            } else if (result.error && isPersistedMiss(result.error)) {\n              if (result.operation.extensions.persistedQuery.miss) {\n                if (process.env.NODE_ENV !== 'production') {\n                  console.warn(\n                    'persistedExchange()’s results include two misses for the same operation.\\n' +\n                      'This is not expected as it means a persisted error has been delivered for a non-persisted query!\\n' +\n                      'Another exchange with a cache may be delivering an outdated result. For example, a server-side ssrExchange() may be caching an errored result.\\n' +\n                      'Try moving the persistedExchange() in past these exchanges, for example in front of your fetchExchange.'\n                  );\n                }\n\n                return result;\n              }\n              // Update operation with unsupported attempt\n              const followupOperation = makeOperation(\n                result.operation.kind,\n                result.operation\n              );\n              // Mark as missed persisted query\n              followupOperation.extensions = {\n                ...followupOperation.extensions,\n                persistedQuery: {\n                  ...(followupOperation.extensions || {}).persistedQuery,\n                  miss: true,\n                } as PersistedRequestExtensions,\n              };\n              retries.next(followupOperation);\n              return null;\n            }\n          }\n          return result;\n        }),\n        filter((result): result is OperationResult => !!result)\n      );\n    };\n  };\n"
  },
  {
    "path": "exchanges/persisted/src/sha256.ts",
    "content": "const webCrypto = (\n  typeof window !== 'undefined'\n    ? window.crypto\n    : typeof self !== 'undefined'\n      ? self.crypto\n      : null\n) as typeof globalThis.crypto | null;\n\nlet nodeCrypto: Promise<typeof import('crypto') | void> | void;\n\nconst getNodeCrypto = async (): Promise<typeof import('crypto') | void> => {\n  if (!nodeCrypto) {\n    // Indirect eval'd require/import to guarantee no side-effects in module scope\n    // (optimization for minifiers)\n    try {\n      nodeCrypto = new Function('require', 'return require(\"crypto\")')(require);\n    } catch (_error) {\n      try {\n        nodeCrypto = new Function('return import(\"crypto\")')();\n      } catch (_error) {}\n    }\n  }\n  return nodeCrypto;\n};\n\nexport const hash = async (query: string): Promise<string> => {\n  if (webCrypto && webCrypto.subtle) {\n    const digest = await webCrypto.subtle.digest(\n      { name: 'SHA-256' },\n      new TextEncoder().encode(query)\n    );\n    return new Uint8Array(digest).reduce(\n      (prev, byte) => prev + byte.toString(16).padStart(2, '0'),\n      ''\n    );\n  } else if (await getNodeCrypto()) {\n    // Node.js support\n    return (await nodeCrypto)!.createHash('sha256').update(query).digest('hex');\n  }\n\n  if (process.env.NODE_ENV !== 'production') {\n    console.warn(\n      '[@urql/exchange-persisted-fetch]: The Node Crypto and Web Crypto APIs are not available.\\n' +\n        'This is an unexpected error. Please report it by filing a GitHub Issue.'\n    );\n  }\n\n  return '';\n};\n"
  },
  {
    "path": "exchanges/persisted/src/test-utils.ts",
    "content": "import type { GraphQLRequest, OperationContext, Operation } from '@urql/core';\nimport { gql, makeOperation } from '@urql/core';\n\nconst context: OperationContext = {\n  fetchOptions: {\n    method: 'POST',\n  },\n  requestPolicy: 'cache-first',\n  url: 'http://localhost:3000/graphql',\n};\n\nconst queryGql: GraphQLRequest = {\n  key: 2,\n  query: gql`\n    query getUser($name: String) {\n      user(name: $name) {\n        id\n        firstName\n        lastName\n      }\n    }\n  `,\n  variables: {\n    name: 'Clara',\n  },\n};\n\nexport const mutationGql: GraphQLRequest = {\n  key: 2,\n  query: gql`\n    mutation AddUser($name: String) {\n      addUser(name: $name) {\n        name\n      }\n    }\n  `,\n  variables: {\n    name: 'Clara',\n  },\n};\n\nexport const queryOperation: Operation = makeOperation(\n  'query',\n  queryGql,\n  context\n);\n\nexport const mutationOperation: Operation = makeOperation(\n  'mutation',\n  mutationGql,\n  context\n);\n"
  },
  {
    "path": "exchanges/persisted/tsconfig.json",
    "content": "{\n  \"extends\": \"../../tsconfig.json\",\n  \"include\": [\"src\"]\n}\n"
  },
  {
    "path": "exchanges/persisted/vitest.config.ts",
    "content": "import { mergeConfig } from 'vitest/config';\nimport baseConfig from '../../vitest.config';\n\nexport default mergeConfig(baseConfig, {});\n"
  },
  {
    "path": "exchanges/populate/CHANGELOG.md",
    "content": "# @urql/exchange-populate\n\n## 2.0.0\n\n### Patch Changes\n\n- Updated dependencies (See [#3789](https://github.com/urql-graphql/urql/pull/3789) and [#3807](https://github.com/urql-graphql/urql/pull/3807))\n  - @urql/core@6.0.0\n\n## 1.2.1\n\n### Patch Changes\n\n- Omit minified files and sourcemaps' `sourcesContent` in published packages\n  Submitted by [@kitten](https://github.com/kitten) (See [#3755](https://github.com/urql-graphql/urql/pull/3755))\n- Updated dependencies (See [#3755](https://github.com/urql-graphql/urql/pull/3755))\n  - @urql/core@5.1.1\n\n## 1.2.0\n\n### Minor Changes\n\n- Mark `@urql/core` as a peer dependency as well as a regular dependency\n  Submitted by [@kitten](https://github.com/kitten) (See [#3579](https://github.com/urql-graphql/urql/pull/3579))\n\n## 1.1.2\n\n### Patch Changes\n\n- Publish with npm provenance\n  Submitted by [@kitten](https://github.com/kitten) (See [#3180](https://github.com/urql-graphql/urql/pull/3180))\n\n## 1.1.1\n\n### Patch Changes\n\n- Upgrade to `wonka@^6.3.0`\n  Submitted by [@kitten](https://github.com/kitten) (See [#3104](https://github.com/urql-graphql/urql/pull/3104))\n- Add TSDocs for all exchanges, documenting API internals\n  Submitted by [@kitten](https://github.com/kitten) (See [#3072](https://github.com/urql-graphql/urql/pull/3072))\n- Updated dependencies (See [#3101](https://github.com/urql-graphql/urql/pull/3101), [#3033](https://github.com/urql-graphql/urql/pull/3033), [#3054](https://github.com/urql-graphql/urql/pull/3054), [#3053](https://github.com/urql-graphql/urql/pull/3053), [#3060](https://github.com/urql-graphql/urql/pull/3060), [#3081](https://github.com/urql-graphql/urql/pull/3081), [#3039](https://github.com/urql-graphql/urql/pull/3039), [#3104](https://github.com/urql-graphql/urql/pull/3104), [#3082](https://github.com/urql-graphql/urql/pull/3082), [#3097](https://github.com/urql-graphql/urql/pull/3097), [#3061](https://github.com/urql-graphql/urql/pull/3061), [#3055](https://github.com/urql-graphql/urql/pull/3055), [#3085](https://github.com/urql-graphql/urql/pull/3085), [#3079](https://github.com/urql-graphql/urql/pull/3079), [#3087](https://github.com/urql-graphql/urql/pull/3087), [#3059](https://github.com/urql-graphql/urql/pull/3059), [#3055](https://github.com/urql-graphql/urql/pull/3055), [#3057](https://github.com/urql-graphql/urql/pull/3057), [#3050](https://github.com/urql-graphql/urql/pull/3050), [#3062](https://github.com/urql-graphql/urql/pull/3062), [#3051](https://github.com/urql-graphql/urql/pull/3051), [#3043](https://github.com/urql-graphql/urql/pull/3043), [#3063](https://github.com/urql-graphql/urql/pull/3063), [#3054](https://github.com/urql-graphql/urql/pull/3054), [#3102](https://github.com/urql-graphql/urql/pull/3102), [#3097](https://github.com/urql-graphql/urql/pull/3097), [#3106](https://github.com/urql-graphql/urql/pull/3106), [#3058](https://github.com/urql-graphql/urql/pull/3058), and [#3062](https://github.com/urql-graphql/urql/pull/3062))\n  - @urql/core@4.0.0\n\n## 1.1.0\n\n### Minor Changes\n\n- Introduce `maxDepth` and `skipType` into the `populateExchange`, these options allow you to specify\n  the maximum depth a mutation should be populated as well as which types should not be counted towards\n  this depth\n  Submitted by [@JoviDeCroock](https://github.com/JoviDeCroock) (See [#3023](https://github.com/urql-graphql/urql/pull/3023))\n\n### Patch Changes\n\n- Updated dependencies (See [#3007](https://github.com/urql-graphql/urql/pull/3007), [#2962](https://github.com/urql-graphql/urql/pull/2962), [#3007](https://github.com/urql-graphql/urql/pull/3007), [#3015](https://github.com/urql-graphql/urql/pull/3015), and [#3022](https://github.com/urql-graphql/urql/pull/3022))\n  - @urql/core@3.2.0\n\n## 1.0.0\n\n### Major Changes\n\n- **Goodbye IE11!** 👋 This major release removes support for IE11. All code that is shipped will be transpiled much less and will _not_ be ES5-compatible anymore, by [@kitten](https://github.com/kitten) (See [#2504](https://github.com/FormidableLabs/urql/pull/2504))\n- Upgrade to [Wonka v6](https://github.com/0no-co/wonka) (`wonka@^6.0.0`), which has no breaking changes but is built to target ES2015 and comes with other minor improvements.\n  The library has fully been migrated to TypeScript which will hopefully help with making contributions easier!, by [@kitten](https://github.com/kitten) (See [#2504](https://github.com/FormidableLabs/urql/pull/2504))\n\n### Minor Changes\n\n- Remove the `babel-plugin-modular-graphql` helper, this because the graphql package hasn't converted to ESM yet which gives issues in node environments, by [@JoviDeCroock](https://github.com/JoviDeCroock) (See [#2551](https://github.com/FormidableLabs/urql/pull/2551))\n\n### Patch Changes\n\n- Updated dependencies (See [#2551](https://github.com/FormidableLabs/urql/pull/2551), [#2504](https://github.com/FormidableLabs/urql/pull/2504), [#2619](https://github.com/FormidableLabs/urql/pull/2619), [#2607](https://github.com/FormidableLabs/urql/pull/2607), and [#2504](https://github.com/FormidableLabs/urql/pull/2504))\n  - @urql/core@3.0.0\n\n## 0.2.3\n\n### Patch Changes\n\n- Extend peer dependency range of `graphql` to include `^16.0.0`.\n  As always when upgrading across many packages of `urql`, especially including `@urql/core` we recommend you to deduplicate dependencies after upgrading, using `npm dedupe` or `npx yarn-deduplicate`, by [@kitten](https://github.com/kitten) (See [#2133](https://github.com/FormidableLabs/urql/pull/2133))\n- Updated dependencies (See [#2133](https://github.com/FormidableLabs/urql/pull/2133))\n  - @urql/core@2.3.6\n\n## 0.2.2\n\n### Patch Changes\n\n- Remove closure-compiler from the build step (See [#1570](https://github.com/FormidableLabs/urql/pull/1570))\n- Updated dependencies (See [#1570](https://github.com/FormidableLabs/urql/pull/1570), [#1509](https://github.com/FormidableLabs/urql/pull/1509), [#1600](https://github.com/FormidableLabs/urql/pull/1600), and [#1515](https://github.com/FormidableLabs/urql/pull/1515))\n  - @urql/core@2.1.0\n\n## 0.2.1\n\n### Patch Changes\n\n- Add missing `.mjs` extension to all imports from `graphql` to fix Webpack 5 builds, which require extension-specific import paths for ESM bundles and packages. **This change allows you to safely upgrade to Webpack 5.**, by [@kitten](https://github.com/kitten) (See [#1094](https://github.com/FormidableLabs/urql/pull/1094))\n- Deprecate the `Operation.operationName` property in favor of `Operation.kind`. This name was\n  previously confusing as `operationName` was effectively referring to two different things. You can\n  safely upgrade to this new version, however to mute all deprecation warnings you will have to\n  **upgrade** all `urql` packages you use. If you have custom exchanges that spread operations, please\n  use [the new `makeOperation` helper\n  function](https://formidable.com/open-source/urql/docs/api/core/#makeoperation) instead, by [@bkonkle](https://github.com/bkonkle) (See [#1045](https://github.com/FormidableLabs/urql/pull/1045))\n- Updated dependencies (See [#1094](https://github.com/FormidableLabs/urql/pull/1094) and [#1045](https://github.com/FormidableLabs/urql/pull/1045))\n  - @urql/core@1.14.0\n\n## 0.2.0\n\n### Minor Changes\n\n- Support interfaces and nested interfaces, by [@JoviDeCroock](https://github.com/JoviDeCroock) (See [#963](https://github.com/FormidableLabs/urql/pull/963))\n\n### Patch Changes\n\n- Updated dependencies (See [#1011](https://github.com/FormidableLabs/urql/pull/1011))\n  - @urql/core@1.13.1\n\n## 0.1.8\n\n### Patch Changes\n\n- Upgrade to a minimum version of wonka@^4.0.14 to work around issues with React Native's minification builds, which use uglify-es and could lead to broken bundles, by [@kitten](https://github.com/kitten) (See [#842](https://github.com/FormidableLabs/urql/pull/842))\n- Updated dependencies (See [#838](https://github.com/FormidableLabs/urql/pull/838) and [#842](https://github.com/FormidableLabs/urql/pull/842))\n  - @urql/core@1.12.0\n\n## 0.1.7\n\n### Patch Changes\n\n- Add a `\"./package.json\"` entry to the `package.json`'s `\"exports\"` field for Node 14. This seems to be required by packages like `rollup-plugin-svelte` to function properly, by [@JoviDeCroock](https://github.com/JoviDeCroock) (See [#771](https://github.com/FormidableLabs/urql/pull/771))\n- ⚠️ Fix `visitWithTypeInfo` import, by [@JoviDeCroock](https://github.com/JoviDeCroock) (See [#771](https://github.com/FormidableLabs/urql/pull/771))\n- Updated dependencies (See [#771](https://github.com/FormidableLabs/urql/pull/771))\n  - @urql/core@1.11.6\n\n## 0.1.6\n\n### Patch Changes\n\n- ⚠️ Fix @urql/exchange-populate visitWithTypeInfo import by bumping babel-plugin-modular-graphql, by [@kitten](https://github.com/kitten) (See [#709](https://github.com/FormidableLabs/urql/pull/709))\n\n## 0.1.5\n\n### Patch Changes\n\n- Pick modules from graphql package, instead of importing from graphql/index.mjs, by [@kitten](https://github.com/kitten) (See [#700](https://github.com/FormidableLabs/urql/pull/700))\n- Updated dependencies (See [#700](https://github.com/FormidableLabs/urql/pull/700))\n  - @urql/core@1.10.9\n\n## 0.1.4\n\n### Patch Changes\n\n- Add graphql@^15.0.0 to peer dependency range, by [@kitten](https://github.com/kitten) (See [#688](https://github.com/FormidableLabs/urql/pull/688))\n- Updated dependencies (See [#688](https://github.com/FormidableLabs/urql/pull/688) and [#678](https://github.com/FormidableLabs/urql/pull/678))\n  - @urql/core@1.10.8\n\n## 0.1.3\n\n### Patch Changes\n\n- ⚠️ Fix node resolution when using Webpack, which experiences a bug where it only resolves\n  `package.json:main` instead of `module` when an `.mjs` file imports a package, by [@JoviDeCroock](https://github.com/JoviDeCroock) (See [#642](https://github.com/FormidableLabs/urql/pull/642))\n- Updated dependencies (See [#642](https://github.com/FormidableLabs/urql/pull/642))\n  - @urql/core@1.10.4\n\n## 0.1.2\n\n### Patch Changes\n\n- ⚠️ Fix Node.js Module support for v13 (experimental-modules) and v14. If your bundler doesn't support\n  `.mjs` files and fails to resolve the new version, please double check your configuration for\n  Webpack, or similar tools, by [@JoviDeCroock](https://github.com/JoviDeCroock) (See [#637](https://github.com/FormidableLabs/urql/pull/637))\n- Updated dependencies (See [#637](https://github.com/FormidableLabs/urql/pull/637))\n  - @urql/core@1.10.3\n\n## 0.1.1\n\n### Patch Changes\n\n- Remove the shared package, this will fix the types file generation for graphcache, by [@JoviDeCroock](https://github.com/JoviDeCroock) (See [#579](https://github.com/FormidableLabs/urql/pull/579))\n- Updated dependencies (See [#577](https://github.com/FormidableLabs/urql/pull/577))\n  - @urql/core@1.9.2\n\n## 0.1.0\n\n### Initial release\n\n- Moved the `populateExchange` from `@urql/exchange-graphcache` to its own package.\n"
  },
  {
    "path": "exchanges/populate/README.md",
    "content": "# @urql/exchange-populate\n\n`populate` is an exchange for auto-populating fields in your mutations.\n\n[Read more about the `populateExchange` on our docs!](https://formidable.com/open-source/urql/docs/advanced/auto-populate-mutations)\n\n## Quick Start Guide\n\nFirst install `@urql/exchange-populate` alongside `urql`:\n\n```sh\nyarn add @urql/exchange-populate\n# or\nnpm install --save @urql/exchange-populate\n```\n\nYou'll then need to add the `populateExchange`, that this package exposes.\n\n```js\nimport { createClient, cacheExchange, fetchExchange } from 'urql';\nimport { populateExchange } from '@urql/exchange-populate';\n\nconst client = createClient({\n  url: 'http://localhost:1234/graphql',\n  exchanges: [populateExchange({ schema }), cacheExchange, fetchExchange],\n});\n```\n\nThe `schema` option is the introspection result for your backend graphql schema, more information\nabout how to get your schema can be found [in the \"Schema Awareness\" Page of the Graphcache documentation.](https://formidable.com/open-source/urql/docs/graphcache/schema-awareness/#getting-your-schema).\n\n## Example usage\n\nConsider the following queries which have been requested in other parts of your application:\n\n```graphql\n# Query 1\n{\n  todos {\n    id\n    name\n  }\n}\n\n# Query 2\n{\n  todos {\n    id\n    createdAt\n  }\n}\n```\n\nWithout the `populateExchange` you may write a mutation like the following which returns a newly created todo item:\n\n```graphql\n# Without populate\nmutation addTodo(id: ID!) {\n  addTodo(id: $id) {\n    id        # To update Query 1 & 2\n    name      # To update Query 1\n    createdAt # To update Query 2\n  }\n}\n```\n\nBy using `populateExchange`, you no longer need to manually specify the selection set required to update your other queries. Instead you can just add the `@populate` directive.\n\n```graphql\n# With populate\nmutation addTodo(id: ID!) {\n  addTodo(id: $id) @populate\n}\n```\n\n> Note: The above two mutations produce an identical GraphQL request.\n"
  },
  {
    "path": "exchanges/populate/jsr.json",
    "content": "{\n  \"name\": \"@urql/exchange-populate\",\n  \"version\": \"2.0.0\",\n  \"exports\": {\n    \".\": \"./src/index.ts\"\n  },\n  \"exclude\": [\n    \"node_modules\",\n    \"cypress\",\n    \"**/*.test.*\",\n    \"**/*.spec.*\",\n    \"**/*.test.*.snap\",\n    \"**/*.spec.*.snap\"\n  ]\n}"
  },
  {
    "path": "exchanges/populate/package.json",
    "content": "{\n  \"name\": \"@urql/exchange-populate\",\n  \"version\": \"2.0.0\",\n  \"description\": \"An exchange that automaticcally populates the mutation selection body\",\n  \"sideEffects\": false,\n  \"homepage\": \"https://formidable.com/open-source/urql/docs/advanced/auto-populate-mutations\",\n  \"bugs\": \"https://github.com/urql-graphql/urql/issues\",\n  \"license\": \"MIT\",\n  \"author\": \"urql GraphQL Contributors\",\n  \"repository\": {\n    \"type\": \"git\",\n    \"url\": \"https://github.com/urql-graphql/urql.git\",\n    \"directory\": \"exchanges/populate\"\n  },\n  \"keywords\": [\n    \"urql\",\n    \"graphql\",\n    \"exchanges\"\n  ],\n  \"main\": \"dist/urql-exchange-populate\",\n  \"module\": \"dist/urql-exchange-populate.mjs\",\n  \"types\": \"dist/urql-exchange-populate.d.ts\",\n  \"source\": \"src/index.ts\",\n  \"exports\": {\n    \".\": {\n      \"types\": \"./dist/urql-exchange-populate.d.ts\",\n      \"import\": \"./dist/urql-exchange-populate.mjs\",\n      \"require\": \"./dist/urql-exchange-populate.js\",\n      \"source\": \"./src/index.ts\"\n    },\n    \"./package.json\": \"./package.json\"\n  },\n  \"files\": [\n    \"LICENSE\",\n    \"CHANGELOG.md\",\n    \"README.md\",\n    \"dist/\",\n    \"extras/\"\n  ],\n  \"scripts\": {\n    \"test\": \"vitest\",\n    \"clean\": \"rimraf dist extras\",\n    \"check\": \"tsc --noEmit\",\n    \"lint\": \"eslint --ext=js,jsx,ts,tsx .\",\n    \"build\": \"rollup -c ../../scripts/rollup/config.mjs\",\n    \"prepare\": \"node ../../scripts/prepare/index.js\",\n    \"prepublishOnly\": \"run-s clean build\"\n  },\n  \"dependencies\": {\n    \"@urql/core\": \"workspace:^6.0.1\",\n    \"wonka\": \"^6.3.2\"\n  },\n  \"peerDependencies\": {\n    \"@urql/core\": \"^6.0.0\",\n    \"graphql\": \"^14.0.0 || ^15.0.0 || ^16.0.0 || ^17.0.0\"\n  },\n  \"devDependencies\": {\n    \"@urql/core\": \"workspace:*\",\n    \"graphql\": \"^16.0.0\"\n  },\n  \"publishConfig\": {\n    \"access\": \"public\",\n    \"provenance\": true\n  }\n}\n"
  },
  {
    "path": "exchanges/populate/src/helpers/help.ts",
    "content": "// These are guards that are used throughout the codebase to warn or error on\n// unexpected behaviour or conditions.\n// Every warning and error comes with a number that uniquely identifies them.\n// You can read more about the messages themselves in `docs/graphcache/errors.md`\nexport type ErrorCode =\n  | 1\n  | 2\n  | 3\n  | 4\n  | 5\n  | 6\n  | 7\n  | 8\n  | 9\n  | 10\n  | 11\n  | 12\n  | 13\n  | 15\n  | 16\n  | 17\n  | 18\n  | 19;\n\n// URL unfurls to https://formidable.com/open-source/urql/docs/graphcache/errors/\nconst helpUrl = '\\nhttps://bit.ly/2XbVrpR#';\nconst cache = new Set<string>();\n\nexport function warn(message: string, code: ErrorCode) {\n  if (!cache.has(message)) {\n    console.warn(message + helpUrl + code);\n    cache.add(message);\n  }\n}\n"
  },
  {
    "path": "exchanges/populate/src/helpers/node.ts",
    "content": "import type { NameNode, GraphQLOutputType, GraphQLWrappingType } from 'graphql';\nimport { isWrappingType, Kind } from 'graphql';\n\nexport type GraphQLFlatType = Exclude<GraphQLOutputType, GraphQLWrappingType>;\n\n/** Returns the name of a given node */\nexport const getName = (node: { name: NameNode }): string => node.name.value;\n\nexport const unwrapType = (\n  type: null | undefined | GraphQLOutputType\n): GraphQLFlatType | null => {\n  if (isWrappingType(type)) {\n    return unwrapType(type.ofType);\n  }\n\n  return type || null;\n};\n\nexport function createNameNode(value: string): NameNode {\n  return {\n    kind: Kind.NAME,\n    value,\n  };\n}\n"
  },
  {
    "path": "exchanges/populate/src/helpers/traverse.ts",
    "content": "import type {\n  SelectionNode,\n  ASTNode,\n  DefinitionNode,\n  GraphQLSchema,\n  GraphQLFieldMap,\n  FragmentDefinitionNode,\n  FragmentSpreadNode,\n} from 'graphql';\nimport { Kind, isAbstractType } from 'graphql';\nimport { unwrapType, getName } from './node';\n\nexport function traverse(\n  node: ASTNode,\n  enter?: (n: ASTNode) => ASTNode | void,\n  exit?: (n: ASTNode) => ASTNode | void\n): any {\n  if (enter) {\n    node = enter(node) || node;\n  }\n\n  switch (node.kind) {\n    case Kind.DOCUMENT: {\n      node = {\n        ...node,\n        definitions: node.definitions.map(\n          n => traverse(n, enter, exit) as DefinitionNode\n        ),\n      };\n      break;\n    }\n    case Kind.OPERATION_DEFINITION:\n    case Kind.FIELD:\n    case Kind.FRAGMENT_DEFINITION: {\n      if (node.selectionSet) {\n        node = {\n          ...node,\n          selectionSet: {\n            ...node.selectionSet,\n            selections: node.selectionSet.selections.map(\n              n => traverse(n, enter, exit) as SelectionNode\n            ),\n          },\n        };\n      }\n      break;\n    }\n  }\n\n  if (exit) {\n    node = exit(node) || node;\n  }\n\n  return node;\n}\n\nexport function resolveFields(\n  schema: GraphQLSchema,\n  visits: string[]\n): GraphQLFieldMap<any, any> {\n  let currentFields = schema.getQueryType()!.getFields();\n\n  for (let i = 0; i < visits.length; i++) {\n    const t = unwrapType(currentFields[visits[i]].type);\n\n    if (isAbstractType(t)) {\n      currentFields = {};\n      schema.getPossibleTypes(t).forEach(implementedType => {\n        currentFields = {\n          ...currentFields,\n          // @ts-ignore TODO: proper casting\n          ...schema.getType(implementedType.name)!.toConfig().fields,\n        };\n      });\n    } else {\n      // @ts-ignore TODO: proper casting\n      currentFields = schema.getType(t!.name)!.toConfig().fields;\n    }\n  }\n\n  return currentFields;\n}\n\n/** Get fragment names referenced by node. */\nexport function getUsedFragmentNames(node: FragmentDefinitionNode) {\n  const names: string[] = [];\n\n  traverse(node, n => {\n    if (n.kind === Kind.FRAGMENT_SPREAD) {\n      names.push(getName(n as FragmentSpreadNode));\n    }\n  });\n\n  return names;\n}\n"
  },
  {
    "path": "exchanges/populate/src/index.ts",
    "content": "export * from './populateExchange';\n"
  },
  {
    "path": "exchanges/populate/src/populateExchange.test.ts",
    "content": "import {\n  buildSchema,\n  print,\n  introspectionFromSchema,\n  visit,\n  DocumentNode,\n  ASTKindToNode,\n  Kind,\n} from 'graphql';\nimport { vi, expect, it, describe } from 'vitest';\n\nimport { fromValue, pipe, fromArray, toArray } from 'wonka';\nimport {\n  gql,\n  Client,\n  Operation,\n  OperationContext,\n  makeOperation,\n} from '@urql/core';\n\nimport { populateExchange } from './populateExchange';\n\nconst schemaDef = `\n  interface Node {\n    id: ID!\n  }\n\n  type User implements Node {\n    id: ID!\n    name: String!\n    age: Int!\n    todos: [Todo]\n  }\n\n  type Todo implements Node {\n    id: ID!\n    text: String!\n    createdAt(timezone: String): String!\n    creator: User!\n  }\n\n  union UnionType = User | Todo\n\n  interface Product {\n    id: ID!\n    name: String!\n    price: Int!\n  }\n\n  interface Store {\n    id: ID!\n    name: String!\n  }\n\n  type PhysicalStore implements Store {\n    id: ID!\n    name: String!\n    address: String\n  }\n\n  type OnlineStore implements Store {\n    id: ID!\n    name: String!\n    website: String\n  }\n\n  type SimpleProduct implements Product {\n    id: ID!\n    name: String!\n    price: Int!\n    store: PhysicalStore\n  }\n\n  type ComplexProduct implements Product {\n    id: ID!\n    name: String!\n    price: Int!\n    tax: Int!\n    store: OnlineStore\n  }\n\n  type Company {\n    id: String\n    employees: [User]\n  }\n\n  type Query {\n    todos: [Todo!]\n    users: [User!]!\n    products: [Product]!\n    company: Company\n  }\n\n  type Mutation {\n    addTodo: [Todo]\n    removeTodo: [Node]\n    updateTodo: [UnionType]\n    addProduct: Product\n    removeCompany: Company\n  }\n`;\n\nconst context = {} as OperationContext;\n\nconst getNodesByType = <T extends keyof ASTKindToNode, N = ASTKindToNode[T]>(\n  query: DocumentNode,\n  type: T\n) => {\n  let result: N[] = [];\n\n  visit(query, {\n    [type]: n => {\n      result = [...result, n];\n    },\n  });\n  return result;\n};\n\nconst schema = introspectionFromSchema(buildSchema(schemaDef));\n\nconst exchangeArgs = {\n  forward: a => a as any,\n  client: {} as Client,\n  dispatchDebug: vi.fn(),\n};\n\ndescribe('on mutation', () => {\n  const operation = makeOperation(\n    'mutation',\n    {\n      key: 1234,\n      variables: undefined,\n      query: gql`\n        mutation MyMutation {\n          addTodo @populate\n        }\n      `,\n    },\n    context\n  );\n\n  describe('mutation query', () => {\n    it('matches snapshot', async () => {\n      const response = pipe<Operation, any, Operation[]>(\n        fromValue(operation),\n        populateExchange({ schema })(exchangeArgs),\n        toArray\n      );\n      expect(print(response[0].query)).toMatchInlineSnapshot(`\n        \"mutation MyMutation {\n          addTodo {\n            __typename\n          }\n        }\"\n      `);\n    });\n  });\n});\n\ndescribe('on query -> mutation', () => {\n  const queryOp = makeOperation(\n    'query',\n    {\n      key: 1234,\n      variables: undefined,\n      query: gql`\n        query {\n          todos {\n            id\n            text\n            creator {\n              id\n              name\n            }\n          }\n          users {\n            todos {\n              text\n            }\n          }\n        }\n      `,\n    },\n    context\n  );\n\n  const mutationOp = makeOperation(\n    'mutation',\n    {\n      key: 5678,\n      variables: undefined,\n      query: gql`\n        mutation MyMutation {\n          addTodo @populate\n        }\n      `,\n    },\n    context\n  );\n\n  describe('mutation query', () => {\n    it('matches snapshot', async () => {\n      const response = pipe<Operation, any, Operation[]>(\n        fromArray([queryOp, mutationOp]),\n        populateExchange({ schema })(exchangeArgs),\n        toArray\n      );\n\n      expect(print(response[1].query)).toMatchInlineSnapshot(`\n        \"mutation MyMutation {\n          addTodo {\n            __typename\n            id\n            text\n            creator {\n              __typename\n              id\n              name\n            }\n          }\n        }\"\n      `);\n    });\n  });\n});\n\ndescribe('on query -> mutation', () => {\n  const queryOp = makeOperation(\n    'query',\n    {\n      key: 1234,\n      variables: undefined,\n      query: gql`\n        query {\n          todos {\n            id\n            text\n            createdAt(timezone: \"GMT+1\")\n          }\n        }\n      `,\n    },\n    context\n  );\n\n  const mutationOp = makeOperation(\n    'mutation',\n    {\n      key: 5678,\n      variables: undefined,\n      query: gql`\n        mutation MyMutation {\n          addTodo @populate\n        }\n      `,\n    },\n    context\n  );\n\n  describe('mutation query', () => {\n    it('matches snapshot', async () => {\n      const response = pipe<Operation, any, Operation[]>(\n        fromArray([queryOp, mutationOp]),\n        populateExchange({ schema })(exchangeArgs),\n        toArray\n      );\n\n      expect(print(response[1].query)).toMatchInlineSnapshot(`\n        \"mutation MyMutation {\n          addTodo {\n            __typename\n            id\n            text\n            createdAt(timezone: \"GMT+1\")\n          }\n        }\"\n      `);\n    });\n  });\n});\n\ndescribe('on (query w/ fragment) -> mutation', () => {\n  const queryOp = makeOperation(\n    'query',\n    {\n      key: 1234,\n      variables: undefined,\n      query: gql`\n        query {\n          todos {\n            ...TodoFragment\n            creator {\n              ...CreatorFragment\n            }\n          }\n        }\n\n        fragment TodoFragment on Todo {\n          id\n          text\n        }\n\n        fragment CreatorFragment on User {\n          id\n          name\n        }\n      `,\n    },\n    context\n  );\n\n  const mutationOp = makeOperation(\n    'mutation',\n    {\n      key: 5678,\n      variables: undefined,\n      query: gql`\n        mutation MyMutation {\n          addTodo @populate {\n            ...TodoFragment\n          }\n        }\n\n        fragment TodoFragment on Todo {\n          id\n          text\n        }\n      `,\n    },\n    context\n  );\n\n  describe('mutation query', () => {\n    it('matches snapshot', async () => {\n      const response = pipe<Operation, any, Operation[]>(\n        fromArray([queryOp, mutationOp]),\n        populateExchange({ schema })(exchangeArgs),\n        toArray\n      );\n\n      expect(print(response[1].query)).toMatchInlineSnapshot(`\n        \"mutation MyMutation {\n          addTodo {\n            ...TodoFragment\n            __typename\n            id\n            text\n            creator {\n              __typename\n              id\n              name\n            }\n          }\n        }\n\n        fragment TodoFragment on Todo {\n          id\n          text\n        }\"\n      `);\n    });\n  });\n});\n\ndescribe('on (query w/ unused fragment) -> mutation', () => {\n  const queryOp = makeOperation(\n    'query',\n    {\n      key: 1234,\n      variables: undefined,\n      query: gql`\n        query {\n          todos {\n            id\n            text\n          }\n          users {\n            ...UserFragment\n          }\n        }\n\n        fragment UserFragment on User {\n          id\n          name\n        }\n      `,\n    },\n    context\n  );\n\n  const mutationOp = makeOperation(\n    'mutation',\n    {\n      key: 5678,\n      variables: undefined,\n      query: gql`\n        mutation MyMutation {\n          addTodo @populate\n        }\n      `,\n    },\n    context\n  );\n\n  describe('mutation query', () => {\n    it('matches snapshot', async () => {\n      const response = pipe<Operation, any, Operation[]>(\n        fromArray([queryOp, mutationOp]),\n        populateExchange({ schema })(exchangeArgs),\n        toArray\n      );\n\n      expect(print(response[1].query)).toMatchInlineSnapshot(`\n        \"mutation MyMutation {\n          addTodo {\n            __typename\n            id\n            text\n          }\n        }\"\n      `);\n    });\n\n    it('excludes user fragment', () => {\n      const response = pipe<Operation, any, Operation[]>(\n        fromArray([queryOp, mutationOp]),\n        populateExchange({ schema })(exchangeArgs),\n        toArray\n      );\n\n      const fragments = getNodesByType(\n        response[1].query,\n        Kind.FRAGMENT_DEFINITION\n      );\n      expect(\n        fragments.filter(f => 'name' in f && f.name.value === 'UserFragment')\n      ).toHaveLength(0);\n    });\n  });\n});\n\ndescribe('on query -> (mutation w/ interface return type)', () => {\n  const queryOp = makeOperation(\n    'query',\n    {\n      key: 1234,\n      variables: undefined,\n      query: gql`\n        query {\n          todos {\n            id\n            name\n          }\n          users {\n            id\n            text\n          }\n        }\n      `,\n    },\n    context\n  );\n\n  const mutationOp = makeOperation(\n    'mutation',\n    {\n      key: 5678,\n      variables: undefined,\n      query: gql`\n        mutation MyMutation {\n          removeTodo @populate\n        }\n      `,\n    },\n    context\n  );\n\n  describe('mutation query', () => {\n    it('matches snapshot', async () => {\n      const response = pipe<Operation, any, Operation[]>(\n        fromArray([queryOp, mutationOp]),\n        populateExchange({ schema })(exchangeArgs),\n        toArray\n      );\n\n      expect(print(response[1].query)).toMatchInlineSnapshot(`\n        \"mutation MyMutation {\n          removeTodo {\n            ... on User {\n              __typename\n              id\n            }\n            ... on Todo {\n              __typename\n              id\n            }\n          }\n        }\"\n      `);\n    });\n  });\n});\n\ndescribe('on query -> (mutation w/ union return type)', () => {\n  const queryOp = makeOperation(\n    'query',\n    {\n      key: 1234,\n      variables: undefined,\n      query: gql`\n        query {\n          todos {\n            id\n            text\n          }\n          users {\n            id\n            name\n          }\n        }\n      `,\n    },\n    context\n  );\n\n  const mutationOp = makeOperation(\n    'mutation',\n    {\n      key: 5678,\n      variables: undefined,\n      query: gql`\n        mutation MyMutation {\n          updateTodo @populate\n        }\n      `,\n    },\n    context\n  );\n\n  describe('mutation query', () => {\n    it('matches snapshot', async () => {\n      const response = pipe<Operation, any, Operation[]>(\n        fromArray([queryOp, mutationOp]),\n        populateExchange({ schema })(exchangeArgs),\n        toArray\n      );\n\n      expect(print(response[1].query)).toMatchInlineSnapshot(`\n        \"mutation MyMutation {\n          updateTodo {\n            ... on User {\n              __typename\n              id\n              name\n            }\n            ... on Todo {\n              __typename\n              id\n              text\n            }\n          }\n        }\"\n      `);\n    });\n  });\n});\n\n// TODO: figure out how to behave with teardown, just removing and\n// not requesting fields feels kinda incorrect as we would start having\n// stale cache values here\ndescribe.skip('on query -> teardown -> mutation', () => {\n  const queryOp = makeOperation(\n    'query',\n    {\n      key: 1234,\n      variables: undefined,\n      query: gql`\n        query {\n          todos {\n            id\n            text\n          }\n        }\n      `,\n    },\n    context\n  );\n\n  const teardownOp = makeOperation('teardown', queryOp, context);\n\n  const mutationOp = makeOperation(\n    'mutation',\n    {\n      key: 5678,\n      variables: undefined,\n      query: gql`\n        mutation MyMutation {\n          addTodo @populate\n        }\n      `,\n    },\n    context\n  );\n\n  describe('mutation query', () => {\n    it('matches snapshot', async () => {\n      const response = pipe<Operation, any, Operation[]>(\n        fromArray([queryOp, teardownOp, mutationOp]),\n        populateExchange({ schema })(exchangeArgs),\n        toArray\n      );\n\n      expect(print(response[2].query)).toMatchInlineSnapshot(`\n        \"mutation MyMutation {\n          addTodo {\n            __typename\n          }\n        }\"\n      `);\n    });\n\n    it('only requests __typename', () => {\n      const response = pipe<Operation, any, Operation[]>(\n        fromArray([queryOp, teardownOp, mutationOp]),\n        populateExchange({ schema })(exchangeArgs),\n        toArray\n      );\n      getNodesByType(response[2].query, Kind.FIELD).forEach(field => {\n        expect((field as any).name.value).toMatch(/addTodo|__typename/);\n      });\n    });\n  });\n});\n\ndescribe('interface returned in mutation', () => {\n  const queryOp = makeOperation(\n    'query',\n    {\n      key: 1234,\n      variables: undefined,\n      query: gql`\n        query {\n          products {\n            id\n            text\n            price\n            tax\n          }\n        }\n      `,\n    },\n    context\n  );\n\n  const mutationOp = makeOperation(\n    'mutation',\n    {\n      key: 5678,\n      variables: undefined,\n      query: gql`\n        mutation MyMutation {\n          addProduct @populate\n        }\n      `,\n    },\n    context\n  );\n\n  it('should correctly make the inline-fragments', () => {\n    const response = pipe<Operation, any, Operation[]>(\n      fromArray([queryOp, mutationOp]),\n      populateExchange({ schema })(exchangeArgs),\n      toArray\n    );\n\n    expect(print(response[1].query)).toMatchInlineSnapshot(`\n      \"mutation MyMutation {\n        addProduct {\n          ... on SimpleProduct {\n            __typename\n            id\n            price\n          }\n          ... on ComplexProduct {\n            __typename\n            id\n            price\n            tax\n          }\n        }\n      }\"\n    `);\n  });\n});\n\ndescribe('nested interfaces', () => {\n  const queryOp = makeOperation(\n    'query',\n    {\n      key: 1234,\n      variables: undefined,\n      query: gql`\n        query {\n          products {\n            id\n            text\n            price\n            tax\n            store {\n              id\n              name\n              address\n              website\n            }\n          }\n        }\n      `,\n    },\n    context\n  );\n\n  const mutationOp = makeOperation(\n    'mutation',\n    {\n      key: 5678,\n      variables: undefined,\n      query: gql`\n        mutation MyMutation {\n          addProduct @populate\n        }\n      `,\n    },\n    context\n  );\n\n  it('should correctly make the inline-fragments', () => {\n    const response = pipe<Operation, any, Operation[]>(\n      fromArray([queryOp, mutationOp]),\n      populateExchange({ schema })(exchangeArgs),\n      toArray\n    );\n\n    expect(print(response[1].query)).toMatchInlineSnapshot(`\n      \"mutation MyMutation {\n        addProduct {\n          ... on SimpleProduct {\n            __typename\n            id\n            price\n            store {\n              __typename\n              id\n              name\n              address\n            }\n          }\n          ... on ComplexProduct {\n            __typename\n            id\n            price\n            tax\n            store {\n              __typename\n              id\n              name\n              website\n            }\n          }\n        }\n      }\"\n    `);\n  });\n});\n\ndescribe('nested fragment', () => {\n  const fragment = gql`\n    fragment TodoFragment on Todo {\n      id\n      author {\n        id\n      }\n    }\n  `;\n\n  const queryOp = makeOperation(\n    'query',\n    {\n      key: 1234,\n      variables: undefined,\n      query: gql`\n        query {\n          todos {\n            ...TodoFragment\n          }\n        }\n        ${fragment}\n      `,\n    },\n    context\n  );\n\n  const mutationOp = makeOperation(\n    'mutation',\n    {\n      key: 5678,\n      variables: undefined,\n      query: gql`\n        mutation MyMutation {\n          updateTodo @populate\n        }\n      `,\n    },\n    context\n  );\n\n  it('should work with nested fragments', () => {\n    const response = pipe<Operation, any, Operation[]>(\n      fromArray([queryOp, mutationOp]),\n      populateExchange({ schema })(exchangeArgs),\n      toArray\n    );\n\n    expect(print(response[1].query)).toMatchInlineSnapshot(`\n    \"mutation MyMutation {\n      updateTodo {\n        ... on Todo {\n          __typename\n          id\n        }\n      }\n    }\"\n  `);\n  });\n});\n\ndescribe('respects max-depth', () => {\n  const queryOp = makeOperation(\n    'query',\n    {\n      key: 1234,\n      variables: undefined,\n      query: gql`\n        query {\n          company {\n            id\n            employees {\n              id\n              todos {\n                id\n              }\n            }\n          }\n        }\n      `,\n    },\n    context\n  );\n\n  const mutationOp = makeOperation(\n    'mutation',\n    {\n      key: 5678,\n      variables: undefined,\n      query: gql`\n        mutation MyMutation {\n          removeCompany @populate\n        }\n      `,\n    },\n    context\n  );\n\n  describe('mutation query', () => {\n    it('matches snapshot', async () => {\n      const response = pipe<Operation, any, Operation[]>(\n        fromArray([queryOp, mutationOp]),\n        populateExchange({ schema, options: { maxDepth: 1 } })(exchangeArgs),\n        toArray\n      );\n\n      expect(print(response[1].query)).toMatchInlineSnapshot(`\n        \"mutation MyMutation {\n          removeCompany {\n            __typename\n            id\n            employees {\n              __typename\n              id\n            }\n          }\n        }\"\n      `);\n    });\n\n    it('respects skip syntax', async () => {\n      const response = pipe<Operation, any, Operation[]>(\n        fromArray([queryOp, mutationOp]),\n        populateExchange({\n          schema,\n          options: { maxDepth: 1, skipType: /User/ },\n        })(exchangeArgs),\n        toArray\n      );\n\n      expect(print(response[1].query)).toMatchInlineSnapshot(`\n        \"mutation MyMutation {\n          removeCompany {\n            __typename\n            id\n            employees {\n              __typename\n              id\n              todos {\n                __typename\n                id\n              }\n            }\n          }\n        }\"\n      `);\n    });\n  });\n});\n"
  },
  {
    "path": "exchanges/populate/src/populateExchange.ts",
    "content": "import type {\n  FragmentDefinitionNode,\n  IntrospectionQuery,\n  SelectionNode,\n  GraphQLInterfaceType,\n  FieldNode,\n  InlineFragmentNode,\n  FragmentSpreadNode,\n  ArgumentNode,\n} from 'graphql';\nimport {\n  buildClientSchema,\n  isAbstractType,\n  Kind,\n  GraphQLObjectType,\n  valueFromASTUntyped,\n  GraphQLScalarType,\n} from 'graphql';\nimport { pipe, tap, map } from 'wonka';\nimport type { Exchange, Operation } from '@urql/core';\nimport { stringifyVariables } from '@urql/core';\n\nimport type { GraphQLFlatType } from './helpers/node';\nimport { getName, unwrapType } from './helpers/node';\nimport { traverse } from './helpers/traverse';\n\n/** Configuration options for the {@link populateExchange}'s behaviour */\nexport interface Options {\n  /** Prevents populating fields for matching types.\n   *\n   * @remarks\n   * `skipType` may be set to a regular expression that, when matching,\n   * prevents fields to be added automatically for the given type by the\n   * `populateExchange`.\n   *\n   * @defaultValue `/^PageInfo|(Connection|Edge)$/` - Omit Relay pagination fields\n   */\n  skipType?: RegExp;\n  /** Specifies a maximum depth for populated fields.\n   *\n   * @remarks\n   * `maxDepth` may be set to a maximum depth at which fields are populated.\n   * This may prevent the `populateExchange` from adding infinitely deep\n   * recursive fields or simply too many fields.\n   *\n   * @defaultValue `2` - Omit fields past a depth of 2.\n   */\n  maxDepth?: number;\n}\n\n/** Input parameters for the {@link populateExchange}. */\nexport interface PopulateExchangeOpts {\n  /** Introspection data for an API’s schema.\n   *\n   * @remarks\n   * `schema` must be passed Schema Introspection data for the GraphQL API\n   * this exchange is applied for.\n   * You may use the `@urql/introspection` package to generate this data.\n   *\n   * @see {@link https://spec.graphql.org/October2021/#sec-Schema-Introspection} for the Schema Introspection spec.\n   */\n  schema: IntrospectionQuery;\n  /** Configuration options for the {@link populateExchange}'s behaviour */\n  options?: Options;\n}\n\nconst makeDict = (): any => Object.create(null);\n\n/** stores information per each type it finds */\ntype TypeKey = GraphQLObjectType | GraphQLInterfaceType;\n/** stores all known fields per each type key */\ntype FieldValue = Record<string, FieldUsage>;\ntype TypeFields = Map<String, FieldValue>;\n/** Describes information about a given field, i.e. type (owner), arguments, how many operations use this field */\ninterface FieldUsage {\n  type: TypeKey;\n  args: null | { [key: string]: { value: any; kind: any } };\n  fieldName: string;\n}\n\ntype FragmentMap<T extends string = string> = Record<T, FragmentDefinitionNode>;\nconst SKIP_COUNT_TYPE = /^PageInfo|(Connection|Edge)$/;\n\n/** Creates an `Exchange` handing automatic mutation selection-set population based on the\n * query selection-sets seen.\n *\n * @param options - A {@link PopulateExchangeOpts} configuration object.\n * @returns the created populate {@link Exchange}.\n *\n * @remarks\n * The `populateExchange` will create an exchange that monitors queries and\n * extracts fields and types so it knows what is currently observed by your\n * application.\n * When a mutation comes in with the `@populate` directive it will fill the\n * selection-set based on these prior queries.\n *\n * This Exchange can ease up the transition from documentCache to graphCache\n *\n * @example\n * ```ts\n * populateExchange({\n *   schema,\n *   options: {\n *     maxDepth: 3,\n *     skipType: /Todo/\n *   },\n * });\n *\n * const query = gql`\n *   mutation { addTodo @popualte }\n * `;\n * ```\n */\nexport const populateExchange =\n  ({ schema: ogSchema, options }: PopulateExchangeOpts): Exchange =>\n  ({ forward }) => {\n    const maxDepth = (options && options.maxDepth) || 2;\n    const skipType = (options && options.skipType) || SKIP_COUNT_TYPE;\n\n    const schema = buildClientSchema(ogSchema);\n    /** List of operation keys that have already been parsed. */\n    const parsedOperations = new Set<number>();\n    /** List of operation keys that have not been torn down. */\n    const activeOperations = new Set<number>();\n    /** Collection of fragments used by the user. */\n    const userFragments: FragmentMap = makeDict();\n\n    // State of the global types & their fields\n    const typeFields: TypeFields = new Map();\n    let currentVariables: object = {};\n\n    /** Handle mutation and inject selections + fragments. */\n    const handleIncomingMutation = (op: Operation) => {\n      if (op.kind !== 'mutation') {\n        return op;\n      }\n\n      const document = traverse(op.query, node => {\n        if (node.kind === Kind.FIELD) {\n          if (!node.directives) return;\n\n          const directives = node.directives.filter(\n            d => getName(d) !== 'populate'\n          );\n\n          if (directives.length === node.directives.length) return;\n\n          const field = schema.getMutationType()!.getFields()[node.name.value];\n\n          if (!field) return;\n\n          const type = unwrapType(field.type);\n\n          if (!type) {\n            return {\n              ...node,\n              selectionSet: {\n                kind: Kind.SELECTION_SET,\n                selections: [\n                  {\n                    kind: Kind.FIELD,\n                    name: {\n                      kind: Kind.NAME,\n                      value: '__typename',\n                    },\n                  },\n                ],\n              },\n              directives,\n            };\n          }\n\n          const visited = new Set();\n          const populateSelections = (\n            type: GraphQLFlatType,\n            selections: Array<\n              FieldNode | InlineFragmentNode | FragmentSpreadNode\n            >,\n            depth: number\n          ) => {\n            let possibleTypes: readonly string[] = [];\n            let isAbstract = false;\n            if (isAbstractType(type)) {\n              isAbstract = true;\n              possibleTypes = schema.getPossibleTypes(type).map(x => x.name);\n            } else {\n              possibleTypes = [type.name];\n            }\n\n            possibleTypes.forEach(typeName => {\n              const fieldsForType = typeFields.get(typeName);\n              if (!fieldsForType) {\n                if (possibleTypes.length === 1) {\n                  selections.push({\n                    kind: Kind.FIELD,\n                    name: {\n                      kind: Kind.NAME,\n                      value: '__typename',\n                    },\n                  });\n                }\n                return;\n              }\n\n              let typeSelections: Array<\n                FieldNode | InlineFragmentNode | FragmentSpreadNode\n              > = selections;\n\n              if (isAbstract) {\n                typeSelections = [\n                  {\n                    kind: Kind.FIELD,\n                    name: {\n                      kind: Kind.NAME,\n                      value: '__typename',\n                    },\n                  },\n                ];\n                selections.push({\n                  kind: Kind.INLINE_FRAGMENT,\n                  typeCondition: {\n                    kind: Kind.NAMED_TYPE,\n                    name: {\n                      kind: Kind.NAME,\n                      value: typeName,\n                    },\n                  },\n                  selectionSet: {\n                    kind: Kind.SELECTION_SET,\n                    selections: typeSelections,\n                  },\n                });\n              } else {\n                typeSelections.push({\n                  kind: Kind.FIELD,\n                  name: {\n                    kind: Kind.NAME,\n                    value: '__typename',\n                  },\n                });\n              }\n\n              Object.keys(fieldsForType).forEach(key => {\n                const value = fieldsForType[key];\n                if (value.type instanceof GraphQLScalarType) {\n                  const args = value.args\n                    ? Object.keys(value.args).map(k => {\n                        const v = value.args![k];\n                        return {\n                          kind: Kind.ARGUMENT,\n                          value: {\n                            kind: v.kind,\n                            value: v.value,\n                          },\n                          name: {\n                            kind: Kind.NAME,\n                            value: k,\n                          },\n                        } as ArgumentNode;\n                      })\n                    : [];\n                  const field: FieldNode = {\n                    kind: Kind.FIELD,\n                    arguments: args,\n                    name: {\n                      kind: Kind.NAME,\n                      value: value.fieldName,\n                    },\n                  };\n\n                  typeSelections.push(field);\n                } else if (\n                  value.type instanceof GraphQLObjectType &&\n                  !visited.has(value.type.name) &&\n                  depth < maxDepth\n                ) {\n                  visited.add(value.type.name);\n                  const fieldSelections: Array<FieldNode> = [];\n\n                  populateSelections(\n                    value.type,\n                    fieldSelections,\n                    skipType.test(value.type.name) ? depth : depth + 1\n                  );\n\n                  const args = value.args\n                    ? Object.keys(value.args).map(k => {\n                        const v = value.args![k];\n                        return {\n                          kind: Kind.ARGUMENT,\n                          value: {\n                            kind: v.kind,\n                            value: v.value,\n                          },\n                          name: {\n                            kind: Kind.NAME,\n                            value: k,\n                          },\n                        } as ArgumentNode;\n                      })\n                    : [];\n\n                  const field: FieldNode = {\n                    kind: Kind.FIELD,\n                    selectionSet: {\n                      kind: Kind.SELECTION_SET,\n                      selections: fieldSelections,\n                    },\n                    arguments: args,\n                    name: {\n                      kind: Kind.NAME,\n                      value: value.fieldName,\n                    },\n                  };\n\n                  typeSelections.push(field);\n                }\n              });\n            });\n          };\n\n          visited.add(type.name);\n          const selections: Array<\n            FieldNode | InlineFragmentNode | FragmentSpreadNode\n          > = node.selectionSet ? [...node.selectionSet.selections] : [];\n          populateSelections(type, selections, 0);\n\n          return {\n            ...node,\n            selectionSet: {\n              kind: Kind.SELECTION_SET,\n              selections,\n            },\n            directives,\n          };\n        }\n      });\n\n      return {\n        ...op,\n        query: document,\n      };\n    };\n\n    const readFromSelectionSet = (\n      type: GraphQLObjectType | GraphQLInterfaceType,\n      selections: readonly SelectionNode[],\n      seenFields: Record<string, TypeKey> = {}\n    ) => {\n      if (isAbstractType(type)) {\n        // TODO: should we add this to typeParents/typeFields as well?\n        schema.getPossibleTypes(type).forEach(t => {\n          readFromSelectionSet(t, selections);\n        });\n      } else {\n        const fieldMap = type.getFields();\n\n        let args: null | Record<string, any> = null;\n        for (let i = 0; i < selections.length; i++) {\n          const selection = selections[i];\n\n          if (selection.kind === Kind.FRAGMENT_SPREAD) {\n            const fragmentName = getName(selection);\n\n            const fragment = userFragments[fragmentName];\n\n            if (fragment) {\n              readFromSelectionSet(type, fragment.selectionSet.selections);\n            }\n\n            continue;\n          }\n\n          if (selection.kind === Kind.INLINE_FRAGMENT) {\n            readFromSelectionSet(type, selection.selectionSet.selections);\n\n            continue;\n          }\n\n          if (selection.kind !== Kind.FIELD) continue;\n\n          const fieldName = selection.name.value;\n          if (!fieldMap[fieldName]) continue;\n\n          const ownerType =\n            seenFields[fieldName] || (seenFields[fieldName] = type);\n\n          let fields = typeFields.get(ownerType.name);\n          if (!fields) typeFields.set(type.name, (fields = {}));\n\n          const childType = unwrapType(\n            fieldMap[fieldName].type\n          ) as GraphQLObjectType;\n\n          if (selection.arguments && selection.arguments.length) {\n            args = {};\n            for (let j = 0; j < selection.arguments.length; j++) {\n              const argNode = selection.arguments[j];\n              args[argNode.name.value] = {\n                value: valueFromASTUntyped(\n                  argNode.value,\n                  currentVariables as any\n                ),\n                kind: argNode.value.kind,\n              };\n            }\n          }\n\n          const fieldKey = args\n            ? `${fieldName}:${stringifyVariables(args)}`\n            : fieldName;\n\n          if (!fields[fieldKey]) {\n            fields[fieldKey] = {\n              type: childType,\n              args,\n              fieldName,\n            };\n          }\n\n          if (selection.selectionSet) {\n            readFromSelectionSet(childType, selection.selectionSet.selections);\n          }\n        }\n      }\n    };\n\n    /** Handle query and extract fragments. */\n    const handleIncomingQuery = ({\n      key,\n      kind,\n      query,\n      variables,\n    }: Operation) => {\n      if (kind !== 'query') {\n        return;\n      }\n\n      activeOperations.add(key);\n      if (parsedOperations.has(key)) {\n        return;\n      }\n\n      parsedOperations.add(key);\n      currentVariables = variables || {};\n\n      for (let i = query.definitions.length; i--; ) {\n        const definition = query.definitions[i];\n\n        if (definition.kind === Kind.FRAGMENT_DEFINITION) {\n          userFragments[getName(definition)] = definition;\n        } else if (definition.kind === Kind.OPERATION_DEFINITION) {\n          const type = schema.getQueryType()!;\n          readFromSelectionSet(\n            unwrapType(type) as GraphQLObjectType,\n            definition.selectionSet.selections!\n          );\n        }\n      }\n    };\n\n    const handleIncomingTeardown = ({ key, kind }: Operation) => {\n      // TODO: we might want to remove fields here, the risk becomes\n      // that data in the cache would become stale potentially\n      if (kind === 'teardown') {\n        activeOperations.delete(key);\n      }\n    };\n\n    return ops$ => {\n      return pipe(\n        ops$,\n        tap(handleIncomingQuery),\n        tap(handleIncomingTeardown),\n        map(handleIncomingMutation),\n        forward\n      );\n    };\n  };\n"
  },
  {
    "path": "exchanges/populate/tsconfig.json",
    "content": "{\n  \"extends\": \"../../tsconfig.json\",\n  \"include\": [\"src\"]\n}\n"
  },
  {
    "path": "exchanges/populate/vitest.config.ts",
    "content": "import { mergeConfig } from 'vitest/config';\nimport baseConfig from '../../vitest.config';\n\nexport default mergeConfig(baseConfig, {});\n"
  },
  {
    "path": "exchanges/refocus/CHANGELOG.md",
    "content": "# Changelog\n\n## 2.1.0\n\n### Minor Changes\n\n- Add `minimumTime` to `refocusExchange` to throttle query reexecution\n  Submitted by [@ThaUnknown](https://github.com/ThaUnknown) (See [#3825](https://github.com/urql-graphql/urql/pull/3825))\n\n## 2.0.0\n\n### Patch Changes\n\n- Updated dependencies (See [#3789](https://github.com/urql-graphql/urql/pull/3789) and [#3807](https://github.com/urql-graphql/urql/pull/3807))\n  - @urql/core@6.0.0\n\n## 1.1.1\n\n### Patch Changes\n\n- Omit minified files and sourcemaps' `sourcesContent` in published packages\n  Submitted by [@kitten](https://github.com/kitten) (See [#3755](https://github.com/urql-graphql/urql/pull/3755))\n- Updated dependencies (See [#3755](https://github.com/urql-graphql/urql/pull/3755))\n  - @urql/core@5.1.1\n\n## 1.1.0\n\n### Minor Changes\n\n- Mark `@urql/core` as a peer dependency as well as a regular dependency\n  Submitted by [@kitten](https://github.com/kitten) (See [#3579](https://github.com/urql-graphql/urql/pull/3579))\n\n## 1.0.2\n\n### Patch Changes\n\n- Publish with npm provenance\n  Submitted by [@kitten](https://github.com/kitten) (See [#3180](https://github.com/urql-graphql/urql/pull/3180))\n\n## 1.0.1\n\n### Patch Changes\n\n- Upgrade to `wonka@^6.3.0`\n  Submitted by [@kitten](https://github.com/kitten) (See [#3104](https://github.com/urql-graphql/urql/pull/3104))\n- Add TSDocs for all exchanges, documenting API internals\n  Submitted by [@kitten](https://github.com/kitten) (See [#3072](https://github.com/urql-graphql/urql/pull/3072))\n- Updated dependencies (See [#3101](https://github.com/urql-graphql/urql/pull/3101), [#3033](https://github.com/urql-graphql/urql/pull/3033), [#3054](https://github.com/urql-graphql/urql/pull/3054), [#3053](https://github.com/urql-graphql/urql/pull/3053), [#3060](https://github.com/urql-graphql/urql/pull/3060), [#3081](https://github.com/urql-graphql/urql/pull/3081), [#3039](https://github.com/urql-graphql/urql/pull/3039), [#3104](https://github.com/urql-graphql/urql/pull/3104), [#3082](https://github.com/urql-graphql/urql/pull/3082), [#3097](https://github.com/urql-graphql/urql/pull/3097), [#3061](https://github.com/urql-graphql/urql/pull/3061), [#3055](https://github.com/urql-graphql/urql/pull/3055), [#3085](https://github.com/urql-graphql/urql/pull/3085), [#3079](https://github.com/urql-graphql/urql/pull/3079), [#3087](https://github.com/urql-graphql/urql/pull/3087), [#3059](https://github.com/urql-graphql/urql/pull/3059), [#3055](https://github.com/urql-graphql/urql/pull/3055), [#3057](https://github.com/urql-graphql/urql/pull/3057), [#3050](https://github.com/urql-graphql/urql/pull/3050), [#3062](https://github.com/urql-graphql/urql/pull/3062), [#3051](https://github.com/urql-graphql/urql/pull/3051), [#3043](https://github.com/urql-graphql/urql/pull/3043), [#3063](https://github.com/urql-graphql/urql/pull/3063), [#3054](https://github.com/urql-graphql/urql/pull/3054), [#3102](https://github.com/urql-graphql/urql/pull/3102), [#3097](https://github.com/urql-graphql/urql/pull/3097), [#3106](https://github.com/urql-graphql/urql/pull/3106), [#3058](https://github.com/urql-graphql/urql/pull/3058), and [#3062](https://github.com/urql-graphql/urql/pull/3062))\n  - @urql/core@4.0.0\n\n## 1.0.0\n\n### Major Changes\n\n- **Goodbye IE11!** 👋 This major release removes support for IE11. All code that is shipped will be transpiled much less and will _not_ be ES5-compatible anymore, by [@kitten](https://github.com/kitten) (See [#2504](https://github.com/FormidableLabs/urql/pull/2504))\n- Upgrade to [Wonka v6](https://github.com/0no-co/wonka) (`wonka@^6.0.0`), which has no breaking changes but is built to target ES2015 and comes with other minor improvements.\n  The library has fully been migrated to TypeScript which will hopefully help with making contributions easier!, by [@kitten](https://github.com/kitten) (See [#2504](https://github.com/FormidableLabs/urql/pull/2504))\n\n### Patch Changes\n\n- Updated dependencies (See [#2551](https://github.com/FormidableLabs/urql/pull/2551), [#2504](https://github.com/FormidableLabs/urql/pull/2504), [#2619](https://github.com/FormidableLabs/urql/pull/2619), [#2607](https://github.com/FormidableLabs/urql/pull/2607), and [#2504](https://github.com/FormidableLabs/urql/pull/2504))\n  - @urql/core@3.0.0\n\n## 0.2.5\n\n### Patch Changes\n\n- Extend peer dependency range of `graphql` to include `^16.0.0`.\n  As always when upgrading across many packages of `urql`, especially including `@urql/core` we recommend you to deduplicate dependencies after upgrading, using `npm dedupe` or `npx yarn-deduplicate`, by [@kitten](https://github.com/kitten) (See [#2133](https://github.com/FormidableLabs/urql/pull/2133))\n- Updated dependencies (See [#2133](https://github.com/FormidableLabs/urql/pull/2133))\n  - @urql/core@2.3.6\n\n## 0.2.4\n\n### Patch Changes\n\n- ⚠️ Fix use context of the reexecuting operation, by [@JoviDeCroock](https://github.com/JoviDeCroock) (See [#2104](https://github.com/FormidableLabs/urql/pull/2104))\n\n## 0.2.3\n\n### Patch Changes\n\n- Remove closure-compiler from the build step (See [#1570](https://github.com/FormidableLabs/urql/pull/1570))\n- Updated dependencies (See [#1570](https://github.com/FormidableLabs/urql/pull/1570), [#1509](https://github.com/FormidableLabs/urql/pull/1509), [#1600](https://github.com/FormidableLabs/urql/pull/1600), and [#1515](https://github.com/FormidableLabs/urql/pull/1515))\n  - @urql/core@2.1.0\n\n## 0.2.2\n\n### Patch Changes\n\n- Prevent the refocus Exchange from being used on a Node env, by [@JoviDeCroock](https://github.com/JoviDeCroock) (See [#1430](https://github.com/FormidableLabs/urql/pull/1430))\n\n## 0.2.1\n\n### Patch Changes\n\n- Deprecate the `Operation.operationName` property in favor of `Operation.kind`. This name was\n  previously confusing as `operationName` was effectively referring to two different things. You can\n  safely upgrade to this new version, however to mute all deprecation warnings you will have to\n  **upgrade** all `urql` packages you use. If you have custom exchanges that spread operations, please\n  use [the new `makeOperation` helper\n  function](https://formidable.com/open-source/urql/docs/api/core/#makeoperation) instead, by [@bkonkle](https://github.com/bkonkle) (See [#1045](https://github.com/FormidableLabs/urql/pull/1045))\n- Updated dependencies (See [#1094](https://github.com/FormidableLabs/urql/pull/1094) and [#1045](https://github.com/FormidableLabs/urql/pull/1045))\n  - @urql/core@1.14.0\n\n## 0.2.0\n\n### Minor Changes\n\n- Switch from a `focus-event` triggering the refetch to a change in [`page-visbility`](https://developer.mozilla.org/en-US/docs/Web/API/Page_Visibility_API). This means that interacting with an `iframe` and then going back to the page won't trigger a refetch, interacting with Devtools won't cause refetches and a bubbled `focusEvent` won't trigger a refetch, by [@tatchi](https://github.com/tatchi) (See [#1077](https://github.com/FormidableLabs/urql/pull/1077))\n\n## v0.1.0\n\n**Initial Release**\n"
  },
  {
    "path": "exchanges/refocus/README.md",
    "content": "# @urql/exchange-refocus\n\n`@urql/exchange-refocus` is an exchange for the [`urql`](../../README.md) GraphQL client that tracks currently active operations and redispatches them when the\nwindow regains focus\n\n## Quick Start Guide\n\nFirst install `@urql/exchange-refocus` alongside `urql`:\n\n```sh\nyarn add @urql/exchange-refocus\n# or\nnpm install --save @urql/exchange-refocus\n```\n\nThen add it to your `Client`, preferably before the `cacheExchange` and in front of any asynchronous\nexchanges, like the `fetchExchange`:\n\n```js\nimport { createClient, cacheExchange, fetchExchange } from 'urql';\nimport { refocusExchange } from '@urql/exchange-refocus';\n\nconst client = createClient({\n  url: 'http://localhost:3000/graphql',\n  exchanges: [refocusExchange({\n    // The minimum time in milliseconds to wait before another refocus can trigger. Default value is 0.\n    minimumTime: 2000\n  }), cacheExchange, fetchExchange],\n});\n```\n"
  },
  {
    "path": "exchanges/refocus/jsr.json",
    "content": "{\n  \"name\": \"@urql/exchange-refocus\",\n  \"version\": \"2.1.0\",\n  \"exports\": {\n    \".\": \"./src/index.ts\"\n  },\n  \"exclude\": [\n    \"node_modules\",\n    \"cypress\",\n    \"**/*.test.*\",\n    \"**/*.spec.*\",\n    \"**/*.test.*.snap\",\n    \"**/*.spec.*.snap\"\n  ]\n}"
  },
  {
    "path": "exchanges/refocus/package.json",
    "content": "{\n  \"name\": \"@urql/exchange-refocus\",\n  \"version\": \"2.1.0\",\n  \"description\": \"An exchange that dispatches active operations when the window regains focus\",\n  \"sideEffects\": false,\n  \"homepage\": \"https://formidable.com/open-source/urql/docs/\",\n  \"bugs\": \"https://github.com/urql-graphql/urql/issues\",\n  \"license\": \"MIT\",\n  \"author\": \"urql GraphQL Contributors\",\n  \"repository\": {\n    \"type\": \"git\",\n    \"url\": \"https://github.com/urql-graphql/urql.git\",\n    \"directory\": \"exchanges/refocus\"\n  },\n  \"keywords\": [\n    \"urql\",\n    \"graphql client\",\n    \"graphql\",\n    \"exchanges\",\n    \"react\",\n    \"focus\"\n  ],\n  \"main\": \"dist/urql-exchange-refocus\",\n  \"module\": \"dist/urql-exchange-refocus.mjs\",\n  \"types\": \"dist/urql-exchange-refocus.d.ts\",\n  \"source\": \"src/index.ts\",\n  \"exports\": {\n    \".\": {\n      \"types\": \"./dist/urql-exchange-refocus.d.ts\",\n      \"import\": \"./dist/urql-exchange-refocus.mjs\",\n      \"require\": \"./dist/urql-exchange-refocus.js\",\n      \"source\": \"./src/index.ts\"\n    },\n    \"./package.json\": \"./package.json\"\n  },\n  \"files\": [\n    \"LICENSE\",\n    \"CHANGELOG.md\",\n    \"README.md\",\n    \"dist/\"\n  ],\n  \"scripts\": {\n    \"test\": \"vitest\",\n    \"clean\": \"rimraf dist\",\n    \"check\": \"tsc --noEmit\",\n    \"lint\": \"eslint --ext=js,jsx,ts,tsx .\",\n    \"build\": \"rollup -c ../../scripts/rollup/config.mjs\",\n    \"prepare\": \"node ../../scripts/prepare/index.js\",\n    \"prepublishOnly\": \"run-s clean build\"\n  },\n  \"devDependencies\": {\n    \"@types/react\": \"^17.0.4\",\n    \"@urql/core\": \"workspace:*\",\n    \"graphql\": \"^16.0.0\"\n  },\n  \"peerDependencies\": {\n    \"@urql/core\": \"^6.0.0\"\n  },\n  \"dependencies\": {\n    \"@urql/core\": \"workspace:^6.0.1\",\n    \"wonka\": \"^6.3.2\"\n  },\n  \"publishConfig\": {\n    \"access\": \"public\",\n    \"provenance\": true\n  }\n}\n"
  },
  {
    "path": "exchanges/refocus/src/index.ts",
    "content": "export { refocusExchange } from './refocusExchange';\n"
  },
  {
    "path": "exchanges/refocus/src/refocusExchange.test.ts",
    "content": "// @vitest-environment jsdom\n\nimport { pipe, map, makeSubject, publish, tap } from 'wonka';\nimport { vi, expect, it, beforeEach } from 'vitest';\n\nimport {\n  gql,\n  createClient,\n  Operation,\n  OperationResult,\n  ExchangeIO,\n} from '@urql/core';\n\nimport { queryResponse } from '../../../packages/core/src/test-utils';\nimport { refocusExchange } from './refocusExchange';\n\nconst dispatchDebug = vi.fn();\n\nconst queryOne = gql`\n  {\n    author {\n      id\n      name\n    }\n  }\n`;\n\nconst queryOneData = {\n  __typename: 'Query',\n  author: {\n    __typename: 'Author',\n    id: '123',\n    name: 'Author',\n  },\n};\n\nlet client, op, ops$, next;\nbeforeEach(() => {\n  client = createClient({\n    url: 'http://0.0.0.0',\n    exchanges: [],\n  });\n  op = client.createRequestOperation('query', {\n    key: 1,\n    query: queryOne,\n  });\n\n  ({ source: ops$, next } = makeSubject<Operation>());\n});\n\nit(`attaches a listener and redispatches queries on call`, () => {\n  const response = vi.fn((forwardOp: Operation): OperationResult => {\n    return {\n      ...queryResponse,\n      operation: forwardOp,\n      data: queryOneData,\n    };\n  });\n\n  let listener;\n  const spy = vi\n    .spyOn(window, 'addEventListener')\n    .mockImplementation((_keyword, fn) => {\n      listener = fn;\n    });\n  const reexecuteSpy = vi\n    .spyOn(client, 'reexecuteOperation')\n    .mockImplementation(() => ({}));\n\n  const result = vi.fn();\n  const forward: ExchangeIO = ops$ => {\n    return pipe(ops$, map(response));\n  };\n\n  pipe(\n    refocusExchange()({\n      forward,\n      client,\n      dispatchDebug,\n    })(ops$),\n    tap(result),\n    publish\n  );\n\n  expect(spy).toBeCalledTimes(1);\n  expect(spy).toBeCalledWith('visibilitychange', expect.anything());\n\n  next(op);\n\n  listener();\n  expect(reexecuteSpy).toBeCalledTimes(1);\n  expect(reexecuteSpy).toBeCalledWith({\n    context: expect.anything(),\n    key: 1,\n    query: queryOne,\n    kind: 'query',\n  });\n});\n"
  },
  {
    "path": "exchanges/refocus/src/refocusExchange.ts",
    "content": "import { pipe, tap } from 'wonka';\nimport type { Exchange, Operation } from '@urql/core';\n\nexport interface RefocusOptions {\n  /** The minimum time in milliseconds to wait before another refocus can trigger.\n   * @defaultValue `0`\n   */\n  minimumTime?: number;\n}\n\n/** Exchange factory that reexecutes operations after a user returns to the tab.\n *\n * @param opts - A {@link RefocusOptions} configuration object.\n *\n * @returns a new refocus {@link Exchange}.\n *\n * @remarks\n * The `refocusExchange` will reexecute `Operation`s with the `cache-and-network`\n * policy when a user switches back to your application's browser tab. This can\n * effectively update all on-screen data when a user has stayed inactive for a\n * long time.\n *\n * The `cache-and-network` policy will refetch data in the background, but will\n * only refetch queries that are currently active.\n */\nexport const refocusExchange = (opts: RefocusOptions = {}): Exchange => {\n  const { minimumTime = 0 } = opts;\n\n  return ({ client, forward }) =>\n    ops$ => {\n      if (typeof window === 'undefined') {\n        return forward(ops$);\n      }\n\n      const watchedOperations = new Map<number, Operation>();\n      const observedOperations = new Map<number, number>();\n\n      let lastHidden = 0;\n\n      window.addEventListener('visibilitychange', () => {\n        const state =\n          typeof document !== 'object' ? 'visible' : document.visibilityState;\n        if (state === 'visible') {\n          if (Date.now() - lastHidden < minimumTime) return;\n          watchedOperations.forEach(op => {\n            client.reexecuteOperation(\n              client.createRequestOperation('query', op, {\n                ...op.context,\n                requestPolicy: 'cache-and-network',\n              })\n            );\n          });\n        } else {\n          lastHidden = Date.now();\n        }\n      });\n\n      const processIncomingOperation = (op: Operation) => {\n        if (op.kind === 'query' && !observedOperations.has(op.key)) {\n          observedOperations.set(op.key, 1);\n          watchedOperations.set(op.key, op);\n        }\n\n        if (op.kind === 'teardown' && observedOperations.has(op.key)) {\n          observedOperations.delete(op.key);\n          watchedOperations.delete(op.key);\n        }\n      };\n\n      return forward(pipe(ops$, tap(processIncomingOperation)));\n    };\n};\n"
  },
  {
    "path": "exchanges/refocus/tsconfig.json",
    "content": "{\n  \"extends\": \"../../tsconfig.json\",\n  \"include\": [\"src\"]\n}\n"
  },
  {
    "path": "exchanges/refocus/vitest.config.ts",
    "content": "import { mergeConfig } from 'vitest/config';\nimport baseConfig from '../../vitest.config';\n\nexport default mergeConfig(baseConfig, {});\n"
  },
  {
    "path": "exchanges/request-policy/CHANGELOG.md",
    "content": "# Changelog\n\n## 2.0.0\n\n### Patch Changes\n\n- Updated dependencies (See [#3789](https://github.com/urql-graphql/urql/pull/3789) and [#3807](https://github.com/urql-graphql/urql/pull/3807))\n  - @urql/core@6.0.0\n\n## 1.2.1\n\n### Patch Changes\n\n- Omit minified files and sourcemaps' `sourcesContent` in published packages\n  Submitted by [@kitten](https://github.com/kitten) (See [#3755](https://github.com/urql-graphql/urql/pull/3755))\n- Updated dependencies (See [#3755](https://github.com/urql-graphql/urql/pull/3755))\n  - @urql/core@5.1.1\n\n## 1.2.0\n\n### Minor Changes\n\n- Mark `@urql/core` as a peer dependency as well as a regular dependency\n  Submitted by [@kitten](https://github.com/kitten) (See [#3579](https://github.com/urql-graphql/urql/pull/3579))\n\n## 1.1.0\n\n### Minor Changes\n\n- Change the request-policy exchange not to rely on OperationMeta set by the cache exchanges\n  Submitted by [@JoviDeCroock](https://github.com/JoviDeCroock) (See [#3521](https://github.com/urql-graphql/urql/pull/3521))\n\n## 1.0.2\n\n### Patch Changes\n\n- Publish with npm provenance\n  Submitted by [@kitten](https://github.com/kitten) (See [#3180](https://github.com/urql-graphql/urql/pull/3180))\n\n## 1.0.1\n\n### Patch Changes\n\n- Upgrade to `wonka@^6.3.0`\n  Submitted by [@kitten](https://github.com/kitten) (See [#3104](https://github.com/urql-graphql/urql/pull/3104))\n- Add TSDocs for all exchanges, documenting API internals\n  Submitted by [@kitten](https://github.com/kitten) (See [#3072](https://github.com/urql-graphql/urql/pull/3072))\n- Updated dependencies (See [#3101](https://github.com/urql-graphql/urql/pull/3101), [#3033](https://github.com/urql-graphql/urql/pull/3033), [#3054](https://github.com/urql-graphql/urql/pull/3054), [#3053](https://github.com/urql-graphql/urql/pull/3053), [#3060](https://github.com/urql-graphql/urql/pull/3060), [#3081](https://github.com/urql-graphql/urql/pull/3081), [#3039](https://github.com/urql-graphql/urql/pull/3039), [#3104](https://github.com/urql-graphql/urql/pull/3104), [#3082](https://github.com/urql-graphql/urql/pull/3082), [#3097](https://github.com/urql-graphql/urql/pull/3097), [#3061](https://github.com/urql-graphql/urql/pull/3061), [#3055](https://github.com/urql-graphql/urql/pull/3055), [#3085](https://github.com/urql-graphql/urql/pull/3085), [#3079](https://github.com/urql-graphql/urql/pull/3079), [#3087](https://github.com/urql-graphql/urql/pull/3087), [#3059](https://github.com/urql-graphql/urql/pull/3059), [#3055](https://github.com/urql-graphql/urql/pull/3055), [#3057](https://github.com/urql-graphql/urql/pull/3057), [#3050](https://github.com/urql-graphql/urql/pull/3050), [#3062](https://github.com/urql-graphql/urql/pull/3062), [#3051](https://github.com/urql-graphql/urql/pull/3051), [#3043](https://github.com/urql-graphql/urql/pull/3043), [#3063](https://github.com/urql-graphql/urql/pull/3063), [#3054](https://github.com/urql-graphql/urql/pull/3054), [#3102](https://github.com/urql-graphql/urql/pull/3102), [#3097](https://github.com/urql-graphql/urql/pull/3097), [#3106](https://github.com/urql-graphql/urql/pull/3106), [#3058](https://github.com/urql-graphql/urql/pull/3058), and [#3062](https://github.com/urql-graphql/urql/pull/3062))\n  - @urql/core@4.0.0\n\n## 1.0.0\n\n### Major Changes\n\n- **Goodbye IE11!** 👋 This major release removes support for IE11. All code that is shipped will be transpiled much less and will _not_ be ES5-compatible anymore, by [@kitten](https://github.com/kitten) (See [#2504](https://github.com/FormidableLabs/urql/pull/2504))\n- Upgrade to [Wonka v6](https://github.com/0no-co/wonka) (`wonka@^6.0.0`), which has no breaking changes but is built to target ES2015 and comes with other minor improvements.\n  The library has fully been migrated to TypeScript which will hopefully help with making contributions easier!, by [@kitten](https://github.com/kitten) (See [#2504](https://github.com/FormidableLabs/urql/pull/2504))\n\n### Patch Changes\n\n- Updated dependencies (See [#2551](https://github.com/FormidableLabs/urql/pull/2551), [#2504](https://github.com/FormidableLabs/urql/pull/2504), [#2619](https://github.com/FormidableLabs/urql/pull/2619), [#2607](https://github.com/FormidableLabs/urql/pull/2607), and [#2504](https://github.com/FormidableLabs/urql/pull/2504))\n  - @urql/core@3.0.0\n\n## 0.1.5\n\n### Patch Changes\n\n- Extend peer dependency range of `graphql` to include `^16.0.0`.\n  As always when upgrading across many packages of `urql`, especially including `@urql/core` we recommend you to deduplicate dependencies after upgrading, using `npm dedupe` or `npx yarn-deduplicate`, by [@kitten](https://github.com/kitten) (See [#2133](https://github.com/FormidableLabs/urql/pull/2133))\n- Updated dependencies (See [#2133](https://github.com/FormidableLabs/urql/pull/2133))\n  - @urql/core@2.3.6\n\n## 0.1.4\n\n### Patch Changes\n\n- Do not set the TTL unless cache outcome is \"miss\". Previously we set the TTL on cache \"miss\" if it was the first time an operation returned a result, now the TTL is only set on cache miss results. This allows the request policy exchange to work when using persisted caching, by [@Mookiies](https://github.com/Mookiies) (See [#1742](https://github.com/FormidableLabs/urql/pull/1742))\n- Updated dependencies (See [#1776](https://github.com/FormidableLabs/urql/pull/1776) and [#1755](https://github.com/FormidableLabs/urql/pull/1755))\n  - @urql/core@2.1.5\n\n## 0.1.3\n\n### Patch Changes\n\n- ⚠️ Fix TTL being updated to a newer timestamp when a cached result comes in, and prevent TTL from being deleted on our React binding's cache probes. Instead we now never delete the TTL and update it on incoming cache miss results, by [@kitten](https://github.com/kitten) (See [#1641](https://github.com/FormidableLabs/urql/pull/1641))\n- Updated dependencies (See [#1634](https://github.com/FormidableLabs/urql/pull/1634) and [#1638](https://github.com/FormidableLabs/urql/pull/1638))\n  - @urql/core@2.1.2\n\n## 0.1.2\n\n### Patch Changes\n\n- Remove closure-compiler from the build step (See [#1570](https://github.com/FormidableLabs/urql/pull/1570))\n- Updated dependencies (See [#1570](https://github.com/FormidableLabs/urql/pull/1570), [#1509](https://github.com/FormidableLabs/urql/pull/1509), [#1600](https://github.com/FormidableLabs/urql/pull/1600), and [#1515](https://github.com/FormidableLabs/urql/pull/1515))\n  - @urql/core@2.1.0\n\n## 0.1.1\n\n### Patch Changes\n\n- ⚠️ Fix non-query operations being upgraded by `requestPolicyExchange` and time being stored by last issuance rather than last result, by [@kitten](https://github.com/kitten) (See [#1377](https://github.com/FormidableLabs/urql/pull/1377))\n- Updated dependencies (See [#1374](https://github.com/FormidableLabs/urql/pull/1374), [#1357](https://github.com/FormidableLabs/urql/pull/1357), and [#1375](https://github.com/FormidableLabs/urql/pull/1375))\n  - @urql/core@2.0.0\n\n## v0.1.0\n\n**Initial Release**\n"
  },
  {
    "path": "exchanges/request-policy/README.md",
    "content": "# @urql/exchange-request-policy (Exchange factory)\n\n`@urql/exchange-request-policy` is an exchange for the [`urql`](../../README.md) GraphQL client that will automatically upgrade operation request-policies\non a time-to-live basis.\n\n## Quick Start Guide\n\nFirst install `@urql/exchange-request-policy` alongside `urql`:\n\n```sh\nyarn add @urql/exchange-request-policy\n# or\nnpm install --save @urql/exchange-request-policy\n```\n\nThen add it to your client.\n\n```js\nimport { createClient, cacheExchange, fetchExchange } from 'urql';\nimport { requestPolicyExchange } from '@urql/exchange-request-policy';\n\nconst client = createClient({\n  url: 'http://localhost:1234/graphql',\n  exchanges: [\n    requestPolicyExchange({\n      // The amount of time in ms that has to go by before upgrading, default is 5 minutes.\n      ttl: 60 * 1000, // 1 minute.\n      // An optional function that allows you to specify whether an operation should be upgraded.\n      shouldUpgrade: operation => operation.context.requestPolicy !== 'cache-only',\n    }),\n    cacheExchange,\n    fetchExchange,\n  ],\n});\n```\n\nNow when the exchange sees a `cache-first` operation that hasn't been seen in ttl amount of time it will upgrade\nthe `requestPolicy` to `cache-and-network`.\n"
  },
  {
    "path": "exchanges/request-policy/jsr.json",
    "content": "{\n  \"name\": \"@urql/exchange-request-policy\",\n  \"version\": \"2.0.0\",\n  \"exports\": {\n    \".\": \"./src/index.ts\"\n  },\n  \"exclude\": [\n    \"node_modules\",\n    \"cypress\",\n    \"**/*.test.*\",\n    \"**/*.spec.*\",\n    \"**/*.test.*.snap\",\n    \"**/*.spec.*.snap\"\n  ]\n}"
  },
  {
    "path": "exchanges/request-policy/package.json",
    "content": "{\n  \"name\": \"@urql/exchange-request-policy\",\n  \"version\": \"2.0.0\",\n  \"description\": \"An exchange for operation request-policy upgrading in urql\",\n  \"sideEffects\": false,\n  \"homepage\": \"https://formidable.com/open-source/urql/docs/\",\n  \"bugs\": \"https://github.com/urql-graphql/urql/issues\",\n  \"license\": \"MIT\",\n  \"author\": \"urql GraphQL Contributors\",\n  \"repository\": {\n    \"type\": \"git\",\n    \"url\": \"https://github.com/urql-graphql/urql.git\",\n    \"directory\": \"exchanges/request-policy\"\n  },\n  \"keywords\": [\n    \"urql\",\n    \"graphql client\",\n    \"graphql\",\n    \"exchanges\",\n    \"request-policy\"\n  ],\n  \"main\": \"dist/urql-exchange-request-policy\",\n  \"module\": \"dist/urql-exchange-request-policy.mjs\",\n  \"types\": \"dist/urql-exchange-request-policy.d.ts\",\n  \"source\": \"src/index.ts\",\n  \"exports\": {\n    \".\": {\n      \"types\": \"./dist/urql-exchange-request-policy.d.ts\",\n      \"import\": \"./dist/urql-exchange-request-policy.mjs\",\n      \"require\": \"./dist/urql-exchange-request-policy.js\",\n      \"source\": \"./src/index.ts\"\n    },\n    \"./package.json\": \"./package.json\"\n  },\n  \"files\": [\n    \"LICENSE\",\n    \"CHANGELOG.md\",\n    \"README.md\",\n    \"dist/\"\n  ],\n  \"scripts\": {\n    \"test\": \"vitest\",\n    \"clean\": \"rimraf dist\",\n    \"check\": \"tsc --noEmit\",\n    \"lint\": \"eslint --ext=js,jsx,ts,tsx .\",\n    \"build\": \"rollup -c ../../scripts/rollup/config.mjs\",\n    \"prepare\": \"node ../../scripts/prepare/index.js\",\n    \"prepublishOnly\": \"run-s clean build\"\n  },\n  \"devDependencies\": {\n    \"@urql/core\": \"workspace:*\",\n    \"graphql\": \"^16.0.0\"\n  },\n  \"peerDependencies\": {\n    \"@urql/core\": \"^6.0.0\"\n  },\n  \"dependencies\": {\n    \"@urql/core\": \"workspace:^6.0.1\",\n    \"wonka\": \"^6.3.2\"\n  },\n  \"publishConfig\": {\n    \"access\": \"public\",\n    \"provenance\": true\n  }\n}\n"
  },
  {
    "path": "exchanges/request-policy/src/index.ts",
    "content": "export { requestPolicyExchange } from './requestPolicyExchange';\n"
  },
  {
    "path": "exchanges/request-policy/src/requestPolicyExchange.test.ts",
    "content": "import { pipe, map, makeSubject, publish, tap } from 'wonka';\nimport { vi, expect, it, beforeEach } from 'vitest';\n\nimport {\n  gql,\n  createClient,\n  Operation,\n  OperationResult,\n  ExchangeIO,\n} from '@urql/core';\n\nimport { queryResponse } from '../../../packages/core/src/test-utils';\nimport { requestPolicyExchange } from './requestPolicyExchange';\n\nconst dispatchDebug = vi.fn();\n\nconst mockOptions = {\n  ttl: 5,\n};\n\nconst queryOne = gql`\n  {\n    author {\n      id\n      name\n    }\n  }\n`;\n\nconst queryOneData = {\n  __typename: 'Query',\n  author: {\n    __typename: 'Author',\n    id: '123',\n    name: 'Author',\n  },\n};\n\nlet client, op, ops$, next;\nbeforeEach(() => {\n  client = createClient({\n    url: 'http://0.0.0.0',\n    exchanges: [],\n  });\n  op = client.createRequestOperation('query', {\n    key: 1,\n    query: queryOne,\n  });\n\n  ({ source: ops$, next } = makeSubject<Operation>());\n});\n\nit(`upgrades to cache-and-network`, async () => {\n  const response = vi.fn((forwardOp: Operation): OperationResult => {\n    return {\n      ...queryResponse,\n      operation: forwardOp,\n      data: queryOneData,\n    };\n  });\n\n  const result = vi.fn();\n  const forward: ExchangeIO = ops$ => {\n    return pipe(ops$, map(response));\n  };\n\n  pipe(\n    requestPolicyExchange(mockOptions)({\n      forward,\n      client,\n      dispatchDebug,\n    })(ops$),\n    tap(result),\n    publish\n  );\n\n  next(op);\n\n  expect(response).toHaveBeenCalledTimes(1);\n  expect(response.mock.calls[0][0].context.requestPolicy).toEqual(\n    'cache-and-network'\n  );\n  expect(result).toHaveBeenCalledTimes(1);\n\n  await new Promise(res => {\n    setTimeout(() => {\n      next(op);\n      expect(response).toHaveBeenCalledTimes(2);\n      expect(response.mock.calls[1][0].context.requestPolicy).toEqual(\n        'cache-and-network'\n      );\n      expect(result).toHaveBeenCalledTimes(2);\n      res(null);\n    }, 10);\n  });\n});\n\nit(`doesn't upgrade when shouldUpgrade returns false`, async () => {\n  const response = vi.fn((forwardOp: Operation): OperationResult => {\n    return {\n      ...queryResponse,\n      operation: forwardOp,\n      data: queryOneData,\n    };\n  });\n\n  const result = vi.fn();\n  const forward: ExchangeIO = ops$ => {\n    return pipe(ops$, map(response));\n  };\n\n  const shouldUpgrade = vi.fn(() => false);\n  pipe(\n    requestPolicyExchange({ ...mockOptions, shouldUpgrade })({\n      forward,\n      client,\n      dispatchDebug,\n    })(ops$),\n    tap(result),\n    publish\n  );\n\n  next(op);\n\n  expect(response).toHaveBeenCalledTimes(1);\n  expect(response.mock.calls[0][0].context.requestPolicy).toEqual(\n    'cache-first'\n  );\n  expect(result).toHaveBeenCalledTimes(1);\n\n  await new Promise(res => {\n    setTimeout(() => {\n      next(op);\n      expect(response).toHaveBeenCalledTimes(2);\n      expect(response.mock.calls[1][0].context.requestPolicy).toEqual(\n        'cache-first'\n      );\n      expect(result).toHaveBeenCalledTimes(2);\n      expect(shouldUpgrade).toBeCalledTimes(2);\n      res(null);\n    }, 10);\n  });\n});\n"
  },
  {
    "path": "exchanges/request-policy/src/requestPolicyExchange.ts",
    "content": "import type { Operation, OperationResult, Exchange } from '@urql/core';\nimport { makeOperation } from '@urql/core';\nimport { pipe, tap, map } from 'wonka';\n\nconst defaultTTL = 5 * 60 * 1000;\n\n/** Input parameters for the {@link requestPolicyExchange}. */\nexport interface Options {\n  /** Predicate allowing you to selectively not upgrade `Operation`s.\n   *\n   * @remarks\n   * When `shouldUpgrade` is set, it may be used to selectively return a boolean\n   * per `Operation`. This allows certain `Operation`s to not be upgraded to a\n   * `cache-and-network` policy, when `false` is returned.\n   *\n   * By default, all `Operation`s are subject to be upgraded.\n   * operation to \"cache-and-network\".\n   */\n  shouldUpgrade?: (op: Operation) => boolean;\n  /** The time-to-live (TTL) for which a request policy won't be upgraded.\n   *\n   * @remarks\n   * The `ttl` defines the time frame in which the `Operation` won't be updated\n   * with a `cache-and-network` request policy. If an `Operation` is sent again\n   * and the `ttl` time period has expired, the policy is upgraded.\n   *\n   * @defaultValue `300_000` - 5min\n   */\n  ttl?: number;\n}\n\n/** Exchange factory that upgrades request policies to `cache-and-network` for queries outside of a defined `ttl`.\n *\n * @param options - An {@link Options} configuration object.\n * @returns the created request-policy {@link Exchange}.\n *\n * @remarks\n * The `requestPolicyExchange` upgrades query operations based on {@link Options.ttl}.\n * The `ttl` defines a timeframe outside of which a query's request policy is set to\n * `cache-and-network` to refetch it in the background.\n *\n * You may define a {@link Options.shouldUpgrade} function to selectively ignore some\n * operations by returning `false` there.\n *\n * @example\n * ```ts\n * requestPolicyExchange({\n *   // Upgrade when we haven't seen this operation for 1 second\n *   ttl: 1000,\n *   // and only upgrade operations that query the `todos` field.\n *   shouldUpgrade: op => op.kind === 'query' && op.query.definitions[0].name?.value === 'todos'\n * });\n * ```\n */\nexport const requestPolicyExchange =\n  (options: Options): Exchange =>\n  ({ forward }) => {\n    const operations = new Map();\n    const TTL = (options || {}).ttl || defaultTTL;\n    const dispatched = new Map<number, number>();\n    let counter = 0;\n\n    const processIncomingOperation = (operation: Operation): Operation => {\n      if (\n        operation.kind !== 'query' ||\n        (operation.context.requestPolicy !== 'cache-first' &&\n          operation.context.requestPolicy !== 'cache-only')\n      ) {\n        return operation;\n      }\n\n      const currentTime = new Date().getTime();\n      // When an operation passes by we track the current time\n      dispatched.set(operation.key, counter);\n      queueMicrotask(() => {\n        counter = (counter + 1) | 0;\n      });\n      const lastOccurrence = operations.get(operation.key) || 0;\n      if (\n        currentTime - lastOccurrence > TTL &&\n        (!options.shouldUpgrade || options.shouldUpgrade(operation))\n      ) {\n        return makeOperation(operation.kind, operation, {\n          ...operation.context,\n          requestPolicy: 'cache-and-network',\n        });\n      }\n\n      return operation;\n    };\n\n    const processIncomingResults = (result: OperationResult): void => {\n      // When we get a result for the operation we check whether it resolved\n      // synchronously by checking whether the counter is different from the\n      // dispatched counter.\n      const lastDispatched = dispatched.get(result.operation.key) || 0;\n      if (counter !== lastDispatched) {\n        // We only delete in the case of a miss to ensure that cache-and-network\n        // is properly taken care of\n        dispatched.delete(result.operation.key);\n        operations.set(result.operation.key, new Date().getTime());\n      }\n    };\n\n    return ops$ => {\n      return pipe(\n        forward(pipe(ops$, map(processIncomingOperation))),\n        tap(processIncomingResults)\n      );\n    };\n  };\n"
  },
  {
    "path": "exchanges/request-policy/tsconfig.json",
    "content": "{\n  \"extends\": \"../../tsconfig.json\",\n  \"include\": [\"src\"]\n}\n"
  },
  {
    "path": "exchanges/request-policy/vitest.config.ts",
    "content": "import { mergeConfig } from 'vitest/config';\nimport baseConfig from '../../vitest.config';\n\nexport default mergeConfig(baseConfig, {});\n"
  },
  {
    "path": "exchanges/retry/CHANGELOG.md",
    "content": "# Changelog\n\n## 2.0.0\n\n### Patch Changes\n\n- Updated dependencies (See [#3789](https://github.com/urql-graphql/urql/pull/3789) and [#3807](https://github.com/urql-graphql/urql/pull/3807))\n  - @urql/core@6.0.0\n\n## 1.3.2\n\n### Patch Changes\n\n- Mark options argument as optional (`retryExchange()`)\n  Submitted by [@jtomaszewski](https://github.com/jtomaszewski) (See [#3775](https://github.com/urql-graphql/urql/pull/3775))\n- Updated dependencies (See [#3773](https://github.com/urql-graphql/urql/pull/3773), [#3767](https://github.com/urql-graphql/urql/pull/3767), [#3730](https://github.com/urql-graphql/urql/pull/3730), and [#3770](https://github.com/urql-graphql/urql/pull/3770))\n  - @urql/core@5.1.2\n\n## 1.3.1\n\n### Patch Changes\n\n- Omit minified files and sourcemaps' `sourcesContent` in published packages\n  Submitted by [@kitten](https://github.com/kitten) (See [#3755](https://github.com/urql-graphql/urql/pull/3755))\n- Updated dependencies (See [#3755](https://github.com/urql-graphql/urql/pull/3755))\n  - @urql/core@5.1.1\n\n## 1.3.0\n\n### Minor Changes\n\n- Mark `@urql/core` as a peer dependency as well as a regular dependency\n  Submitted by [@kitten](https://github.com/kitten) (See [#3579](https://github.com/urql-graphql/urql/pull/3579))\n\n## 1.2.1\n\n### Patch Changes\n\n---\n\nFixed the delay amount not increasing as retry count increases\nSubmitted by [@DoisKoh](https://github.com/DoisKoh) (See [#3478](https://github.com/urql-graphql/urql/pull/3478))\n\n## 1.2.0\n\n### Minor Changes\n\n- Reset `retryExchange`’s previous attempts and delay if an operation succeeds. This prevents the exchange from keeping its old retry count and delay if the operation delivered a result in the meantime. This is important for it to help recover from failing subscriptions\n  Submitted by [@kitten](https://github.com/kitten) (See [#3229](https://github.com/urql-graphql/urql/pull/3229))\n\n## 1.1.1\n\n### Patch Changes\n\n- Publish with npm provenance\n  Submitted by [@kitten](https://github.com/kitten) (See [#3180](https://github.com/urql-graphql/urql/pull/3180))\n\n## 1.1.0\n\n### Minor Changes\n\n- Update exchanges to drop redundant `share` calls, since `@urql/core`’s `composeExchanges` utility now automatically does so for us\n  Submitted by [@kitten](https://github.com/kitten) (See [#3082](https://github.com/urql-graphql/urql/pull/3082))\n\n### Patch Changes\n\n- Upgrade to `wonka@^6.3.0`\n  Submitted by [@kitten](https://github.com/kitten) (See [#3104](https://github.com/urql-graphql/urql/pull/3104))\n- Add TSDocs for all exchanges, documenting API internals\n  Submitted by [@kitten](https://github.com/kitten) (See [#3072](https://github.com/urql-graphql/urql/pull/3072))\n- Updated dependencies (See [#3101](https://github.com/urql-graphql/urql/pull/3101), [#3033](https://github.com/urql-graphql/urql/pull/3033), [#3054](https://github.com/urql-graphql/urql/pull/3054), [#3053](https://github.com/urql-graphql/urql/pull/3053), [#3060](https://github.com/urql-graphql/urql/pull/3060), [#3081](https://github.com/urql-graphql/urql/pull/3081), [#3039](https://github.com/urql-graphql/urql/pull/3039), [#3104](https://github.com/urql-graphql/urql/pull/3104), [#3082](https://github.com/urql-graphql/urql/pull/3082), [#3097](https://github.com/urql-graphql/urql/pull/3097), [#3061](https://github.com/urql-graphql/urql/pull/3061), [#3055](https://github.com/urql-graphql/urql/pull/3055), [#3085](https://github.com/urql-graphql/urql/pull/3085), [#3079](https://github.com/urql-graphql/urql/pull/3079), [#3087](https://github.com/urql-graphql/urql/pull/3087), [#3059](https://github.com/urql-graphql/urql/pull/3059), [#3055](https://github.com/urql-graphql/urql/pull/3055), [#3057](https://github.com/urql-graphql/urql/pull/3057), [#3050](https://github.com/urql-graphql/urql/pull/3050), [#3062](https://github.com/urql-graphql/urql/pull/3062), [#3051](https://github.com/urql-graphql/urql/pull/3051), [#3043](https://github.com/urql-graphql/urql/pull/3043), [#3063](https://github.com/urql-graphql/urql/pull/3063), [#3054](https://github.com/urql-graphql/urql/pull/3054), [#3102](https://github.com/urql-graphql/urql/pull/3102), [#3097](https://github.com/urql-graphql/urql/pull/3097), [#3106](https://github.com/urql-graphql/urql/pull/3106), [#3058](https://github.com/urql-graphql/urql/pull/3058), and [#3062](https://github.com/urql-graphql/urql/pull/3062))\n  - @urql/core@4.0.0\n\n## 1.0.0\n\n### Major Changes\n\n- **Goodbye IE11!** 👋 This major release removes support for IE11. All code that is shipped will be transpiled much less and will _not_ be ES5-compatible anymore, by [@kitten](https://github.com/kitten) (See [#2504](https://github.com/FormidableLabs/urql/pull/2504))\n- Upgrade to [Wonka v6](https://github.com/0no-co/wonka) (`wonka@^6.0.0`), which has no breaking changes but is built to target ES2015 and comes with other minor improvements.\n  The library has fully been migrated to TypeScript which will hopefully help with making contributions easier!, by [@kitten](https://github.com/kitten) (See [#2504](https://github.com/FormidableLabs/urql/pull/2504))\n\n### Patch Changes\n\n- make `randomDelay` work correctly, by [@JoviDeCroock](https://github.com/JoviDeCroock) (See [#2615](https://github.com/FormidableLabs/urql/pull/2615))\n- Updated dependencies (See [#2551](https://github.com/FormidableLabs/urql/pull/2551), [#2504](https://github.com/FormidableLabs/urql/pull/2504), [#2619](https://github.com/FormidableLabs/urql/pull/2619), [#2607](https://github.com/FormidableLabs/urql/pull/2607), and [#2504](https://github.com/FormidableLabs/urql/pull/2504))\n  - @urql/core@3.0.0\n\n## 0.3.3\n\n### Patch Changes\n\n- Export `RetryExchangeOption` type from top level export, by [@KoltonG](https://github.com/KoltonG) (See [#2351](https://github.com/FormidableLabs/urql/pull/2351))\n- Updated dependencies (See [#2384](https://github.com/FormidableLabs/urql/pull/2384) and [#2386](https://github.com/FormidableLabs/urql/pull/2386))\n  - @urql/core@2.4.4\n\n## 0.3.2\n\n### Patch Changes\n\n- Extend peer dependency range of `graphql` to include `^16.0.0`.\n  As always when upgrading across many packages of `urql`, especially including `@urql/core` we recommend you to deduplicate dependencies after upgrading, using `npm dedupe` or `npx yarn-deduplicate`, by [@kitten](https://github.com/kitten) (See [#2133](https://github.com/FormidableLabs/urql/pull/2133))\n- Updated dependencies (See [#2133](https://github.com/FormidableLabs/urql/pull/2133))\n  - @urql/core@2.3.6\n\n## 0.3.1\n\n### Patch Changes\n\n- ⚠️ Fix operations sometimes not being executed after a retry is supposed to be triggered, due to a `setTimeout` reordering issue when the timer isn't as predictable as it should be, by [@kitten](https://github.com/kitten) (See [#2124](https://github.com/FormidableLabs/urql/pull/2124))\n\n## 0.3.0\n\n### Minor Changes\n\n- Add a new `retryWith` option which allows operations to be updated when a request is being retried, by [@kitten](https://github.com/kitten) (See [#1881](https://github.com/FormidableLabs/urql/pull/1881))\n\n### Patch Changes\n\n- Updated dependencies (See [#1870](https://github.com/FormidableLabs/urql/pull/1870) and [#1880](https://github.com/FormidableLabs/urql/pull/1880))\n  - @urql/core@2.3.1\n\n## 0.2.1\n\n### Patch Changes\n\n- Remove closure-compiler from the build step (See [#1570](https://github.com/FormidableLabs/urql/pull/1570))\n- Updated dependencies (See [#1570](https://github.com/FormidableLabs/urql/pull/1570), [#1509](https://github.com/FormidableLabs/urql/pull/1509), [#1600](https://github.com/FormidableLabs/urql/pull/1600), and [#1515](https://github.com/FormidableLabs/urql/pull/1515))\n  - @urql/core@2.1.0\n\n## 0.2.0\n\n### Minor Changes\n\n- Add a second `Operation` input argument to the `retryIf` predicate, so that retrying can be actively avoided for specific types of operations, e.g. mutations or subscriptions, in certain user-defined cases, by [@kitten](https://github.com/kitten) (See [#1117](https://github.com/FormidableLabs/urql/pull/1117))\n\n### Patch Changes\n\n- Updated dependencies (See [#1119](https://github.com/FormidableLabs/urql/pull/1119), [#1113](https://github.com/FormidableLabs/urql/pull/1113), [#1104](https://github.com/FormidableLabs/urql/pull/1104), and [#1123](https://github.com/FormidableLabs/urql/pull/1123))\n  - @urql/core@1.15.0\n\n## 0.1.10\n\n### Patch Changes\n\n- ⚠️ Fix the production build overwriting the development build. Specifically in the previous release we mistakenly replaced all development bundles with production bundles. This doesn't have any direct influence on how these packages work, but prevented development warnings from being logged or full errors from being thrown, by [@kitten](https://github.com/kitten) (See [#1097](https://github.com/FormidableLabs/urql/pull/1097))\n- Updated dependencies (See [#1097](https://github.com/FormidableLabs/urql/pull/1097))\n  - @urql/core@1.14.1\n\n## 0.1.9\n\n### Patch Changes\n\n- Deprecate the `Operation.operationName` property in favor of `Operation.kind`. This name was\n  previously confusing as `operationName` was effectively referring to two different things. You can\n  safely upgrade to this new version, however to mute all deprecation warnings you will have to\n  **upgrade** all `urql` packages you use. If you have custom exchanges that spread operations, please\n  use [the new `makeOperation` helper\n  function](https://formidable.com/open-source/urql/docs/api/core/#makeoperation) instead, by [@bkonkle](https://github.com/bkonkle) (See [#1045](https://github.com/FormidableLabs/urql/pull/1045))\n- Updated dependencies (See [#1094](https://github.com/FormidableLabs/urql/pull/1094) and [#1045](https://github.com/FormidableLabs/urql/pull/1045))\n  - @urql/core@1.14.0\n\n## 0.1.8\n\n### Patch Changes\n\n- Upgrade to a minimum version of wonka@^4.0.14 to work around issues with React Native's minification builds, which use uglify-es and could lead to broken bundles, by [@kitten](https://github.com/kitten) (See [#842](https://github.com/FormidableLabs/urql/pull/842))\n- Updated dependencies (See [#838](https://github.com/FormidableLabs/urql/pull/838) and [#842](https://github.com/FormidableLabs/urql/pull/842))\n  - @urql/core@1.12.0\n\n## 0.1.7\n\n### Patch Changes\n\n- Add `source` debug name to all `dispatchDebug` calls during build time to identify events by which exchange dispatched them, by [@JoviDeCroock](https://github.com/JoviDeCroock) (See [#780](https://github.com/FormidableLabs/urql/pull/780))\n- Updated dependencies (See [#780](https://github.com/FormidableLabs/urql/pull/780))\n  - @urql/core@1.11.7\n\n## 0.1.6\n\n### Patch Changes\n\n- Add a `\"./package.json\"` entry to the `package.json`'s `\"exports\"` field for Node 14. This seems to be required by packages like `rollup-plugin-svelte` to function properly, by [@JoviDeCroock](https://github.com/JoviDeCroock) (See [#771](https://github.com/FormidableLabs/urql/pull/771))\n- Updated dependencies (See [#771](https://github.com/FormidableLabs/urql/pull/771))\n  - @urql/core@1.11.6\n\n## 0.1.5\n\n### Patch Changes\n\n- Add debugging events to exchanges that add more detailed information on what is happening\n  internally, which will be displayed by devtools like the urql [Chrome / Firefox extension](https://github.com/FormidableLabs/urql-devtools), by [@andyrichardson](https://github.com/andyrichardson) (See [#608](https://github.com/FormidableLabs/urql/pull/608))\n- Updated dependencies (See [#608](https://github.com/FormidableLabs/urql/pull/608), [#718](https://github.com/FormidableLabs/urql/pull/718), and [#722](https://github.com/FormidableLabs/urql/pull/722))\n  - @urql/core@1.11.0\n\n## 0.1.4\n\n### Patch Changes\n\n- Add graphql@^15.0.0 to peer dependency range, by [@kitten](https://github.com/kitten) (See [#688](https://github.com/FormidableLabs/urql/pull/688))\n- Updated dependencies (See [#688](https://github.com/FormidableLabs/urql/pull/688) and [#678](https://github.com/FormidableLabs/urql/pull/678))\n  - @urql/core@1.10.8\n\n## 0.1.3\n\n### Patch Changes\n\n- ⚠️ Fix node resolution when using Webpack, which experiences a bug where it only resolves\n  `package.json:main` instead of `module` when an `.mjs` file imports a package, by [@JoviDeCroock](https://github.com/JoviDeCroock) (See [#642](https://github.com/FormidableLabs/urql/pull/642))\n- Updated dependencies (See [#642](https://github.com/FormidableLabs/urql/pull/642))\n  - @urql/core@1.10.4\n\n## 0.1.2\n\n### Patch Changes\n\n- ⚠️ Fix Node.js Module support for v13 (experimental-modules) and v14. If your bundler doesn't support\n  `.mjs` files and fails to resolve the new version, please double check your configuration for\n  Webpack, or similar tools, by [@JoviDeCroock](https://github.com/JoviDeCroock) (See [#637](https://github.com/FormidableLabs/urql/pull/637))\n- Updated dependencies (See [#637](https://github.com/FormidableLabs/urql/pull/637))\n  - @urql/core@1.10.3\n\n## 0.1.1\n\n### Patch Changes\n\n- ⚠️ Fix Rollup bundle output being written to .es.js instead of .esm.js, by [@kitten](https://github.com/kitten) (See [#609](https://github.com/FormidableLabs/urql/pull/609))\n- Updated dependencies (See [#609](https://github.com/FormidableLabs/urql/pull/609))\n  - @urql/core@1.10.1\n\n## v0.1.0\n\n**Initial Release**\n"
  },
  {
    "path": "exchanges/retry/README.md",
    "content": "# @urql/exchange-retry (Exchange factory)\n\n`@urql/exchange-retry` is an exchange for the [`urql`](../../README.md) GraphQL client that allows operations (queries, mutations, subscriptions) to be retried based on an `options` parameter.\n\n## Quick Start Guide\n\nFirst install `@urql/exchange-retry` alongside `urql`:\n\n```sh\nyarn add @urql/exchange-retry\n# or\nnpm install --save @urql/exchange-retry\n```\n\nRead more about the [retry exchange](https://formidable.com/open-source/urql/docs/advanced/retry-operations).\n"
  },
  {
    "path": "exchanges/retry/jsr.json",
    "content": "{\n  \"name\": \"@urql/exchange-retry\",\n  \"version\": \"2.0.0\",\n  \"exports\": {\n    \".\": \"./src/index.ts\"\n  },\n  \"exclude\": [\n    \"node_modules\",\n    \"cypress\",\n    \"**/*.test.*\",\n    \"**/*.spec.*\",\n    \"**/*.test.*.snap\",\n    \"**/*.spec.*.snap\"\n  ]\n}"
  },
  {
    "path": "exchanges/retry/package.json",
    "content": "{\n  \"name\": \"@urql/exchange-retry\",\n  \"version\": \"2.0.0\",\n  \"description\": \"An exchange for operation retry support in urql\",\n  \"sideEffects\": false,\n  \"homepage\": \"https://formidable.com/open-source/urql/docs/\",\n  \"bugs\": \"https://github.com/urql-graphql/urql/issues\",\n  \"license\": \"MIT\",\n  \"author\": \"urql GraphQL Contributors\",\n  \"repository\": {\n    \"type\": \"git\",\n    \"url\": \"https://github.com/urql-graphql/urql.git\",\n    \"directory\": \"exchanges/retry\"\n  },\n  \"keywords\": [\n    \"urql\",\n    \"graphql client\",\n    \"graphql\",\n    \"exchanges\",\n    \"retry\"\n  ],\n  \"main\": \"dist/urql-exchange-retry\",\n  \"module\": \"dist/urql-exchange-retry.mjs\",\n  \"types\": \"dist/urql-exchange-retry.d.ts\",\n  \"source\": \"src/index.ts\",\n  \"exports\": {\n    \".\": {\n      \"types\": \"./dist/urql-exchange-retry.d.ts\",\n      \"import\": \"./dist/urql-exchange-retry.mjs\",\n      \"require\": \"./dist/urql-exchange-retry.js\",\n      \"source\": \"./src/index.ts\"\n    },\n    \"./package.json\": \"./package.json\"\n  },\n  \"files\": [\n    \"LICENSE\",\n    \"CHANGELOG.md\",\n    \"README.md\",\n    \"dist/\"\n  ],\n  \"scripts\": {\n    \"test\": \"vitest\",\n    \"clean\": \"rimraf dist\",\n    \"check\": \"tsc --noEmit\",\n    \"lint\": \"eslint --ext=js,jsx,ts,tsx .\",\n    \"build\": \"rollup -c ../../scripts/rollup/config.mjs\",\n    \"prepare\": \"node ../../scripts/prepare/index.js\",\n    \"prepublishOnly\": \"run-s clean build\"\n  },\n  \"devDependencies\": {\n    \"@urql/core\": \"workspace:*\",\n    \"graphql\": \"^16.0.0\"\n  },\n  \"peerDependencies\": {\n    \"@urql/core\": \"^6.0.0\"\n  },\n  \"dependencies\": {\n    \"@urql/core\": \"workspace:^6.0.1\",\n    \"wonka\": \"^6.3.2\"\n  },\n  \"publishConfig\": {\n    \"access\": \"public\",\n    \"provenance\": true\n  }\n}\n"
  },
  {
    "path": "exchanges/retry/src/index.ts",
    "content": "export { retryExchange } from './retryExchange';\nexport type { RetryExchangeOptions } from './retryExchange';\n"
  },
  {
    "path": "exchanges/retry/src/retryExchange.test.ts",
    "content": "import {\n  Source,\n  pipe,\n  map,\n  makeSubject,\n  mergeMap,\n  fromValue,\n  fromArray,\n  publish,\n  tap,\n} from 'wonka';\nimport { vi, expect, it, beforeEach, afterEach } from 'vitest';\n\nimport {\n  gql,\n  createClient,\n  makeOperation,\n  Operation,\n  OperationResult,\n  ExchangeIO,\n} from '@urql/core';\n\nimport { retryExchange } from './retryExchange';\n\nconst dispatchDebug = vi.fn();\n\nbeforeEach(() => {\n  vi.useFakeTimers();\n});\n\nafterEach(() => {\n  vi.useRealTimers();\n});\n\nconst mockOptions = {\n  initialDelayMs: 50,\n  maxDelayMs: 500,\n  randomDelay: true,\n  maxNumberAttempts: 10,\n  retryIf: () => true,\n};\n\nconst queryOne = gql`\n  {\n    author {\n      id\n      name\n    }\n  }\n`;\n\nconst queryOneData = {\n  __typename: 'Query',\n  author: {\n    __typename: 'Author',\n    id: '123',\n    name: 'Author',\n  },\n};\n\nconst queryOneError = {\n  name: 'error',\n  message: 'scary error',\n};\n\nlet client, op, ops$, next;\nbeforeEach(() => {\n  client = createClient({\n    url: 'http://0.0.0.0',\n    exchanges: [],\n  });\n  op = client.createRequestOperation('query', {\n    key: 1,\n    query: queryOne,\n  });\n\n  ({ source: ops$, next } = makeSubject<Operation>());\n});\n\nit('retries if it hits an error and works for multiple concurrent operations', () => {\n  const queryTwo = gql`\n    {\n      films {\n        id\n        name\n      }\n    }\n  `;\n  const queryTwoError = {\n    name: 'error2',\n    message: 'scary error2',\n  };\n  const opTwo = client.createRequestOperation('query', {\n    key: 2,\n    query: queryTwo,\n  });\n\n  const response = vi.fn((forwardOp: Operation): OperationResult => {\n    expect(\n      forwardOp.key === op.key || forwardOp.key === opTwo.key\n    ).toBeTruthy();\n\n    return {\n      operation: forwardOp,\n      // @ts-ignore\n      error: forwardOp.key === 2 ? queryTwoError : queryOneError,\n    };\n  });\n\n  const result = vi.fn();\n  const forward: ExchangeIO = ops$ => {\n    return pipe(ops$, map(response));\n  };\n\n  const mockRetryIf = vi.fn(() => true);\n\n  pipe(\n    retryExchange({\n      ...mockOptions,\n      retryIf: mockRetryIf,\n    })({\n      forward,\n      client,\n      dispatchDebug,\n    })(ops$),\n    tap(result),\n    publish\n  );\n\n  next(op);\n\n  expect(mockRetryIf).toHaveBeenCalledTimes(1);\n  expect(mockRetryIf).toHaveBeenCalledWith(queryOneError as any, op);\n\n  vi.runAllTimers();\n\n  expect(mockRetryIf).toHaveBeenCalledTimes(mockOptions.maxNumberAttempts);\n\n  expect(response).toHaveBeenCalledTimes(mockOptions.maxNumberAttempts);\n\n  // result should only ever be called once per operation\n  expect(result).toHaveBeenCalledTimes(1);\n\n  next(opTwo);\n\n  vi.runAllTimers();\n\n  expect(mockRetryIf).toHaveBeenCalledWith(queryTwoError as any, opTwo);\n\n  // max number of retries for each op\n  expect(response).toHaveBeenCalledTimes(mockOptions.maxNumberAttempts * 2);\n  expect(result).toHaveBeenCalledTimes(2);\n});\n\nit('should retry x number of times and then return the successful result', () => {\n  const numberRetriesBeforeSuccess = 3;\n  const response = vi.fn((forwardOp: Operation): OperationResult => {\n    expect(forwardOp.key).toBe(op.key);\n    // @ts-ignore\n    return {\n      operation: forwardOp,\n      ...(forwardOp.context.retry?.count >= numberRetriesBeforeSuccess\n        ? { data: queryOneData }\n        : { error: queryOneError }),\n    };\n  });\n\n  const result = vi.fn();\n  const forward: ExchangeIO = ops$ => {\n    return pipe(ops$, map(response));\n  };\n\n  const mockRetryIf = vi.fn(() => true);\n\n  pipe(\n    retryExchange({\n      ...mockOptions,\n      retryIf: mockRetryIf,\n    })({\n      forward,\n      client,\n      dispatchDebug,\n    })(ops$),\n    tap(result),\n    publish\n  );\n\n  next(op);\n  vi.runAllTimers();\n\n  expect(mockRetryIf).toHaveBeenCalledTimes(numberRetriesBeforeSuccess);\n  expect(mockRetryIf).toHaveBeenCalledWith(queryOneError as any, op);\n\n  // one for original source, one for retry\n  expect(response).toHaveBeenCalledTimes(1 + numberRetriesBeforeSuccess);\n  expect(result).toHaveBeenCalledTimes(1);\n});\n\nit('should reset the retry counter if an operation succeeded first', () => {\n  let call = 0;\n  const response = vi.fn((forwardOp: Operation): Source<any> => {\n    expect(forwardOp.key).toBe(op.key);\n    if (call === 0) {\n      call++;\n      return fromValue({\n        operation: forwardOp,\n        error: queryOneError,\n      } as any);\n    } else if (call === 1) {\n      call++;\n      return fromArray([\n        {\n          operation: forwardOp,\n          error: queryOneError,\n        } as any,\n        {\n          operation: forwardOp,\n          data: queryOneData,\n        } as any,\n      ]);\n    } else {\n      expect(forwardOp.context.retry).toEqual({ count: 0, delay: null });\n\n      return fromValue({\n        operation: forwardOp,\n        data: queryOneData,\n      } as any);\n    }\n  });\n\n  const result = vi.fn();\n  const forward: ExchangeIO = ops$ => {\n    return pipe(ops$, mergeMap(response));\n  };\n\n  const mockRetryIf = vi.fn(() => true);\n\n  pipe(\n    retryExchange({\n      ...mockOptions,\n      retryIf: mockRetryIf,\n    })({\n      forward,\n      client,\n      dispatchDebug,\n    })(ops$),\n    tap(result),\n    publish\n  );\n\n  next(op);\n  vi.runAllTimers();\n\n  expect(mockRetryIf).toHaveBeenCalledTimes(2);\n  expect(mockRetryIf).toHaveBeenCalledWith(queryOneError as any, op);\n\n  expect(response).toHaveBeenCalledTimes(3);\n  expect(result).toHaveBeenCalledTimes(2);\n});\n\nit(`should still retry if retryIf undefined but there is a networkError`, () => {\n  const errorWithNetworkError = {\n    ...queryOneError,\n    networkError: 'scary network error',\n  };\n  const response = vi.fn((forwardOp: Operation): OperationResult => {\n    expect(forwardOp.key).toBe(op.key);\n    return {\n      operation: forwardOp,\n      // @ts-ignore\n      error: errorWithNetworkError,\n    };\n  });\n\n  const result = vi.fn();\n  const forward: ExchangeIO = ops$ => {\n    return pipe(ops$, map(response));\n  };\n\n  pipe(\n    retryExchange({\n      ...mockOptions,\n      retryIf: undefined,\n    })({\n      forward,\n      client,\n      dispatchDebug,\n    })(ops$),\n    tap(result),\n    publish\n  );\n\n  next(op);\n\n  vi.runAllTimers();\n\n  // max number of retries, plus original call\n  expect(response).toHaveBeenCalledTimes(mockOptions.maxNumberAttempts);\n  expect(result).toHaveBeenCalledTimes(1);\n});\n\nit('should allow retryWhen to return falsy value and act as replacement of retryIf', () => {\n  const errorWithNetworkError = {\n    ...queryOneError,\n    networkError: 'scary network error',\n  };\n  const response = vi.fn((forwardOp: Operation): OperationResult => {\n    expect(forwardOp.key).toBe(op.key);\n    return {\n      operation: forwardOp,\n      // @ts-ignore\n      error: errorWithNetworkError,\n    };\n  });\n\n  const result = vi.fn();\n  const forward: ExchangeIO = ops$ => {\n    return pipe(ops$, map(response));\n  };\n\n  const retryWith = vi.fn(() => null);\n\n  pipe(\n    retryExchange({\n      ...mockOptions,\n      retryIf: undefined,\n      retryWith,\n    })({\n      forward,\n      client,\n      dispatchDebug,\n    })(ops$),\n    tap(result),\n    publish\n  );\n\n  next(op);\n\n  vi.runAllTimers();\n\n  // max number of retries, plus original call\n  expect(retryWith).toHaveBeenCalledTimes(1);\n  expect(response).toHaveBeenCalledTimes(1);\n  expect(result).toHaveBeenCalledTimes(1);\n});\n\nit('should allow retryWhen to return new operations when retrying', () => {\n  const errorWithNetworkError = {\n    ...queryOneError,\n    networkError: 'scary network error',\n  };\n  const response = vi.fn((forwardOp: Operation): OperationResult => {\n    expect(forwardOp.key).toBe(op.key);\n    return {\n      operation: forwardOp,\n      // @ts-ignore\n      error: errorWithNetworkError,\n    };\n  });\n\n  const result = vi.fn();\n  const forward: ExchangeIO = ops$ => {\n    return pipe(ops$, map(response));\n  };\n\n  const retryWith = vi.fn((_error, operation) => {\n    return makeOperation(operation.kind, operation, {\n      ...operation.context,\n      counter: (operation.context?.counter || 0) + 1,\n    });\n  });\n\n  pipe(\n    retryExchange({\n      ...mockOptions,\n      retryIf: undefined,\n      retryWith,\n    })({\n      forward,\n      client,\n      dispatchDebug,\n    })(ops$),\n    tap(result),\n    publish\n  );\n\n  next(op);\n\n  vi.runAllTimers();\n\n  // max number of retries, plus original call\n  expect(retryWith).toHaveBeenCalledTimes(mockOptions.maxNumberAttempts - 1);\n  expect(response).toHaveBeenCalledTimes(mockOptions.maxNumberAttempts);\n  expect(result).toHaveBeenCalledTimes(1);\n\n  expect(response.mock.calls[1][0]).toHaveProperty('context.counter', 1);\n  expect(response.mock.calls[2][0]).toHaveProperty('context.counter', 2);\n});\n\nit('should increase retries by initialDelayMs for each subsequent failure', () => {\n  const errorWithNetworkError = {\n    ...queryOneError,\n    networkError: 'scary network error',\n  };\n  const response = vi.fn((forwardOp: Operation): OperationResult => {\n    expect(forwardOp.key).toBe(op.key);\n    return {\n      operation: forwardOp,\n      // @ts-ignore\n      error: errorWithNetworkError,\n    };\n  });\n\n  const result = vi.fn();\n  const forward: ExchangeIO = ops$ => {\n    return pipe(ops$, map(response));\n  };\n\n  const retryWith = vi.fn((_error, operation) => {\n    return makeOperation(operation.kind, operation, {\n      ...operation.context,\n      counter: (operation.context?.counter || 0) + 1,\n    });\n  });\n\n  const fixedDelayMs = 50;\n\n  const fixedDelayOptions = {\n    ...mockOptions,\n    randomDelay: false,\n    initialDelayMs: fixedDelayMs,\n  };\n\n  pipe(\n    retryExchange({\n      ...fixedDelayOptions,\n      retryIf: undefined,\n      retryWith,\n    })({\n      forward,\n      client,\n      dispatchDebug,\n    })(ops$),\n    tap(result),\n    publish\n  );\n\n  next(op);\n\n  // delay between each call should be increased by initialDelayMs\n  // (e.g. if initialDelayMs is 5s, first retry is waits 5 seconds, second retry waits 10 seconds)\n  for (let i = 1; i <= fixedDelayOptions.maxNumberAttempts; i++) {\n    expect(response).toHaveBeenCalledTimes(i);\n    vi.advanceTimersByTime(i * fixedDelayOptions.initialDelayMs);\n  }\n});\n"
  },
  {
    "path": "exchanges/retry/src/retryExchange.ts",
    "content": "import {\n  makeSubject,\n  pipe,\n  merge,\n  filter,\n  fromValue,\n  debounce,\n  mergeMap,\n  takeUntil,\n} from 'wonka';\n\nimport type { Exchange, Operation, CombinedError } from '@urql/core';\nimport { makeOperation } from '@urql/core';\n\n/** Input parameters for the {@link retryExchange}. */\nexport interface RetryExchangeOptions {\n  /** Specify the minimum time to wait until retrying.\n   *\n   * @remarks\n   * `initialDelayMs` specifies the minimum time (in milliseconds) to wait\n   * until a failed operation is retried.\n   *\n   * @defaultValue `1_000` - one second\n   */\n  initialDelayMs?: number;\n  /** Specifies the maximum time to wait until retrying.\n   *\n   * @remarks\n   * `maxDelayMs` specifies the maximum time (in milliseconds) to wait\n   * until a failed operation is retried. While `initialDelayMs`\n   * specifies the minimum amount of time, `randomDelay` may cause\n   * the delay to increase over multiple attempts.\n   *\n   * @defaultValue `15_000` - 15 seconds\n   */\n  maxDelayMs?: number;\n  /** Enables a random exponential backoff to increase the delay over multiple retries.\n   *\n   * @remarks\n   * `randomDelay`, unless disabled, increases the time until a failed\n   * operation is retried over multiple attempts. It increases the time\n   * starting at `initialDelayMs` by 1.5x with an added factor of 0–1,\n   * until `maxDelayMs` is reached.\n   *\n   * @defaultValue `true` - enables random exponential backoff\n   */\n  randomDelay?: boolean;\n  /** Specifies the maximum number of attempts, including the initial request.\n   *\n   * @remarks\n   * `maxNumberAttempts` defines the total number of attempts before it's\n   * considered failed.\n   *\n   * @defaultValue `2` - Retry once, i.e. two attempts\n   */\n  maxNumberAttempts?: number;\n  /** Predicate allowing you to selectively not retry `Operation`s.\n   *\n   * @remarks\n   * `retryIf` is called with a {@link CombinedError} and the {@link Operation} that\n   * failed. If this function returns false the failed `Operation` is not retried.\n   *\n   * @defaultValue `(error) => !!error.networkError` - retries only on network errors.\n   */\n  retryIf?(error: CombinedError, operation: Operation): boolean;\n  /** Transform function allowing you to selectively replace a retried `Operation` or return nullish value.\n   *\n   * @remarks\n   * `retryWhen` is called with a {@link CombinedError} and the {@link Operation} that\n   * failed. If this function returns an `Operation`, `retryExchange` will replace the\n   * failed `Operation` and retry. It won't retry the `Operation` if a nullish value\n   * is returned.\n   *\n   * The `retryIf` function, if defined, takes precedence and overrides this option.\n   */\n  retryWith?(\n    error: CombinedError,\n    operation: Operation\n  ): Operation | null | undefined;\n}\n\ninterface RetryState {\n  count: number;\n  delay: number | null;\n}\n\n/** Exchange factory that retries failed operations.\n *\n * @param options - A {@link RetriesExchangeOptions} configuration object.\n * @returns the created retry {@link Exchange}.\n *\n * @remarks\n * The `retryExchange` retries failed operations with specified delays\n * and exponential backoff.\n *\n * You may define a {@link RetryExchangeOptions.retryIf} or\n * {@link RetryExchangeOptions.retryWhen} function to only retry\n * certain kinds of operations, e.g. only queries.\n *\n * @example\n * ```ts\n * retryExchange({\n *   initialDelayMs: 1000,\n *   maxDelayMs: 15000,\n *   randomDelay: true,\n *   maxNumberAttempts: 2,\n *   retryIf: err => err && err.networkError,\n * });\n * ```\n */\nexport const retryExchange = (options: RetryExchangeOptions = {}): Exchange => {\n  const { retryIf, retryWith } = options;\n  const MIN_DELAY = options.initialDelayMs || 1000;\n  const MAX_DELAY = options.maxDelayMs || 15_000;\n  const MAX_ATTEMPTS = options.maxNumberAttempts || 2;\n  const RANDOM_DELAY =\n    options.randomDelay != null ? !!options.randomDelay : true;\n\n  return ({ forward, dispatchDebug }) =>\n    operations$ => {\n      const { source: retry$, next: nextRetryOperation } =\n        makeSubject<Operation>();\n\n      const retryWithBackoff$ = pipe(\n        retry$,\n        mergeMap((operation: Operation) => {\n          const retry: RetryState = operation.context.retry || {\n            count: 0,\n            delay: null,\n          };\n\n          const retryCount = ++retry.count;\n          let delayAmount = retry.delay || MIN_DELAY;\n\n          const backoffFactor = Math.random() + 1.5;\n          if (RANDOM_DELAY) {\n            // if randomDelay is enabled and it won't exceed the max delay, apply a random\n            // amount to the delay to avoid thundering herd problem\n            if (delayAmount * backoffFactor < MAX_DELAY) {\n              delayAmount *= backoffFactor;\n            } else {\n              delayAmount = MAX_DELAY;\n            }\n          } else {\n            // otherwise, increase the delay proportionately by the initial delay\n            delayAmount = Math.min(retryCount * MIN_DELAY, MAX_DELAY);\n          }\n\n          // ensure the delay is carried over to the next context\n          retry.delay = delayAmount;\n\n          // We stop the retries if a teardown event for this operation comes in\n          // But if this event comes through regularly we also stop the retries, since it's\n          // basically the query retrying itself, no backoff should be added!\n          const teardown$ = pipe(\n            operations$,\n            filter(op => {\n              return (\n                (op.kind === 'query' || op.kind === 'teardown') &&\n                op.key === operation.key\n              );\n            })\n          );\n\n          dispatchDebug({\n            type: 'retryAttempt',\n            message: `The operation has failed and a retry has been triggered (${retryCount} / ${MAX_ATTEMPTS})`,\n            operation,\n            data: {\n              retryCount,\n              delayAmount,\n            },\n          });\n\n          // Add new retryDelay and retryCount to operation\n          return pipe(\n            fromValue(\n              makeOperation(operation.kind, operation, {\n                ...operation.context,\n                retry,\n              })\n            ),\n            debounce(() => delayAmount),\n            // Stop retry if a teardown comes in\n            takeUntil(teardown$)\n          );\n        })\n      );\n\n      return pipe(\n        merge([operations$, retryWithBackoff$]),\n        forward,\n        filter(res => {\n          const retry = res.operation.context.retry as RetryState | undefined;\n          // Only retry if the error passes the conditional retryIf function (if passed)\n          // or if the error contains a networkError\n          if (\n            !res.error ||\n            (retryIf\n              ? !retryIf(res.error, res.operation)\n              : !retryWith && !res.error.networkError)\n          ) {\n            // Reset the delay state for a successful operation\n            if (retry) {\n              retry.count = 0;\n              retry.delay = null;\n            }\n            return true;\n          }\n\n          const maxNumberAttemptsExceeded =\n            ((retry && retry.count) || 0) >= MAX_ATTEMPTS - 1;\n          if (!maxNumberAttemptsExceeded) {\n            const operation = retryWith\n              ? retryWith(res.error, res.operation)\n              : res.operation;\n            if (!operation) return true;\n\n            // Send failed responses to be retried by calling next on the retry$ subject\n            // Exclude operations that have been retried more than the specified max\n            nextRetryOperation(operation);\n            return false;\n          }\n\n          dispatchDebug({\n            type: 'retryExhausted',\n            message:\n              'Maximum number of retries has been reached. No further retries will be performed.',\n            operation: res.operation,\n          });\n\n          return true;\n        })\n      );\n    };\n};\n"
  },
  {
    "path": "exchanges/retry/tsconfig.json",
    "content": "{\n  \"extends\": \"../../tsconfig.json\",\n  \"include\": [\"src\"]\n}\n"
  },
  {
    "path": "exchanges/retry/vitest.config.ts",
    "content": "import { mergeConfig } from 'vitest/config';\nimport baseConfig from '../../vitest.config';\n\nexport default mergeConfig(baseConfig, {});\n"
  },
  {
    "path": "exchanges/throw-on-error/CHANGELOG.md",
    "content": "# @urql/exchange-throw-on-error\n\n## 1.0.0\n\n### Patch Changes\n\n- Updated dependencies (See [#3789](https://github.com/urql-graphql/urql/pull/3789) and [#3807](https://github.com/urql-graphql/urql/pull/3807))\n  - @urql/core@6.0.0\n\n## 0.1.2\n\n### Patch Changes\n\n- Update `graphql-toe` and add more detail to README\n  Submitted by [@benjie](https://github.com/benjie) (See [#3765](https://github.com/urql-graphql/urql/pull/3765))\n\n## 0.1.1\n\n### Patch Changes\n\n- Omit minified files and sourcemaps' `sourcesContent` in published packages\n  Submitted by [@kitten](https://github.com/kitten) (See [#3755](https://github.com/urql-graphql/urql/pull/3755))\n- Updated dependencies (See [#3755](https://github.com/urql-graphql/urql/pull/3755))\n  - @urql/core@5.1.1\n\n## 0.1.0\n\n### Minor Changes\n\n- Initial release\n  Submitted by [@XiNiHa](https://github.com/XiNiHa) (See [#3677](https://github.com/urql-graphql/urql/pull/3677))\n"
  },
  {
    "path": "exchanges/throw-on-error/README.md",
    "content": "# @urql/exchange-throw-on-error (Exchange factory)\n\n`@urql/exchange-throw-on-error` is an exchange for the [`urql`](https://github.com/urql-graphql/urql) GraphQL client that throws on field access to errored fields.\n\nIt is built on top of the [`graphql-toe`](https://github.com/graphile/graphql-toe) package - please see that package for more information.\n\n## Quick Start Guide\n\nFirst install `@urql/exchange-throw-on-error` alongside `urql`:\n\n```sh\nyarn add @urql/exchange-throw-on-error\n# or\nnpm install --save @urql/exchange-throw-on-error\n```\n\nThen add the `throwOnErrorExchange`, to your client:\n\n```js\nimport { createClient, cacheExchange, fetchExchange } from 'urql';\nimport { throwOnErrorExchange } from '@urql/exchange-throw-on-error';\n\nconst client = createClient({\n  url: '/graphql',\n  exchanges: [cacheExchange, throwOnErrorExchange(), fetchExchange],\n});\n```\n"
  },
  {
    "path": "exchanges/throw-on-error/jsr.json",
    "content": "{\n  \"name\": \"@urql/exchange-throw-on-error\",\n  \"version\": \"1.0.0\",\n  \"exports\": {\n    \".\": \"./src/index.ts\"\n  },\n  \"exclude\": [\n    \"node_modules\",\n    \"cypress\",\n    \"**/*.test.*\",\n    \"**/*.spec.*\",\n    \"**/*.test.*.snap\",\n    \"**/*.spec.*.snap\"\n  ]\n}"
  },
  {
    "path": "exchanges/throw-on-error/package.json",
    "content": "{\n  \"name\": \"@urql/exchange-throw-on-error\",\n  \"version\": \"1.0.0\",\n  \"description\": \"An exchange for throw-on-error support in urql\",\n  \"sideEffects\": false,\n  \"homepage\": \"https://formidable.com/open-source/urql/docs/\",\n  \"bugs\": \"https://github.com/urql-graphql/urql/issues\",\n  \"license\": \"MIT\",\n  \"author\": \"urql GraphQL Contributors\",\n  \"repository\": {\n    \"type\": \"git\",\n    \"url\": \"https://github.com/urql-graphql/urql.git\",\n    \"directory\": \"exchanges/throw-on-error\"\n  },\n  \"keywords\": [\n    \"urql\",\n    \"graphql client\",\n    \"graphql\",\n    \"exchanges\",\n    \"throw on error\"\n  ],\n  \"main\": \"dist/urql-exchange-throw-on-error\",\n  \"module\": \"dist/urql-exchange-throw-on-error.mjs\",\n  \"types\": \"dist/urql-exchange-throw-on-error.d.ts\",\n  \"source\": \"src/index.ts\",\n  \"exports\": {\n    \".\": {\n      \"types\": \"./dist/urql-exchange-throw-on-error.d.ts\",\n      \"import\": \"./dist/urql-exchange-throw-on-error.mjs\",\n      \"require\": \"./dist/urql-exchange-throw-on-error.js\",\n      \"source\": \"./src/index.ts\"\n    },\n    \"./package.json\": \"./package.json\"\n  },\n  \"files\": [\n    \"LICENSE\",\n    \"CHANGELOG.md\",\n    \"README.md\",\n    \"dist/\"\n  ],\n  \"scripts\": {\n    \"test\": \"vitest\",\n    \"clean\": \"rimraf dist\",\n    \"check\": \"tsc --noEmit\",\n    \"lint\": \"eslint --ext=js,jsx,ts,tsx .\",\n    \"build\": \"rollup -c ../../scripts/rollup/config.mjs\",\n    \"prepare\": \"node ../../scripts/prepare/index.js\",\n    \"prepublishOnly\": \"run-s clean build\"\n  },\n  \"devDependencies\": {\n    \"@urql/core\": \"workspace:*\",\n    \"graphql\": \"^16.0.0\"\n  },\n  \"peerDependencies\": {\n    \"@urql/core\": \"^6.0.0\"\n  },\n  \"dependencies\": {\n    \"@urql/core\": \"workspace:^6.0.1\",\n    \"graphql-toe\": \"^1.0.0-rc.0\",\n    \"wonka\": \"^6.3.2\"\n  },\n  \"publishConfig\": {\n    \"access\": \"public\",\n    \"provenance\": true\n  }\n}\n"
  },
  {
    "path": "exchanges/throw-on-error/src/index.ts",
    "content": "export { throwOnErrorExchange } from './throwOnErrorExchange';\n"
  },
  {
    "path": "exchanges/throw-on-error/src/throwOnErrorExchange.test.ts",
    "content": "import { pipe, map, fromValue, toPromise, take } from 'wonka';\nimport { vi, expect, it, beforeEach } from 'vitest';\nimport { GraphQLError } from 'graphql';\n\nimport {\n  gql,\n  createClient,\n  Operation,\n  ExchangeIO,\n  Client,\n  CombinedError,\n} from '@urql/core';\n\nimport { throwOnErrorExchange } from './throwOnErrorExchange';\n\nconst dispatchDebug = vi.fn();\n\nconst query = gql`\n  {\n    topLevel\n    topLevelList\n    object {\n      inner\n    }\n    objectList {\n      inner\n    }\n  }\n`;\nconst mockData = {\n  topLevel: 'topLevel',\n  topLevelList: ['topLevelList'],\n  object: { inner: 'inner' },\n  objectList: [{ inner: 'inner' }],\n};\n\nlet client: Client, op: Operation;\nbeforeEach(() => {\n  client = createClient({\n    url: 'http://0.0.0.0',\n    exchanges: [],\n  });\n  op = client.createRequestOperation('query', { key: 1, query, variables: {} });\n});\n\nit('throws on top level field error', async () => {\n  const forward: ExchangeIO = ops$ =>\n    pipe(\n      ops$,\n      map(\n        operation =>\n          ({\n            operation,\n            data: {\n              ...mockData,\n              topLevel: null,\n            },\n            error: new CombinedError({\n              graphQLErrors: [\n                new GraphQLError('top level error', { path: ['topLevel'] }),\n              ],\n            }),\n          }) as any\n      )\n    );\n\n  const res = await pipe(\n    fromValue(op),\n    throwOnErrorExchange()({ forward, client, dispatchDebug }),\n    take(1),\n    toPromise\n  );\n\n  expect(() => res.data?.topLevel).toThrow('top level error');\n  expect(() => res.data).not.toThrow();\n  expect(() => res.data?.topLevelList[0]).not.toThrow();\n});\n\nit('throws on top level list element error', async () => {\n  const forward: ExchangeIO = ops$ =>\n    pipe(\n      ops$,\n      map(\n        operation =>\n          ({\n            operation,\n            data: {\n              ...mockData,\n              topLevelList: ['topLevelList', null],\n            },\n            error: new CombinedError({\n              graphQLErrors: [\n                new GraphQLError('top level list error', {\n                  path: ['topLevelList', 1],\n                }),\n              ],\n            }),\n          }) as any\n      )\n    );\n\n  const res = await pipe(\n    fromValue(op),\n    throwOnErrorExchange()({ forward, client, dispatchDebug }),\n    take(1),\n    toPromise\n  );\n\n  expect(() => res.data?.topLevelList[1]).toThrow('top level list error');\n  expect(() => res.data).not.toThrow();\n  expect(() => res.data?.topLevelList[0]).not.toThrow();\n});\n\nit('throws on object field error', async () => {\n  const forward: ExchangeIO = ops$ =>\n    pipe(\n      ops$,\n      map(\n        operation =>\n          ({\n            operation,\n            data: {\n              ...mockData,\n              object: null,\n            },\n            error: new CombinedError({\n              graphQLErrors: [\n                new GraphQLError('object field error', { path: ['object'] }),\n              ],\n            }),\n          }) as any\n      )\n    );\n\n  const res = await pipe(\n    fromValue(op),\n    throwOnErrorExchange()({ forward, client, dispatchDebug }),\n    take(1),\n    toPromise\n  );\n\n  expect(() => res.data?.object).toThrow('object field error');\n  expect(() => res.data?.object.inner).toThrow('object field error');\n  expect(() => res.data).not.toThrow();\n  expect(() => res.data?.topLevel).not.toThrow();\n});\n\nit('throws on object inner field error', async () => {\n  const forward: ExchangeIO = ops$ =>\n    pipe(\n      ops$,\n      map(\n        operation =>\n          ({\n            operation,\n            data: {\n              ...mockData,\n              object: {\n                inner: null,\n              },\n            },\n            error: new CombinedError({\n              graphQLErrors: [\n                new GraphQLError('object inner field error', {\n                  path: ['object', 'inner'],\n                }),\n              ],\n            }),\n          }) as any\n      )\n    );\n\n  const res = await pipe(\n    fromValue(op),\n    throwOnErrorExchange()({ forward, client, dispatchDebug }),\n    take(1),\n    toPromise\n  );\n\n  expect(() => res.data?.object.inner).toThrow('object inner field error');\n  expect(() => res.data).not.toThrow();\n  expect(() => res.data?.object).not.toThrow();\n});\n\nit('throws on object list field error', async () => {\n  const forward: ExchangeIO = ops$ =>\n    pipe(\n      ops$,\n      map(\n        operation =>\n          ({\n            operation,\n            data: {\n              ...mockData,\n              objectList: null,\n            },\n            error: new CombinedError({\n              graphQLErrors: [\n                new GraphQLError('object list field error', {\n                  path: ['objectList'],\n                }),\n              ],\n            }),\n          }) as any\n      )\n    );\n\n  const res = await pipe(\n    fromValue(op),\n    throwOnErrorExchange()({ forward, client, dispatchDebug }),\n    take(1),\n    toPromise\n  );\n\n  expect(() => res.data?.objectList).toThrow('object list field error');\n  expect(() => res.data?.objectList[0]).toThrow('object list field error');\n  expect(() => res.data?.objectList[0].inner).toThrow(\n    'object list field error'\n  );\n  expect(() => res.data).not.toThrow();\n  expect(() => res.data?.topLevel).not.toThrow();\n});\n\nit('throws on object inner field error', async () => {\n  const forward: ExchangeIO = ops$ =>\n    pipe(\n      ops$,\n      map(\n        operation =>\n          ({\n            operation,\n            data: {\n              ...mockData,\n              objectList: [{ inner: 'inner' }, { inner: null }],\n            },\n            error: new CombinedError({\n              graphQLErrors: [\n                new GraphQLError('object list inner field error', {\n                  path: ['objectList', 1, 'inner'],\n                }),\n              ],\n            }),\n          }) as any\n      )\n    );\n\n  const res = await pipe(\n    fromValue(op),\n    throwOnErrorExchange()({ forward, client, dispatchDebug }),\n    take(1),\n    toPromise\n  );\n\n  expect(() => res.data?.objectList[1].inner).toThrow(\n    'object list inner field error'\n  );\n  expect(() => res.data).not.toThrow();\n  expect(() => res.data?.objectList[0].inner).not.toThrow();\n});\n"
  },
  {
    "path": "exchanges/throw-on-error/src/throwOnErrorExchange.ts",
    "content": "import type { Exchange } from '@urql/core';\nimport { mapExchange } from '@urql/core';\nimport { toe } from 'graphql-toe';\n\n/** Exchange factory that maps the fields of the data to throw an error on access if the field was errored.\n *\n * @returns the created throw-on-error {@link Exchange}.\n */\nexport const throwOnErrorExchange = (): Exchange => {\n  return mapExchange({\n    onResult(result) {\n      if (result.data) {\n        const errors = result.error && result.error.graphQLErrors;\n        result.data = toe({ data: result.data, errors });\n      }\n      return result;\n    },\n  });\n};\n"
  },
  {
    "path": "exchanges/throw-on-error/tsconfig.json",
    "content": "{\n  \"extends\": \"../../tsconfig.json\",\n  \"include\": [\"src\"]\n}\n"
  },
  {
    "path": "exchanges/throw-on-error/vitest.config.ts",
    "content": "import { mergeConfig } from 'vitest/config';\nimport baseConfig from '../../vitest.config';\n\nexport default mergeConfig(baseConfig, {});\n"
  },
  {
    "path": "package.json",
    "content": "{\n  \"private\": true,\n  \"scripts\": {\n    \"test\": \"test -z $CI && vitest || vitest\",\n    \"check\": \"tsc\",\n    \"lint\": \"eslint --ext=js,jsx,ts,tsx .\",\n    \"build\": \"node ./scripts/actions/build-all.mjs\",\n    \"postinstall\": \"node ./scripts/prepare/postinstall.js\",\n    \"pack\": \"node ./scripts/actions/pack-all.mjs\",\n    \"changeset:version\": \"node ./scripts/changesets/version.mjs\",\n    \"changeset:publish\": \"changeset publish && pnpm jsr\",\n    \"jsr\": \"pnpm --filter @urql/core jsr\",\n    \"jsr:dryrun\": \"pnpm --filter @urql/core jsr --dry-run\"\n  },\n  \"eslintConfig\": {\n    \"root\": true,\n    \"extends\": [\n      \"./scripts/eslint/preset.js\"\n    ]\n  },\n  \"prettier\": {\n    \"singleQuote\": true,\n    \"arrowParens\": \"avoid\",\n    \"trailingComma\": \"es5\"\n  },\n  \"lint-staged\": {\n    \"*.{js,jsx,ts,tsx}\": \"eslint -c scripts/eslint/preset.js --fix\",\n    \"*.json\": \"prettier --write\",\n    \"*.md\": \"prettier --write\"\n  },\n  \"husky\": {\n    \"hooks\": {\n      \"pre-commit\": \"lint-staged --quiet --relative\"\n    }\n  },\n  \"pnpm\": {\n    \"peerDependencyRules\": {\n      \"ignoreMissing\": [\n        \"react-native\"\n      ],\n      \"allowedVersions\": {\n        \"styled-components\": \"5\"\n      }\n    },\n    \"overrides\": {\n      \"graphql\": \"^16.6.0\",\n      \"styled-components\": \"^5.2.3\",\n      \"wonka\": \"^6.3.2\"\n    }\n  },\n  \"devDependencies\": {\n    \"@0no-co/graphql.web\": \"^1.0.13\",\n    \"@actions/artifact\": \"^2.3.2\",\n    \"@actions/core\": \"^1.11.1\",\n    \"@babel/core\": \"^7.25.2\",\n    \"@babel/plugin-transform-block-scoping\": \"^7.25.0\",\n    \"@babel/plugin-transform-react-jsx\": \"^7.25.2\",\n    \"@babel/plugin-transform-typescript\": \"^7.25.2\",\n    \"@changesets/cli\": \"^2.29.6\",\n    \"@changesets/get-github-info\": \"0.6.0\",\n    \"@npmcli/arborist\": \"^7.5.4\",\n    \"@rollup/plugin-babel\": \"^6.0.4\",\n    \"@rollup/plugin-commonjs\": \"^26.0.1\",\n    \"@rollup/plugin-node-resolve\": \"^15.2.3\",\n    \"@rollup/plugin-replace\": \"^5.0.7\",\n    \"@rollup/plugin-terser\": \"^0.4.4\",\n    \"@rollup/pluginutils\": \"^5.1.0\",\n    \"@types/node\": \"^18.19.50\",\n    \"@typescript-eslint/eslint-plugin\": \"^6.21.0\",\n    \"@typescript-eslint/parser\": \"^6.21.0\",\n    \"cypress\": \"^12.17.4\",\n    \"dotenv\": \"^16.4.5\",\n    \"eslint\": \"^8.57.0\",\n    \"eslint-config-prettier\": \"^8.10.0\",\n    \"eslint-plugin-es5\": \"^1.5.0\",\n    \"eslint-plugin-prettier\": \"^5.2.1\",\n    \"eslint-plugin-react\": \"^7.36.1\",\n    \"eslint-plugin-react-hooks\": \"^4.6.2\",\n    \"execa\": \"^8.0.0\",\n    \"glob\": \"^9.3.5\",\n    \"graphql\": \"^16.9.0\",\n    \"husky-v4\": \"^4.3.8\",\n    \"invariant\": \"^2.2.4\",\n    \"jsdom\": \"^25.0.0\",\n    \"jsr\": \"^0.13.2\",\n    \"lint-staged\": \"^13.3.0\",\n    \"npm-packlist\": \"^8.0.2\",\n    \"npm-run-all\": \"^4.1.5\",\n    \"prettier\": \"^3.3.3\",\n    \"react\": \"^17.0.2\",\n    \"react-dom\": \"^17.0.2\",\n    \"react-is\": \"^17.0.2\",\n    \"rimraf\": \"^6.0.1\",\n    \"rollup\": \"^3.29.4\",\n    \"rollup-plugin-cjs-check\": \"^1.0.3\",\n    \"rollup-plugin-dts\": \"^5.3.1\",\n    \"rollup-plugin-visualizer\": \"^5.12.0\",\n    \"tar\": \"^7.4.3\",\n    \"terser\": \"^5.32.0\",\n    \"typescript\": \"^5.6.2\",\n    \"vite\": \"^5.4.5\",\n    \"vite-tsconfig-paths\": \"^4.3.2\",\n    \"vitest\": \"^2.1.1\"\n  },\n  \"dependencies\": {\n    \"@actions/github\": \"^6.0.0\",\n    \"node-fetch\": \"^3.3.2\"\n  },\n  \"engines\": {\n    \"pnpm\": \">=9.0.0\",\n    \"node\": \">=18.0.0\"\n  }\n}\n"
  },
  {
    "path": "packages/core/.gitignore",
    "content": "/internal\n"
  },
  {
    "path": "packages/core/CHANGELOG.md",
    "content": "# @urql/core\n\n## 6.0.1\n\n### Patch Changes\n\n- Use nullish coalescing for `preferGetMethod` and `preferGetForPersistedQueries` so that `false` is kept if set\n  Submitted by [@dargmuesli](https://github.com/dargmuesli) (See [#3812](https://github.com/urql-graphql/urql/pull/3812))\n\n## 6.0.0\n\n### Major Changes\n\n- By default leverage GET for queries where the query-string + variables comes down to less than 2048 characters.\n  When upgrading it's important to see whether your server supports `GET`, if it doesn't ideally adding support for it\n  or alternatively setting `preferGetMethod` in the `createClient` method as well as `preferGetForPersistedQueries` for\n  the persisted exchange to `false`\n  Submitted by [@JoviDeCroock](https://github.com/JoviDeCroock) (See [#3789](https://github.com/urql-graphql/urql/pull/3789))\n\n### Minor Changes\n\n- Fix type definition for `GraphQLRequestParams` to make `variables` field optional if and only if **all** fields are optional or nullish\n  Submitted by [@arkandias](https://github.com/arkandias) (See [#3807](https://github.com/urql-graphql/urql/pull/3807))\n\n## 5.2.0\n\n### Minor Changes\n\n- export the getOperationName utility function\n  Submitted by [@giacomocerquone](https://github.com/giacomocerquone) (See [#3785](https://github.com/urql-graphql/urql/pull/3785))\n\n## 5.1.2\n\n### Patch Changes\n\n- Correct typo in cacheHit debug message of the `debugExchange`\n  Submitted by [@jorrit](https://github.com/jorrit) (See [#3773](https://github.com/urql-graphql/urql/pull/3773))\n- ⚠️ Fix `fetchSource` not text-decoding response chunks as streams, which could cause UTF-8 decoding to break\n  Submitted by [@i110](https://github.com/i110) (See [#3767](https://github.com/urql-graphql/urql/pull/3767))\n- ⚠️ Fix compatibility with Typescript >5.5 (See: https://github.com/0no-co/graphql.web/pull/49)\n  Submitted by [@andreisergiu98](https://github.com/andreisergiu98) (See [#3730](https://github.com/urql-graphql/urql/pull/3730))\n- Change debug log verbosity to `console.debug` rather than `console.log`\n  Submitted by [@kitten](https://github.com/kitten) (See [#3770](https://github.com/urql-graphql/urql/pull/3770))\n\n## 5.1.1\n\n### Patch Changes\n\n- Omit minified files and sourcemaps' `sourcesContent` in published packages\n  Submitted by [@kitten](https://github.com/kitten) (See [#3755](https://github.com/urql-graphql/urql/pull/3755))\n\n## 5.1.0\n\n### Minor Changes\n\n- Remove `addMetadata` transform where we'd strip out metadata for production environments, this particularly affects `OperationResult.context.metadata.cacheOutcome`\n  Submitted by [@alpavlove](https://github.com/alpavlove) (See [#3714](https://github.com/urql-graphql/urql/pull/3714))\n\n## 5.0.8\n\n### Patch Changes\n\n- ⚠️ Fix `deepMerge` regression on array values\n  Submitted by [@JoviDeCroock](https://github.com/JoviDeCroock) (See [#3696](https://github.com/urql-graphql/urql/pull/3696))\n\n## 5.0.7\n\n### Patch Changes\n\n- Remove `for-of` syntax from `@urql/core` helpers for JSC memory reduction\n  Submitted by [@kitten](https://github.com/kitten) (See [#3690](https://github.com/urql-graphql/urql/pull/3690))\n\n## 5.0.6\n\n### Patch Changes\n\n- Allow empty error messages when re-hydrating GraphQL errors\n  Submitted by [@JoviDeCroock](https://github.com/JoviDeCroock) (See [#3650](https://github.com/urql-graphql/urql/pull/3650))\n\n## 5.0.5\n\n### Patch Changes\n\n- Removes double serialization of `data` in `ssrExchange`\n  Submitted by [@negezor](https://github.com/negezor) (See [#3632](https://github.com/urql-graphql/urql/pull/3632))\n\n## 5.0.4\n\n### Patch Changes\n\n- Change how we calculate the `OperationKey` to take files into account, before we\n  would encode them to `null` resulting in every mutation with the same variables\n  (excluding the files) to have the same key. This resulted in mutations that upload\n  different files at the same time to share a result in GraphCache\n  Submitted by [@JoviDeCroock](https://github.com/JoviDeCroock) (See [#3601](https://github.com/urql-graphql/urql/pull/3601))\n\n## 5.0.3\n\n### Patch Changes\n\n- Use `documentId` from persisted documents for document keys, when it's available\n  Submitted by [@kitten](https://github.com/kitten) (See [#3575](https://github.com/urql-graphql/urql/pull/3575))\n\n## 5.0.2\n\n### Patch Changes\n\n- ⚠️ Fix issue where a reexecute on an in-flight operation would lead to multiple network-requests.\n  For example, this issue presents itself when Graphcache is concurrently updating multiple, inter-dependent queries with shared entities. One query completing while others are still in-flight may lead to duplicate operations being issued\n  Submitted by [@JoviDeCroock](https://github.com/JoviDeCroock) (See [#3573](https://github.com/urql-graphql/urql/pull/3573))\n\n## 5.0.1\n\n### Patch Changes\n\n- ⚠️ Fix `@ts-ignore` on TypeScript peer dependency import in typings not being applied due to a leading `!` character\n  Submitted by [@kitten](https://github.com/kitten) (See [#3567](https://github.com/urql-graphql/urql/pull/3567))\n\n## 5.0.0\n\n### Major Changes\n\n- Remove deprecated `dedupExchange`\n  Submitted by [@JoviDeCroock](https://github.com/JoviDeCroock) (See [#3520](https://github.com/urql-graphql/urql/pull/3520))\n- Remove deprecated `maskTypename`\n  Submitted by [@JoviDeCroock](https://github.com/JoviDeCroock) (See [#3520](https://github.com/urql-graphql/urql/pull/3520))\n\n### Patch Changes\n\n- Upgrade `@0no-co/graphql.web` to `1.0.5`\n  Submitted by [@kitten](https://github.com/kitten) (See [#3553](https://github.com/urql-graphql/urql/pull/3553))\n\n## 4.3.0\n\n### Minor Changes\n\n- Support [Apollo Federation's format](https://www.apollographql.com/docs/router/executing-operations/subscription-multipart-protocol/) for subscription results in `multipart/mixed` responses (result properties essentially are namespaced on a `payload` key)\n  Submitted by [@JoviDeCroock](https://github.com/JoviDeCroock) (See [#3499](https://github.com/urql-graphql/urql/pull/3499))\n- Add support for sending persisted documents. Any `DocumentNode` with no/empty definitions and a `documentId` property is considered a persisted document. When this is detected a `documentId` parameter rather than a `query` string is sent to the GraphQL API, similar to Automatic Persisted Queries (APQs). However, APQs are only supported via `@urql/exchange-persisted`, while support for `documentId` is now built-in\n  Submitted by [@kitten](https://github.com/kitten) (See [#3515](https://github.com/urql-graphql/urql/pull/3515))\n\n### Patch Changes\n\n- Allow `url` to be a plain, non-URL pathname (i.e. `/api/graphql`) to be used with `preferGetMethod`\n  Submitted by [@akrantz01](https://github.com/akrantz01) (See [#3514](https://github.com/urql-graphql/urql/pull/3514))\n- Correctly support the `Headers` class being used in `fetchOptions`\n  Submitted by [@JoviDeCroock](https://github.com/JoviDeCroock) (See [#3505](https://github.com/urql-graphql/urql/pull/3505))\n\n## 4.2.3\n\n### Patch Changes\n\n- Add back our cache-outcome on the document-cache, this was behind a development flag however in our normalized cache we always add it already\n  Submitted by [@JoviDeCroock](https://github.com/JoviDeCroock) (See [#3464](https://github.com/urql-graphql/urql/pull/3464))\n\n## 4.2.2\n\n### Patch Changes\n\n- ⚠️ Fix the default `cacheExchange` crashing on `cache-only` request policies with cache misses due to `undefined` results\n  Submitted by [@JoviDeCroock](https://github.com/JoviDeCroock) (See [#3459](https://github.com/urql-graphql/urql/pull/3459))\n\n## 4.2.1\n\n### Patch Changes\n\n- ⚠️ Fix incorrect JSON stringification of objects from different JS contexts. This could lead to invalid variables being generated in the Vercel Edge runtime specifically\n  Submitted by [@SoraKumo001](https://github.com/SoraKumo001) (See [#3453](https://github.com/urql-graphql/urql/pull/3453))\n\n## 4.2.0\n\n### Minor Changes\n\n- Try to parse `text/plain` content-type as JSON before bailing out with an error\n  Submitted by [@JoviDeCroock](https://github.com/JoviDeCroock) (See [#3430](https://github.com/urql-graphql/urql/pull/3430))\n\n## 4.1.4\n\n### Patch Changes\n\n- Implement new `@defer` / `@stream` transport protocol spec changes\n  Submitted by [@JoviDeCroock](https://github.com/JoviDeCroock) (See [#3389](https://github.com/urql-graphql/urql/pull/3389))\n- Support non spec-compliant error bodies, i.e. the Shopify API does return `errors` but as an object. Adding\n  a check whether we are really dealing with an Array of errors enables this\n  Submitted by [@JoviDeCroock](https://github.com/JoviDeCroock) (See [#3395](https://github.com/urql-graphql/urql/pull/3395))\n- ⚠️ Fix `preferGetMethod: 'force' | 'within-url-limit'` not being applied correctly by the `Client`\n  Submitted by [@Burbenog](https://github.com/Burbenog) (See [#3403](https://github.com/urql-graphql/urql/pull/3403))\n\n## 4.1.3\n\n### Patch Changes\n\n- ⚠️ Fix missing `teardown` operation handling in the `ssrExchange`. This could lead to duplicate network operations being executed\n  Submitted by [@kitten](https://github.com/kitten) (See [#3386](https://github.com/urql-graphql/urql/pull/3386))\n\n## 4.1.2\n\n### Patch Changes\n\n- Explicitly unblock `client.reexecuteOperation` calls to allow stalled operations from continuing and re-executing. Previously, this could cause `@urql/exchange-graphcache` to stall if an optimistic mutation led to a cache miss\n  Submitted by [@kitten](https://github.com/kitten) (See [#3363](https://github.com/urql-graphql/urql/pull/3363))\n\n## 4.1.1\n\n### Patch Changes\n\n- Add case for `subscriptionExchange` to handle `GraphQLError[]` received in the `error` observer callback.\n  **Note:** This doesn't strictly check for the `GraphQLError` shape and only checks for arrays and receiving errors in the `ExecutionResult` on the `next` observer callback is preferred and recommended for transports\n  Submitted by [@kitten](https://github.com/kitten) (See [#3346](https://github.com/urql-graphql/urql/pull/3346))\n\n## 4.1.0\n\n### Minor Changes\n\n- Update `formatDocument` to output `FormattedNode` type mapping. The formatter will now annotate added `__typename` fields with `_generated: true`, place selection nodes' directives onto a `_directives` dictionary, and will filter directives to not include `\"_\"` underscore prefixed directives in the final query. This prepares us for a feature that allows enhanced client-side directives in Graphcache\n  Submitted by [@kitten](https://github.com/kitten) (See [#3317](https://github.com/urql-graphql/urql/pull/3317))\n\n### Patch Changes\n\n- Add `OperationContext.optimistic` flag as an internal indication on whether a mutation triggered an optimistic update in `@urql/exchange-graphcache`'s `cacheExchange`\n  Submitted by [@kitten](https://github.com/kitten) (See [#3308](https://github.com/urql-graphql/urql/pull/3308))\n\n## 4.0.11\n\n### Patch Changes\n\n- Re-order `maskTypename` to apply masking earlier in the chain\n  Submitted by [@kitten](https://github.com/kitten) (See [#3298](https://github.com/urql-graphql/urql/pull/3298))\n- ⚠️ Fix `ssrExchange` not formatting query documents using `formatDocument`. Without this call we'd run the risk of not having `__typename` available on the client-side when rehydrating\n  Submitted by [@kitten](https://github.com/kitten) (See [#3288](https://github.com/urql-graphql/urql/pull/3288))\n- Add deprecation notice for `maskTypename` option.\n  Masking typenames in a result is no longer recommended. It’s only\n  useful when multiple pre-conditions are applied and inferior to\n  mapping to an input object manually\n  Submitted by [@kitten](https://github.com/kitten) (See [#3299](https://github.com/urql-graphql/urql/pull/3299))\n\n## 4.0.10\n\n### Patch Changes\n\n- Add missing `fetchSubscriptions` entry to `OperationContext`. The Client’s `fetchSubscriptions` now works properly and can be used to execute subscriptions as multipart/event-stream requests\n  Submitted by [@kitten](https://github.com/kitten) (See [#3244](https://github.com/urql-graphql/urql/pull/3244))\n- ⚠️ Fix `fetchSource` not working for subscriptions since `hasNext` isn’t necessarily set\n  Submitted by [@kitten](https://github.com/kitten) (See [#3244](https://github.com/urql-graphql/urql/pull/3244))\n\n## 4.0.9\n\n### Patch Changes\n\n- Return `AbortController` invocation to previous behaviour where it used to be more forceful. It will now properly abort outside of when our generator yields results, and hence now also cancels requests again that have already delivered headers but are currently awaiting a response body\n  Submitted by [@kitten](https://github.com/kitten) (See [#3239](https://github.com/urql-graphql/urql/pull/3239))\n\n## 4.0.8\n\n### Patch Changes\n\n- Respect `additionalTypenames` on subscriptions and re-execute queries for them as well, as one would intuitively expect\n  Submitted by [@kitten](https://github.com/kitten) (See [#3230](https://github.com/urql-graphql/urql/pull/3230))\n- Update build process to generate correct source maps\n  Submitted by [@kitten](https://github.com/kitten) (See [#3201](https://github.com/urql-graphql/urql/pull/3201))\n- Don't allow `isSubscriptionOperation` option in `subscriptionExchange` to include `teardown` operations, to avoid confusion\n  Submitted by [@kitten](https://github.com/kitten) (See [#3206](https://github.com/urql-graphql/urql/pull/3206))\n\n## 4.0.7\n\n### Patch Changes\n\n- Publish with npm provenance\n  Submitted by [@kitten](https://github.com/kitten) (See [#3180](https://github.com/urql-graphql/urql/pull/3180))\n\n## 4.0.6\n\n### Patch Changes\n\n- Handle `multipart/mixed` variations starting with boundary rather than CRLF and a boundary\n  Submitted by [@kitten](https://github.com/kitten) (See [#3172](https://github.com/urql-graphql/urql/pull/3172))\n- ⚠️ Fix regression which would disallow `network-only` operations after `cache-and-network` completed\n  Submitted by [@kitten](https://github.com/kitten) (See [#3174](https://github.com/urql-graphql/urql/pull/3174))\n\n## 4.0.5\n\n### Patch Changes\n\n- Replace `File` and `Blob` objects with `null` in variables if multipart request will be started\n  Submitted by [@kitten](https://github.com/kitten) (See [#3169](https://github.com/urql-graphql/urql/pull/3169))\n- Strictly deduplicate `cache-and-network` and `network-only` operations, while a non-stale response is being waited for\n  Submitted by [@kitten](https://github.com/kitten) (See [#3157](https://github.com/urql-graphql/urql/pull/3157))\n- ⚠️ Fix boundary stopping `multipart/mixed` streams when it randomly occurs in response payloads\n  Submitted by [@kitten](https://github.com/kitten) (See [#3155](https://github.com/urql-graphql/urql/pull/3155))\n- Improve dispatching of arbitrary operations using `reexecuteOperation`\n  Submitted by [@kitten](https://github.com/kitten) (See [#3159](https://github.com/urql-graphql/urql/pull/3159))\n\n## 4.0.4\n\n### Patch Changes\n\n- ⚠️ Fix `hasNext` being defaulted to `false` when a new subscription event is received on the `subscriptionExchange` that doesn't have `hasNext` set\n  Submitted by [@kitten](https://github.com/kitten) (See [#3137](https://github.com/urql-graphql/urql/pull/3137))\n\n## 4.0.3\n\n### Patch Changes\n\n- Handle `fetch` rejections in `makeFetchSource` and properly hand them over to `CombinedError`s\n  Submitted by [@kitten](https://github.com/kitten) (See [#3131](https://github.com/urql-graphql/urql/pull/3131))\n\n## 4.0.2\n\n### Patch Changes\n\n- ⚠️ Fix incremental delivery payloads not merging data correctly, or not handling patches on root\n  results\n  Submitted by [@kitten](https://github.com/kitten) (See [#3124](https://github.com/urql-graphql/urql/pull/3124))\n\n## 4.0.1\n\n### Patch Changes\n\n- ⚠️ Fix format of `map` form data field on multipart upload requests. This was erroneously set to a string rather than a string tuple\n  Submitted by [@kitten](https://github.com/kitten) (See [#3118](https://github.com/urql-graphql/urql/pull/3118))\n\n## 4.0.0\n\n### Major Changes\n\n- Remove `defaultExchanges` from `@urql/core` and make `exchanges` a required property on `Client` construction.\n  In doing so we make the `urql` package more tree-shakeable as the three default exchanges are in no code paths\n  meaning they can be removed if not used.\n  A migration would look as follows if you are currently creating a client without exchanges\n\n  ```js\n  import { createClient, cacheExchange, fetchExchange } from '@urql/core';\n\n  const client = createClient({\n    url: '',\n    exchanges: [cacheExchange, fetchExchange],\n  });\n  ```\n\n  Submitted by [@JoviDeCroock](https://github.com/JoviDeCroock) (See [#3033](https://github.com/urql-graphql/urql/pull/3033))\n\n- Update `subscriptionExchange` to receive `FetchBody` instead. In the usual usage of `subscriptionExchange` (for instance with `graphql-ws`) you can expect no breaking changes. However, the `key` and `extensions` field has been removed and instead the `forwardSubscription` function receives the full `Operation` as a second argument\n  Submitted by [@kitten](https://github.com/kitten) (See [#3054](https://github.com/urql-graphql/urql/pull/3054))\n- Remove dependence on `graphql` package and replace it with `@0no-co/graphql.web`, which reduces the default bundlesize impact of `urql` packages to a minimum. All types should remain compatible, even if you use `graphql` elsewhere in your app, and if other dependencies are using `graphql` you may alias it to `graphql-web-lite`\n  Submitted by [@kitten](https://github.com/kitten) (See [#3097](https://github.com/urql-graphql/urql/pull/3097))\n- Update `OperationResult.hasNext` and `OperationResult.stale` to be required fields. If you have a custom exchange creating results, you'll have to add these fields or use the `makeResult`, `mergeResultPatch`, or `makeErrorResult` helpers\n  Submitted by [@kitten](https://github.com/kitten) (See [#3061](https://github.com/urql-graphql/urql/pull/3061))\n- Remove `getOperationName` export from `@urql/core`\n  Submitted by [@kitten](https://github.com/kitten) (See [#3062](https://github.com/urql-graphql/urql/pull/3062))\n\n### Minor Changes\n\n- Return a new `OperationResultSource` from all `Client` methods (which replaces `PromisifiedSource` on shortcut methods). This allows not only `toPromise()` to be called, but it can also be used as an awaitable `PromiseLike` and has a `.subscribe(onResult)` method aliasing the subscribe utility from `wonka`\n  Submitted by [@kitten](https://github.com/kitten) (See [#3060](https://github.com/urql-graphql/urql/pull/3060))\n- Update `subscriptionExchange` to support incremental results out of the box. If a subscription proactively completes, results are also now updated with `hasNext: false`\n  Submitted by [@kitten](https://github.com/kitten) (See [#3055](https://github.com/urql-graphql/urql/pull/3055))\n- Implement `text/event-stream` response support. This generally adheres to the GraphQL SSE protocol and GraphQL Yoga push responses, and is an alternative to `multipart/mixed`\n  Submitted by [@kitten](https://github.com/kitten) (See [#3050](https://github.com/urql-graphql/urql/pull/3050))\n- Implement GraphQL Multipart Request support in `@urql/core`. This adds the File/Blob upload support to `@urql/core`, which effectively deprecates `@urql/exchange-multipart-fetch`\n  Submitted by [@kitten](https://github.com/kitten) (See [#3051](https://github.com/urql-graphql/urql/pull/3051))\n- Support `GraphQLRequest.extensions` as spec-extensions input to GraphQL requests\n  Submitted by [@kitten](https://github.com/kitten) (See [#3054](https://github.com/urql-graphql/urql/pull/3054))\n- Allow subscriptions to be handled by the `fetchExchange` when `fetchSubscriptions` is turned on\n  Submitted by [@kitten](https://github.com/kitten) (See [#3106](https://github.com/urql-graphql/urql/pull/3106))\n- Deprecate the `dedupExchange`. The functionality of deduplicating queries and subscriptions has now been moved into and absorbed by the `Client`.\n  Previously, the `Client` already started doing some work to share results between\n  queries, and to avoid dispatching operations as needed. It now only dispatches operations\n  strictly when the `dedupExchange` would allow so as well, moving its logic into the\n  `Client`\n  Submitted by [@kitten](https://github.com/kitten) (See [#3058](https://github.com/urql-graphql/urql/pull/3058))\n\n### Patch Changes\n\n- Deduplicate operations as the `dedupExchange` did; by filtering out duplicate operations until either the original operation has been cancelled (teardown) or a first result (without `hasNext: true`) has come in\n  Submitted by [@kitten](https://github.com/kitten) (See [#3101](https://github.com/urql-graphql/urql/pull/3101))\n- ⚠️ Fix source maps included with recently published packages, which lost their `sourcesContent`, including additional source files, and had incorrect paths in some of them\n  Submitted by [@kitten](https://github.com/kitten) (See [#3053](https://github.com/urql-graphql/urql/pull/3053))\n- Allow `makeOperation` to be called with a partial `OperationContext` when it’s called to copy an operation. When it receives an `Operation` as a second argument now, the third argument, the context, will be spread into the prior `operation.context`\n  Submitted by [@kitten](https://github.com/kitten) (See [#3081](https://github.com/urql-graphql/urql/pull/3081))\n- Move `multipart/mixed` to end of `Accept` header to avoid cauing Yoga to unnecessarily use it\n  Submitted by [@JoviDeCroock](https://github.com/JoviDeCroock) (See [#3039](https://github.com/urql-graphql/urql/pull/3039))\n- Upgrade to `wonka@^6.3.0`\n  Submitted by [@kitten](https://github.com/kitten) (See [#3104](https://github.com/urql-graphql/urql/pull/3104))\n- Update `Exchange` contract and `composeExchanges` utility to remove the need to manually call `share` on either incoming `Source<Operation>` or `forward()`’s `Source<OperationResult>`. This is now taken care of internally in `composeExchanges` and should make it easier for you to create custom exchanges and for us to explain them\n  Submitted by [@kitten](https://github.com/kitten) (See [#3082](https://github.com/urql-graphql/urql/pull/3082))\n- Add support for `graphql`’s built-in `TypedQueryDocumentNode` typings for type inference\n  Submitted by [@kitten](https://github.com/kitten) (See [#3085](https://github.com/urql-graphql/urql/pull/3085))\n- Add missing type exports of SSR-related types (`SerializedResult`, `SSRExchangeParams`, `SSRExchange`, and `SSRData`) to `@urql/core`'s type exports\n  Submitted by [@kitten](https://github.com/kitten) (See [#3079](https://github.com/urql-graphql/urql/pull/3079))\n- Allow any object fitting the `GraphQLError` shape to rehydrate without passing through a `GraphQLError` constructor in `CombinedError`\n  Submitted by [@kitten](https://github.com/kitten) (See [#3087](https://github.com/urql-graphql/urql/pull/3087))\n- Add missing `hasNext` and `stale` passthroughs on caching exchanges\n  Submitted by [@kitten](https://github.com/kitten) (See [#3059](https://github.com/urql-graphql/urql/pull/3059))\n- ⚠️ Fix incremental results not merging `errors` from subsequent non-incremental results\n  Submitted by [@kitten](https://github.com/kitten) (See [#3055](https://github.com/urql-graphql/urql/pull/3055))\n- Add logic for `request.extensions.persistedQuery` to `@urql/core` to omit sending `query` as needed\n  Submitted by [@kitten](https://github.com/kitten) (See [#3057](https://github.com/urql-graphql/urql/pull/3057))\n- ⚠️ Fix incorrect operation name being picked from queries that contain multiple operations\n  Submitted by [@kitten](https://github.com/kitten) (See [#3062](https://github.com/urql-graphql/urql/pull/3062))\n- Replace fetch source implementation with async generator implementation, based on Wonka's `fromAsyncIterable`.\n  This also further hardens our support for the \"Incremental Delivery\" specification and\n  refactors its implementation and covers more edge cases\n  Submitted by [@kitten](https://github.com/kitten) (See [#3043](https://github.com/urql-graphql/urql/pull/3043))\n- Ensure network errors are always issued with `CombinedError`s, while downstream errors are re-thrown\n  Submitted by [@kitten](https://github.com/kitten) (See [#3063](https://github.com/urql-graphql/urql/pull/3063))\n- Refactor `Client` result source construction code and allow multiple mutation\n  results, if `result.hasNext` on a mutation result is set to `true`, indicating\n  deferred or streamed results\n  Submitted by [@kitten](https://github.com/kitten) (See [#3102](https://github.com/urql-graphql/urql/pull/3102))\n- Remove dependence on `import { visit } from 'graphql';` with smaller but functionally equivalent alternative\n  Submitted by [@kitten](https://github.com/kitten) (See [#3097](https://github.com/urql-graphql/urql/pull/3097))\n\n## 3.2.2\n\n### Patch Changes\n\n- ⚠️ Fix generated empty `Variables` type as passed to generics, that outputs a type of `{ [var: string]: never; }`.\n  A legacy/unsupported version of `typescript-urql`, which wraps `urql`'s React hooks, generates\n  empty variables types as the following code snippet, which is not detected:\n  ```ts\n  type Exact<T extends { [key: string]: unknown }> = { [K in keyof T]: T[K] };\n  type Variables = Exact<{ [key: string]: never }>;\n  ```\n  Submitted by [@kitten](https://github.com/kitten) (See [#3029](https://github.com/urql-graphql/urql/pull/3029))\n\n## 3.2.1\n\n### Patch Changes\n\n- Bump to `@urql/core@3.2.1` due to invalid `3.2.0` release\n  Submitted by [@kitten](https://github.com/kitten) (See [`a84268db`](https://github.com/urql-graphql/urql/commit/a84268db98789b2fd23de009c7b5e1c09fca7103))\n\n## 3.2.0\n\n### Minor Changes\n\n- Update support for the \"Incremental Delivery\" payload specification, accepting the new `incremental` property on execution results, as per the specification. This will expand support for newer APIs implementing the more up-to-date specification\n  Submitted by [@kitten](https://github.com/kitten) (See [#3007](https://github.com/urql-graphql/urql/pull/3007))\n- Update default `Accept` header to include `multipart/mixed` and `application/graphql-response+json`. The former seems to now be a defactor standard-accepted indication for support of the \"Incremental Delivery\" GraphQL over HTTP spec addition/RFC, and the latter is an updated form of the older `Content-Type` of GraphQL responses, so both the old and new one should now be included\n  Submitted by [@kitten](https://github.com/kitten) (See [#3007](https://github.com/urql-graphql/urql/pull/3007))\n\n### Patch Changes\n\n- Add TSDoc annotations to all external `@urql/core` APIs\n  Submitted by [@kitten](https://github.com/kitten) (See [#2962](https://github.com/urql-graphql/urql/pull/2962))\n- ⚠️ Fix subscriptions not being duplicated when `hasNext` isn't set. The `hasNext` field is an upcoming \"Incremental Delivery\" field. When a subscription result doesn't set it we now set it to `true` manually. This indicates to the `dedupExchange` that no duplicate subscription operations should be started\n  Submitted by [@kitten](https://github.com/kitten) (See [#3015](https://github.com/urql-graphql/urql/pull/3015))\n- Expose consistent `GraphQLRequestParams` utility type from which `GraphQLRequest`s are created in all bindings\n  Submitted by [@kitten](https://github.com/kitten) (See [#3022](https://github.com/urql-graphql/urql/pull/3022))\n\n## 3.1.1\n\n### Patch Changes\n\n- Correctly mark cache-hits from the ssr-exchange, by [@JoviDeCroock](https://github.com/JoviDeCroock) (See [#2872](https://github.com/urql-graphql/urql/pull/2872))\n- ⚠️ Fix type-generation, with a change in TS/Rollup the type generation took the paths as src and resolved them into the types dir, by [@JoviDeCroock](https://github.com/JoviDeCroock) (See [#2870](https://github.com/urql-graphql/urql/pull/2870))\n- ⚠️ Fix regression in `@urql/core`'s `stringifyDocument` that caused some formatted documents to not be reprinted, by [@JoviDeCroock](https://github.com/JoviDeCroock) (See [#2871](https://github.com/urql-graphql/urql/pull/2871))\n\n## 3.1.0\n\n### Minor Changes\n\n- Implement `mapExchange`, which replaces `errorExchange`, allowing `onOperation` and `onResult` to be called to either react to or replace operations and results. For backwards compatibility, this exchange is also exported as `errorExchange` and supports `onError`, by [@kitten](https://github.com/kitten) (See [#2846](https://github.com/urql-graphql/urql/pull/2846))\n\n### Patch Changes\n\n- Move remaining `Variables` generics over from `object` default to `Variables extends AnyVariables = AnyVariables`. This has been introduced previously in [#2607](https://github.com/urql-graphql/urql/pull/2607) but some missing ports have been missed due to TypeScript not catching them previously. Depending on your TypeScript version the `object` default is incompatible with `AnyVariables`, by [@kitten](https://github.com/kitten) (See [#2843](https://github.com/urql-graphql/urql/pull/2843))\n- Reuse output of `stringifyDocument` in place of repeated `print`. This will mean that we now prevent calling `print` repeatedly for identical operations and are instead only reusing the result once.\n  This change has a subtle consequence of our internals. Operation keys will change due to this\n  refactor and we will no longer sanitise strip newlines from queries that `@urql/core` has printed, by [@kitten](https://github.com/kitten) (See [#2847](https://github.com/urql-graphql/urql/pull/2847))\n- Update to `wonka@^6.1.2` to fix memory leak in `fetch` caused in Node.js by a lack of clean up after initiating a request, by [@kitten](https://github.com/kitten) (See [#2850](https://github.com/urql-graphql/urql/pull/2850))\n\n## 3.0.5\n\n### Patch Changes\n\n- Update typings of the client to encompass the changes of https://github.com/FormidableLabs/urql/pull/2692, by [@c-schwan](https://github.com/c-schwan) (See [#2758](https://github.com/FormidableLabs/urql/pull/2758))\n- ⚠️ Fix case where our transform-debug-target babel plugin would override the root dispatchDebug in `compose.ts` with the latest found exchange, in this case `fetchExchange`, by [@JoviDeCroock](https://github.com/JoviDeCroock) (See [#2762](https://github.com/FormidableLabs/urql/pull/2762))\n\n## 3.0.4\n\n### Patch Changes\n\n- ⚠️ Fix `ssrExchange` bug which prevented `staleWhileRevalidate` from sending off requests as network-only requests, and caused unrelated `network-only` operations to be dropped, by [@kitten](https://github.com/kitten) (See [#2691](https://github.com/FormidableLabs/urql/pull/2691))\n- Allow URL limit for GET requests to be bypassed using `preferGetMethod: 'force'` rather than the default `true` or `'within-url-limit'` value, by [@kitten](https://github.com/kitten) (See [#2692](https://github.com/FormidableLabs/urql/pull/2692))\n- ⚠️ Fix operation identities preventing users from deeply cloning operation contexts. Instead, we now use a client-wide counter (rolling over as needed).\n  While this changes an internal data structure in `@urql/core` only, this change also affects the `offlineExchange` in `@urql/exchange-graphcache` due to it relying on the identity being previously an object rather than an integer, by [@kitten](https://github.com/kitten) (See [#2732](https://github.com/FormidableLabs/urql/pull/2732))\n\n## 3.0.3\n\n### Patch Changes\n\n- ⚠️ Fix variable types in core makeOperation, by [@JoviDeCroock](https://github.com/JoviDeCroock) (See [#2665](https://github.com/FormidableLabs/urql/pull/2665))\n\n## 3.0.2\n\n### Patch Changes\n\n- ⚠️ Fix case where `maskTypename` would not traverse down when the root query-field does not contain a `__typename`, by [@mlecoq](https://github.com/mlecoq) (See [#2643](https://github.com/FormidableLabs/urql/pull/2643))\n\n## 3.0.1\n\n### Patch Changes\n\n- ⚠️ fix setting a client default requestPolicy, we set `context.requestPolicy: undefined`\n  from our bindings which makes a spread override the client-set default, by [@JoviDeCroock](https://github.com/JoviDeCroock) (See [#2634](https://github.com/FormidableLabs/urql/pull/2634))\n\n## 3.0.0\n\n### Major Changes\n\n- **Goodbye IE11!** 👋 This major release removes support for IE11. All code that is shipped will be transpiled much less and will _not_ be ES5-compatible anymore, by [@kitten](https://github.com/kitten) (See [#2504](https://github.com/FormidableLabs/urql/pull/2504))\n- Remove support for options on the `Client` and `Client.createOperationContext`. We've noticed that there's no real need for `createOperationContext` or the options on the `Client` and that it actually encourages modifying properties on the `Client` that are really meant to be modified dynamically via exchanges, by [@kitten](https://github.com/kitten) (See [#2619](https://github.com/FormidableLabs/urql/pull/2619))\n- Implement stricter variables types, which require variables to always be passed and match TypeScript types when the generic is set or inferred. This is a breaking change for TypeScript users potentially, unless all types are adhered to, by [@kitten](https://github.com/kitten) (See [#2607](https://github.com/FormidableLabs/urql/pull/2607))\n- Upgrade to [Wonka v6](https://github.com/0no-co/wonka) (`wonka@^6.0.0`), which has no breaking changes but is built to target ES2015 and comes with other minor improvements.\n  The library has fully been migrated to TypeScript which will hopefully help with making contributions easier!, by [@kitten](https://github.com/kitten) (See [#2504](https://github.com/FormidableLabs/urql/pull/2504))\n\n### Minor Changes\n\n- Remove the `babel-plugin-modular-graphql` helper, this because the graphql package hasn't converted to ESM yet which gives issues in node environments, by [@JoviDeCroock](https://github.com/JoviDeCroock) (See [#2551](https://github.com/FormidableLabs/urql/pull/2551))\n\n## 2.6.1\n\n### Patch Changes\n\n- ⚠️ Fix missing React updates after an incoming response that schedules a mount. We now prevent dispatched operations from continuing to flush synchronously when the original source that runs the queue has terminated. This is important for the React bindings, because an update (e.g. `setState`) may recursively schedule a mount, which then disabled other `setState` updates from being processed. Previously we assumed that React used a trampoline scheduler for updates, however it appears that `setState` can recursively start more React work, by [@kitten](https://github.com/kitten) (See [#2556](https://github.com/FormidableLabs/urql/pull/2556))\n\n## 2.6.0\n\n### Minor Changes\n\n- Allow providing a custom `isSubscriptionOperation` implementation, by [@n1ru4l](https://github.com/n1ru4l) (See [#2534](https://github.com/FormidableLabs/urql/pull/2534))\n\n## 2.5.0\n\n### Minor Changes\n\n- Add `Accept` header to GraphQL HTTP requests. This complies to the specification but doesn't go as far as sending `Content-Type` which would throw a lot of APIs off. Instead, we'll now be sending an accept header for `application/graphql+json, application/json` to indicate that we comply with the GraphQL over HTTP protocol.\n  This also fixes headers merging to allow overriding `Accept` and `Content-Type` regardless of the user options' casing, by [@kitten](https://github.com/kitten) (See [#2457](https://github.com/FormidableLabs/urql/pull/2457))\n\n### Patch Changes\n\n- Support aborting in `withPromise` cases, by [@JoviDeCroock](https://github.com/JoviDeCroock) (See [#2446](https://github.com/FormidableLabs/urql/pull/2446))\n- Passthrough responses with content type of `text/*` as error messages, by [@kitten](https://github.com/kitten) (See [#2456](https://github.com/FormidableLabs/urql/pull/2456))\n\n## 2.4.4\n\n### Patch Changes\n\n- cut off `url` when using the GET method at 2048 characters (lowest url-size coming from chromium), by [@JoviDeCroock](https://github.com/JoviDeCroock) (See [#2384](https://github.com/FormidableLabs/urql/pull/2384))\n- ⚠️ Fix issue where a synchronous `toPromise()` return would not result in the stream tearing down, by [@JoviDeCroock](https://github.com/JoviDeCroock) (See [#2386](https://github.com/FormidableLabs/urql/pull/2386))\n\n## 2.4.3\n\n### Patch Changes\n\n- Prevent ignored characters in GraphQL queries from being replaced inside strings and block strings. Previously we accepted sanitizing strings via regular expressions causing duplicate hashes as acceptable, since it'd only be caused when a string wasn't extracted into variables. This is fixed now however, by [@kitten](https://github.com/kitten) (See [#2295](https://github.com/FormidableLabs/urql/pull/2295))\n\n## 2.4.2\n\n### Patch Changes\n\n- Undo logic to catch errors from incremental fetching and forking the response stream, introduce logic\n  to detect results, by [@JoviDeCroock](https://github.com/JoviDeCroock) (See [#2287](https://github.com/FormidableLabs/urql/pull/2287))\n\n## 2.4.1\n\n### Patch Changes\n\n- ⚠️ Fix mutation operation being used as compared identity and instead add a stand-in comparison, by [@kitten](https://github.com/kitten) (See [#2228](https://github.com/FormidableLabs/urql/pull/2228))\n\n## 2.4.0\n\n### Minor Changes\n\n- Allow for repeated mutations that have similar inputs which results in the same key, this is for instance the case with file uploads, by [@JoviDeCroock](https://github.com/JoviDeCroock) (See [#2189](https://github.com/FormidableLabs/urql/pull/2189))\n\n### Patch Changes\n\n- Bump `@graphql-typed-document-node/core` to 3.1.1 for `graphql@16` support, by [@JoviDeCroock](https://github.com/JoviDeCroock) (See [#2153](https://github.com/FormidableLabs/urql/pull/2153))\n- ⚠️ Fix error bubbling, when an error happened in the exchange-pipeline we would treat it as a GraphQL-error, by [@JoviDeCroock](https://github.com/JoviDeCroock) (See [#2210](https://github.com/FormidableLabs/urql/pull/2210))\n- Filter `network-only` requests from the `ssrExchange`, this is to enable `staleWhileRevalidated` queries to successfully dispatch their queries, by [@JoviDeCroock](https://github.com/JoviDeCroock) (See [#2198](https://github.com/FormidableLabs/urql/pull/2198))\n\n## 2.3.6\n\n### Patch Changes\n\n- Extend peer dependency range of `graphql` to include `^16.0.0`.\n  As always when upgrading across many packages of `urql`, especially including `@urql/core` we recommend you to deduplicate dependencies after upgrading, using `npm dedupe` or `npx yarn-deduplicate`, by [@kitten](https://github.com/kitten) (See [#2133](https://github.com/FormidableLabs/urql/pull/2133))\n\n## 2.3.5\n\n### Patch Changes\n\n- ⚠️ Fix issue where `maskTypename` would ignore array shapes, by [@JoviDeCroock](https://github.com/JoviDeCroock) (See [#2074](https://github.com/FormidableLabs/urql/pull/2074))\n\n## 2.3.4\n\n### Patch Changes\n\n- Prevent `Buffer` from being polyfilled by an automatic detection in Webpack. Instead of referencing the `Buffer` global we now simply check the constructor name, by [@kitten](https://github.com/kitten) (See [#2027](https://github.com/FormidableLabs/urql/pull/2027))\n- ⚠️ Fix error-type of an `ExecutionResult` to line up with subscription-libs, by [@JoviDeCroock](https://github.com/JoviDeCroock) (See [#1998](https://github.com/FormidableLabs/urql/pull/1998))\n\n## 2.3.3\n\n### Patch Changes\n\n- Adding option to `ssrExchange` to include the `extensions` field of operation results in the cache, by [@dios-david](https://github.com/dios-david) (See [#1985](https://github.com/FormidableLabs/urql/pull/1985))\n\n## 2.3.2\n\n### Patch Changes\n\n- ⚠️ Fix issue where the ssr-exchange would loop due to checking network-only revalidations, by [@JoviDeCroock](https://github.com/JoviDeCroock) (See [#1944](https://github.com/FormidableLabs/urql/pull/1944))\n\n## 2.3.1\n\n### Patch Changes\n\n- ⚠️ Fix mark `query.__key` as non-enumerable so `formatDocument` does not restore previous invocations when cloning the gql-ast, by [@JoviDeCroock](https://github.com/JoviDeCroock) (See [#1870](https://github.com/FormidableLabs/urql/pull/1870))\n- ⚠️ Fix: update toPromise to exclude `hasNext` results. This change ensures that\n  when we call toPromise() on a query we wont serve an incomplete result, the\n  user will expect to receive a non-stale full-result when using toPromise(), by [@JoviDeCroock](https://github.com/JoviDeCroock) (See [#1880](https://github.com/FormidableLabs/urql/pull/1880))\n\n## 2.3.0\n\n### Minor Changes\n\n- Add **experimental** support for `@defer` and `@stream` responses for GraphQL. This implements the [\"GraphQL Defer and Stream Directives\"](https://github.com/graphql/graphql-spec/blob/4fd39e0/rfcs/DeferStream.md) and [\"Incremental Delivery over HTTP\"](https://github.com/graphql/graphql-over-http/blob/290b0e2/rfcs/IncrementalDelivery.md) specifications. If a GraphQL API supports `multipart/mixed` responses for deferred and streamed delivery of GraphQL results, `@urql/core` (and all its derived fetch implementations) will attempt to stream results. This is _only supported_ on browsers [supporting streamed fetch responses](https://developer.mozilla.org/en-US/docs/Web/API/Response/body), which excludes IE11.\n  The implementation of streamed multipart responses is derived from [`meros` by `@maraisr`](https://github.com/maraisr/meros), and is subject to change if the RFCs end up changing, by [@kitten](https://github.com/kitten) (See [#1854](https://github.com/FormidableLabs/urql/pull/1854))\n\n## 2.2.0\n\n### Minor Changes\n\n- Add a `staleWhileRevalidate` option to the `ssrExchange`, which allows the client to immediately refetch a new result on hydration, which may be used for cached / stale SSR or SSG pages. This is different from using `cache-and-network` by default (which isn't recommended) as the `ssrExchange` typically acts like a \"replacement fetch request\", by [@kitten](https://github.com/kitten) (See [#1852](https://github.com/FormidableLabs/urql/pull/1852))\n\n### Patch Changes\n\n- ⚠️ Fix prevent mangling embedded strings in queries sent using the `GET` method, by [@JoviDeCroock](https://github.com/JoviDeCroock) (See [#1851](https://github.com/FormidableLabs/urql/pull/1851))\n- The [single-source behavior previously](https://github.com/FormidableLabs/urql/pull/1515) wasn't effective for implementations like React,\n  where the issue presents itself when the state of an operation is first polled. This led to the operation being torn down erroneously.\n  We now ensure that operations started at the same time still use a shared single-source, by [@JoviDeCroock](https://github.com/JoviDeCroock) (See [#1850](https://github.com/FormidableLabs/urql/pull/1850))\n\n## 2.1.6\n\n### Patch Changes\n\n- Warn for invalid operation passed to query/subscription/mutation, by [@JoviDeCroock](https://github.com/JoviDeCroock) (See [#1829](https://github.com/FormidableLabs/urql/pull/1829))\n\n## 2.1.5\n\n### Patch Changes\n\n- Prevent `ssrExchange().restoreData()` from adding results to the exchange that have already been invalidated. This may happen when `restoreData()` is called repeatedly, e.g. per page. When a prior run has already invalidated an SSR result then the result is 'migrated' to the user's `cacheExchange`, which means that `restoreData()` should never attempt to re-add it again, by [@kitten](https://github.com/kitten) (See [#1776](https://github.com/FormidableLabs/urql/pull/1776))\n- ⚠️ Fix accidental change in passive `stale: true`, where a `cache-first` operation issued by Graphcache wouldn't yield an affected query and update its result to reflect the loading state with `stale: true`. This is a regression from `v2.1.0` and mostly becomes unexpected when `cache.invalidate(...)` is used, by [@kitten](https://github.com/kitten) (See [#1755](https://github.com/FormidableLabs/urql/pull/1755))\n\n## 2.1.4\n\n### Patch Changes\n\n- Prevent stale results from being emitted by promisified query sources, e.g. `client.query(...).toPromise()` yielding a partial result with `stale: true` set. Instead, `.toPromise()` will now filter out stale results, by [@kitten](https://github.com/kitten) (See [#1709](https://github.com/FormidableLabs/urql/pull/1709))\n\n## 2.1.3\n\n### Patch Changes\n\n- Treat empty variables the same as no variables in `@urql/core`'s `createRequest`, by [@kitten](https://github.com/kitten) (See [#1695](https://github.com/FormidableLabs/urql/pull/1695))\n\n## 2.1.2\n\n### Patch Changes\n\n- ⚠️ Fix a condition under which the `Client` would hang when a query is started and consumed with `toPromise()`, by [@kitten](https://github.com/kitten) (See [#1634](https://github.com/FormidableLabs/urql/pull/1634))\n- Refactor `Client` to hide some implementation details and to reduce size, by [@kitten](https://github.com/kitten) (See [#1638](https://github.com/FormidableLabs/urql/pull/1638))\n\n## 2.1.1\n\n### Patch Changes\n\n- ⚠️ Fix a regression in `@urql/core@2.1.1` that prevented concurrent operations from being dispatched with differing request policies, which for instance prevented the explicit `executeQuery` calls on bindings to fail, by [@kitten](https://github.com/kitten) (See [#1626](https://github.com/FormidableLabs/urql/pull/1626))\n\n## 2.1.0\n\n### Minor Changes\n\n- With the \"single-source behavior\" the `Client` will now also avoid executing an operation if it's already active, has a previous result available, and is either run with the `cache-first` or `cache-only` request policies. This is similar to a \"short circuiting\" behavior, where unnecessary work is avoided by not issuing more operations into the exchange pipeline than expected, by [@kitten](https://github.com/kitten) (See [#1600](https://github.com/FormidableLabs/urql/pull/1600))\n- Add consistent \"single-source behavior\" which makes the `Client` more forgiving when duplicate\n  sources are used, which previously made it difficult to use the same operation across an app\n  together with `cache-and-network`; This was a rare use-case, and it isn't recommended to overfetch\n  data across an app, however, the new `Client` implementation of shared sources ensures that when an\n  operation is active that the `Client` distributes the last known result for the active operation to\n  any new usages of it (which is called “replaying stale results”) (See [#1515](https://github.com/FormidableLabs/urql/pull/1515))\n\n### Patch Changes\n\n- Remove closure-compiler from the build step (See [#1570](https://github.com/FormidableLabs/urql/pull/1570))\n- ⚠️ Fix inconsistency in generating keys for `DocumentNode`s, especially when using GraphQL Code Generator, which could cause SSR serialization to fail, by [@zenflow](https://github.com/zenflow) (See [#1509](https://github.com/FormidableLabs/urql/pull/1509))\n\n## 2.0.0\n\n### Major Changes\n\n- **Breaking**: Remove `pollInterval` feature from `OperationContext`. Instead consider using a source that uses `Wonka.interval` and `Wonka.switchMap` over `client.query()`'s source, by [@kitten](https://github.com/kitten) (See [#1374](https://github.com/FormidableLabs/urql/pull/1374))\n- Remove deprecated `operationName` property from `Operation`s. The new `Operation.kind` property is now preferred. If you're creating new operations you may also use the `makeOperation` utility instead.\n  When upgrading `@urql/core` please ensure that your package manager didn't install any duplicates of it. You may deduplicate it manually using `npx yarn-deduplicate` (for Yarn) or `npm dedupe` (for npm), by [@kitten](https://github.com/kitten) (See [#1357](https://github.com/FormidableLabs/urql/pull/1357))\n\n### Minor Changes\n\n- Reemit an `OperationResult` as `stale: true` if it's being reexecuted as `network-only` operation to give bindings immediate feedback on background refetches, by [@kitten](https://github.com/kitten) (See [#1375](https://github.com/FormidableLabs/urql/pull/1375))\n\n## 1.16.2\n\n### Patch Changes\n\n- Add a workaround for `graphql-tag/loader`, which provides filtered query documents (where the original document contains multiple operations) without updating or providing a correct `document.loc.source.body` string, by [@kitten](https://github.com/kitten) (See [#1315](https://github.com/FormidableLabs/urql/pull/1315))\n\n## 1.16.1\n\n### Patch Changes\n\n- Add fragment deduplication to `gql` tag. Identical fragments can now be interpolated multiple times without a warning being triggered or them being duplicated in `gql`'s output, by [@kitten](https://github.com/kitten) (See [#1225](https://github.com/FormidableLabs/urql/pull/1225))\n\n## 1.16.0\n\n### Minor Changes\n\n- Add a built-in `gql` tag function helper to `@urql/core`. This behaves similarly to `graphql-tag` but only warns about _locally_ duplicated fragment names rather than globally. It also primes `@urql/core`'s key cache with the parsed `DocumentNode`, by [@kitten](https://github.com/kitten) (See [#1187](https://github.com/FormidableLabs/urql/pull/1187))\n\n### Patch Changes\n\n- ⚠️ Fix edge case in `formatDocument`, which fails to add a `__typename` field if it has been aliased to a different name, by [@kitten](https://github.com/kitten) (See [#1186](https://github.com/FormidableLabs/urql/pull/1186))\n- Cache results of `formatDocument` by the input document's key, by [@kitten](https://github.com/kitten) (See [#1186](https://github.com/FormidableLabs/urql/pull/1186))\n\n## 1.15.2\n\n### Patch Changes\n\n- Don't add `undefined` to any property of the `ssrExchange`'s serialized results, as this would crash in Next.js, by [@JoviDeCroock](https://github.com/JoviDeCroock) (See [#1168](https://github.com/FormidableLabs/urql/pull/1168))\n\n## 1.15.1\n\n### Patch Changes\n\n- Export `getOperationName` from `@urql/core` and use it in `@urql/exchange-execute`, fixing several imports, by [@JoviDeCroock](https://github.com/JoviDeCroock) (See [#1135](https://github.com/FormidableLabs/urql/pull/1135))\n\n## 1.15.0\n\n### Minor Changes\n\n- Improve the Suspense implementation, which fixes edge-cases when Suspense is used with subscriptions, partially disabled, or _used on the client-side_. It has now been ensured that client-side suspense functions without the deprecated `suspenseExchange` and uncached results are loaded consistently. As part of this work, the `Client` itself does now never throw Suspense promises anymore, which is functionality that either way has no place outside of the React/Preact bindings, by [@kitten](https://github.com/kitten) (See [#1123](https://github.com/FormidableLabs/urql/pull/1123))\n\n### Patch Changes\n\n- Use `Record` over `object` type for subscription operation variables. The `object` type is currently hard to use ([see this issue](https://github.com/microsoft/TypeScript/issues/21732)), by [@enisdenjo](https://github.com/enisdenjo) (See [#1119](https://github.com/FormidableLabs/urql/pull/1119))\n- Add support for `TypedDocumentNode` to infer the type of the `OperationResult` and `Operation` for all methods, functions, and hooks that either directly or indirectly accept a `DocumentNode`. See [`graphql-typed-document-node` and the corresponding blog post for more information.](https://github.com/dotansimha/graphql-typed-document-node), by [@kitten](https://github.com/kitten) (See [#1113](https://github.com/FormidableLabs/urql/pull/1113))\n- Refactor `useSource` hooks which powers `useQuery` and `useSubscription` to improve various edge case behaviour. This will not change the behaviour of these hooks dramatically but avoid unnecessary state updates when any updates are obviously equivalent and the hook will furthermore improve continuation from mount to effects, which will fix cases where the state between the mounting and effect phase may slightly change, by [@kitten](https://github.com/kitten) (See [#1104](https://github.com/FormidableLabs/urql/pull/1104))\n\n## 1.14.1\n\n### Patch Changes\n\n- ⚠️ Fix the production build overwriting the development build. Specifically in the previous release we mistakenly replaced all development bundles with production bundles. This doesn't have any direct influence on how these packages work, but prevented development warnings from being logged or full errors from being thrown, by [@kitten](https://github.com/kitten) (See [#1097](https://github.com/FormidableLabs/urql/pull/1097))\n\n## 1.14.0\n\nThis version of `@urql/core` renames `Operation.operationName` to `Operation.kind`. For now the old\nproperty is merely deprecated and will issue a warning if it's used directly. That said, all\nexchanges that are released today also need this new version of `@urql/core@>=1.14.0`, so if you\nupgrade to any of the following packages, you will also need to upgrade `@urql/core`. If you upgrade\nand see the deprecation warning, check whether all following exchanges have been upgraded:\n\n- `@urql/exchange-auth@0.1.2`\n- `@urql/exchange-execute@1.0.2`\n- `@urql/exchange-graphcache@3.1.8`\n- `@urql/exchange-multipart-fetch@0.1.10`\n- `@urql/exchange-persisted-fetch@1.2.2`\n- `@urql/exchange-populate@0.2.1`\n- `@urql/exchange-refocus@0.2.1`\n- `@urql/exchange-retry@0.1.9`\n- `@urql/exchange-suspense@1.9.2`\n\nOnce you've upgraded `@urql/core` please also ensure that your package manager hasn't accidentally\nduplicated the `@urql/core` package. If you're using `npm` you can do so by running `npm dedupe`,\nand if you use `yarn` you can do so by running `yarn-deduplicate`.\n\nIf you have a custom exchange, you can mute the deprecation warning by using `Operation.kind` rather\nthan `Operation.operationName`. If these exchanges are copying or altering operations by spreading\nthem this will also trigger the warning, which you can fix by using [the new `makeOperation` helper\nfunction.](https://formidable.com/open-source/urql/docs/api/core/#makeoperation)\n\n### Minor Changes\n\n- Deprecate the `Operation.operationName` property in favor of `Operation.kind`. This name was\n  previously confusing as `operationName` was effectively referring to two different things. You can\n  safely upgrade to this new version, however to mute all deprecation warnings you will have to\n  **upgrade** all `urql` packages you use. If you have custom exchanges that spread operations, please\n  use [the new `makeOperation` helper\n  function](https://formidable.com/open-source/urql/docs/api/core/#makeoperation) instead, by [@bkonkle](https://github.com/bkonkle) (See [#1045](https://github.com/FormidableLabs/urql/pull/1045))\n\n### Patch Changes\n\n- Add missing `.mjs` extension to all imports from `graphql` to fix Webpack 5 builds, which require extension-specific import paths for ESM bundles and packages. **This change allows you to safely upgrade to Webpack 5.**, by [@kitten](https://github.com/kitten) (See [#1094](https://github.com/FormidableLabs/urql/pull/1094))\n\n## 1.13.1\n\n### Patch Changes\n\n- Allow `client.reexecuteOperation` to be called with mutations which skip the active operation minimums, by [@kitten](https://github.com/kitten) (See [#1011](https://github.com/FormidableLabs/urql/pull/1011))\n\n## 1.13.0\n\nPlease note that this release changes the data structure of the `ssrExchange`'s\noutput. We don't treat this as a breaking change, since this data is considered\na private structure, but if your tests or other code relies on this, please check\nthe type changes and update it.\n\n### Minor Changes\n\n- Adds an error exchange to urql-core. This allows tapping into all graphql errors within the urql client. Useful for logging, debugging, handling authentication errors etc, by [@kadikraman](https://github.com/kadikraman) (See [#947](https://github.com/FormidableLabs/urql/pull/947))\n\n### Patch Changes\n\n- ⚠️ Fix condition where mutated result data would be picked up by the `ssrExchange`, for instance as a result of mutations by Graphcache. Instead the `ssrExchange` now serializes data early, by [@kitten](https://github.com/kitten) (See [#962](https://github.com/FormidableLabs/urql/pull/962))\n- Omit the `Content-Type: application/json` HTTP header when using GET in the `fetchExchange`, `persistedFetchExchange`, or `multipartFetchExchange`, by [@JoviDeCroock](https://github.com/JoviDeCroock) (See [#957](https://github.com/FormidableLabs/urql/pull/957))\n\n## 1.12.3\n\n### Patch Changes\n\n- Remove whitespace and comments from string-queries, by [@JoviDeCroock](https://github.com/JoviDeCroock) (See [#911](https://github.com/FormidableLabs/urql/pull/911))\n- Remove redundant whitespaces when using GET for graphql queries, by [@JoviDeCroock](https://github.com/JoviDeCroock) (See [#908](https://github.com/FormidableLabs/urql/pull/908))\n\n## 1.12.2\n\n### Patch Changes\n\n- ⚠️ Fix `formatDocument` mutating parts of the `DocumentNode` which may be shared by other documents and queries. Also ensure that a formatted document will always generate the same key in `createRequest` as the original document, by [@kitten](https://github.com/kitten) (See [#880](https://github.com/FormidableLabs/urql/pull/880))\n- ⚠️ Fix `ssrExchange` invalidating results on the client-side too eagerly, by delaying invalidation by a tick, by [@kitten](https://github.com/kitten) (See [#885](https://github.com/FormidableLabs/urql/pull/885))\n\n## 1.12.1\n\n### Patch Changes\n\n- ⚠️ Fix timing for out-of-band `client.reexecuteOperation` calls. This would surface in asynchronous caching scenarios, where no result would be delivered by the cache synchronously, while it still calls `client.reexecuteOperation` for e.g. a `network-only` request, which happens for `cache-and-network`. This issue becomes especially obvious in highly synchronous frameworks like Svelte, by [@kitten](https://github.com/kitten) (See [#860](https://github.com/FormidableLabs/urql/pull/860))\n- Replace unnecessary `scheduleTask` polyfill with inline `Promise.resolve().then(fn)` calls, by [@kitten](https://github.com/kitten) (See [#861](https://github.com/FormidableLabs/urql/pull/861))\n\n## 1.12.0\n\nAs always, please ensure that you deduplicate `@urql/core` when upgrading. Additionally\ndeduplicating the versions of `wonka` that you have installed may also reduce your bundlesize.\n\n### Minor Changes\n\n- Expose a `client.subscription` shortcut method, similar to `client.query` and `client.mutation`, by [@FredyC](https://github.com/FredyC) (See [#838](https://github.com/FormidableLabs/urql/pull/838))\n\n### Patch Changes\n\n- Upgrade to a minimum version of wonka@^4.0.14 to work around issues with React Native's minification builds, which use uglify-es and could lead to broken bundles, by [@kitten](https://github.com/kitten) (See [#842](https://github.com/FormidableLabs/urql/pull/842))\n\n## 1.11.8\n\n### Patch Changes\n\n- Add operationName to GET queries, by [@jakubriedl](https://github.com/jakubriedl) (See [#798](https://github.com/FormidableLabs/urql/pull/798))\n\n## 1.11.7\n\n### Patch Changes\n\n- Add `source` debug name to all `dispatchDebug` calls during build time to identify events by which exchange dispatched them, by [@JoviDeCroock](https://github.com/JoviDeCroock) (See [#780](https://github.com/FormidableLabs/urql/pull/780))\n\n## 1.11.6\n\n### Patch Changes\n\n- Add a `\"./package.json\"` entry to the `package.json`'s `\"exports\"` field for Node 14. This seems to be required by packages like `rollup-plugin-svelte` to function properly, by [@JoviDeCroock](https://github.com/JoviDeCroock) (See [#771](https://github.com/FormidableLabs/urql/pull/771))\n\n## 1.11.5\n\n### Patch Changes\n\n- Hoist variables in unminified build output for Metro Bundler builds which otherwise fails for `process.env.NODE_ENV` if-clauses, by [@kitten](https://github.com/kitten) (See [#737](https://github.com/FormidableLabs/urql/pull/737))\n- Add a babel-plugin that removes empty imports from the final build output, by [@JoviDeCroock](https://github.com/JoviDeCroock) (See [#735](https://github.com/FormidableLabs/urql/pull/735))\n\n## 1.11.4\n\n### Patch Changes\n\nSorry for the many updates; Please only upgrade to `>=1.11.4` and don't use the deprecated `1.11.3`\nand `1.11.2` release.\n\n- ⚠️ Fix nested package path for @urql/core/internal and @urql/exchange-graphcache/extras, by [@kitten](https://github.com/kitten) (See [#734](https://github.com/FormidableLabs/urql/pull/734))\n\n## 1.11.3\n\n### Patch Changes\n\n- Make the extension of the main export unknown, which fixes a Webpack issue where the resolver won't pick `module` fields in `package.json` files once it's importing from another `.mjs` file, by [@JoviDeCroock](https://github.com/JoviDeCroock) (See [#733](https://github.com/FormidableLabs/urql/pull/733))\n\n## 1.11.1\n\n### Patch Changes\n\n- ⚠️ Fix missing `@urql/core/internal` entrypoint in the npm-release, which was previously not included, by [@JoviDeCroock](https://github.com/JoviDeCroock) (See [#731](https://github.com/FormidableLabs/urql/pull/731))\n\n## 1.11.0\n\n### Minor Changes\n\n- Add debugging events to exchanges that add more detailed information on what is happening\n  internally, which will be displayed by devtools like the urql [Chrome / Firefox extension](https://github.com/FormidableLabs/urql-devtools), by [@andyrichardson](https://github.com/andyrichardson) (See [#608](https://github.com/FormidableLabs/urql/pull/608))\n- Add @urql/core/internal entrypoint for internally shared utilities and start sharing fetchExchange-related code, by [@kitten](https://github.com/kitten) (See [#722](https://github.com/FormidableLabs/urql/pull/722))\n\n### Patch Changes\n\n- ⚠️ Fix stringifyVariables breaking on x.toJSON scalars, by [@kitten](https://github.com/kitten) (See [#718](https://github.com/FormidableLabs/urql/pull/718))\n\n## 1.10.9\n\n### Patch Changes\n\n- Pick modules from graphql package, instead of importing from graphql/index.mjs, by [@kitten](https://github.com/kitten) (See [#700](https://github.com/FormidableLabs/urql/pull/700))\n\n## 1.10.8\n\n### Patch Changes\n\n- Add graphql@^15.0.0 to peer dependency range, by [@kitten](https://github.com/kitten) (See [#688](https://github.com/FormidableLabs/urql/pull/688))\n- ⚠️ Fix non-2xx results never being parsed as GraphQL results. This can result in valid GraphQLErrors being hidden, which should take precedence over generic HTTP NetworkErrors, by [@kitten](https://github.com/kitten) (See [#678](https://github.com/FormidableLabs/urql/pull/678))\n\n## 1.10.7\n\n### Patch Changes\n\n- ⚠️ Fix oversight in edge case for #662. The operation queue wasn't marked as being active which caused `stale` results and `cache-and-network` operations from reissuing operations immediately (unqueued essentially) which would then be filtered out by the `dedupExchange`, by [@kitten](https://github.com/kitten) (See [#669](https://github.com/FormidableLabs/urql/pull/669))\n\n## 1.10.6\n\n### Patch Changes\n\n- ⚠️ Fix critical bug in operation queueing that can lead to unexpected teardowns and swallowed operations. This would happen when a teardown operation kicks off the queue, by [@kitten](https://github.com/kitten) (See [#662](https://github.com/FormidableLabs/urql/pull/662))\n\n## 1.10.5\n\n### Patch Changes\n\n- Refactor a couple of core helpers for minor bundlesize savings, by [@kitten](https://github.com/kitten) (See [#658](https://github.com/FormidableLabs/urql/pull/658))\n- Add support for variables that contain non-plain objects without any enumerable keys, e.g. `File` or `Blob`. In this case `stringifyVariables` will now use a stable (but random) key, which means that mutations containing `File`s — or other objects like this — will now be distinct, as they should be, by [@kitten](https://github.com/kitten) (See [#650](https://github.com/FormidableLabs/urql/pull/650))\n\n## 1.10.4\n\n### Patch Changes\n\n- ⚠️ Fix node resolution when using Webpack, which experiences a bug where it only resolves\n  `package.json:main` instead of `module` when an `.mjs` file imports a package, by [@JoviDeCroock](https://github.com/JoviDeCroock) (See [#642](https://github.com/FormidableLabs/urql/pull/642))\n\n## 1.10.3\n\n### Patch Changes\n\n- ⚠️ Fix Node.js Module support for v13 (experimental-modules) and v14. If your bundler doesn't support\n  `.mjs` files and fails to resolve the new version, please double check your configuration for\n  Webpack, or similar tools, by [@JoviDeCroock](https://github.com/JoviDeCroock) (See [#637](https://github.com/FormidableLabs/urql/pull/637))\n\n## 1.10.2\n\n### Patch Changes\n\n- Add a guard to \"maskTypenames\" so a null value isn't considered an object, by [@JoviDeCroock](https://github.com/JoviDeCroock) (See [#621](https://github.com/FormidableLabs/urql/pull/621))\n\n## 1.10.1\n\n### Patch Changes\n\n- ⚠️ Fix Rollup bundle output being written to .es.js instead of .esm.js, by [@kitten](https://github.com/kitten) (See [#609](https://github.com/FormidableLabs/urql/pull/609))\n\n## 1.10.0\n\n### Minor Changes\n\n- Add `additionalTypenames` to the `OperationContext`, which allows the document cache to invalidate efficiently when the `__typename` is unknown at the initial fetch, by [@JoviDeCroock](https://github.com/JoviDeCroock) (See [#601](https://github.com/FormidableLabs/urql/pull/601)) [You can learn more about this change in our docs.](https://formidable.com/open-source/urql/docs/basics/document-caching/#adding-typenames)\n\n### Patch Changes\n\n- Add missing GraphQLError serialization for extensions and path field to ssrExchange, by [@kitten](https://github.com/kitten) (See [#607](https://github.com/FormidableLabs/urql/pull/607))\n\n## 1.9.2\n\n### Patch Changes\n\n- Prevent active teardowns for queries on subscriptionExchange, by [@kitten](https://github.com/kitten) (See [#577](https://github.com/FormidableLabs/urql/pull/577))\n\n## 1.9.1\n\n### Patch Changes\n\n- ⚠️ Fix `cache-only` operations being forwarded and triggering fetch requests, by [@JoviDeCroock](https://github.com/JoviDeCroock) (See [#551](https://github.com/FormidableLabs/urql/pull/551))\n- Adds a one-tick delay to the subscriptionExchange to prevent unnecessary early tear downs, by [@JoviDeCroock](https://github.com/JoviDeCroock) (See [#542](https://github.com/FormidableLabs/urql/pull/542))\n- Add enableAllOperations option to subscriptionExchange to let it handle queries and mutations as well, by [@kitten](https://github.com/kitten) (See [#544](https://github.com/FormidableLabs/urql/pull/544))\n\n## 1.9.0\n\n### Minor Changes\n\n- Adds the `maskTypename` export to urql-core, this deeply masks typenames from the given payload.\n  Masking `__typename` properties is also available as a `maskTypename` option on the `Client`. Setting this to true will\n  strip typenames from results, by [@JoviDeCroock](https://github.com/JoviDeCroock) (See [#533](https://github.com/FormidableLabs/urql/pull/533))\n- Add support for sending queries using GET instead of POST method (See [#519](https://github.com/FormidableLabs/urql/pull/519))\n- Add client.readQuery method (See [#518](https://github.com/FormidableLabs/urql/pull/518))\n\n### Patch Changes\n\n- ⚠️ Fix ssrExchange not serialising networkError on CombinedErrors correctly. (See [#515](https://github.com/FormidableLabs/urql/pull/515))\n- Add explicit error when creating Client without a URL in development. (See [#512](https://github.com/FormidableLabs/urql/pull/512))\n"
  },
  {
    "path": "packages/core/README.md",
    "content": "# @urql/core\n\n> The shared core for the highly customizable and versatile GraphQL client, urql\n\nMore documentation is available at [formidable.com/open-source/urql](https://formidable.com/open-source/urql/).\n"
  },
  {
    "path": "packages/core/jsr.json",
    "content": "{\n  \"name\": \"@urql/core\",\n  \"version\": \"6.0.1\",\n  \"exports\": {\n    \".\": \"./src/index.ts\",\n    \"./internal\": \"./src/internal/index.ts\"\n  },\n  \"exclude\": [\n    \"node_modules\",\n    \"cypress\",\n    \"**/*.test.*\",\n    \"**/*.spec.*\",\n    \"**/*.test.*.snap\",\n    \"**/*.spec.*.snap\"\n  ]\n}"
  },
  {
    "path": "packages/core/package.json",
    "content": "{\n  \"name\": \"@urql/core\",\n  \"version\": \"6.0.1\",\n  \"description\": \"The shared core for the highly customizable and versatile GraphQL client\",\n  \"sideEffects\": false,\n  \"homepage\": \"https://formidable.com/open-source/urql/docs/\",\n  \"bugs\": \"https://github.com/urql-graphql/urql/issues\",\n  \"license\": \"MIT\",\n  \"author\": \"urql GraphQL Contributors\",\n  \"repository\": {\n    \"type\": \"git\",\n    \"url\": \"https://github.com/urql-graphql/urql.git\",\n    \"directory\": \"packages/core\"\n  },\n  \"keywords\": [\n    \"graphql\",\n    \"graphql client\",\n    \"state management\",\n    \"cache\",\n    \"exchanges\"\n  ],\n  \"main\": \"dist/urql-core\",\n  \"module\": \"dist/urql-core.mjs\",\n  \"types\": \"dist/urql-core.d.ts\",\n  \"source\": \"src/index.ts\",\n  \"exports\": {\n    \".\": {\n      \"types\": \"./dist/urql-core.d.ts\",\n      \"import\": \"./dist/urql-core.mjs\",\n      \"require\": \"./dist/urql-core.js\",\n      \"source\": \"./src/index.ts\"\n    },\n    \"./package.json\": \"./package.json\",\n    \"./internal\": {\n      \"types\": \"./dist/urql-core-internal.d.ts\",\n      \"import\": \"./dist/urql-core-internal.mjs\",\n      \"require\": \"./dist/urql-core-internal.js\",\n      \"source\": \"./src/internal/index.ts\"\n    }\n  },\n  \"files\": [\n    \"LICENSE\",\n    \"README.md\",\n    \"dist/\",\n    \"internal/\"\n  ],\n  \"scripts\": {\n    \"test\": \"vitest\",\n    \"clean\": \"rimraf dist\",\n    \"check\": \"tsc --noEmit\",\n    \"lint\": \"eslint --ext=js,jsx,ts,tsx .\",\n    \"build\": \"rollup -c ../../scripts/rollup/config.mjs\",\n    \"prepare\": \"node ../../scripts/prepare/index.js\",\n    \"prepublishOnly\": \"run-s clean build\",\n    \"jsr\": \"jsr publish\"\n  },\n  \"dependencies\": {\n    \"@0no-co/graphql.web\": \"^1.0.13\",\n    \"wonka\": \"^6.3.2\"\n  },\n  \"publishConfig\": {\n    \"access\": \"public\",\n    \"provenance\": true\n  }\n}\n"
  },
  {
    "path": "packages/core/src/__snapshots__/client.test.ts.snap",
    "content": "// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html\n\nexports[`createClient / Client > passes snapshot 1`] = `\nClient2 {\n  \"createRequestOperation\": [Function],\n  \"executeMutation\": [Function],\n  \"executeQuery\": [Function],\n  \"executeRequestOperation\": [Function],\n  \"executeSubscription\": [Function],\n  \"mutation\": [Function],\n  \"operations$\": [Function],\n  \"query\": [Function],\n  \"readQuery\": [Function],\n  \"reexecuteOperation\": [Function],\n  \"subscribeToDebugTarget\": [Function],\n  \"subscription\": [Function],\n  \"suspense\": false,\n}\n`;\n"
  },
  {
    "path": "packages/core/src/client.test.ts",
    "content": "import { print } from '@0no-co/graphql.web';\nimport { vi, expect, it, beforeEach, describe, afterEach } from 'vitest';\n\n/** NOTE: Testing in this file is designed to test both the client and its interaction with default Exchanges */\n\nimport {\n  Source,\n  delay,\n  map,\n  never,\n  pipe,\n  merge,\n  subscribe,\n  publish,\n  filter,\n  share,\n  toArray,\n  toPromise,\n  onPush,\n  tap,\n  take,\n  fromPromise,\n  fromValue,\n  mergeMap,\n} from 'wonka';\n\nimport { gql } from './gql';\nimport { Exchange, Operation, OperationResult } from './types';\nimport { makeOperation } from './utils';\nimport { Client, createClient } from './client';\nimport {\n  mutationOperation,\n  queryOperation,\n  subscriptionOperation,\n} from './test-utils';\n\nconst url = 'https://hostname.com';\n\ndescribe('createClient / Client', () => {\n  it('creates an instance of Client', () => {\n    expect(createClient({ url, exchanges: [] }) instanceof Client).toBeTruthy();\n    expect(new Client({ url, exchanges: [] }) instanceof Client).toBeTruthy();\n  });\n\n  it('passes snapshot', () => {\n    const client = createClient({ url, exchanges: [] });\n    expect(client).toMatchSnapshot();\n  });\n});\n\nconst query = {\n  key: 1,\n  query: gql`\n    {\n      todos {\n        id\n      }\n    }\n  `,\n  variables: { example: 1234 },\n};\n\nconst mutation = {\n  key: 1,\n  query: gql`\n    mutation {\n      todos {\n        id\n      }\n    }\n  `,\n  variables: { example: 1234 },\n};\n\nconst subscription = {\n  key: 1,\n  query: gql`\n    subscription {\n      todos {\n        id\n      }\n    }\n  `,\n  variables: { example: 1234 },\n};\n\nlet receivedOps: Operation[] = [];\nlet client = createClient({\n  url: '1234',\n  exchanges: [],\n});\nconst receiveMock = vi.fn((s: Source<Operation>) =>\n  pipe(\n    s,\n    tap(op => (receivedOps = [...receivedOps, op])),\n    map(op => ({ operation: op }))\n  )\n);\nconst exchangeMock = vi.fn(() => receiveMock);\n\nbeforeEach(() => {\n  receivedOps = [];\n  exchangeMock.mockClear();\n  receiveMock.mockClear();\n  client = createClient({\n    url,\n    exchanges: [exchangeMock] as any[],\n    requestPolicy: 'cache-and-network',\n  });\n});\n\ndescribe('exchange args', () => {\n  it('receives forward function', () => {\n    // @ts-ignore\n    expect(typeof exchangeMock.mock.calls[0][0].forward).toBe('function');\n  });\n\n  it('receives client', () => {\n    // @ts-ignore\n    expect(exchangeMock.mock.calls[0][0]).toHaveProperty('client', client);\n  });\n});\n\ndescribe('promisified methods', () => {\n  it('query', () => {\n    const queryResult = client\n      .query(\n        gql`\n          {\n            todos {\n              id\n            }\n          }\n        `,\n        { example: 1234 },\n        { requestPolicy: 'cache-only' }\n      )\n      .toPromise();\n\n    const received = receivedOps[0];\n    expect(print(received.query)).toEqual(print(query.query));\n    expect(received.key).toBeDefined();\n    expect(received.variables).toEqual({ example: 1234 });\n    expect(received.kind).toEqual('query');\n    expect(received.context).toEqual({\n      url: 'https://hostname.com',\n      requestPolicy: 'cache-only',\n      fetchOptions: undefined,\n      fetch: undefined,\n      suspense: false,\n      preferGetMethod: 'within-url-limit',\n    });\n    expect(queryResult).toHaveProperty('then');\n  });\n\n  it('mutation', () => {\n    const mut = gql`\n      mutation {\n        todos {\n          id\n        }\n      }\n    `;\n    const mutationResult = client.mutation(mut, { example: 1234 }).toPromise();\n\n    const received = receivedOps[0];\n    expect(print(received.query)).toEqual(print(mut));\n    expect(received.key).toBeDefined();\n    expect(received.variables).toEqual({ example: 1234 });\n    expect(received.kind).toEqual('mutation');\n    expect(received.context).toMatchObject({\n      url: 'https://hostname.com',\n      requestPolicy: 'cache-and-network',\n      fetchOptions: undefined,\n      fetch: undefined,\n      suspense: false,\n      preferGetMethod: 'within-url-limit',\n    });\n    expect(mutationResult).toHaveProperty('then');\n  });\n});\n\ndescribe('synchronous methods', () => {\n  it('readQuery', () => {\n    const result = client.readQuery(\n      gql`\n        {\n          todos {\n            id\n          }\n        }\n      `,\n      { example: 1234 }\n    );\n\n    expect(receivedOps.length).toBe(2);\n    expect(receivedOps[0].kind).toBe('query');\n    expect(receivedOps[1].kind).toBe('teardown');\n    expect(result).toEqual({\n      operation: {\n        ...query,\n        context: expect.anything(),\n        key: expect.any(Number),\n        kind: 'query',\n      },\n    });\n  });\n});\n\ndescribe('executeQuery', () => {\n  it('passes query string exchange', () => {\n    pipe(\n      client.executeQuery(query),\n      subscribe(x => x)\n    );\n\n    const receivedQuery = receivedOps[0].query;\n    expect(print(receivedQuery)).toBe(print(query.query));\n  });\n\n  it('should throw when passing in a mutation', () => {\n    try {\n      client.executeQuery(mutation);\n      expect(true).toBeFalsy();\n    } catch (e: any) {\n      expect(e.message).toMatchInlineSnapshot(\n        `\"Expected operation of type \"query\" but found \"mutation\"\"`\n      );\n    }\n  });\n\n  it('passes variables type to exchange', () => {\n    pipe(\n      client.executeQuery(query),\n      subscribe(x => x)\n    );\n\n    expect(receivedOps[0]).toHaveProperty('variables', query.variables);\n  });\n\n  it('passes requestPolicy to exchange', () => {\n    pipe(\n      client.executeQuery(query),\n      subscribe(x => x)\n    );\n\n    expect(receivedOps[0].context).toHaveProperty(\n      'requestPolicy',\n      'cache-and-network'\n    );\n  });\n\n  it('allows overriding the requestPolicy', () => {\n    pipe(\n      client.executeQuery(query, { requestPolicy: 'cache-first' }),\n      subscribe(x => x)\n    );\n\n    expect(receivedOps[0].context).toHaveProperty(\n      'requestPolicy',\n      'cache-first'\n    );\n  });\n\n  it('passes kind type to exchange', () => {\n    pipe(\n      client.executeQuery(query),\n      subscribe(x => x)\n    );\n\n    expect(receivedOps[0]).toHaveProperty('kind', 'query');\n  });\n\n  it('passes url (from context) to exchange', () => {\n    pipe(\n      client.executeQuery(query),\n      subscribe(x => x)\n    );\n\n    expect(receivedOps[0]).toHaveProperty('context.url', url);\n  });\n});\n\ndescribe('executeMutation', () => {\n  it('passes query string exchange', async () => {\n    pipe(\n      client.executeMutation(mutation),\n      subscribe(x => x)\n    );\n\n    const receivedQuery = receivedOps[0].query;\n    expect(print(receivedQuery)).toBe(print(mutation.query));\n  });\n\n  it('passes variables type to exchange', () => {\n    pipe(\n      client.executeMutation(mutation),\n      subscribe(x => x)\n    );\n\n    expect(receivedOps[0]).toHaveProperty('variables', query.variables);\n  });\n\n  it('passes kind type to exchange', () => {\n    pipe(\n      client.executeMutation(mutation),\n      subscribe(x => x)\n    );\n\n    expect(receivedOps[0]).toHaveProperty('kind', 'mutation');\n  });\n\n  it('passes url (from context) to exchange', () => {\n    pipe(\n      client.executeMutation(mutation),\n      subscribe(x => x)\n    );\n\n    expect(receivedOps[0]).toHaveProperty('context.url', url);\n  });\n});\n\ndescribe('executeSubscription', () => {\n  it('passes query string exchange', async () => {\n    pipe(\n      client.executeSubscription(subscription),\n      subscribe(x => x)\n    );\n\n    const receivedQuery = receivedOps[0].query;\n    expect(print(receivedQuery)).toBe(print(subscription.query));\n  });\n\n  it('passes variables type to exchange', () => {\n    pipe(\n      client.executeSubscription(subscription),\n      subscribe(x => x)\n    );\n\n    expect(receivedOps[0]).toHaveProperty('variables', subscription.variables);\n  });\n\n  it('passes kind type to exchange', () => {\n    pipe(\n      client.executeSubscription(subscription),\n      subscribe(x => x)\n    );\n\n    expect(receivedOps[0]).toHaveProperty('kind', 'subscription');\n  });\n});\n\ndescribe('queuing behavior', () => {\n  beforeEach(() => {\n    vi.useFakeTimers();\n  });\n\n  afterEach(() => {\n    vi.useRealTimers();\n  });\n\n  it('queues reexecuteOperation, which dispatchOperation consumes', () => {\n    const output: Array<Operation | OperationResult> = [];\n\n    const exchange: Exchange =\n      ({ client }) =>\n      ops$ => {\n        return pipe(\n          ops$,\n          filter(op => op.kind !== 'teardown'),\n          tap(op => {\n            output.push(op);\n            if (\n              op.key === queryOperation.key &&\n              op.context.requestPolicy !== 'network-only'\n            ) {\n              client.reexecuteOperation({\n                ...op,\n                context: {\n                  ...op.context,\n                  requestPolicy: 'network-only',\n                },\n              });\n            }\n          }),\n          map(op => ({\n            stale: false,\n            hasNext: false,\n            data: op.key,\n            operation: op,\n          }))\n        );\n      };\n\n    const client = createClient({\n      url: 'test',\n      exchanges: [exchange],\n    });\n\n    const shared = pipe(\n      client.executeRequestOperation(queryOperation),\n      onPush(result => output.push(result)),\n      share\n    );\n\n    const results = pipe(shared, toArray);\n    pipe(shared, publish);\n\n    expect(output.length).toBe(8);\n    expect(results.length).toBe(2);\n\n    expect(output[0]).toHaveProperty('key', queryOperation.key);\n    expect(output[0]).toHaveProperty('context.requestPolicy', 'cache-first');\n\n    expect(output[1]).toHaveProperty('operation.key', queryOperation.key);\n    expect(output[1]).toHaveProperty(\n      'operation.context.requestPolicy',\n      'cache-first'\n    );\n\n    expect(output[2]).toHaveProperty('key', queryOperation.key);\n    expect(output[2]).toHaveProperty('context.requestPolicy', 'network-only');\n\n    expect(output[3]).toHaveProperty('operation.key', queryOperation.key);\n    expect(output[3]).toHaveProperty(\n      'operation.context.requestPolicy',\n      'network-only'\n    );\n\n    expect(output[1]).toBe(results[0]);\n    expect(output[3]).toBe(results[1]);\n  });\n\n  it('reemits previous results as stale if the operation is reexecuted as network-only', async () => {\n    const output: OperationResult[] = [];\n\n    const exchange: Exchange = () => {\n      let countRes = 0;\n      return ops$ => {\n        return pipe(\n          ops$,\n          filter(op => op.kind !== 'teardown'),\n          map(op => ({\n            hasNext: false,\n            stale: false,\n            data: ++countRes,\n            operation: op,\n          })),\n          delay(1)\n        );\n      };\n    };\n\n    const client = createClient({\n      url: 'test',\n      exchanges: [exchange],\n    });\n\n    const { unsubscribe } = pipe(\n      client.executeRequestOperation(queryOperation),\n      subscribe(result => {\n        output.push(result);\n      })\n    );\n\n    vi.advanceTimersByTime(1);\n\n    expect(output.length).toBe(1);\n    expect(output[0]).toHaveProperty('data', 1);\n    expect(output[0]).toHaveProperty('operation.key', queryOperation.key);\n    expect(output[0]).toHaveProperty(\n      'operation.context.requestPolicy',\n      'cache-first'\n    );\n\n    client.reexecuteOperation(\n      makeOperation(queryOperation.kind, queryOperation, {\n        ...queryOperation.context,\n        requestPolicy: 'network-only',\n      })\n    );\n\n    await Promise.resolve();\n\n    expect(output.length).toBe(2);\n    expect(output[1]).toHaveProperty('data', 1);\n    expect(output[1]).toHaveProperty('stale', true);\n    expect(output[1]).toHaveProperty('operation.key', queryOperation.key);\n    expect(output[1]).toHaveProperty(\n      'operation.context.requestPolicy',\n      'cache-first'\n    );\n\n    vi.advanceTimersByTime(1);\n\n    expect(output.length).toBe(3);\n    expect(output[2]).toHaveProperty('data', 2);\n    expect(output[2]).toHaveProperty('stale', false);\n    expect(output[2]).toHaveProperty('operation.key', queryOperation.key);\n    expect(output[2]).toHaveProperty(\n      'operation.context.requestPolicy',\n      'network-only'\n    );\n\n    unsubscribe();\n  });\n});\n\ndescribe('deduplication behavior', () => {\n  beforeEach(() => {\n    vi.useFakeTimers();\n  });\n\n  afterEach(() => {\n    vi.useRealTimers();\n  });\n\n  it('deduplicates operations when no result has been sent yet', () => {\n    const onOperation = vi.fn();\n\n    const exchange: Exchange = () => ops$ => {\n      let i = 0;\n      return pipe(\n        ops$,\n        onPush(onOperation),\n        map(op => ({\n          hasNext: false,\n          stale: false,\n          data: ++i,\n          operation: op,\n        })),\n        delay(1)\n      );\n    };\n\n    const client = createClient({\n      url: 'test',\n      exchanges: [exchange],\n    });\n\n    const resultOne = vi.fn();\n    const resultTwo = vi.fn();\n    const operationOne = makeOperation('query', queryOperation, {\n      ...queryOperation.context,\n      requestPolicy: 'cache-first',\n    });\n    const operationTwo = makeOperation('query', queryOperation, {\n      ...queryOperation.context,\n      requestPolicy: 'network-only',\n    });\n\n    pipe(client.executeRequestOperation(operationOne), subscribe(resultOne));\n    pipe(client.executeRequestOperation(operationTwo), subscribe(resultTwo));\n    expect(resultOne).toHaveBeenCalledTimes(0);\n    expect(resultTwo).toHaveBeenCalledTimes(0);\n\n    vi.advanceTimersByTime(1);\n\n    expect(resultOne).toHaveBeenCalledTimes(1);\n    expect(resultTwo).toHaveBeenCalledTimes(1);\n    expect(onOperation).toHaveBeenCalledTimes(1);\n  });\n\n  it('deduplicates operations when hasNext: true is set', () => {\n    const onOperation = vi.fn();\n\n    const exchange: Exchange = () => ops$ => {\n      let i = 0;\n      return pipe(\n        ops$,\n        onPush(onOperation),\n        map(op => ({\n          hasNext: true,\n          stale: false,\n          data: ++i,\n          operation: op,\n        }))\n      );\n    };\n\n    const client = createClient({\n      url: 'test',\n      exchanges: [exchange],\n    });\n\n    const resultOne = vi.fn();\n    const resultTwo = vi.fn();\n    const operationOne = makeOperation('query', queryOperation, {\n      ...queryOperation.context,\n      requestPolicy: 'cache-first',\n    });\n    const operationTwo = makeOperation('query', queryOperation, {\n      ...queryOperation.context,\n      requestPolicy: 'network-only',\n    });\n\n    pipe(client.executeRequestOperation(operationOne), subscribe(resultOne));\n    pipe(client.executeRequestOperation(operationTwo), subscribe(resultTwo));\n    expect(resultOne).toHaveBeenCalledTimes(1);\n    expect(resultTwo).toHaveBeenCalledTimes(1);\n\n    vi.advanceTimersByTime(1);\n\n    expect(resultOne).toHaveBeenCalledTimes(1);\n    expect(resultTwo).toHaveBeenCalledTimes(1);\n    expect(onOperation).toHaveBeenCalledTimes(1);\n  });\n\n  it('deduplicates otherwise if operation has already been sent', () => {\n    const onOperation = vi.fn();\n    const onResult = vi.fn();\n\n    let hasSent = false;\n    const exchange: Exchange = () => ops$ =>\n      pipe(\n        ops$,\n        onPush(onOperation),\n        map(op => ({\n          hasNext: false,\n          stale: false,\n          data: 'test',\n          operation: op,\n        })),\n        filter(() => {\n          return hasSent ? false : (hasSent = true);\n        }),\n        delay(1)\n      );\n\n    const client = createClient({\n      url: 'test',\n      exchanges: [exchange],\n    });\n\n    const operationOne = makeOperation('query', queryOperation, {\n      ...queryOperation.context,\n      requestPolicy: 'cache-first',\n    });\n\n    const operationTwo = makeOperation('query', queryOperation, {\n      ...queryOperation.context,\n      requestPolicy: 'network-only',\n    });\n\n    const operationThree = makeOperation('query', queryOperation, {\n      ...queryOperation.context,\n      requestPolicy: 'network-only',\n    });\n\n    pipe(client.executeRequestOperation(operationOne), subscribe(onResult));\n    pipe(client.executeRequestOperation(operationTwo), subscribe(onResult));\n    pipe(client.executeRequestOperation(operationThree), subscribe(onResult));\n    vi.advanceTimersByTime(1);\n\n    expect(onOperation).toHaveBeenCalledTimes(1);\n    expect(onResult).toHaveBeenCalledTimes(3);\n  });\n\n  it('does not deduplicate cache-and-network’s follow-up operations', () => {\n    const onOperation = vi.fn();\n    const onResult = vi.fn();\n\n    const operationOne = makeOperation('query', queryOperation, {\n      ...queryOperation.context,\n      requestPolicy: 'cache-and-network',\n    });\n\n    const operationTwo = makeOperation('query', queryOperation, {\n      ...queryOperation.context,\n      requestPolicy: 'network-only',\n    });\n\n    let shouldSend = true;\n    const exchange: Exchange = () => ops$ =>\n      pipe(\n        ops$,\n        onPush(onOperation),\n        map(op => ({\n          hasNext: false,\n          stale: true,\n          data: 'test',\n          operation: op,\n        })),\n        filter(() => {\n          if (shouldSend) {\n            shouldSend = false;\n            client.reexecuteOperation(operationTwo);\n            return true;\n          } else {\n            return false;\n          }\n        })\n      );\n\n    const client = createClient({\n      url: 'test',\n      exchanges: [exchange],\n    });\n\n    const operationThree = makeOperation('query', queryOperation, {\n      ...queryOperation.context,\n      requestPolicy: 'network-only',\n    });\n\n    pipe(client.executeRequestOperation(operationOne), subscribe(onResult));\n    pipe(client.executeRequestOperation(operationThree), subscribe(onResult));\n\n    expect(onOperation).toHaveBeenCalledTimes(2);\n  });\n\n  it('unblocks mutation operations on call to reexecuteOperation', async () => {\n    const onOperation = vi.fn();\n    const onResult = vi.fn();\n\n    let hasSent = false;\n    const exchange: Exchange = () => ops$ =>\n      pipe(\n        ops$,\n        onPush(onOperation),\n        map(op => ({\n          hasNext: false,\n          stale: false,\n          data: 'test',\n          operation: op,\n        })),\n        filter(() => hasSent || !(hasSent = true))\n      );\n\n    const client = createClient({\n      url: 'test',\n      exchanges: [exchange],\n    });\n\n    const operation = makeOperation('mutation', mutationOperation, {\n      ...mutationOperation.context,\n      requestPolicy: 'cache-first',\n    });\n\n    pipe(client.executeRequestOperation(operation), subscribe(onResult));\n\n    expect(onOperation).toHaveBeenCalledTimes(1);\n    expect(onResult).toHaveBeenCalledTimes(0);\n\n    client.reexecuteOperation(operation);\n    await Promise.resolve();\n\n    expect(onOperation).toHaveBeenCalledTimes(2);\n    expect(onResult).toHaveBeenCalledTimes(1);\n  });\n\n  // See https://github.com/urql-graphql/urql/issues/3254\n  it('unblocks stale operations', async () => {\n    const onOperation = vi.fn();\n    const onResult = vi.fn();\n\n    let sends = 0;\n    const exchange: Exchange = () => ops$ =>\n      pipe(\n        ops$,\n        onPush(onOperation),\n        map(op => ({\n          hasNext: false,\n          stale: sends++ ? false : true,\n          data: 'test',\n          operation: op,\n        }))\n      );\n\n    const client = createClient({\n      url: 'test',\n      exchanges: [exchange],\n    });\n\n    const operation = makeOperation('query', queryOperation, {\n      ...queryOperation.context,\n      requestPolicy: 'cache-first',\n    });\n\n    pipe(client.executeRequestOperation(operation), subscribe(onResult));\n\n    expect(onOperation).toHaveBeenCalledTimes(1);\n    expect(onResult).toHaveBeenCalledTimes(1);\n\n    client.reexecuteOperation(operation);\n    await Promise.resolve();\n\n    expect(onOperation).toHaveBeenCalledTimes(2);\n    expect(onResult).toHaveBeenCalledTimes(2);\n  });\n\n  // See https://github.com/urql-graphql/urql/issues/3565\n  it('blocks reexecuting operations that are in-flight', async () => {\n    const onOperation = vi.fn();\n    const onResult = vi.fn();\n\n    let resolve;\n    const exchange: Exchange =\n      ({ client }) =>\n      ops$ =>\n        pipe(\n          ops$,\n          onPush(onOperation),\n          mergeMap(op => {\n            if (op.key === queryOperation.key) {\n              const promise = new Promise<OperationResult>(res => {\n                resolve = res;\n              });\n              return fromPromise(\n                promise.then(() => {\n                  return {\n                    hasNext: false,\n                    stale: false,\n                    data: 'test',\n                    operation: op,\n                  };\n                })\n              );\n            } else {\n              client.reexecuteOperation(queryOperation);\n              return fromValue({\n                hasNext: false,\n                stale: false,\n                data: 'test',\n                operation: op,\n              });\n            }\n          })\n        );\n\n    const client = createClient({\n      url: 'test',\n      exchanges: [exchange],\n    });\n\n    const operation = makeOperation('query', queryOperation, {\n      ...queryOperation.context,\n      requestPolicy: 'cache-first',\n    });\n\n    const mutation = makeOperation('mutation', mutationOperation, {\n      ...mutationOperation.context,\n      requestPolicy: 'cache-first',\n    });\n\n    pipe(client.executeRequestOperation(operation), subscribe(onResult));\n\n    expect(onOperation).toHaveBeenCalledTimes(1);\n    expect(onResult).toHaveBeenCalledTimes(0);\n\n    pipe(client.executeRequestOperation(mutation), subscribe(onResult));\n    await Promise.resolve();\n\n    expect(onOperation).toHaveBeenCalledTimes(2);\n    expect(onResult).toHaveBeenCalledTimes(1);\n\n    resolve();\n    await Promise.resolve();\n    await Promise.resolve();\n    await Promise.resolve();\n    expect(onOperation).toHaveBeenCalledTimes(2);\n    expect(onResult).toHaveBeenCalledTimes(2);\n  });\n});\n\ndescribe('shared sources behavior', () => {\n  beforeEach(() => {\n    vi.useFakeTimers();\n  });\n\n  afterEach(() => {\n    vi.useRealTimers();\n  });\n\n  it('replays results from prior operation result as needed (cache-first)', async () => {\n    const exchange: Exchange = () => ops$ => {\n      let i = 0;\n      return pipe(\n        ops$,\n        map(op => ({\n          hasNext: false,\n          stale: false,\n          data: ++i,\n          operation: op,\n        })),\n        delay(1)\n      );\n    };\n\n    const client = createClient({\n      url: 'test',\n      exchanges: [exchange],\n    });\n\n    const resultOne = vi.fn();\n    const resultTwo = vi.fn();\n\n    pipe(client.executeRequestOperation(queryOperation), subscribe(resultOne));\n\n    expect(resultOne).toHaveBeenCalledTimes(0);\n\n    vi.advanceTimersByTime(1);\n\n    expect(resultOne).toHaveBeenCalledTimes(1);\n    expect(resultOne).toHaveBeenCalledWith({\n      data: 1,\n      operation: queryOperation,\n      stale: false,\n      hasNext: false,\n    });\n\n    pipe(client.executeRequestOperation(queryOperation), subscribe(resultTwo));\n\n    expect(resultTwo).toHaveBeenCalledWith({\n      data: 1,\n      operation: queryOperation,\n      stale: true,\n      hasNext: false,\n    });\n\n    vi.advanceTimersByTime(1);\n\n    // With cache-first we don't expect a new operation to be issued\n    expect(resultTwo).toHaveBeenCalledTimes(2);\n  });\n\n  it('dispatches the correct request policy on subsequent sources', async () => {\n    const exchange: Exchange = () => ops$ => {\n      let i = 0;\n      return pipe(\n        ops$,\n        map(op => ({\n          hasNext: false,\n          stale: false,\n          data: ++i,\n          operation: op,\n        })),\n        delay(1)\n      );\n    };\n\n    const client = createClient({\n      url: 'test',\n      exchanges: [exchange],\n    });\n\n    const resultOne = vi.fn();\n    const resultTwo = vi.fn();\n    const operationOne = makeOperation('query', queryOperation, {\n      ...queryOperation.context,\n      requestPolicy: 'cache-first',\n    });\n    const operationTwo = makeOperation('query', queryOperation, {\n      ...queryOperation.context,\n      requestPolicy: 'network-only',\n    });\n\n    pipe(client.executeRequestOperation(operationOne), subscribe(resultOne));\n\n    expect(resultOne).toHaveBeenCalledTimes(0);\n\n    vi.advanceTimersByTime(1);\n\n    expect(resultOne).toHaveBeenCalledTimes(1);\n    expect(resultOne).toHaveBeenCalledWith({\n      data: 1,\n      operation: operationOne,\n      hasNext: false,\n      stale: false,\n    });\n\n    pipe(client.executeRequestOperation(operationTwo), subscribe(resultTwo));\n\n    expect(resultTwo).toHaveBeenCalledWith({\n      data: 1,\n      operation: operationOne,\n      stale: true,\n      hasNext: false,\n    });\n\n    vi.advanceTimersByTime(1);\n\n    expect(resultTwo).toHaveBeenCalledWith({\n      data: 2,\n      operation: operationTwo,\n      stale: false,\n      hasNext: false,\n    });\n  });\n\n  it('replays results from prior operation result as needed (network-only)', async () => {\n    const exchange: Exchange = () => ops$ => {\n      let i = 0;\n      return pipe(\n        ops$,\n        map(op => ({\n          hasNext: false,\n          stale: false,\n          data: ++i,\n          operation: op,\n        })),\n        delay(1)\n      );\n    };\n\n    const client = createClient({\n      url: 'test',\n      exchanges: [exchange],\n    });\n\n    const operation = makeOperation('query', queryOperation, {\n      ...queryOperation.context,\n      requestPolicy: 'network-only',\n    });\n\n    const resultOne = vi.fn();\n    const resultTwo = vi.fn();\n\n    pipe(client.executeRequestOperation(operation), subscribe(resultOne));\n\n    expect(resultOne).toHaveBeenCalledTimes(0);\n\n    vi.advanceTimersByTime(1);\n\n    expect(resultOne).toHaveBeenCalledTimes(1);\n    expect(resultOne).toHaveBeenCalledWith({\n      data: 1,\n      operation,\n      stale: false,\n      hasNext: false,\n    });\n\n    pipe(client.executeRequestOperation(operation), subscribe(resultTwo));\n\n    expect(resultTwo).toHaveBeenCalledWith({\n      data: 1,\n      operation,\n      stale: true,\n      hasNext: false,\n    });\n\n    expect(resultOne).toHaveBeenCalledWith({\n      data: 1,\n      operation,\n      stale: true,\n      hasNext: false,\n    });\n\n    expect(resultTwo).toHaveBeenCalledTimes(1);\n    expect(resultOne).toHaveBeenCalledTimes(2);\n\n    vi.advanceTimersByTime(1);\n\n    // With network-only we expect a new operation to be issued, hence a new result\n    expect(resultTwo).toHaveBeenCalledTimes(2);\n    expect(resultOne).toHaveBeenCalledTimes(3);\n\n    expect(resultTwo).toHaveBeenCalledWith({\n      data: 2,\n      operation,\n      stale: false,\n      hasNext: false,\n    });\n\n    expect(resultOne).toHaveBeenCalledWith({\n      data: 2,\n      operation,\n      stale: false,\n      hasNext: false,\n    });\n  });\n\n  it('does not replay values from a past subscription', async () => {\n    const exchange: Exchange = () => ops$ => {\n      let i = 0;\n      return pipe(\n        ops$,\n        filter(op => op.kind !== 'teardown'),\n        map(op => ({\n          hasNext: false,\n          stale: false,\n          data: ++i,\n          operation: op,\n        })),\n        delay(1)\n      );\n    };\n\n    const client = createClient({\n      url: 'test',\n      exchanges: [exchange],\n    });\n\n    // We keep the source in-memory\n    const source = client.executeRequestOperation(queryOperation);\n    const resultOne = vi.fn();\n    let subscription;\n\n    subscription = pipe(source, subscribe(resultOne));\n\n    expect(resultOne).toHaveBeenCalledTimes(0);\n    vi.advanceTimersByTime(1);\n\n    expect(resultOne).toHaveBeenCalledWith({\n      data: 1,\n      operation: queryOperation,\n      hasNext: false,\n      stale: false,\n    });\n\n    subscription.unsubscribe();\n    const resultTwo = vi.fn();\n    subscription = pipe(source, subscribe(resultTwo));\n\n    expect(resultTwo).toHaveBeenCalledTimes(0);\n    vi.advanceTimersByTime(1);\n\n    expect(resultTwo).toHaveBeenCalledWith({\n      data: 2,\n      operation: queryOperation,\n      stale: false,\n      hasNext: false,\n    });\n  });\n\n  it('replayed results are not emitted on the shared source', () => {\n    const exchange: Exchange = () => ops$ => {\n      let i = 0;\n      return pipe(\n        ops$,\n        map(op => ({\n          data: ++i,\n          operation: op,\n          hasNext: false,\n          stale: false,\n        })),\n        take(1)\n      );\n    };\n\n    const client = createClient({\n      url: 'test',\n      exchanges: [exchange],\n    });\n\n    const operation = makeOperation('query', queryOperation, {\n      ...queryOperation.context,\n      requestPolicy: 'network-only',\n    });\n\n    const resultOne = vi.fn();\n    const resultTwo = vi.fn();\n\n    pipe(client.executeRequestOperation(operation), subscribe(resultOne));\n    pipe(client.executeRequestOperation(operation), subscribe(resultTwo));\n\n    expect(resultTwo).toHaveBeenCalledTimes(1);\n    expect(resultTwo).toHaveBeenCalledWith({\n      data: 1,\n      operation,\n      stale: true,\n      hasNext: false,\n    });\n  });\n\n  it('does nothing when no operation result has been emitted yet', () => {\n    const dispatched = vi.fn();\n\n    const exchange: Exchange = () => ops$ => {\n      return pipe(\n        ops$,\n        map(op => {\n          dispatched(op);\n          return { hasNext: false, stale: false, data: 1, operation: op };\n        }),\n        filter(() => false)\n      );\n    };\n\n    const client = createClient({\n      url: 'test',\n      exchanges: [exchange],\n    });\n\n    const resultOne = vi.fn();\n    const resultTwo = vi.fn();\n\n    pipe(client.executeRequestOperation(queryOperation), subscribe(resultOne));\n\n    pipe(client.executeRequestOperation(queryOperation), subscribe(resultTwo));\n\n    expect(resultOne).toHaveBeenCalledTimes(0);\n    expect(resultTwo).toHaveBeenCalledTimes(0);\n    expect(dispatched).toHaveBeenCalledTimes(1);\n  });\n\n  it('skips replaying results when a result is emitted immediately (network-only)', () => {\n    const exchange: Exchange = () => ops$ => {\n      let i = 0;\n      return pipe(\n        ops$,\n        map(op => ({ hasNext: false, stale: false, data: ++i, operation: op }))\n      );\n    };\n\n    const client = createClient({\n      url: 'test',\n      exchanges: [exchange],\n    });\n\n    const operation = makeOperation('query', queryOperation, {\n      ...queryOperation.context,\n      requestPolicy: 'network-only',\n    });\n\n    const resultOne = vi.fn();\n    const resultTwo = vi.fn();\n\n    pipe(client.executeRequestOperation(operation), subscribe(resultOne));\n\n    expect(resultOne).toHaveBeenCalledWith({\n      data: 1,\n      operation,\n      hasNext: false,\n      stale: false,\n    });\n\n    pipe(client.executeRequestOperation(operation), subscribe(resultTwo));\n\n    expect(resultTwo).toHaveBeenCalledWith({\n      data: 2,\n      operation,\n      hasNext: false,\n      stale: false,\n    });\n\n    expect(resultOne).toHaveBeenCalledWith({\n      data: 2,\n      operation,\n      hasNext: false,\n      stale: false,\n    });\n  });\n\n  it('replays stale results as needed', () => {\n    const exchange: Exchange = () => ops$ => {\n      return pipe(\n        ops$,\n        map(op => ({ hasNext: false, stale: true, data: 1, operation: op })),\n        take(1)\n      );\n    };\n\n    const client = createClient({\n      url: 'test',\n      exchanges: [exchange],\n    });\n\n    const resultOne = vi.fn();\n    const resultTwo = vi.fn();\n\n    pipe(client.executeRequestOperation(queryOperation), subscribe(resultOne));\n\n    expect(resultOne).toHaveBeenCalledWith({\n      data: 1,\n      operation: queryOperation,\n      stale: true,\n      hasNext: false,\n    });\n\n    pipe(client.executeRequestOperation(queryOperation), subscribe(resultTwo));\n\n    expect(resultTwo).toHaveBeenCalledWith({\n      data: 1,\n      operation: queryOperation,\n      stale: true,\n      hasNext: false,\n    });\n  });\n\n  it('does nothing when operation is a subscription has been emitted yet', () => {\n    const exchange: Exchange = () => ops$ => {\n      return merge([\n        pipe(\n          ops$,\n          map(op => ({ hasNext: true, data: 1, operation: op })),\n          take(1)\n        ),\n        never,\n      ]);\n    };\n\n    const client = createClient({\n      url: 'test',\n      exchanges: [exchange],\n    });\n\n    const resultOne = vi.fn();\n    const resultTwo = vi.fn();\n\n    pipe(\n      client.executeRequestOperation(subscriptionOperation),\n      subscribe(resultOne)\n    );\n    expect(resultOne).toHaveBeenCalledTimes(1);\n\n    pipe(\n      client.executeRequestOperation(subscriptionOperation),\n      subscribe(resultTwo)\n    );\n    expect(resultTwo).toHaveBeenCalledTimes(0);\n  });\n\n  it('supports promisified sources', async () => {\n    const exchange: Exchange = () => ops$ => {\n      return pipe(\n        ops$,\n        map(op => ({ hasNext: false, stale: true, data: 1, operation: op }))\n      );\n    };\n\n    const client = createClient({\n      url: 'test',\n      exchanges: [exchange],\n    });\n\n    const resultOne = await pipe(\n      client.executeRequestOperation(queryOperation),\n      take(1),\n      toPromise\n    );\n\n    expect(resultOne).toEqual({\n      data: 1,\n      operation: queryOperation,\n      stale: true,\n      hasNext: false,\n    });\n  });\n});\n"
  },
  {
    "path": "packages/core/src/client.ts",
    "content": "/* eslint-disable @typescript-eslint/no-use-before-define */\n\nimport type { Source, Subscription } from 'wonka';\nimport {\n  lazy,\n  filter,\n  makeSubject,\n  onEnd,\n  onPush,\n  onStart,\n  pipe,\n  share,\n  take,\n  takeUntil,\n  takeWhile,\n  publish,\n  subscribe,\n  switchMap,\n  fromValue,\n  merge,\n  map,\n} from 'wonka';\n\nimport { composeExchanges } from './exchanges';\nimport { fallbackExchange } from './exchanges/fallback';\n\nimport type {\n  DocumentInput,\n  AnyVariables,\n  Exchange,\n  ExchangeInput,\n  GraphQLRequest,\n  Operation,\n  OperationInstance,\n  OperationContext,\n  OperationResult,\n  OperationResultSource,\n  OperationType,\n  RequestPolicy,\n  DebugEvent,\n} from './types';\n\nimport {\n  createRequest,\n  withPromise,\n  noop,\n  makeOperation,\n  getOperationType,\n} from './utils';\n\n/** Configuration options passed when creating a new {@link Client}.\n *\n * @remarks\n * The `ClientOptions` are passed when creating a new {@link Client}, and\n * are used to instantiate the pipeline of {@link Exchange | Exchanges}, configure\n * options used to initialize {@link OperationContext | OperationContexts}, or to\n * change the general behaviour of the {@link Client}.\n */\nexport interface ClientOptions {\n  /** Target URL used by fetch exchanges to make GraphQL API requests to.\n   *\n   * @remarks\n   * This is the URL that fetch exchanges will call to make GraphQL API requests.\n   * This value is copied to {@link OperationContext.url}.\n   */\n  url: string;\n  /** Additional options used by fetch exchanges that'll be passed to the `fetch` call on API requests.\n   *\n   * @remarks\n   * The options in this object or an object returned by a callback function will be merged into the\n   * {@link RequestInit} options passed to the `fetch` call.\n   *\n   * Hint: If you're trying to implement more complex changes per {@link Operation}, it's worth considering\n   * to use the {@link mapExchange} instead, which allows you to change `Operation`s and `OperationResult`s.\n   *\n   * Hint: If you're trying to use this as a function for authentication, consider checking out\n   * `@urql/exchange-auth` instead, which allows you to handle refresh auth flows, and more\n   * complex auth flows.\n   *\n   * @see {@link https://developer.mozilla.org/en-US/docs/Web/API/fetch} for a description of this object.\n   */\n  fetchOptions?: RequestInit | (() => RequestInit);\n  /** A `fetch` function polyfill used by fetch exchanges to make API calls.\n   *\n   * @remarks\n   * This is the fetch polyfill used by any fetch exchange to make an API request. By default, when this\n   * option isn't set, any fetch exchange will attempt to use the globally available `fetch` function\n   * to make a request instead.\n   *\n   * It's recommended to only pass a polyfill, if any of the environments you're running the {@link Client}\n   * in don't support the Fetch API natively.\n   *\n   * Hint: If you're using the \"Incremental Delivery\" multipart spec, for instance with `@defer` directives,\n   * you're better off using the native `fetch` function, or must ensure that your polyfill supports streamed\n   * results. However, a \"Streaming requests unsupported\" error will be thrown, to let you know that your `fetch`\n   * API doesn't support incrementally streamed responses, if this mode is used.\n   *\n   * @see {@link https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API} for the Fetch API spec.\n   */\n  fetch?: typeof fetch;\n  /** Allows a subscription to be executed using a `fetch` API request.\n   *\n   * @remarks\n   * If your API supports the `text/event-stream` and/or `multipart/mixed` response protocol, and you use\n   * this protocol to handle subscriptions, then you may switch this flag to `true`.\n   *\n   * This means you won’t have to create a {@link subscriptionExchange} to handle subscriptions with an\n   * external transport, and will instead be able to use GraphQL over HTTP transports.\n   */\n  fetchSubscriptions?: boolean;\n  /** A list of `Exchange`s that will be used to create the `Client`'s execution pipeline.\n   *\n   * @remarks\n   * The {@link Client} accepts and composes a list of {@link Exchange | Exchanges} into an “exchange pipeline”\n   * which receive a stream of {@link Operation | Operations} the `Client` wishes to execute, and return a stream\n   * of {@link OperationResult | OperationResults}.\n   *\n   * This is the basis for how `urql` handles GraphQL operations, and exchanges handle the creation, execution,\n   * and control flow of exchanges for the `Client`.\n   *\n   * To easily get started you should consider using the {@link cacheExchange} and {@link fetchExchange}\n   * these are all exported from the core package.\n   *\n   * @see {@link https://urql.dev/goto/docs/architecture/#the-client-and-exchanges} for more information\n   * on what `Exchange`s are and how they work.\n   */\n  exchanges: Exchange[];\n  /** A configuration flag indicating whether support for \"Suspense\" is activated.\n   *\n   * @remarks\n   * This configuration flag is only relevant for using `urql` with the React or Preact bindings.\n   * When activated it allows `useQuery` to \"suspend\" instead of returning a loading state, which\n   * will stop updates in a querying component and instead cascade\n   * to a higher suspense boundary for a loading state.\n   *\n   * Hint: While, when this option is enabled, by default all `useQuery` hooks will suspense, you can\n   * disable Suspense selectively for each hook.\n   *\n   * @see {@link https://beta.reactjs.org/blog/2022/03/29/react-v18#new-suspense-features} for more information on React Suspense.\n   */\n  suspense?: boolean;\n  /** The request and caching strategy that all `Operation`s on this `Client` will use by default.\n   *\n   * @remarks\n   * The {@link RequestPolicy} instructs cache exchanges how to use and treat their cached results.\n   * By default `cache-first` is set and used, which will use cache results, and only make an API request\n   * on a cache miss.\n   *\n   * The `requestPolicy` can be overriden per operation, since it's added to the {@link OperationContext},\n   * which allows you to change the policy per `Operation`, rather than changing it by default here.\n   *\n   * Hint: We don’t recommend changing this from the default `cache-first` option, unless you know what\n   * you‘re doing. Setting this to `cache-and-network` is not recommend and may not lead to the behaviour\n   * you expect. If you’re looking to always update your cache frequently, use `@urql/exchange-request-policy`\n   * instead.\n   */\n  requestPolicy?: RequestPolicy;\n  /** Instructs fetch exchanges to use a GET request.\n   *\n   * @remarks\n   * This changes the {@link OperationContext.preferGetMethod} option, which tells fetch exchanges\n   * to use GET requests for queries instead of POST requests.\n   *\n   * When set to `true` or `'within-url-limit'`, built-in fetch exchanges will always attempt to send query\n   * operations as GET requests, unless the resulting URL exceeds a length of 2,048 characters.\n   * If you want to bypass this restriction, set this option to `'force'` instead, to always send GET.\n   * requests for queries.\n   */\n  preferGetMethod?: boolean | 'force' | 'within-url-limit';\n}\n\n/** The `Client` is the central hub for your GraphQL operations and holds `urql`'s state.\n *\n * @remarks\n * The `Client` manages your active GraphQL operations and their state, and contains the\n * {@link Exchange} pipeline to execute your GraphQL operations.\n *\n * It contains methods that allow you to execute GraphQL operations manually, but the `Client`\n * is also interacted with by bindings (for React, Preact, Vue, Svelte, etc) to execute GraphQL\n * operations.\n *\n * While {@link Exchange | Exchanges} are ultimately responsible for the control flow of operations,\n * sending API requests, and caching, the `Client` still has the important responsibility for\n * creating operations, managing consumers of active operations, sharing results for operations,\n * and more tasks as a “central hub”.\n *\n * @see {@link https://urql.dev/goto/docs/architecture/#requests-and-operations-on-the-client} for more information\n * on what the `Client` is and does.\n */\nexport interface Client {\n  new (options: ClientOptions): Client;\n\n  /** Exposes the stream of `Operation`s that is passed to the `Exchange` pipeline.\n   *\n   * @remarks\n   * This is a Wonka {@link Source} that issues the {@link Operation | Operations} going into\n   * the exchange pipeline.\n   * @internal\n   */\n  operations$: Source<Operation>;\n\n  /** Flag indicating whether support for “Suspense” is activated.\n   *\n   * @remarks\n   * This flag indicates whether support for “Suspense” has been activated via the\n   * {@link ClientOptions.suspense} flag.\n   *\n   * When this is enabled, the {@link Client} itself doesn’t function any differently, and the flag\n   * only serves as an instructions for the React/Preact bindings to change their behaviour.\n   *\n   * @see {@link ClientOptions.suspense} for more information.\n   * @internal\n   */\n  suspense: boolean;\n\n  /** Dispatches an `Operation` to the `Exchange` pipeline, if this `Operation` is active.\n   *\n   * @remarks\n   * This method is frequently used in {@link Exchange | Exchanges}, for instance caches, to reexecute\n   * an operation. It’s often either called because an `Operation` will need to be queried against the\n   * cache again, if a cache result has changed or been invalidated, or it’s called with an {@link Operation}'s\n   * {@link RequestPolicy} set to `network-only` to issue a network request.\n   *\n   * This method will only dispatch an {@link Operation} if it has active consumers, meaning,\n   * active subscribers to the sources of {@link OperationResult}. For instance, if no bindings\n   * (e.g. `useQuery`) is subscribed to the `Operation`, then `reexecuteOperation` will do nothing.\n   *\n   * All operations are put onto a queue and executed after a micro-tick. The queue of operations is\n   * emptied eagerly and synchronously, similar to a trampoline scheduler.\n   */\n  reexecuteOperation(operation: Operation): void;\n\n  /** Subscribe method to add an event listener to debug events.\n   *\n   * @param onEvent - A callback called with new debug events, each time an `Exchange` issues them.\n   * @returns A Wonka {@link Subscription} which is used to optionally terminate the event listener.\n   *\n   * @remarks\n   * This is a method that's only available in development, and allows the `urql-devtools` to receive\n   * to debug events that are issued by exchanges, giving the devtools more information about the flow\n   * and execution of {@link Operation | Operations}.\n   *\n   * @see {@link DebugEventTypes} for a description of all debug events.\n   * @internal\n   */\n  subscribeToDebugTarget?(onEvent: (event: DebugEvent) => void): Subscription;\n\n  /** Creates an `Operation` from a `GraphQLRequest` and optionally, overriding `OperationContext` options.\n   *\n   * @param kind - The {@link OperationType} of GraphQL operation, i.e. `query`, `mutation`, or `subscription`.\n   * @param request - A {@link GraphQLRequest} created prior to calling this method.\n   * @param opts - {@link OperationContext} options that'll override and be merged with options from the {@link ClientOptions}.\n   * @returns An {@link Operation} created from the parameters.\n   *\n   * @remarks\n   * This method is expected to be called with a `kind` set to the `OperationType` of the GraphQL operation.\n   * In development, this is enforced by checking that the GraphQL document's operation matches this `kind`.\n   *\n   * Hint: While bindings will use this method combined with {@link Client.executeRequestOperation}, if\n   * you’re executing operations manually, you can use one of the other convenience methods instead.\n   *\n   * @see {@link Client.executeRequestOperation} for the method used to execute operations.\n   * @see {@link createRequest} which creates a `GraphQLRequest` from a `DocumentNode` and variables.\n   */\n  createRequestOperation<\n    Data = any,\n    Variables extends AnyVariables = AnyVariables,\n  >(\n    kind: OperationType,\n    request: GraphQLRequest<Data, Variables>,\n    opts?: Partial<OperationContext> | undefined\n  ): Operation<Data, Variables>;\n\n  /** Creates a `Source` that executes the `Operation` and issues `OperationResult`s for this `Operation`.\n   *\n   * @param operation - {@link Operation} that will be executed.\n   * @returns A Wonka {@link Source} of {@link OperationResult | OperationResults} for the passed `Operation`.\n   *\n   * @remarks\n   * The {@link Operation} will be dispatched to the pipeline of {@link Exchange | Exchanges} when\n   * subscribing to the returned {@link Source}, which issues {@link OperationResult | OperationResults}\n   * belonging to this `Operation`.\n   *\n   * Internally, {@link OperationResult | OperationResults} are filtered and deliverd to this source by\n   * comparing the {@link Operation.key} on the operation and the {@link OperationResult.operation}.\n   * For mutations, the {@link OperationContext._instance | `OperationContext._instance`} will additionally be compared, since two mutations\n   * with, even given the same variables, will have two distinct results and will be executed separately.\n   *\n   * The {@link Client} dispatches the {@link Operation} when we subscribe to the returned {@link Source}\n   * and will from then on consider the `Operation` as “active” until we unsubscribe. When all consumers unsubscribe\n   * from an `Operation` and it becomes “inactive” a `teardown` signal will be dispatched to the\n   * {@link Exchange | Exchanges}.\n   *\n   * Hint: While bindings will use this method, if you’re executing operations manually, you can use one\n   * of the other convenience methods instead, like {@link Client.executeQuery} et al.\n   */\n  executeRequestOperation<\n    Data = any,\n    Variables extends AnyVariables = AnyVariables,\n  >(\n    operation: Operation<Data, Variables>\n  ): OperationResultSource<OperationResult<Data, Variables>>;\n\n  /** Creates a `Source` that executes the GraphQL query operation created from the passed parameters.\n   *\n   * @param query - a GraphQL document containing the query operation that will be executed.\n   * @param variables - the variables used to execute the operation.\n   * @param opts - {@link OperationContext} options that'll override and be merged with options from the {@link ClientOptions}.\n   * @returns A {@link OperationResultSource} issuing the {@link OperationResult | OperationResults} for the GraphQL operation.\n   *\n   * @remarks\n   * The `Client.query` method is useful to programmatically create and issue a GraphQL query operation.\n   * It automatically calls {@link createRequest}, {@link client.createRequestOperation}, and\n   * {@link client.executeRequestOperation} for you, and is a convenience method.\n   *\n   * Since it returns a {@link OperationResultSource} it may be chained with a `toPromise()` call to only\n   * await a single result in an async function.\n   *\n   * Hint: This is the recommended way to create queries programmatically when not using the bindings,\n   * or when you’re trying to get a single, promisified result.\n   *\n   * @example\n   * ```ts\n   * const getBookQuery = gql`\n   *   query GetBook($id: ID!) {\n   *     book(id: $id) {\n   *       id\n   *       name\n   *       author {\n   *         name\n   *       }\n   *     }\n   *   }\n   * `;\n   *\n   * async function getBook(id) {\n   *   const result = await client.query(getBookQuery, { id }).toPromise();\n   *   if (result.error) {\n   *     throw result.error;\n   *   }\n   *\n   *   return result.data.book;\n   * }\n   * ```\n   */\n  query<Data = any, Variables extends AnyVariables = AnyVariables>(\n    query: DocumentInput<Data, Variables>,\n    variables: Variables,\n    context?: Partial<OperationContext>\n  ): OperationResultSource<OperationResult<Data, Variables>>;\n\n  /** Returns the first synchronous result a `Client` provides for a given operation.\n   *\n   * @param query - a GraphQL document containing the query operation that will be executed.\n   * @param variables - the variables used to execute the operation.\n   * @param opts - {@link OperationContext} options that'll override and be merged with options from the {@link ClientOptions}.\n   * @returns An {@link OperationResult} if one became available synchronously or `null`.\n   *\n   * @remarks\n   * The `Client.readQuery` method returns a result synchronously or defaults to `null`. This is useful\n   * as it limits the result for a query operation to whatever the cache {@link Exchange} of a {@link Client}\n   * had stored and available at that moment.\n   *\n   * In `urql`, it's expected that cache exchanges return their results synchronously. The bindings\n   * and this method exploit this by using synchronous results, like these, to check what data is already\n   * in the cache.\n   *\n   * This method is similar to what all bindings do to synchronously provide the initial state for queries,\n   * regardless of whether effects afterwards that subscribe to the query operation update this state synchronously\n   * or asynchronously.\n   */\n  readQuery<Data = any, Variables extends AnyVariables = AnyVariables>(\n    query: DocumentInput<Data, Variables>,\n    variables: Variables,\n    context?: Partial<OperationContext>\n  ): OperationResult<Data, Variables> | null;\n\n  /** Creates a `Source` that executes the GraphQL query operation for the passed `GraphQLRequest`.\n   *\n   * @param query - a {@link GraphQLRequest}\n   * @param opts - {@link OperationContext} options that'll override and be merged with options from the {@link ClientOptions}.\n   * @returns A {@link PromisifiedSource} issuing the {@link OperationResult | OperationResults} for the GraphQL operation.\n   *\n   * @remarks\n   * The `Client.executeQuery` method is used to programmatically issue a GraphQL query operation.\n   * It automatically calls {@link client.createRequestOperation} and {@link client.executeRequestOperation} for you,\n   * but requires you to create a {@link GraphQLRequest} using {@link createRequest} yourself first.\n   *\n   * @see {@link Client.query} for a method that doesn't require calling {@link createRequest} yourself.\n   */\n  executeQuery<Data = any, Variables extends AnyVariables = AnyVariables>(\n    query: GraphQLRequest<Data, Variables>,\n    opts?: Partial<OperationContext> | undefined\n  ): OperationResultSource<OperationResult<Data, Variables>>;\n\n  /** Creates a `Source` that executes the GraphQL subscription operation created from the passed parameters.\n   *\n   * @param query - a GraphQL document containing the subscription operation that will be executed.\n   * @param variables - the variables used to execute the operation.\n   * @param opts - {@link OperationContext} options that'll override and be merged with options from the {@link ClientOptions}.\n   * @returns A Wonka {@link Source} issuing the {@link OperationResult | OperationResults} for the GraphQL operation.\n   *\n   * @remarks\n   * The `Client.subscription` method is useful to programmatically create and issue a GraphQL subscription operation.\n   * It automatically calls {@link createRequest}, {@link client.createRequestOperation}, and\n   * {@link client.executeRequestOperation} for you, and is a convenience method.\n   *\n   * Hint: This is the recommended way to create subscriptions programmatically when not using the bindings.\n   *\n   * @example\n   * ```ts\n   * import { pipe, subscribe } from 'wonka';\n   *\n   * const getNewsSubscription = gql`\n   *   subscription GetNews {\n   *     breakingNews {\n   *       id\n   *       text\n   *       createdAt\n   *     }\n   *   }\n   * `;\n   *\n   * function subscribeToBreakingNews() {\n   *   const subscription = pipe(\n   *     client.subscription(getNewsSubscription, {}),\n   *     subscribe(result => {\n   *       if (result.data) {\n   *         console.log(result.data.breakingNews.text);\n   *       }\n   *     })\n   *   );\n   *\n   *   return subscription.unsubscribe;\n   * }\n   * ```\n   */\n  subscription<Data = any, Variables extends AnyVariables = AnyVariables>(\n    query: DocumentInput<Data, Variables>,\n    variables: Variables,\n    context?: Partial<OperationContext>\n  ): OperationResultSource<OperationResult<Data, Variables>>;\n\n  /** Creates a `Source` that executes the GraphQL subscription operation for the passed `GraphQLRequest`.\n   *\n   * @param query - a {@link GraphQLRequest}\n   * @param opts - {@link OperationContext} options that'll override and be merged with options from the {@link ClientOptions}.\n   * @returns A {@link PromisifiedSource} issuing the {@link OperationResult | OperationResults} for the GraphQL operation.\n   *\n   * @remarks\n   * The `Client.executeSubscription` method is used to programmatically issue a GraphQL subscription operation.\n   * It automatically calls {@link client.createRequestOperation} and {@link client.executeRequestOperation} for you,\n   * but requires you to create a {@link GraphQLRequest} using {@link createRequest} yourself first.\n   *\n   * @see {@link Client.subscription} for a method that doesn't require calling {@link createRequest} yourself.\n   */\n  executeSubscription<\n    Data = any,\n    Variables extends AnyVariables = AnyVariables,\n  >(\n    query: GraphQLRequest<Data, Variables>,\n    opts?: Partial<OperationContext> | undefined\n  ): OperationResultSource<OperationResult<Data, Variables>>;\n\n  /** Creates a `Source` that executes the GraphQL mutation operation created from the passed parameters.\n   *\n   * @param query - a GraphQL document containing the mutation operation that will be executed.\n   * @param variables - the variables used to execute the operation.\n   * @param opts - {@link OperationContext} options that'll override and be merged with options from the {@link ClientOptions}.\n   * @returns A {@link PromisifiedSource} issuing the {@link OperationResult | OperationResults} for the GraphQL operation.\n   *\n   * @remarks\n   * The `Client.mutation` method is useful to programmatically create and issue a GraphQL mutation operation.\n   * It automatically calls {@link createRequest}, {@link client.createRequestOperation}, and\n   * {@link client.executeRequestOperation} for you, and is a convenience method.\n   *\n   * Since it returns a {@link PromisifiedSource} it may be chained with a `toPromise()` call to only\n   * await a single result in an async function. Since mutations will only typically issue one result,\n   * using this method is recommended.\n   *\n   * Hint: This is the recommended way to create mutations programmatically when not using the bindings,\n   * or when you’re trying to get a single, promisified result.\n   *\n   * @example\n   * ```ts\n   * const createPostMutation = gql`\n   *   mutation CreatePost($text: String!) {\n   *     createPost(text: $text) {\n   *       id\n   *       text\n   *     }\n   *   }\n   * `;\n   *\n   * async function createPost(text) {\n   *   const result = await client.mutation(createPostMutation, {\n   *     text,\n   *   }).toPromise();\n   *   if (result.error) {\n   *     throw result.error;\n   *   }\n   *\n   *   return result.data.createPost;\n   * }\n   * ```\n   */\n  mutation<Data = any, Variables extends AnyVariables = AnyVariables>(\n    query: DocumentInput<Data, Variables>,\n    variables: Variables,\n    context?: Partial<OperationContext>\n  ): OperationResultSource<OperationResult<Data, Variables>>;\n\n  /** Creates a `Source` that executes the GraphQL mutation operation for the passed `GraphQLRequest`.\n   *\n   * @param query - a {@link GraphQLRequest}\n   * @param opts - {@link OperationContext} options that'll override and be merged with options from the {@link ClientOptions}.\n   * @returns A {@link PromisifiedSource} issuing the {@link OperationResult | OperationResults} for the GraphQL operation.\n   *\n   * @remarks\n   * The `Client.executeMutation` method is used to programmatically issue a GraphQL mutation operation.\n   * It automatically calls {@link client.createRequestOperation} and {@link client.executeRequestOperation} for you,\n   * but requires you to create a {@link GraphQLRequest} using {@link createRequest} yourself first.\n   *\n   * @see {@link Client.mutation} for a method that doesn't require calling {@link createRequest} yourself.\n   */\n  executeMutation<Data = any, Variables extends AnyVariables = AnyVariables>(\n    query: GraphQLRequest<Data, Variables>,\n    opts?: Partial<OperationContext> | undefined\n  ): OperationResultSource<OperationResult<Data, Variables>>;\n}\n\nexport const Client: new (opts: ClientOptions) => Client = function Client(\n  this: Client | {},\n  opts: ClientOptions\n) {\n  if (process.env.NODE_ENV !== 'production' && !opts.url) {\n    throw new Error('You are creating an urql-client without a url.');\n  }\n\n  let ids = 0;\n\n  const replays = new Map<number, OperationResult>();\n  const active: Map<number, Source<OperationResult>> = new Map();\n  const dispatched = new Set<number>();\n  const queue: Operation[] = [];\n\n  const baseOpts = {\n    url: opts.url,\n    fetchSubscriptions: opts.fetchSubscriptions,\n    fetchOptions: opts.fetchOptions,\n    fetch: opts.fetch,\n    preferGetMethod:\n      opts.preferGetMethod != null ? opts.preferGetMethod : 'within-url-limit',\n    requestPolicy: opts.requestPolicy || 'cache-first',\n  };\n\n  // This subject forms the input of operations; executeOperation may be\n  // called to dispatch a new operation on the subject\n  const operations = makeSubject<Operation>();\n\n  function nextOperation(operation: Operation) {\n    if (\n      operation.kind === 'mutation' ||\n      operation.kind === 'teardown' ||\n      !dispatched.has(operation.key)\n    ) {\n      if (operation.kind === 'teardown') {\n        dispatched.delete(operation.key);\n      } else if (operation.kind !== 'mutation') {\n        dispatched.add(operation.key);\n      }\n      operations.next(operation);\n    }\n  }\n\n  // We define a queued dispatcher on the subject, which empties the queue when it's\n  // activated to allow `reexecuteOperation` to be trampoline-scheduled\n  let isOperationBatchActive = false;\n  function dispatchOperation(operation?: Operation | void) {\n    if (operation) nextOperation(operation);\n\n    if (!isOperationBatchActive) {\n      isOperationBatchActive = true;\n      while (isOperationBatchActive && (operation = queue.shift()))\n        nextOperation(operation);\n      isOperationBatchActive = false;\n    }\n  }\n\n  /** Defines how result streams are created */\n  const makeResultSource = (operation: Operation) => {\n    let result$ = pipe(\n      results$,\n      // Filter by matching key (or _instance if it’s set)\n      filter(\n        (res: OperationResult) =>\n          res.operation.kind === operation.kind &&\n          res.operation.key === operation.key &&\n          (!res.operation.context._instance ||\n            res.operation.context._instance === operation.context._instance)\n      ),\n      // End the results stream when an active teardown event is sent\n      takeUntil(\n        pipe(\n          operations.source,\n          filter(op => op.kind === 'teardown' && op.key === operation.key)\n        )\n      )\n    );\n\n    if (operation.kind !== 'query') {\n      // Interrupt subscriptions and mutations when they have no more results\n      result$ = pipe(\n        result$,\n        takeWhile(result => !!result.hasNext, true)\n      );\n    } else {\n      result$ = pipe(\n        result$,\n        // Add `stale: true` flag when a new operation is sent for queries\n        switchMap(result => {\n          const value$ = fromValue(result);\n          return result.stale || result.hasNext\n            ? value$\n            : merge([\n                value$,\n                pipe(\n                  operations.source,\n                  filter(op => op.key === operation.key),\n                  take(1),\n                  map(() => {\n                    result.stale = true;\n                    return result;\n                  })\n                ),\n              ]);\n        })\n      );\n    }\n\n    if (operation.kind !== 'mutation') {\n      result$ = pipe(\n        result$,\n        // Store replay result\n        onPush(result => {\n          if (result.stale) {\n            if (!result.hasNext) {\n              // we are dealing with an optimistic mutation or a partial result\n              dispatched.delete(operation.key);\n            } else {\n              // If the current result has queued up an operation of the same\n              // key, then `stale` refers to it\n              for (let i = 0; i < queue.length; i++) {\n                const operation = queue[i];\n                if (operation.key === result.operation.key) {\n                  dispatched.delete(operation.key);\n                  break;\n                }\n              }\n            }\n          } else if (!result.hasNext) {\n            dispatched.delete(operation.key);\n          }\n          replays.set(operation.key, result);\n        }),\n        // Cleanup active states on end of source\n        onEnd(() => {\n          // Delete the active operation handle\n          dispatched.delete(operation.key);\n          replays.delete(operation.key);\n          active.delete(operation.key);\n          // Interrupt active queue\n          isOperationBatchActive = false;\n          // Delete all queued up operations of the same key on end\n          for (let i = queue.length - 1; i >= 0; i--)\n            if (queue[i].key === operation.key) queue.splice(i, 1);\n          // Dispatch a teardown signal for the stopped operation\n          nextOperation(\n            makeOperation('teardown', operation, operation.context)\n          );\n        })\n      );\n    } else {\n      result$ = pipe(\n        result$,\n        // Send mutation operation on start\n        onStart(() => {\n          nextOperation(operation);\n        })\n      );\n    }\n\n    return share(result$);\n  };\n\n  const instance: Client =\n    this instanceof Client ? this : Object.create(Client.prototype);\n  const client: Client = Object.assign(instance, {\n    suspense: !!opts.suspense,\n    operations$: operations.source,\n\n    reexecuteOperation(operation: Operation) {\n      // Reexecute operation only if any subscribers are still subscribed to the\n      // operation's exchange results\n      if (operation.kind === 'teardown') {\n        dispatchOperation(operation);\n      } else if (operation.kind === 'mutation') {\n        queue.push(operation);\n        Promise.resolve().then(dispatchOperation);\n      } else if (active.has(operation.key)) {\n        let queued = false;\n        for (let i = 0; i < queue.length; i++) {\n          if (queue[i].key === operation.key) {\n            queue[i] = operation;\n            queued = true;\n          }\n        }\n\n        if (\n          !queued &&\n          (!dispatched.has(operation.key) ||\n            operation.context.requestPolicy === 'network-only')\n        ) {\n          queue.push(operation);\n          Promise.resolve().then(dispatchOperation);\n        } else {\n          dispatched.delete(operation.key);\n          Promise.resolve().then(dispatchOperation);\n        }\n      }\n    },\n\n    createRequestOperation(kind, request, opts) {\n      if (!opts) opts = {};\n\n      let requestOperationType: string | undefined;\n      if (\n        process.env.NODE_ENV !== 'production' &&\n        kind !== 'teardown' &&\n        (requestOperationType = getOperationType(request.query)) !== kind\n      ) {\n        throw new Error(\n          `Expected operation of type \"${kind}\" but found \"${requestOperationType}\"`\n        );\n      }\n\n      return makeOperation(kind, request, {\n        _instance:\n          kind === 'mutation'\n            ? ((ids = (ids + 1) | 0) as OperationInstance)\n            : undefined,\n        ...baseOpts,\n        ...opts,\n        requestPolicy: opts.requestPolicy || baseOpts.requestPolicy,\n        suspense: opts.suspense || (opts.suspense !== false && client.suspense),\n      });\n    },\n\n    executeRequestOperation(operation) {\n      if (operation.kind === 'mutation') {\n        return withPromise(makeResultSource(operation));\n      }\n\n      return withPromise(\n        lazy<OperationResult>(() => {\n          let source = active.get(operation.key);\n          if (!source) {\n            active.set(operation.key, (source = makeResultSource(operation)));\n          }\n\n          source = pipe(\n            source,\n            onStart(() => {\n              dispatchOperation(operation);\n            })\n          );\n\n          const replay = replays.get(operation.key);\n          if (\n            operation.kind === 'query' &&\n            replay &&\n            (replay.stale || replay.hasNext)\n          ) {\n            return pipe(\n              merge([\n                source,\n                pipe(\n                  fromValue(replay),\n                  filter(replay => replay === replays.get(operation.key))\n                ),\n              ]),\n              switchMap(fromValue)\n            );\n          } else {\n            return source;\n          }\n        })\n      );\n    },\n\n    executeQuery(query, opts) {\n      const operation = client.createRequestOperation('query', query, opts);\n      return client.executeRequestOperation(operation);\n    },\n\n    executeSubscription(query, opts) {\n      const operation = client.createRequestOperation(\n        'subscription',\n        query,\n        opts\n      );\n      return client.executeRequestOperation(operation);\n    },\n\n    executeMutation(query, opts) {\n      const operation = client.createRequestOperation('mutation', query, opts);\n      return client.executeRequestOperation(operation);\n    },\n\n    readQuery(query, variables, context) {\n      let result: OperationResult | null = null;\n\n      pipe(\n        client.query(query, variables, context),\n        subscribe(res => {\n          result = res;\n        })\n      ).unsubscribe();\n\n      return result;\n    },\n\n    query(query, variables, context) {\n      return client.executeQuery(createRequest(query, variables), context);\n    },\n\n    subscription(query, variables, context) {\n      return client.executeSubscription(\n        createRequest(query, variables),\n        context\n      );\n    },\n\n    mutation(query, variables, context) {\n      return client.executeMutation(createRequest(query, variables), context);\n    },\n  } as Client);\n\n  let dispatchDebug: ExchangeInput['dispatchDebug'] = noop;\n  if (process.env.NODE_ENV !== 'production') {\n    const { next, source } = makeSubject<DebugEvent>();\n    client.subscribeToDebugTarget = (onEvent: (e: DebugEvent) => void) =>\n      pipe(source, subscribe(onEvent));\n    dispatchDebug = next as ExchangeInput['dispatchDebug'];\n  }\n\n  // All exchange are composed into a single one and are called using the constructed client\n  // and the fallback exchange stream\n  const composedExchange = composeExchanges(opts.exchanges);\n\n  // All exchanges receive inputs using which they can forward operations to the next exchange\n  // and receive a stream of results in return, access the client, or dispatch debugging events\n  // All operations then run through the Exchange IOs in a pipeline-like fashion\n  const results$ = share(\n    composedExchange({\n      client,\n      dispatchDebug,\n      forward: fallbackExchange({ dispatchDebug }),\n    })(operations.source)\n  );\n\n  // Prevent the `results$` exchange pipeline from being closed by active\n  // cancellations cascading up from components\n  pipe(results$, publish);\n\n  return client;\n} as any;\n\n/** Accepts `ClientOptions` and creates a `Client`.\n * @param opts - A {@link ClientOptions} objects with options for the `Client`.\n * @returns A {@link Client} instantiated with `opts`.\n */\nexport const createClient = Client as any as (opts: ClientOptions) => Client;\n"
  },
  {
    "path": "packages/core/src/exchanges/__snapshots__/fetch.test.ts.snap",
    "content": "// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html\n\nexports[`on error > returns error data 1`] = `\n{\n  \"data\": undefined,\n  \"error\": [CombinedError: [Network] No Content],\n  \"extensions\": undefined,\n  \"hasNext\": false,\n  \"operation\": {\n    \"context\": {\n      \"fetchOptions\": {\n        \"method\": \"POST\",\n      },\n      \"requestPolicy\": \"cache-first\",\n      \"url\": \"http://localhost:3000/graphql\",\n    },\n    \"key\": 2,\n    \"kind\": \"query\",\n    \"query\": {\n      \"__key\": -2395444236,\n      \"definitions\": [\n        {\n          \"directives\": undefined,\n          \"kind\": \"OperationDefinition\",\n          \"name\": {\n            \"kind\": \"Name\",\n            \"value\": \"getUser\",\n          },\n          \"operation\": \"query\",\n          \"selectionSet\": {\n            \"kind\": \"SelectionSet\",\n            \"selections\": [\n              {\n                \"alias\": undefined,\n                \"arguments\": [\n                  {\n                    \"kind\": \"Argument\",\n                    \"name\": {\n                      \"kind\": \"Name\",\n                      \"value\": \"name\",\n                    },\n                    \"value\": {\n                      \"kind\": \"Variable\",\n                      \"name\": {\n                        \"kind\": \"Name\",\n                        \"value\": \"name\",\n                      },\n                    },\n                  },\n                ],\n                \"directives\": undefined,\n                \"kind\": \"Field\",\n                \"name\": {\n                  \"kind\": \"Name\",\n                  \"value\": \"user\",\n                },\n                \"selectionSet\": {\n                  \"kind\": \"SelectionSet\",\n                  \"selections\": [\n                    {\n                      \"alias\": undefined,\n                      \"arguments\": undefined,\n                      \"directives\": undefined,\n                      \"kind\": \"Field\",\n                      \"name\": {\n                        \"kind\": \"Name\",\n                        \"value\": \"id\",\n                      },\n                      \"selectionSet\": undefined,\n                    },\n                    {\n                      \"alias\": undefined,\n                      \"arguments\": undefined,\n                      \"directives\": undefined,\n                      \"kind\": \"Field\",\n                      \"name\": {\n                        \"kind\": \"Name\",\n                        \"value\": \"firstName\",\n                      },\n                      \"selectionSet\": undefined,\n                    },\n                    {\n                      \"alias\": undefined,\n                      \"arguments\": undefined,\n                      \"directives\": undefined,\n                      \"kind\": \"Field\",\n                      \"name\": {\n                        \"kind\": \"Name\",\n                        \"value\": \"lastName\",\n                      },\n                      \"selectionSet\": undefined,\n                    },\n                  ],\n                },\n              },\n            ],\n          },\n          \"variableDefinitions\": [\n            {\n              \"defaultValue\": undefined,\n              \"directives\": undefined,\n              \"kind\": \"VariableDefinition\",\n              \"type\": {\n                \"kind\": \"NamedType\",\n                \"name\": {\n                  \"kind\": \"Name\",\n                  \"value\": \"String\",\n                },\n              },\n              \"variable\": {\n                \"kind\": \"Variable\",\n                \"name\": {\n                  \"kind\": \"Name\",\n                  \"value\": \"name\",\n                },\n              },\n            },\n          ],\n        },\n      ],\n      \"kind\": \"Document\",\n      \"loc\": {\n        \"end\": 92,\n        \"source\": {\n          \"body\": \"query getUser($name: String) {\n  user(name: $name) {\n    id\n    firstName\n    lastName\n  }\n}\",\n          \"locationOffset\": {\n            \"column\": 1,\n            \"line\": 1,\n          },\n          \"name\": \"gql\",\n        },\n        \"start\": 0,\n      },\n    },\n    \"variables\": {\n      \"name\": \"Clara\",\n    },\n  },\n  \"stale\": false,\n}\n`;\n\nexports[`on error > returns error data with status 400 and manual redirect mode 1`] = `\n{\n  \"data\": undefined,\n  \"error\": [CombinedError: [Network] No Content],\n  \"extensions\": undefined,\n  \"hasNext\": false,\n  \"operation\": {\n    \"context\": {\n      \"fetchOptions\": [MockFunction spy] {\n        \"calls\": [\n          [],\n        ],\n        \"results\": [\n          {\n            \"type\": \"return\",\n            \"value\": {\n              \"redirect\": \"manual\",\n            },\n          },\n        ],\n      },\n      \"requestPolicy\": \"cache-first\",\n      \"url\": \"http://localhost:3000/graphql\",\n    },\n    \"key\": 2,\n    \"kind\": \"query\",\n    \"query\": {\n      \"__key\": -2395444236,\n      \"definitions\": [\n        {\n          \"directives\": undefined,\n          \"kind\": \"OperationDefinition\",\n          \"name\": {\n            \"kind\": \"Name\",\n            \"value\": \"getUser\",\n          },\n          \"operation\": \"query\",\n          \"selectionSet\": {\n            \"kind\": \"SelectionSet\",\n            \"selections\": [\n              {\n                \"alias\": undefined,\n                \"arguments\": [\n                  {\n                    \"kind\": \"Argument\",\n                    \"name\": {\n                      \"kind\": \"Name\",\n                      \"value\": \"name\",\n                    },\n                    \"value\": {\n                      \"kind\": \"Variable\",\n                      \"name\": {\n                        \"kind\": \"Name\",\n                        \"value\": \"name\",\n                      },\n                    },\n                  },\n                ],\n                \"directives\": undefined,\n                \"kind\": \"Field\",\n                \"name\": {\n                  \"kind\": \"Name\",\n                  \"value\": \"user\",\n                },\n                \"selectionSet\": {\n                  \"kind\": \"SelectionSet\",\n                  \"selections\": [\n                    {\n                      \"alias\": undefined,\n                      \"arguments\": undefined,\n                      \"directives\": undefined,\n                      \"kind\": \"Field\",\n                      \"name\": {\n                        \"kind\": \"Name\",\n                        \"value\": \"id\",\n                      },\n                      \"selectionSet\": undefined,\n                    },\n                    {\n                      \"alias\": undefined,\n                      \"arguments\": undefined,\n                      \"directives\": undefined,\n                      \"kind\": \"Field\",\n                      \"name\": {\n                        \"kind\": \"Name\",\n                        \"value\": \"firstName\",\n                      },\n                      \"selectionSet\": undefined,\n                    },\n                    {\n                      \"alias\": undefined,\n                      \"arguments\": undefined,\n                      \"directives\": undefined,\n                      \"kind\": \"Field\",\n                      \"name\": {\n                        \"kind\": \"Name\",\n                        \"value\": \"lastName\",\n                      },\n                      \"selectionSet\": undefined,\n                    },\n                  ],\n                },\n              },\n            ],\n          },\n          \"variableDefinitions\": [\n            {\n              \"defaultValue\": undefined,\n              \"directives\": undefined,\n              \"kind\": \"VariableDefinition\",\n              \"type\": {\n                \"kind\": \"NamedType\",\n                \"name\": {\n                  \"kind\": \"Name\",\n                  \"value\": \"String\",\n                },\n              },\n              \"variable\": {\n                \"kind\": \"Variable\",\n                \"name\": {\n                  \"kind\": \"Name\",\n                  \"value\": \"name\",\n                },\n              },\n            },\n          ],\n        },\n      ],\n      \"kind\": \"Document\",\n      \"loc\": {\n        \"end\": 92,\n        \"source\": {\n          \"body\": \"query getUser($name: String) {\n  user(name: $name) {\n    id\n    firstName\n    lastName\n  }\n}\",\n          \"locationOffset\": {\n            \"column\": 1,\n            \"line\": 1,\n          },\n          \"name\": \"gql\",\n        },\n        \"start\": 0,\n      },\n    },\n    \"variables\": {\n      \"name\": \"Clara\",\n    },\n  },\n  \"stale\": false,\n}\n`;\n\nexports[`on success > returns response data 1`] = `\n{\n  \"data\": {\n    \"data\": {\n      \"user\": 1200,\n    },\n  },\n  \"error\": undefined,\n  \"extensions\": undefined,\n  \"hasNext\": false,\n  \"operation\": {\n    \"context\": {\n      \"fetchOptions\": [MockFunction spy] {\n        \"calls\": [\n          [],\n        ],\n        \"results\": [\n          {\n            \"type\": \"return\",\n            \"value\": {},\n          },\n        ],\n      },\n      \"requestPolicy\": \"cache-first\",\n      \"url\": \"http://localhost:3000/graphql\",\n    },\n    \"key\": 2,\n    \"kind\": \"query\",\n    \"query\": {\n      \"__key\": -2395444236,\n      \"definitions\": [\n        {\n          \"directives\": undefined,\n          \"kind\": \"OperationDefinition\",\n          \"name\": {\n            \"kind\": \"Name\",\n            \"value\": \"getUser\",\n          },\n          \"operation\": \"query\",\n          \"selectionSet\": {\n            \"kind\": \"SelectionSet\",\n            \"selections\": [\n              {\n                \"alias\": undefined,\n                \"arguments\": [\n                  {\n                    \"kind\": \"Argument\",\n                    \"name\": {\n                      \"kind\": \"Name\",\n                      \"value\": \"name\",\n                    },\n                    \"value\": {\n                      \"kind\": \"Variable\",\n                      \"name\": {\n                        \"kind\": \"Name\",\n                        \"value\": \"name\",\n                      },\n                    },\n                  },\n                ],\n                \"directives\": undefined,\n                \"kind\": \"Field\",\n                \"name\": {\n                  \"kind\": \"Name\",\n                  \"value\": \"user\",\n                },\n                \"selectionSet\": {\n                  \"kind\": \"SelectionSet\",\n                  \"selections\": [\n                    {\n                      \"alias\": undefined,\n                      \"arguments\": undefined,\n                      \"directives\": undefined,\n                      \"kind\": \"Field\",\n                      \"name\": {\n                        \"kind\": \"Name\",\n                        \"value\": \"id\",\n                      },\n                      \"selectionSet\": undefined,\n                    },\n                    {\n                      \"alias\": undefined,\n                      \"arguments\": undefined,\n                      \"directives\": undefined,\n                      \"kind\": \"Field\",\n                      \"name\": {\n                        \"kind\": \"Name\",\n                        \"value\": \"firstName\",\n                      },\n                      \"selectionSet\": undefined,\n                    },\n                    {\n                      \"alias\": undefined,\n                      \"arguments\": undefined,\n                      \"directives\": undefined,\n                      \"kind\": \"Field\",\n                      \"name\": {\n                        \"kind\": \"Name\",\n                        \"value\": \"lastName\",\n                      },\n                      \"selectionSet\": undefined,\n                    },\n                  ],\n                },\n              },\n            ],\n          },\n          \"variableDefinitions\": [\n            {\n              \"defaultValue\": undefined,\n              \"directives\": undefined,\n              \"kind\": \"VariableDefinition\",\n              \"type\": {\n                \"kind\": \"NamedType\",\n                \"name\": {\n                  \"kind\": \"Name\",\n                  \"value\": \"String\",\n                },\n              },\n              \"variable\": {\n                \"kind\": \"Variable\",\n                \"name\": {\n                  \"kind\": \"Name\",\n                  \"value\": \"name\",\n                },\n              },\n            },\n          ],\n        },\n      ],\n      \"kind\": \"Document\",\n      \"loc\": {\n        \"end\": 92,\n        \"source\": {\n          \"body\": \"query getUser($name: String) {\n  user(name: $name) {\n    id\n    firstName\n    lastName\n  }\n}\",\n          \"locationOffset\": {\n            \"column\": 1,\n            \"line\": 1,\n          },\n          \"name\": \"gql\",\n        },\n        \"start\": 0,\n      },\n    },\n    \"variables\": {\n      \"name\": \"Clara\",\n    },\n  },\n  \"stale\": false,\n}\n`;\n\nexports[`on success > returns response data 2`] = `\"{\"operationName\":\"getUser\",\"query\":\"query getUser($name: String) {\\\\n  user(name: $name) {\\\\n    id\\\\n    firstName\\\\n    lastName\\\\n  }\\\\n}\",\"variables\":{\"name\":\"Clara\"}}\"`;\n"
  },
  {
    "path": "packages/core/src/exchanges/__snapshots__/subscription.test.ts.snap",
    "content": "// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html\n\nexports[`should return response data from forwardSubscription observable 1`] = `\n{\n  \"data\": {},\n  \"error\": undefined,\n  \"extensions\": undefined,\n  \"hasNext\": true,\n  \"operation\": {\n    \"context\": {\n      \"fetchOptions\": {\n        \"method\": \"POST\",\n      },\n      \"requestPolicy\": \"cache-first\",\n      \"url\": \"http://localhost:3000/graphql\",\n    },\n    \"key\": 4,\n    \"kind\": \"subscription\",\n    \"query\": {\n      \"__key\": 7623921801,\n      \"definitions\": [\n        {\n          \"directives\": undefined,\n          \"kind\": \"OperationDefinition\",\n          \"name\": {\n            \"kind\": \"Name\",\n            \"value\": \"subscribeToUser\",\n          },\n          \"operation\": \"subscription\",\n          \"selectionSet\": {\n            \"kind\": \"SelectionSet\",\n            \"selections\": [\n              {\n                \"alias\": undefined,\n                \"arguments\": [\n                  {\n                    \"kind\": \"Argument\",\n                    \"name\": {\n                      \"kind\": \"Name\",\n                      \"value\": \"user\",\n                    },\n                    \"value\": {\n                      \"kind\": \"Variable\",\n                      \"name\": {\n                        \"kind\": \"Name\",\n                        \"value\": \"user\",\n                      },\n                    },\n                  },\n                ],\n                \"directives\": undefined,\n                \"kind\": \"Field\",\n                \"name\": {\n                  \"kind\": \"Name\",\n                  \"value\": \"user\",\n                },\n                \"selectionSet\": {\n                  \"kind\": \"SelectionSet\",\n                  \"selections\": [\n                    {\n                      \"alias\": undefined,\n                      \"arguments\": undefined,\n                      \"directives\": undefined,\n                      \"kind\": \"Field\",\n                      \"name\": {\n                        \"kind\": \"Name\",\n                        \"value\": \"name\",\n                      },\n                      \"selectionSet\": undefined,\n                    },\n                  ],\n                },\n              },\n            ],\n          },\n          \"variableDefinitions\": [\n            {\n              \"defaultValue\": undefined,\n              \"directives\": undefined,\n              \"kind\": \"VariableDefinition\",\n              \"type\": {\n                \"kind\": \"NamedType\",\n                \"name\": {\n                  \"kind\": \"Name\",\n                  \"value\": \"String\",\n                },\n              },\n              \"variable\": {\n                \"kind\": \"Variable\",\n                \"name\": {\n                  \"kind\": \"Name\",\n                  \"value\": \"user\",\n                },\n              },\n            },\n          ],\n        },\n      ],\n      \"kind\": \"Document\",\n      \"loc\": {\n        \"end\": 82,\n        \"source\": {\n          \"body\": \"subscription subscribeToUser($user: String) {\n  user(user: $user) {\n    name\n  }\n}\",\n          \"locationOffset\": {\n            \"column\": 1,\n            \"line\": 1,\n          },\n          \"name\": \"gql\",\n        },\n        \"start\": 0,\n      },\n    },\n    \"variables\": {\n      \"user\": \"colin\",\n    },\n  },\n  \"stale\": false,\n}\n`;\n"
  },
  {
    "path": "packages/core/src/exchanges/cache.test.ts",
    "content": "import {\n  makeSubject,\n  map,\n  pipe,\n  publish,\n  Source,\n  Subject,\n  forEach,\n  scan,\n  toPromise,\n} from 'wonka';\nimport { vi, expect, it, beforeEach, describe } from 'vitest';\n\nimport { Client } from '../client';\nimport {\n  mutationOperation,\n  mutationResponse,\n  queryOperation,\n  queryResponse,\n  subscriptionOperation,\n  subscriptionResult,\n  undefinedQueryResponse,\n} from '../test-utils';\nimport { Operation, OperationResult, ExchangeInput } from '../types';\nimport { cacheExchange } from './cache';\n\nconst reexecuteOperation = vi.fn();\nconst dispatchDebug = vi.fn();\n\nlet response;\nlet exchangeArgs: ExchangeInput;\nlet forwardedOperations: Operation[];\nlet input: Subject<Operation>;\n\nbeforeEach(() => {\n  response = queryResponse;\n  forwardedOperations = [];\n  input = makeSubject<Operation>();\n\n  // Collect all forwarded operations\n  const forward = (s: Source<Operation>) => {\n    return pipe(\n      s,\n      map(op => {\n        forwardedOperations.push(op);\n        return response;\n      })\n    );\n  };\n\n  const client = {\n    reexecuteOperation: reexecuteOperation as any,\n  } as Client;\n\n  exchangeArgs = { forward, client, dispatchDebug };\n});\n\ndescribe('on query', () => {\n  it('forwards to next exchange when no cache hit', () => {\n    const { source: ops$, next, complete } = input;\n    const exchange = cacheExchange(exchangeArgs)(ops$);\n\n    publish(exchange);\n    next(queryOperation);\n    complete();\n    expect(forwardedOperations.length).toBe(1);\n    expect(reexecuteOperation).not.toBeCalled();\n  });\n\n  it('caches results', () => {\n    const { source: ops$, next, complete } = input;\n    const exchange = cacheExchange(exchangeArgs)(ops$);\n\n    publish(exchange);\n    next(queryOperation);\n    next(queryOperation);\n    complete();\n    expect(forwardedOperations.length).toBe(1);\n    expect(reexecuteOperation).not.toBeCalled();\n  });\n\n  it('respects cache-and-network', () => {\n    const { source: ops$, next, complete } = input;\n    const result = vi.fn();\n    const exchange = cacheExchange(exchangeArgs)(ops$);\n\n    pipe(exchange, forEach(result));\n    next(queryOperation);\n\n    next({\n      ...queryOperation,\n      context: {\n        ...queryOperation.context,\n        requestPolicy: 'cache-and-network',\n      },\n    });\n\n    complete();\n    expect(forwardedOperations.length).toBe(1);\n    expect(reexecuteOperation).toHaveBeenCalledTimes(1);\n    expect(result).toHaveBeenCalledTimes(2);\n    expect(result.mock.calls[1][0].stale).toBe(true);\n\n    expect(reexecuteOperation.mock.calls[0][0]).toEqual({\n      ...queryOperation,\n      context: { ...queryOperation.context, requestPolicy: 'network-only' },\n    });\n  });\n\n  it('respects cache-only', () => {\n    const { source: ops$, next, complete } = input;\n    const exchange = cacheExchange(exchangeArgs)(ops$);\n\n    publish(exchange);\n    next({\n      ...queryOperation,\n      context: {\n        ...queryOperation.context,\n        requestPolicy: 'cache-only',\n      },\n    });\n    complete();\n    expect(forwardedOperations.length).toBe(0);\n    expect(reexecuteOperation).not.toBeCalled();\n  });\n\n  describe('cache hit', () => {\n    it('is miss when operation is forwarded', () => {\n      const { source: ops$, next, complete } = input;\n      const exchange = cacheExchange(exchangeArgs)(ops$);\n\n      publish(exchange);\n      next(queryOperation);\n      complete();\n\n      expect(forwardedOperations[0].context).toHaveProperty(\n        'meta.cacheOutcome',\n        'miss'\n      );\n    });\n\n    it('is true when cached response is returned', async () => {\n      const { source: ops$, next, complete } = input;\n      const exchange = cacheExchange(exchangeArgs)(ops$);\n\n      const results$ = pipe(\n        exchange,\n        scan((acc, x) => [...acc, x], [] as OperationResult[]),\n        toPromise\n      );\n\n      publish(exchange);\n      next(queryOperation);\n      next(queryOperation);\n      complete();\n\n      const results = await results$;\n      expect(results[1].operation.context).toHaveProperty(\n        'meta.cacheOutcome',\n        'hit'\n      );\n    });\n  });\n});\n\ndescribe('on mutation', () => {\n  it('does not cache', () => {\n    response = mutationResponse;\n    const { source: ops$, next, complete } = input;\n    const exchange = cacheExchange(exchangeArgs)(ops$);\n\n    publish(exchange);\n    next(mutationOperation);\n    next(mutationOperation);\n    complete();\n    expect(forwardedOperations.length).toBe(2);\n    expect(reexecuteOperation).not.toBeCalled();\n  });\n});\n\ndescribe('on subscription', () => {\n  it('forwards subscriptions', () => {\n    response = subscriptionResult;\n    const { source: ops$, next, complete } = input;\n    const exchange = cacheExchange(exchangeArgs)(ops$);\n\n    publish(exchange);\n    next(subscriptionOperation);\n    next(subscriptionOperation);\n    complete();\n    expect(forwardedOperations.length).toBe(2);\n    expect(reexecuteOperation).not.toBeCalled();\n  });\n});\n\n// Empty query response implies the data propertys is undefined\ndescribe('on empty query response', () => {\n  beforeEach(() => {\n    response = undefinedQueryResponse;\n    forwardedOperations = [];\n    input = makeSubject<Operation>();\n\n    // Collect all forwarded operations\n    const forward = (s: Source<Operation>) => {\n      return pipe(\n        s,\n        map(op => {\n          forwardedOperations.push(op);\n          return response;\n        })\n      );\n    };\n\n    const client = {\n      reexecuteOperation: reexecuteOperation as any,\n    } as Client;\n\n    exchangeArgs = { forward, client, dispatchDebug };\n  });\n\n  it('does not cache response', () => {\n    const { source: ops$, next, complete } = input;\n    const exchange = cacheExchange(exchangeArgs)(ops$);\n\n    publish(exchange);\n    next(queryOperation);\n    next(queryOperation);\n    complete();\n    // 2 indicates it's not cached.\n    expect(forwardedOperations.length).toBe(2);\n    expect(reexecuteOperation).not.toBeCalled();\n  });\n});\n"
  },
  {
    "path": "packages/core/src/exchanges/cache.ts",
    "content": "/* eslint-disable @typescript-eslint/no-use-before-define */\nimport { filter, map, merge, pipe, tap } from 'wonka';\n\nimport type { Client } from '../client';\nimport type { Exchange, Operation, OperationResult } from '../types';\n\nimport {\n  makeOperation,\n  addMetadata,\n  collectTypenames,\n  formatDocument,\n  makeResult,\n} from '../utils';\n\ntype ResultCache = Map<number, OperationResult>;\ntype OperationCache = Map<string, Set<number>>;\n\nconst shouldSkip = ({ kind }: Operation) =>\n  kind !== 'mutation' && kind !== 'query';\n\n/** Adds unique typenames to query (for invalidating cache entries) */\nexport const mapTypeNames = (operation: Operation): Operation => {\n  const query = formatDocument(operation.query);\n  if (query !== operation.query) {\n    const formattedOperation = makeOperation(operation.kind, operation);\n    formattedOperation.query = query;\n    return formattedOperation;\n  } else {\n    return operation;\n  }\n};\n\n/** Default document cache exchange.\n *\n * @remarks\n * The default document cache in `urql` avoids sending the same GraphQL request\n * multiple times by caching it using the {@link Operation.key}. It will invalidate\n * query results automatically whenever it sees a mutation responses with matching\n * `__typename`s in their responses.\n *\n * The document cache will get the introspected `__typename` fields by modifying\n * your GraphQL operation documents using the {@link formatDocument} utility.\n *\n * This automatic invalidation strategy can fail if your query or mutation don’t\n * contain matching typenames, for instance, because the query contained an\n * empty list.\n * You can manually add hints for this exchange by specifying a list of\n * {@link OperationContext.additionalTypenames} for queries and mutations that\n * should invalidate one another.\n *\n * @see {@link https://urql.dev/goto/docs/basics/document-caching} for more information on this cache.\n */\nexport const cacheExchange: Exchange = ({ forward, client, dispatchDebug }) => {\n  const resultCache: ResultCache = new Map();\n  const operationCache: OperationCache = new Map();\n\n  const isOperationCached = (operation: Operation) =>\n    operation.kind === 'query' &&\n    operation.context.requestPolicy !== 'network-only' &&\n    (operation.context.requestPolicy === 'cache-only' ||\n      resultCache.has(operation.key));\n\n  return ops$ => {\n    const cachedOps$ = pipe(\n      ops$,\n      filter(op => !shouldSkip(op) && isOperationCached(op)),\n      map(operation => {\n        const cachedResult = resultCache.get(operation.key);\n\n        dispatchDebug({\n          operation,\n          ...(cachedResult\n            ? {\n                type: 'cacheHit',\n                message: 'The result was successfully retrieved from the cache',\n              }\n            : {\n                type: 'cacheMiss',\n                message: 'The result could not be retrieved from the cache',\n              }),\n        });\n\n        let result: OperationResult =\n          cachedResult ||\n          makeResult(operation, {\n            data: null,\n          });\n\n        result = {\n          ...result,\n          operation: addMetadata(operation, {\n            cacheOutcome: cachedResult ? 'hit' : 'miss',\n          }),\n        };\n\n        if (operation.context.requestPolicy === 'cache-and-network') {\n          result.stale = true;\n          reexecuteOperation(client, operation);\n        }\n\n        return result;\n      })\n    );\n\n    const forwardedOps$ = pipe(\n      merge([\n        pipe(\n          ops$,\n          filter(op => !shouldSkip(op) && !isOperationCached(op)),\n          map(mapTypeNames)\n        ),\n        pipe(\n          ops$,\n          filter(op => shouldSkip(op))\n        ),\n      ]),\n      map(op => addMetadata(op, { cacheOutcome: 'miss' })),\n      filter(\n        op => op.kind !== 'query' || op.context.requestPolicy !== 'cache-only'\n      ),\n      forward,\n      tap(response => {\n        let { operation } = response;\n        if (!operation) return;\n\n        let typenames = operation.context.additionalTypenames || [];\n        // NOTE: For now, we only respect `additionalTypenames` from subscriptions to\n        // avoid unexpected breaking changes\n        // We'd expect live queries or other update mechanisms to be more suitable rather\n        // than using subscriptions as “signals” to reexecute queries. However, if they’re\n        // just used as signals, it’s intuitive to hook them up using `additionalTypenames`\n        if (response.operation.kind !== 'subscription') {\n          typenames = collectTypenames(response.data).concat(typenames);\n        }\n\n        // Invalidates the cache given a mutation's response\n        if (\n          response.operation.kind === 'mutation' ||\n          response.operation.kind === 'subscription'\n        ) {\n          const pendingOperations = new Set<number>();\n\n          dispatchDebug({\n            type: 'cacheInvalidation',\n            message: `The following typenames have been invalidated: ${typenames}`,\n            operation,\n            data: { typenames, response },\n          });\n\n          for (let i = 0; i < typenames.length; i++) {\n            const typeName = typenames[i];\n            let operations = operationCache.get(typeName);\n            if (!operations)\n              operationCache.set(typeName, (operations = new Set()));\n            for (const key of operations.values()) pendingOperations.add(key);\n            operations.clear();\n          }\n\n          for (const key of pendingOperations.values()) {\n            if (resultCache.has(key)) {\n              operation = (resultCache.get(key) as OperationResult).operation;\n              resultCache.delete(key);\n              reexecuteOperation(client, operation);\n            }\n          }\n        } else if (operation.kind === 'query' && response.data) {\n          resultCache.set(operation.key, response);\n          for (let i = 0; i < typenames.length; i++) {\n            const typeName = typenames[i];\n            let operations = operationCache.get(typeName);\n            if (!operations)\n              operationCache.set(typeName, (operations = new Set()));\n            operations.add(operation.key);\n          }\n        }\n      })\n    );\n\n    return merge([cachedOps$, forwardedOps$]);\n  };\n};\n\n/** Reexecutes an `Operation` with the `network-only` request policy.\n * @internal\n */\nexport const reexecuteOperation = (client: Client, operation: Operation) => {\n  return client.reexecuteOperation(\n    makeOperation(operation.kind, operation, {\n      requestPolicy: 'network-only',\n    })\n  );\n};\n"
  },
  {
    "path": "packages/core/src/exchanges/compose.test.ts",
    "content": "import { empty, Source } from 'wonka';\nimport { vi, expect, it, beforeEach, describe } from 'vitest';\n\nimport { Exchange } from '../types';\nimport { composeExchanges } from './compose';\nimport { noop } from '../utils';\n\nconst mockClient = {} as any;\n\nconst forward = vi.fn();\nconst noopExchange: Exchange =\n  ({ forward }) =>\n  ops$ =>\n    forward(ops$);\n\nbeforeEach(() => {\n  vi.spyOn(Date, 'now').mockReturnValue(1234);\n});\n\nit('composes exchanges correctly', () => {\n  let counter = 0;\n\n  const firstExchange: Exchange = ({ client, forward }) => {\n    expect(client).toBe(mockClient);\n    expect(counter++).toBe(1);\n\n    return ops$ => {\n      expect(counter++).toBe(2);\n      return forward(ops$);\n    };\n  };\n\n  const secondExchange: Exchange = ({ client, forward }) => {\n    expect(client).toBe(mockClient);\n    expect(counter++).toBe(0);\n\n    return ops$ => {\n      expect(counter++).toBe(3);\n      return forward(ops$);\n    };\n  };\n\n  const exchange = composeExchanges([firstExchange, secondExchange]);\n  const outerFw = vi.fn(() => noopExchange) as any;\n\n  exchange({ client: mockClient, forward: outerFw, dispatchDebug: noop })(\n    empty as Source<any>\n  );\n  expect(outerFw).toHaveBeenCalled();\n  expect(counter).toBe(4);\n});\n\ndescribe('on dispatchDebug', () => {\n  it('dispatches debug event with exchange source name', () => {\n    const dispatchDebug = vi.fn();\n    const debugArgs = {\n      type: 'test',\n      message: 'Hello',\n    } as any;\n\n    const testExchange: Exchange = ({ dispatchDebug }) => {\n      dispatchDebug(debugArgs);\n      return () => empty as Source<any>;\n    };\n\n    composeExchanges([testExchange])({\n      client: mockClient,\n      forward,\n      dispatchDebug,\n    });\n\n    expect(dispatchDebug).toBeCalledTimes(1);\n    expect(dispatchDebug).toBeCalledWith({\n      ...debugArgs,\n      timestamp: Date.now(),\n      source: 'testExchange',\n    });\n  });\n});\n"
  },
  {
    "path": "packages/core/src/exchanges/compose.ts",
    "content": "import { share } from 'wonka';\nimport type { ExchangeIO, Exchange, ExchangeInput } from '../types';\n\n/** Composes an array of Exchanges into a single one.\n *\n * @param exchanges - An array of {@link Exchange | Exchanges}.\n * @returns - A composed {@link Exchange}.\n *\n * @remarks\n * `composeExchanges` returns an {@link Exchange} that when instantiated\n * composes the array of passed `Exchange`s into one, calling them from\n * right to left, with the prior `Exchange`’s {@link ExchangeIO} function\n * as the {@link ExchangeInput.forward} input.\n *\n * This simply merges all exchanges into one and is used by the {@link Client}\n * to merge the `exchanges` option it receives.\n *\n * @throws\n * In development, if {@link ExchangeInput.forward} is called repeatedly\n * by an {@link Exchange} an error is thrown, since `forward()` must only\n * be called once per `Exchange`.\n */\nexport const composeExchanges =\n  (exchanges: Exchange[]): Exchange =>\n  ({ client, forward, dispatchDebug }: ExchangeInput): ExchangeIO =>\n    exchanges.reduceRight((forward, exchange) => {\n      let forwarded = false;\n      return exchange({\n        client,\n        forward(operations$) {\n          if (process.env.NODE_ENV !== 'production') {\n            if (forwarded)\n              throw new Error(\n                'forward() must only be called once in each Exchange.'\n              );\n            forwarded = true;\n          }\n          return share(forward(share(operations$)));\n        },\n        dispatchDebug(event) {\n          dispatchDebug({\n            timestamp: Date.now(),\n            source: exchange.name,\n            ...event,\n          });\n        },\n      });\n    }, forward);\n"
  },
  {
    "path": "packages/core/src/exchanges/debug.test.ts",
    "content": "import { makeSubject, map, pipe, publish, Source, Subject } from 'wonka';\nimport { vi, expect, it, beforeEach, describe, afterEach } from 'vitest';\n\nimport { Client } from '../client';\nimport { queryOperation, queryResponse } from '../test-utils';\nimport { Operation } from '../types';\nimport { debugExchange } from './debug';\n\nlet exchangeArgs;\nlet forwardedOperations: Operation[];\nlet input: Subject<Operation>;\n\nbeforeEach(() => {\n  forwardedOperations = [];\n  input = makeSubject<Operation>();\n\n  // Collect all forwarded operations\n  const forward = (s: Source<Operation>) => {\n    return pipe(\n      s,\n      map(op => {\n        forwardedOperations.push(op);\n        return queryResponse;\n      })\n    );\n  };\n\n  exchangeArgs = { forward, subject: {} as Client };\n});\n\nit('forwards query operations correctly', async () => {\n  vi.spyOn(globalThis.console, 'debug').mockImplementation(() => {\n    /** Do NOthing */\n  });\n  const { source: ops$, next, complete } = input;\n  const exchange = debugExchange(exchangeArgs)(ops$);\n\n  publish(exchange);\n  next(queryOperation);\n  complete();\n  // eslint-disable-next-line no-console\n  expect(console.debug).toBeCalled();\n  // eslint-disable-next-line no-console\n  expect(console.debug).toBeCalledTimes(2);\n});\n\ndescribe('production', () => {\n  beforeEach(() => {\n    process.env.NODE_ENV = 'production';\n  });\n\n  afterEach(() => {\n    process.env.NODE_ENV = 'test';\n  });\n\n  it('is a noop in production', () => {\n    const { source: ops$ } = input;\n\n    debugExchange({\n      forward: ops => {\n        expect(ops).toBe(ops$);\n      },\n    } as any)(ops$);\n  });\n});\n"
  },
  {
    "path": "packages/core/src/exchanges/debug.ts",
    "content": "import { pipe, tap } from 'wonka';\nimport type { Exchange } from '../types';\n\n/** Simple log debugger exchange.\n *\n * @remarks\n * An exchange that logs incoming {@link Operation | Operations} and\n * {@link OperationResult | OperationResults} in development.\n *\n * This exchange is a no-op in production and often used in issue reporting\n * to understand certain usage patterns of `urql` without having access to\n * the original source code.\n *\n * Hint: When you report an issue you’re having with `urql`, adding\n * this as your first exchange and posting its output can speed up\n * issue triaging a lot!\n */\nexport const debugExchange: Exchange = ({ forward }) => {\n  if (process.env.NODE_ENV === 'production') {\n    return ops$ => forward(ops$);\n  } else {\n    return ops$ =>\n      pipe(\n        ops$,\n        // eslint-disable-next-line no-console\n        tap(op => console.debug('[Exchange debug]: Incoming operation: ', op)),\n        forward,\n        tap(result =>\n          // eslint-disable-next-line no-console\n          console.debug('[Exchange debug]: Completed operation: ', result)\n        )\n      );\n  }\n};\n"
  },
  {
    "path": "packages/core/src/exchanges/fallback.test.ts",
    "content": "import { forEach, fromValue, pipe } from 'wonka';\nimport { vi, expect, it, beforeEach, afterAll } from 'vitest';\n\nimport { queryOperation, teardownOperation } from '../test-utils';\nimport { fallbackExchange } from './fallback';\n\nconst consoleWarn = console.warn;\n\nconst dispatchDebug = vi.fn();\n\nbeforeEach(() => {\n  console.warn = vi.fn();\n});\n\nafterAll(() => {\n  console.warn = consoleWarn;\n});\n\nit('filters all results and warns about input', () => {\n  const res: any[] = [];\n\n  pipe(\n    fallbackExchange({ dispatchDebug })(fromValue(queryOperation)),\n    forEach(x => res.push(x))\n  );\n\n  expect(res.length).toBe(0);\n  expect(console.warn).toHaveBeenCalled();\n});\n\nit('filters all results and does not warn about teardown operations', () => {\n  const res: any[] = [];\n\n  pipe(\n    fallbackExchange({ dispatchDebug })(fromValue(teardownOperation)),\n    forEach(x => res.push(x))\n  );\n\n  expect(res.length).toBe(0);\n  expect(console.warn).not.toHaveBeenCalled();\n});\n"
  },
  {
    "path": "packages/core/src/exchanges/fallback.ts",
    "content": "import { filter, pipe, tap } from 'wonka';\nimport type { ExchangeIO, ExchangeInput } from '../types';\n\n/** Used by the `Client` as the last exchange to warn about unhandled operations.\n *\n * @remarks\n * In a normal setup, some operations may go unhandled when a {@link Client} isn’t set up\n * with the right exchanges.\n * For instance, a `Client` may be missing a fetch exchange, or an exchange handling subscriptions.\n * This {@link Exchange} is added by the `Client` automatically to log warnings about unhandled\n * {@link Operaiton | Operations} in development.\n */\nexport const fallbackExchange: ({\n  dispatchDebug,\n}: Pick<ExchangeInput, 'dispatchDebug'>) => ExchangeIO =\n  ({ dispatchDebug }) =>\n  ops$ => {\n    if (process.env.NODE_ENV !== 'production') {\n      ops$ = pipe(\n        ops$,\n        tap(operation => {\n          if (\n            operation.kind !== 'teardown' &&\n            process.env.NODE_ENV !== 'production'\n          ) {\n            const message = `No exchange has handled operations of kind \"${operation.kind}\". Check whether you've added an exchange responsible for these operations.`;\n\n            dispatchDebug({\n              type: 'fallbackCatch',\n              message,\n              operation,\n            });\n            console.warn(message);\n          }\n        })\n      );\n    }\n\n    // All operations that skipped through the entire exchange chain should be filtered from the output\n    return filter((_x): _x is never => false)(ops$);\n  };\n"
  },
  {
    "path": "packages/core/src/exchanges/fetch.test.ts",
    "content": "import { empty, fromValue, pipe, Source, subscribe, toPromise } from 'wonka';\nimport {\n  vi,\n  expect,\n  it,\n  beforeEach,\n  describe,\n  beforeAll,\n  Mock,\n  afterEach,\n  afterAll,\n} from 'vitest';\n\nimport { Client } from '../client';\nimport { makeOperation } from '../utils';\nimport { queryOperation } from '../test-utils';\nimport { OperationResult } from '../types';\nimport { fetchExchange } from './fetch';\n\nconst fetch = (globalThis as any).fetch as Mock;\nconst abort = vi.fn();\n\nconst abortError = new Error();\nabortError.name = 'AbortError';\n\nbeforeAll(() => {\n  (globalThis as any).AbortController = function AbortController() {\n    this.signal = undefined;\n    this.abort = abort;\n  };\n});\n\nafterEach(() => {\n  fetch.mockClear();\n  abort.mockClear();\n});\n\nafterAll(() => {\n  (globalThis as any).AbortController = undefined;\n});\n\nconst response = JSON.stringify({\n  status: 200,\n  data: {\n    data: {\n      user: 1200,\n    },\n  },\n});\n\nconst exchangeArgs = {\n  dispatchDebug: vi.fn(),\n  forward: () => empty as Source<OperationResult>,\n  client: {\n    debugTarget: {\n      dispatchEvent: vi.fn(),\n    },\n  } as any as Client,\n};\n\ndescribe('on success', () => {\n  beforeEach(() => {\n    fetch.mockResolvedValue({\n      status: 200,\n      headers: { get: () => 'application/json' },\n      text: vi.fn().mockResolvedValue(response),\n    });\n  });\n\n  it('returns response data', async () => {\n    const fetchOptions = vi.fn().mockReturnValue({});\n\n    const data = await pipe(\n      fromValue({\n        ...queryOperation,\n        context: {\n          ...queryOperation.context,\n          fetchOptions,\n        },\n      }),\n      fetchExchange(exchangeArgs),\n      toPromise\n    );\n\n    expect(data).toMatchSnapshot();\n    expect(fetchOptions).toHaveBeenCalled();\n    expect(fetch.mock.calls[0][1].body).toMatchSnapshot();\n  });\n});\n\ndescribe('on error', () => {\n  beforeEach(() => {\n    fetch.mockResolvedValue({\n      status: 400,\n      headers: { get: () => 'application/json' },\n      text: vi.fn().mockResolvedValue(JSON.stringify({})),\n    });\n  });\n\n  it('returns error data', async () => {\n    const data = await pipe(\n      fromValue(queryOperation),\n      fetchExchange(exchangeArgs),\n      toPromise\n    );\n\n    expect(data).toMatchSnapshot();\n  });\n\n  it('returns error data with status 400 and manual redirect mode', async () => {\n    const fetchOptions = vi.fn().mockReturnValue({ redirect: 'manual' });\n\n    const data = await pipe(\n      fromValue({\n        ...queryOperation,\n        context: {\n          ...queryOperation.context,\n          fetchOptions,\n        },\n      }),\n      fetchExchange(exchangeArgs),\n      toPromise\n    );\n\n    expect(data).toMatchSnapshot();\n  });\n\n  it('ignores the error when a result is available', async () => {\n    fetch.mockResolvedValue({\n      status: 400,\n      headers: { get: () => 'application/json' },\n      text: vi.fn().mockResolvedValue(response),\n    });\n\n    const data = await pipe(\n      fromValue(queryOperation),\n      fetchExchange(exchangeArgs),\n      toPromise\n    );\n\n    expect(data.data).toEqual(JSON.parse(response).data);\n  });\n});\n\ndescribe('on teardown', () => {\n  const fail = () => {\n    expect(true).toEqual(false);\n  };\n\n  it('does not start the outgoing request on immediate teardowns', async () => {\n    fetch.mockImplementation(async () => {\n      await new Promise(() => {\n        /*noop*/\n      });\n    });\n\n    const { unsubscribe } = pipe(\n      fromValue(queryOperation),\n      fetchExchange(exchangeArgs),\n      subscribe(fail)\n    );\n\n    unsubscribe();\n\n    // NOTE: We can only observe the async iterator's final run after a macro tick\n    await new Promise(resolve => setTimeout(resolve));\n    expect(fetch).toHaveBeenCalledTimes(0);\n    expect(abort).toHaveBeenCalledTimes(1);\n  });\n\n  it('aborts the outgoing request', async () => {\n    fetch.mockResolvedValue({\n      status: 200,\n      headers: new Map([['Content-Type', 'application/json']]),\n      text: vi.fn().mockResolvedValue('{ \"data\": null }'),\n    });\n\n    const { unsubscribe } = pipe(\n      fromValue(queryOperation),\n      fetchExchange(exchangeArgs),\n      subscribe(() => {\n        /*noop*/\n      })\n    );\n\n    await new Promise(resolve => setTimeout(resolve));\n    unsubscribe();\n\n    // NOTE: We can only observe the async iterator's final run after a macro tick\n    await new Promise(resolve => setTimeout(resolve));\n    expect(fetch).toHaveBeenCalledTimes(1);\n    expect(abort).toHaveBeenCalledTimes(1);\n  });\n\n  it('does not call the query', () => {\n    fetch.mockResolvedValue(new Response('text', { status: 200 }));\n\n    pipe(\n      fromValue(\n        makeOperation('teardown', queryOperation, queryOperation.context)\n      ),\n      fetchExchange(exchangeArgs),\n      subscribe(fail)\n    );\n\n    expect(fetch).toHaveBeenCalledTimes(0);\n    expect(abort).toHaveBeenCalledTimes(0);\n  });\n});\n"
  },
  {
    "path": "packages/core/src/exchanges/fetch.ts",
    "content": "/* eslint-disable @typescript-eslint/no-use-before-define */\nimport { filter, merge, mergeMap, pipe, takeUntil, onPush } from 'wonka';\n\nimport type { Exchange } from '../types';\nimport {\n  makeFetchBody,\n  makeFetchURL,\n  makeFetchOptions,\n  makeFetchSource,\n} from '../internal';\n\n/** Default GraphQL over HTTP fetch exchange.\n *\n * @remarks\n * The default fetch exchange in `urql` supports sending GraphQL over HTTP\n * requests, can optionally send GraphQL queries as GET requests, and\n * handles incremental multipart responses.\n *\n * This exchange does not handle persisted queries or multipart uploads.\n * Support for the former can be added using `@urql/exchange-persisted-fetch`\n * and the latter using `@urql/exchange-multipart-fetch`.\n *\n * Hint: The `fetchExchange` and the two other exchanges all use the built-in fetch\n * utilities in `@urql/core/internal`, which you can also use to implement\n * a customized fetch exchange.\n *\n * @see {@link makeFetchSource} for the shared utility calling the Fetch API.\n */\nexport const fetchExchange: Exchange = ({ forward, dispatchDebug }) => {\n  return ops$ => {\n    const fetchResults$ = pipe(\n      ops$,\n      filter(operation => {\n        return (\n          operation.kind !== 'teardown' &&\n          (operation.kind !== 'subscription' ||\n            !!operation.context.fetchSubscriptions)\n        );\n      }),\n      mergeMap(operation => {\n        const body = makeFetchBody(operation);\n        const url = makeFetchURL(operation, body);\n        const fetchOptions = makeFetchOptions(operation, body);\n\n        dispatchDebug({\n          type: 'fetchRequest',\n          message: 'A fetch request is being executed.',\n          operation,\n          data: {\n            url,\n            fetchOptions,\n          },\n        });\n\n        const source = pipe(\n          makeFetchSource(operation, url, fetchOptions),\n          takeUntil(\n            pipe(\n              ops$,\n              filter(op => op.kind === 'teardown' && op.key === operation.key)\n            )\n          )\n        );\n\n        if (process.env.NODE_ENV !== 'production') {\n          return pipe(\n            source,\n            onPush(result => {\n              const error = !result.data ? result.error : undefined;\n\n              dispatchDebug({\n                type: error ? 'fetchError' : 'fetchSuccess',\n                message: `A ${\n                  error ? 'failed' : 'successful'\n                } fetch response has been returned.`,\n                operation,\n                data: {\n                  url,\n                  fetchOptions,\n                  value: error || result,\n                },\n              });\n            })\n          );\n        }\n\n        return source;\n      })\n    );\n\n    const forward$ = pipe(\n      ops$,\n      filter(operation => {\n        return (\n          operation.kind === 'teardown' ||\n          (operation.kind === 'subscription' &&\n            !operation.context.fetchSubscriptions)\n        );\n      }),\n      forward\n    );\n\n    return merge([fetchResults$, forward$]);\n  };\n};\n"
  },
  {
    "path": "packages/core/src/exchanges/index.ts",
    "content": "export { ssrExchange } from './ssr';\nexport { cacheExchange } from './cache';\nexport { subscriptionExchange } from './subscription';\nexport { debugExchange } from './debug';\nexport { fetchExchange } from './fetch';\nexport { composeExchanges } from './compose';\n\nexport type {\n  SerializedResult,\n  SSRExchangeParams,\n  SSRExchange,\n  SSRData,\n} from './ssr';\n\nexport type {\n  SubscriptionOperation,\n  SubscriptionForwarder,\n  SubscriptionExchangeOpts,\n} from './subscription';\n\nexport { mapExchange, mapExchange as errorExchange } from './map';\nexport type { MapExchangeOpts } from './map';\n"
  },
  {
    "path": "packages/core/src/exchanges/map.test.ts",
    "content": "import { map, tap, pipe, fromValue, toArray, toPromise } from 'wonka';\nimport { vi, expect, describe, it } from 'vitest';\n\nimport { Client } from '../client';\nimport { queryResponse, queryOperation } from '../test-utils';\nimport { Operation } from '../types';\nimport { mapExchange } from './map';\n\nimport {\n  makeOperation,\n  makeErrorResult,\n  makeResult,\n  CombinedError,\n} from '../utils';\n\ndescribe('onOperation', () => {\n  it('triggers and maps on operations', () => {\n    const mockOperation = makeOperation('query', queryOperation, {\n      ...queryOperation.context,\n      mock: true,\n    });\n\n    const onOperation = vi.fn().mockReturnValue(mockOperation);\n    const onExchangeResult = vi.fn();\n\n    const exchangeArgs = {\n      forward: op$ =>\n        pipe(\n          op$,\n          tap(onExchangeResult),\n          map((operation: Operation) => makeResult(operation, { data: null }))\n        ),\n      client: {} as Client,\n      dispatchDebug: () => null,\n    };\n\n    pipe(\n      fromValue(queryOperation),\n      mapExchange({ onOperation })(exchangeArgs),\n      toArray\n    );\n\n    expect(onOperation).toBeCalledTimes(1);\n    expect(onOperation).toBeCalledWith(queryOperation);\n    expect(onExchangeResult).toBeCalledTimes(1);\n    expect(onExchangeResult).toBeCalledWith(mockOperation);\n  });\n\n  it('triggers and forwards identity when returning undefined', () => {\n    const onOperation = vi.fn().mockReturnValue(undefined);\n    const onExchangeResult = vi.fn();\n\n    const exchangeArgs = {\n      forward: op$ =>\n        pipe(\n          op$,\n          tap(onExchangeResult),\n          map((operation: Operation) => makeResult(operation, { data: null }))\n        ),\n      client: {} as Client,\n      dispatchDebug: () => null,\n    };\n\n    pipe(\n      fromValue(queryOperation),\n      mapExchange({ onOperation })(exchangeArgs),\n      toArray\n    );\n\n    expect(onOperation).toBeCalledTimes(1);\n    expect(onOperation).toBeCalledWith(queryOperation);\n    expect(onExchangeResult).toBeCalledTimes(1);\n    expect(onExchangeResult).toBeCalledWith(queryOperation);\n  });\n\n  it('awaits returned promises as needed', async () => {\n    const mockOperation = makeOperation('query', queryOperation, {\n      ...queryOperation.context,\n      mock: true,\n    });\n\n    const onOperation = vi.fn().mockResolvedValue(mockOperation);\n    const onExchangeResult = vi.fn();\n\n    const exchangeArgs = {\n      forward: op$ =>\n        pipe(\n          op$,\n          tap(onExchangeResult),\n          map((operation: Operation) => makeResult(operation, { data: null }))\n        ),\n      client: {} as Client,\n      dispatchDebug: () => null,\n    };\n\n    await pipe(\n      fromValue(queryOperation),\n      mapExchange({ onOperation })(exchangeArgs),\n      toPromise\n    );\n\n    expect(onOperation).toBeCalledTimes(1);\n    expect(onOperation).toBeCalledWith(queryOperation);\n    expect(onExchangeResult).toBeCalledTimes(1);\n    expect(onExchangeResult).toBeCalledWith(mockOperation);\n  });\n});\n\ndescribe('onResult', () => {\n  it('triggers and maps on results', async () => {\n    const mockOperation = makeOperation('query', queryOperation, {\n      ...queryOperation.context,\n      mock: true,\n    });\n\n    const mockResult = makeErrorResult(mockOperation, new Error('Mock'));\n    const onResult = vi.fn().mockReturnValue(mockResult);\n    const onExchangeResult = vi.fn();\n\n    const exchangeArgs = {\n      forward: op$ =>\n        pipe(\n          op$,\n          map((operation: Operation) => makeResult(operation, { data: null }))\n        ),\n      client: {} as Client,\n      dispatchDebug: () => null,\n    };\n\n    pipe(\n      fromValue(queryOperation),\n      mapExchange({ onResult })(exchangeArgs),\n      tap(onExchangeResult),\n      toArray\n    );\n\n    expect(onResult).toBeCalledTimes(1);\n    expect(onResult).toBeCalledWith(makeResult(queryOperation, { data: null }));\n    expect(onExchangeResult).toBeCalledTimes(1);\n    expect(onExchangeResult).toBeCalledWith(mockResult);\n  });\n\n  it('triggers and forwards identity when returning undefined', async () => {\n    const onResult = vi.fn().mockReturnValue(undefined);\n    const onExchangeResult = vi.fn();\n\n    const exchangeArgs = {\n      forward: op$ =>\n        pipe(\n          op$,\n          map((operation: Operation) => makeResult(operation, { data: null }))\n        ),\n      client: {} as Client,\n      dispatchDebug: () => null,\n    };\n\n    pipe(\n      fromValue(queryOperation),\n      mapExchange({ onResult })(exchangeArgs),\n      tap(onExchangeResult),\n      toArray\n    );\n\n    const result = makeResult(queryOperation, { data: null });\n    expect(onResult).toBeCalledTimes(1);\n    expect(onResult).toBeCalledWith(result);\n    expect(onExchangeResult).toBeCalledTimes(1);\n    expect(onExchangeResult).toBeCalledWith(result);\n  });\n\n  it('awaits returned promises as needed', async () => {\n    const mockOperation = makeOperation('query', queryOperation, {\n      ...queryOperation.context,\n      mock: true,\n    });\n\n    const mockResult = makeErrorResult(mockOperation, new Error('Mock'));\n    const onResult = vi.fn().mockResolvedValue(mockResult);\n    const onExchangeResult = vi.fn();\n\n    const exchangeArgs = {\n      forward: op$ =>\n        pipe(\n          op$,\n          map((operation: Operation) => makeResult(operation, { data: null }))\n        ),\n      client: {} as Client,\n      dispatchDebug: () => null,\n    };\n\n    await pipe(\n      fromValue(queryOperation),\n      mapExchange({ onResult })(exchangeArgs),\n      tap(onExchangeResult),\n      toPromise\n    );\n\n    expect(onResult).toBeCalledTimes(1);\n    expect(onResult).toBeCalledWith(makeResult(queryOperation, { data: null }));\n    expect(onExchangeResult).toBeCalledTimes(1);\n    expect(onExchangeResult).toBeCalledWith(mockResult);\n  });\n});\n\ndescribe('onError', () => {\n  it('does not trigger when there are no errors', async () => {\n    const onError = vi.fn();\n\n    const exchangeArgs = {\n      forward: op$ =>\n        pipe(\n          op$,\n          map((operation: Operation) => ({ ...queryResponse, operation }))\n        ),\n      client: {} as Client,\n      dispatchDebug: () => null,\n    };\n\n    pipe(\n      fromValue(queryOperation),\n      mapExchange({ onError })(exchangeArgs),\n      toArray\n    );\n\n    expect(onError).toBeCalledTimes(0);\n  });\n\n  it('triggers correctly when the operations has an error', async () => {\n    const onError = vi.fn();\n    const error = new Error('Sad times');\n\n    const exchangeArgs = {\n      forward: op$ =>\n        pipe(\n          op$,\n          map((operation: Operation) => makeErrorResult(operation, error))\n        ),\n      client: {} as Client,\n      dispatchDebug: () => null,\n    };\n\n    pipe(\n      fromValue(queryOperation),\n      mapExchange({ onError })(exchangeArgs),\n      toArray\n    );\n\n    expect(onError).toBeCalledTimes(1);\n    expect(onError).toBeCalledWith(\n      new CombinedError({ networkError: error }),\n      queryOperation\n    );\n  });\n});\n"
  },
  {
    "path": "packages/core/src/exchanges/map.ts",
    "content": "import { mergeMap, fromValue, fromPromise, pipe } from 'wonka';\nimport type { Operation, OperationResult, Exchange } from '../types';\nimport type { CombinedError } from '../utils';\n\n/** Options for the `mapExchange` allowing it to react to incoming operations, results, or errors. */\nexport interface MapExchangeOpts {\n  /** Accepts a callback for incoming `Operation`s.\n   *\n   * @param operation - An {@link Operation} that the {@link mapExchange} received.\n   * @returns optionally a new {@link Operation} replacing the original.\n   *\n   * @remarks\n   * You may return new {@link Operation | Operations} from this function replacing\n   * the original that the {@link mapExchange} received.\n   * It’s recommended that you use the {@link makeOperation} utility to create a copy\n   * of the original when you do this. (However, this isn’t required)\n   *\n   * Hint: The callback may also be promisified and return a new {@link Operation} asynchronously,\n   * provided you place your {@link mapExchange} after all synchronous {@link Exchange | Exchanges},\n   * like after your `cacheExchange`.\n   */\n  onOperation?(operation: Operation): Promise<Operation> | Operation | void;\n  /** Accepts a callback for incoming `OperationResult`s.\n   *\n   * @param result - An {@link OperationResult} that the {@link mapExchange} received.\n   * @returns optionally a new {@link OperationResult} replacing the original.\n   *\n   * @remarks\n   * This callback may optionally return a new {@link OperationResult} that replaces the original,\n   * which you can use to modify incoming API results.\n   *\n   * Hint: The callback may also be promisified and return a new {@link Operation} asynchronously,\n   * provided you place your {@link mapExchange} after all synchronous {@link Exchange | Exchanges},\n   * like after your `cacheExchange`.\n   */\n  onResult?(\n    result: OperationResult\n  ): Promise<OperationResult> | OperationResult | void;\n  /** Accepts a callback for incoming `CombinedError`s.\n   *\n   * @param error - A {@link CombinedError} that an incoming {@link OperationResult} contained.\n   * @param operation - The {@link Operation} of the incoming {@link OperationResult}.\n   *\n   * @remarks\n   * The callback may also be promisified and return a new {@link Operation} asynchronously,\n   * provided you place your {@link mapExchange} after all synchronous {@link Exchange | Exchanges},\n   * like after your `cacheExchange`.\n   */\n  onError?(error: CombinedError, operation: Operation): void;\n}\n\n/** Creates an `Exchange` mapping over incoming operations, results, and/or errors.\n *\n * @param opts - A {@link MapExchangeOpts} configuration object, containing the callbacks the `mapExchange` will use.\n * @returns the created {@link Exchange}\n *\n * @remarks\n * The `mapExchange` may be used to react to or modify incoming {@link Operation | Operations}\n * and {@link OperationResult | OperationResults}. Optionally, it can also modify these\n * asynchronously, when a promise is returned from the callbacks.\n *\n * This is useful to, for instance, add an authentication token to a given request, when\n * the `@urql/exchange-auth` package would be overkill.\n *\n * It can also accept an `onError` callback, which can be used to react to incoming\n * {@link CombinedError | CombinedErrors} on results, and trigger side-effects.\n *\n */\nexport const mapExchange = ({\n  onOperation,\n  onResult,\n  onError,\n}: MapExchangeOpts): Exchange => {\n  return ({ forward }) =>\n    ops$ => {\n      return pipe(\n        pipe(\n          ops$,\n          mergeMap(operation => {\n            const newOperation =\n              (onOperation && onOperation(operation)) || operation;\n            return 'then' in newOperation\n              ? fromPromise(newOperation)\n              : fromValue(newOperation);\n          })\n        ),\n        forward,\n        mergeMap(result => {\n          if (onError && result.error) onError(result.error, result.operation);\n          const newResult = (onResult && onResult(result)) || result;\n          return 'then' in newResult\n            ? fromPromise(newResult)\n            : fromValue(newResult);\n        })\n      );\n    };\n};\n"
  },
  {
    "path": "packages/core/src/exchanges/ssr.test.ts",
    "content": "import { makeSubject, pipe, map, publish, forEach, Subject } from 'wonka';\nimport { vi, expect, it, beforeEach, afterEach } from 'vitest';\n\nimport { Client } from '../client';\nimport { queryOperation, queryResponse } from '../test-utils';\nimport { ExchangeIO, Operation, OperationResult } from '../types';\nimport { CombinedError, formatDocument } from '../utils';\nimport { ssrExchange } from './ssr';\n\nlet forward: ExchangeIO;\nlet exchangeInput;\nlet client: Client;\nlet input: Subject<Operation>;\nlet output;\n\nconst serializedQueryResponse = {\n  ...queryResponse,\n  data: JSON.stringify(queryResponse.data),\n};\n\nbeforeEach(() => {\n  input = makeSubject<Operation>();\n  output = vi.fn(operation => ({ operation }));\n  forward = ops$ => pipe(ops$, map(output));\n  client = { suspense: true } as any;\n  exchangeInput = { forward, client };\n});\n\nafterEach(() => {\n  output.mockClear();\n});\n\nit('caches query results correctly', () => {\n  output.mockReturnValueOnce(queryResponse);\n\n  const ssr = ssrExchange();\n  const { source: ops$, next } = input;\n  const exchange = ssr(exchangeInput)(ops$);\n\n  publish(exchange);\n  next(queryOperation);\n\n  const data = ssr.extractData();\n  expect(Object.keys(data)).toEqual(['' + queryOperation.key]);\n\n  expect(data).toEqual({\n    [queryOperation.key]: {\n      data: serializedQueryResponse.data,\n      error: undefined,\n      hasNext: false,\n    },\n  });\n});\n\nit('serializes query results quickly', () => {\n  const result: OperationResult = {\n    ...queryResponse,\n    operation: queryOperation,\n    data: {\n      user: {\n        name: 'Clive',\n      },\n    },\n  };\n\n  const serializedQueryResponse = {\n    ...result,\n    data: JSON.stringify(result.data),\n  };\n\n  output.mockReturnValueOnce(result);\n\n  const ssr = ssrExchange();\n  const { source: ops$, next } = input;\n  const exchange = ssr(exchangeInput)(ops$);\n\n  publish(exchange);\n  next(queryOperation);\n  result.data.user.name = 'Not Clive';\n\n  const data = ssr.extractData();\n  expect(Object.keys(data)).toEqual(['' + queryOperation.key]);\n\n  expect(data).toEqual({\n    [queryOperation.key]: {\n      data: serializedQueryResponse.data,\n      error: undefined,\n      hasNext: false,\n    },\n  });\n});\n\nit('caches errored query results correctly', () => {\n  output.mockReturnValueOnce({\n    ...queryResponse,\n    data: null,\n    error: new CombinedError({\n      graphQLErrors: ['Oh no!'],\n    }),\n  });\n\n  const ssr = ssrExchange();\n  const { source: ops$, next } = input;\n  const exchange = ssr(exchangeInput)(ops$);\n\n  publish(exchange);\n  next(queryOperation);\n\n  const data = ssr.extractData();\n  expect(Object.keys(data)).toEqual(['' + queryOperation.key]);\n\n  expect(data).toEqual({\n    [queryOperation.key]: {\n      data: 'null',\n      error: {\n        graphQLErrors: [\n          {\n            extensions: {},\n            message: 'Oh no!',\n            path: undefined,\n          },\n        ],\n        networkError: undefined,\n      },\n      hasNext: false,\n    },\n  });\n});\n\nit('caches extensions when includeExtensions=true', () => {\n  output.mockReturnValueOnce({\n    ...queryResponse,\n    extensions: {\n      foo: 'bar',\n    },\n  });\n\n  const ssr = ssrExchange({\n    includeExtensions: true,\n  });\n  const { source: ops$, next } = input;\n  const exchange = ssr(exchangeInput)(ops$);\n\n  publish(exchange);\n  next(queryOperation);\n\n  const data = ssr.extractData();\n  expect(Object.keys(data)).toEqual(['' + queryOperation.key]);\n\n  expect(data).toEqual({\n    [queryOperation.key]: {\n      data: '{\"user\":{\"name\":\"Clive\"}}',\n      extensions: '{\"foo\":\"bar\"}',\n      hasNext: false,\n    },\n  });\n});\n\nit('caches complex GraphQLErrors in query results correctly', () => {\n  output.mockReturnValueOnce({\n    ...queryResponse,\n    data: null,\n    error: new CombinedError({\n      graphQLErrors: [\n        {\n          message: 'Oh no!',\n          path: ['Query'],\n          extensions: { test: true },\n        },\n      ],\n    }),\n  });\n\n  const ssr = ssrExchange();\n  const { source: ops$, next } = input;\n  const exchange = ssr(exchangeInput)(ops$);\n\n  publish(exchange);\n  next(queryOperation);\n\n  const error = ssr.extractData()[queryOperation.key]!.error;\n\n  expect(error).toHaveProperty('graphQLErrors.0.message', 'Oh no!');\n  expect(error).toHaveProperty('graphQLErrors.0.path', ['Query']);\n  expect(error).toHaveProperty('graphQLErrors.0.extensions.test', true);\n});\n\nit('resolves cached query results correctly', () => {\n  const onPush = vi.fn();\n\n  const ssr = ssrExchange({\n    initialState: { [queryOperation.key]: serializedQueryResponse as any },\n  });\n\n  const { source: ops$, next } = input;\n  const exchange = ssr(exchangeInput)(ops$);\n\n  pipe(exchange, forEach(onPush));\n  next(queryOperation);\n\n  const data = ssr.extractData();\n  expect(Object.keys(data).length).toBe(1);\n  expect(output).not.toHaveBeenCalled();\n  expect(onPush).toHaveBeenCalledWith({\n    ...queryResponse,\n    stale: false,\n    hasNext: false,\n    operation: {\n      ...queryResponse.operation,\n      context: {\n        ...queryResponse.operation.context,\n        meta: {\n          cacheOutcome: 'hit',\n        },\n      },\n    },\n  });\n});\n\nit('resolves deferred, cached query results correctly', () => {\n  const onPush = vi.fn();\n\n  const ssr = ssrExchange({\n    isClient: true,\n    initialState: {\n      [queryOperation.key]: {\n        ...(serializedQueryResponse as any),\n        hasNext: true,\n      },\n    },\n  });\n\n  const { source: ops$, next } = input;\n  const exchange = ssr(exchangeInput)(ops$);\n\n  pipe(exchange, forEach(onPush));\n  next(queryOperation);\n\n  const data = ssr.extractData();\n  expect(Object.keys(data).length).toBe(1);\n  expect(output).toHaveBeenCalledTimes(1);\n  expect(onPush).toHaveBeenCalledTimes(2);\n  expect(onPush.mock.calls[1][0]).toEqual({\n    ...queryResponse,\n    hasNext: true,\n    stale: false,\n    operation: {\n      ...queryResponse.operation,\n      context: {\n        ...queryResponse.operation.context,\n        meta: {\n          cacheOutcome: 'hit',\n        },\n      },\n    },\n  });\n\n  expect(output.mock.calls[0][0].query).toBe(\n    formatDocument(queryOperation.query)\n  );\n});\n\nit('deletes cached results in non-suspense environments', async () => {\n  client.suspense = false;\n  const onPush = vi.fn();\n  const ssr = ssrExchange();\n\n  ssr.restoreData({ [queryOperation.key]: serializedQueryResponse as any });\n  expect(Object.keys(ssr.extractData()).length).toBe(1);\n\n  const { source: ops$, next } = input;\n  const exchange = ssr(exchangeInput)(ops$);\n\n  pipe(exchange, forEach(onPush));\n  next(queryOperation);\n\n  await Promise.resolve();\n\n  expect(Object.keys(ssr.extractData()).length).toBe(0);\n  expect(onPush).toHaveBeenCalledWith({\n    ...queryResponse,\n    stale: false,\n    hasNext: false,\n    operation: {\n      ...queryResponse.operation,\n      context: {\n        ...queryResponse.operation.context,\n        meta: {\n          cacheOutcome: 'hit',\n        },\n      },\n    },\n  });\n\n  // NOTE: The operation should not be duplicated\n  expect(output).not.toHaveBeenCalled();\n});\n\nit('never allows restoration of invalidated results', async () => {\n  client.suspense = false;\n\n  const onPush = vi.fn();\n  const initialState = { [queryOperation.key]: serializedQueryResponse as any };\n\n  const ssr = ssrExchange({\n    isClient: true,\n    initialState: { ...initialState },\n  });\n\n  const { source: ops$, next } = input;\n  const exchange = ssr(exchangeInput)(ops$);\n\n  pipe(exchange, forEach(onPush));\n  next(queryOperation);\n\n  await Promise.resolve();\n\n  expect(Object.keys(ssr.extractData()).length).toBe(0);\n  expect(onPush).toHaveBeenCalledTimes(1);\n  expect(output).not.toHaveBeenCalled();\n\n  ssr.restoreData(initialState);\n  expect(Object.keys(ssr.extractData()).length).toBe(0);\n\n  next(queryOperation);\n  expect(onPush).toHaveBeenCalledTimes(2);\n  expect(output).toHaveBeenCalledTimes(1);\n});\n"
  },
  {
    "path": "packages/core/src/exchanges/ssr.ts",
    "content": "import type { GraphQLError } from '../utils/graphql';\nimport { pipe, filter, merge, map, tap } from 'wonka';\nimport type { Exchange, OperationResult, Operation } from '../types';\nimport { addMetadata, CombinedError } from '../utils';\nimport { reexecuteOperation, mapTypeNames } from './cache';\n\n/** A serialized version of an {@link OperationResult}.\n *\n * @remarks\n * All properties are serialized separately as JSON strings, except for the\n * {@link CombinedError} to speed up JS parsing speed, even if a result doesn’t\n * end up being used.\n *\n * @internal\n */\nexport interface SerializedResult {\n  hasNext?: boolean;\n  /** JSON-serialized version of {@link OperationResult.data}. */\n  data?: string | undefined; // JSON string of data\n  /** JSON-serialized version of {@link OperationResult.extensions}. */\n  extensions?: string | undefined;\n  /** JSON version of {@link CombinedError}. */\n  error?: {\n    graphQLErrors: Array<Partial<GraphQLError> | string>;\n    networkError?: string;\n  };\n}\n\n/** A dictionary of {@link Operation.key} keys to serializable {@link SerializedResult} objects.\n *\n * @remarks\n * It’s not recommended to modify the serialized data manually, however, multiple payloads of\n * this dictionary may safely be merged and combined.\n */\nexport interface SSRData {\n  [key: string]: SerializedResult;\n}\n\n/** Options for the `ssrExchange` allowing it to either operate on the server- or client-side. */\nexport interface SSRExchangeParams {\n  /** Indicates to the {@link SSRExchange} whether it's currently in server-side or client-side mode.\n   *\n   * @remarks\n   * Depending on this option, the {@link SSRExchange} will either capture or replay results.\n   * When `true`, it’s in client-side mode and results will be serialized. When `false`, it’ll\n   * use its deserialized data and replay results from it.\n   */\n  isClient?: boolean;\n  /** May be used on the client-side to pass the {@link SSRExchange} serialized data from the server-side.\n   *\n   * @remarks\n   * Alternatively, {@link SSRExchange.restoreData} may be called to imperatively add serialized data to\n   * the exchange.\n   *\n   * Hint: This method also works on the server-side to add to the initial serialized data, which enables\n   * you to combine multiple {@link SSRExchange} results, as needed.\n   */\n  initialState?: SSRData;\n  /** Forces a new API request to be sent in the background after replaying the deserialized result.\n   *\n   * @remarks\n   * Similarly to the `cache-and-network` {@link RequestPolicy}, this option tells the {@link SSRExchange}\n   * to send a new API request for the {@link Operation} after replaying a serialized result.\n   *\n   * Hint: This is useful when you're caching SSR results and need the client-side to update itself after\n   * rendering the initial serialized SSR results.\n   */\n  staleWhileRevalidate?: boolean;\n  /** Forces {@link OperationResult.extensions} to be serialized alongside the rest of a result.\n   *\n   * @remarks\n   * Entries in the `extension` object of a GraphQL result are often non-standard metdata, and many\n   * APIs use it for data that changes between every request. As such, the {@link SSRExchange} will\n   * not serialize this data by default, unless this flag is set.\n   */\n  includeExtensions?: boolean;\n}\n\n/** An `SSRExchange` either in server-side mode, serializing results, or client-side mode, deserializing and replaying results..\n *\n * @remarks\n * This same {@link Exchange} is used in your code both for the client-side and server-side as it’s “universal”\n * and can be put into either client-side or server-side mode using the {@link SSRExchangeParams.isClient} flag.\n *\n * In server-side mode, the `ssrExchange` will “record” results it sees from your API and provide them for you\n * to send to the client-side using the {@link SSRExchange.extractData} method.\n *\n * In client-side mode, the `ssrExchange` will use these serialized results, rehydrated either using\n * {@link SSRExchange.restoreData} or {@link SSRexchangeParams.initialState}, to replay results the\n * server-side has seen and sent before.\n *\n * Each serialized result will only be replayed once, as it’s assumed that your cache exchange will have the\n * results cached afterwards.\n */\nexport interface SSRExchange extends Exchange {\n  /** Client-side method to add serialized results to the {@link SSRExchange}.\n   * @param data - {@link SSRData},\n   */\n  restoreData(data: SSRData): void;\n  /** Server-side method to get all serialized results the {@link SSRExchange} has captured.\n   * @returns an {@link SSRData} dictionary.\n   */\n  extractData(): SSRData;\n}\n\n/** Serialize an OperationResult to plain JSON */\nconst serializeResult = (\n  result: OperationResult,\n  includeExtensions: boolean\n): SerializedResult => {\n  const serialized: SerializedResult = {\n    hasNext: result.hasNext,\n  };\n\n  if (result.data !== undefined) {\n    serialized.data = JSON.stringify(result.data);\n  }\n\n  if (includeExtensions && result.extensions !== undefined) {\n    serialized.extensions = JSON.stringify(result.extensions);\n  }\n\n  if (result.error) {\n    serialized.error = {\n      graphQLErrors: result.error.graphQLErrors.map(error => {\n        if (!error.path && !error.extensions) return error.message;\n\n        return {\n          message: error.message,\n          path: error.path,\n          extensions: error.extensions,\n        };\n      }),\n    };\n\n    if (result.error.networkError) {\n      serialized.error.networkError = '' + result.error.networkError;\n    }\n  }\n\n  return serialized;\n};\n\n/** Deserialize plain JSON to an OperationResult\n * @internal\n */\nconst deserializeResult = (\n  operation: Operation,\n  result: SerializedResult,\n  includeExtensions: boolean\n): OperationResult => ({\n  operation,\n  data: result.data ? JSON.parse(result.data) : undefined,\n  extensions:\n    includeExtensions && result.extensions\n      ? JSON.parse(result.extensions)\n      : undefined,\n  error: result.error\n    ? new CombinedError({\n        networkError: result.error.networkError\n          ? new Error(result.error.networkError)\n          : undefined,\n        graphQLErrors: result.error.graphQLErrors,\n      })\n    : undefined,\n  stale: false,\n  hasNext: !!result.hasNext,\n});\n\nconst revalidated = new Set<number>();\n\n/** Creates a server-side rendering `Exchange` that either captures responses on the server-side or replays them on the client-side.\n *\n * @param params - An {@link SSRExchangeParams} configuration object.\n * @returns the created {@link SSRExchange}\n *\n * @remarks\n * When dealing with server-side rendering, we essentially have two {@link Client | Clients} making requests,\n * the server-side client, and the client-side one. The `ssrExchange` helps implementing a tiny cache on both\n * sides that:\n *\n * - captures results on the server-side which it can serialize,\n * - replays results on the client-side that it deserialized from the server-side.\n *\n * Hint: The `ssrExchange` is basically an exchange that acts like a replacement for any fetch exchange\n * temporarily. As such, you should place it after your cache exchange but in front of any fetch exchange.\n */\nexport const ssrExchange = (params: SSRExchangeParams = {}): SSRExchange => {\n  const staleWhileRevalidate = !!params.staleWhileRevalidate;\n  const includeExtensions = !!params.includeExtensions;\n  const data: Record<string, SerializedResult | null> = {};\n\n  // On the client-side, we delete results from the cache as they're resolved\n  // this is delayed so that concurrent queries don't delete each other's data\n  const invalidateQueue: number[] = [];\n  const invalidate = (result: OperationResult) => {\n    invalidateQueue.push(result.operation.key);\n    if (invalidateQueue.length === 1) {\n      Promise.resolve().then(() => {\n        let key: number | void;\n        while ((key = invalidateQueue.shift())) {\n          data[key] = null;\n        }\n      });\n    }\n  };\n\n  // The SSR Exchange is a temporary cache that can populate results into data for suspense\n  // On the client it can be used to retrieve these temporary results from a rehydrated cache\n  const ssr: SSRExchange =\n    ({ client, forward }) =>\n    ops$ => {\n      // params.isClient tells us whether we're on the client-side\n      // By default we assume that we're on the client if suspense-mode is disabled\n      const isClient =\n        params && typeof params.isClient === 'boolean'\n          ? !!params.isClient\n          : !client.suspense;\n\n      let forwardedOps$ = pipe(\n        ops$,\n        filter(\n          operation =>\n            operation.kind === 'teardown' ||\n            !data[operation.key] ||\n            !!data[operation.key]!.hasNext ||\n            operation.context.requestPolicy === 'network-only'\n        ),\n        map(mapTypeNames),\n        forward\n      );\n\n      // NOTE: Since below we might delete the cached entry after accessing\n      // it once, cachedOps$ needs to be merged after forwardedOps$\n      let cachedOps$ = pipe(\n        ops$,\n        filter(\n          operation =>\n            operation.kind !== 'teardown' &&\n            !!data[operation.key] &&\n            operation.context.requestPolicy !== 'network-only'\n        ),\n        map(op => {\n          const serialized = data[op.key]!;\n          const cachedResult = deserializeResult(\n            op,\n            serialized,\n            includeExtensions\n          );\n\n          if (staleWhileRevalidate && !revalidated.has(op.key)) {\n            cachedResult.stale = true;\n            revalidated.add(op.key);\n            reexecuteOperation(client, op);\n          }\n\n          const result: OperationResult = {\n            ...cachedResult,\n            operation: addMetadata(op, {\n              cacheOutcome: 'hit',\n            }),\n          };\n          return result;\n        })\n      );\n\n      if (!isClient) {\n        // On the server we cache results in the cache as they're resolved\n        forwardedOps$ = pipe(\n          forwardedOps$,\n          tap((result: OperationResult) => {\n            const { operation } = result;\n            if (operation.kind !== 'mutation') {\n              const serialized = serializeResult(result, includeExtensions);\n              data[operation.key] = serialized;\n            }\n          })\n        );\n      } else {\n        // On the client we delete results from the cache as they're resolved\n        cachedOps$ = pipe(cachedOps$, tap(invalidate));\n      }\n\n      return merge([forwardedOps$, cachedOps$]);\n    };\n\n  ssr.restoreData = (restore: SSRData) => {\n    for (const key in restore) {\n      // We only restore data that hasn't been previously invalidated\n      if (data[key] !== null) {\n        data[key] = restore[key];\n      }\n    }\n  };\n\n  ssr.extractData = () => {\n    const result: SSRData = {};\n    for (const key in data) if (data[key] != null) result[key] = data[key]!;\n    return result;\n  };\n\n  if (params && params.initialState) {\n    ssr.restoreData(params.initialState);\n  }\n\n  return ssr;\n};\n"
  },
  {
    "path": "packages/core/src/exchanges/subscription.test.ts",
    "content": "import { vi, expect, it } from 'vitest';\n\nimport {\n  empty,\n  publish,\n  fromValue,\n  pipe,\n  Source,\n  take,\n  toPromise,\n} from 'wonka';\n\nimport { Client } from '../client';\nimport { subscriptionOperation, subscriptionResult } from '../test-utils';\nimport { stringifyDocument } from '../utils';\nimport { OperationResult } from '../types';\nimport { subscriptionExchange, SubscriptionForwarder } from './subscription';\n\nit('should return response data from forwardSubscription observable', async () => {\n  const exchangeArgs = {\n    dispatchDebug: vi.fn(),\n    forward: () => empty as Source<OperationResult>,\n    client: {} as Client,\n  };\n\n  const unsubscribe = vi.fn();\n  const forwardSubscription: SubscriptionForwarder = operation => {\n    expect(operation.query).toBe(\n      stringifyDocument(subscriptionOperation.query)\n    );\n    expect(operation.variables).toBe(subscriptionOperation.variables);\n\n    return {\n      subscribe(observer) {\n        Promise.resolve().then(() => {\n          observer.next(subscriptionResult);\n        });\n\n        return { unsubscribe };\n      },\n    };\n  };\n\n  const data = await pipe(\n    fromValue(subscriptionOperation),\n    subscriptionExchange({ forwardSubscription })(exchangeArgs),\n    take(1),\n    toPromise\n  );\n\n  expect(data).toMatchSnapshot();\n  expect(unsubscribe).toHaveBeenCalled();\n});\n\nit('should tear down the operation if the source subscription ends', async () => {\n  const reexecuteOperation = vi.fn();\n  const unsubscribe = vi.fn();\n\n  const exchangeArgs = {\n    dispatchDebug: vi.fn(),\n    forward: () => empty as Source<OperationResult>,\n    client: { reexecuteOperation: reexecuteOperation as any } as Client,\n  };\n\n  const forwardSubscription: SubscriptionForwarder = () => ({\n    subscribe(observer) {\n      observer.complete();\n      return { unsubscribe };\n    },\n  });\n\n  pipe(\n    fromValue(subscriptionOperation),\n    subscriptionExchange({ forwardSubscription })(exchangeArgs),\n    publish\n  );\n\n  await Promise.resolve();\n\n  expect(unsubscribe).not.toHaveBeenCalled();\n  expect(reexecuteOperation).toHaveBeenCalled();\n});\n\nit('should allow providing a custom isSubscriptionOperation implementation', async () => {\n  const exchangeArgs = {\n    dispatchDebug: vi.fn(),\n    forward: () => empty as Source<OperationResult>,\n    client: {} as Client,\n  };\n\n  const isSubscriptionOperation = vi.fn(() => true);\n\n  const forwardSubscription: SubscriptionForwarder = () => ({\n    subscribe(observer) {\n      observer.next(subscriptionResult);\n      return { unsubscribe: vi.fn() };\n    },\n  });\n\n  await pipe(\n    fromValue(subscriptionOperation),\n    subscriptionExchange({ forwardSubscription, isSubscriptionOperation })(\n      exchangeArgs\n    ),\n    take(1),\n    toPromise\n  );\n\n  expect(isSubscriptionOperation).toHaveBeenCalled();\n});\n"
  },
  {
    "path": "packages/core/src/exchanges/subscription.ts",
    "content": "import type { Subscription, Source } from 'wonka';\nimport { filter, make, merge, mergeMap, pipe, takeUntil } from 'wonka';\n\nimport {\n  makeResult,\n  mergeResultPatch,\n  makeErrorResult,\n  makeOperation,\n} from '../utils';\n\nimport type {\n  Exchange,\n  ExecutionResult,\n  Operation,\n  OperationResult,\n} from '../types';\n\nimport type { FetchBody } from '../internal';\nimport { makeFetchBody } from '../internal';\n\n/** An abstract observer-like interface.\n *\n * @remarks\n * Observer-like interfaces are passed to {@link ObservableLike.subscribe} to provide them\n * with callbacks for their events.\n *\n * @see {@link https://github.com/tc39/proposal-observable} for the full TC39 Observable proposal.\n */\nexport interface ObserverLike<T> {\n  /** Callback for values an {@link ObservableLike} emits. */\n  next: (value: T) => void;\n  /** Callback for an error an {@link ObservableLike} emits, which ends the subscription. */\n  error: (err: any) => void;\n  /** Callback for the completion of an {@link ObservableLike}, which ends the subscription. */\n  complete: () => void;\n}\n\n/** An abstract observable-like interface.\n *\n * @remarks\n * Observable, or Observable-like interfaces, are often used by GraphQL transports to abstract\n * how they send {@link ExecutionResult | ExecutionResults} to consumers. These generally contain\n * a `subscribe` method accepting an {@link ObserverLike} structure.\n *\n * @see {@link https://github.com/tc39/proposal-observable} for the full TC39 Observable proposal.\n */\nexport interface ObservableLike<T> {\n  /** Start the Observable-like subscription and returns a subscription handle.\n   *\n   * @param observer - an {@link ObserverLike} object with result, error, and completion callbacks.\n   * @returns a subscription handle providing an `unsubscribe` method to stop the subscription.\n   */\n  subscribe(observer: ObserverLike<T>): {\n    unsubscribe: () => void;\n  };\n}\n\n/** A more cross-compatible version of the {@link GraphQLRequest} structure.\n * {@link FetchBody} for more details\n */\nexport type SubscriptionOperation = FetchBody;\n\n/** A subscription forwarding function, which must accept a {@link SubscriptionOperation}.\n *\n * @param operation - A {@link SubscriptionOperation}\n * @returns An {@link ObservableLike} object issuing {@link ExecutionResult | ExecutionResults}.\n */\nexport type SubscriptionForwarder = (\n  request: FetchBody,\n  operation: Operation\n) => ObservableLike<ExecutionResult>;\n\n/** This is called to create a subscription and needs to be hooked up to a transport client. */\nexport interface SubscriptionExchangeOpts {\n  /** A subscription forwarding function, which must accept a {@link SubscriptionOperation}.\n   *\n   * @param operation - A {@link SubscriptionOperation}\n   * @returns An {@link ObservableLike} object issuing {@link ExecutionResult | ExecutionResults}.\n   *\n   * @remarks\n   * This callback is called for each {@link Operation} that this `subscriptionExchange` will\n   * handle. It receives the {@link SubscriptionOperation}, which is a more compatible version\n   * of the raw {@link Operation} objects and must return an {@link ObservableLike} of results.\n   */\n  forwardSubscription: SubscriptionForwarder;\n\n  /** Flag to enable this exchange to handle all types of GraphQL operations.\n   *\n   * @remarks\n   * When you aren’t using fetch exchanges and GraphQL over HTTP as a transport for your GraphQL requests,\n   * or you have a third-party GraphQL transport implementation, which must also be used for queries and\n   * mutations, this flag may be used to allow this exchange to handle all kinds of GraphQL operations.\n   *\n   * By default, this flag is `false` and the exchange will only handle GraphQL subscription operations.\n   */\n  enableAllOperations?: boolean;\n\n  /** A predicate function that causes an operation to be handled by this `subscriptionExchange` if `true` is returned.\n   *\n   * @param operation - an {@link Operation}\n   * @returns true when the operation is handled by this exchange.\n   *\n   * @remarks\n   * In some cases, a `subscriptionExchange` will be used to only handle some {@link Operation | Operations},\n   * e.g. all that contain `@live` directive. For these cases, this function may be passed to precisely\n   * determine which `Operation`s this exchange should handle, instead of forwarding.\n   *\n   * When specified, the {@link SubscriptionExchangeOpts.enableAllOperations} flag is disregarded.\n   */\n  isSubscriptionOperation?: (operation: Operation) => boolean;\n}\n\n/** Generic subscription exchange factory used to either create an exchange handling just subscriptions or all operation kinds.\n *\n * @remarks\n * `subscriptionExchange` can be used to create an {@link Exchange} that either\n * handles just GraphQL subscription operations, or optionally all operations,\n * when the {@link SubscriptionExchangeOpts.enableAllOperations} flag is passed.\n *\n * The {@link SubscriptionExchangeOpts.forwardSubscription} function must\n * be provided and provides a generic input that's based on {@link Operation}\n * but is compatible with many libraries implementing GraphQL request or\n * subscription interfaces.\n */\nexport const subscriptionExchange =\n  ({\n    forwardSubscription,\n    enableAllOperations,\n    isSubscriptionOperation,\n  }: SubscriptionExchangeOpts): Exchange =>\n  ({ client, forward }) => {\n    const createSubscriptionSource = (\n      operation: Operation\n    ): Source<OperationResult> => {\n      const observableish = forwardSubscription(\n        makeFetchBody(operation),\n        operation\n      );\n\n      return make<OperationResult>(observer => {\n        let isComplete = false;\n        let sub: Subscription | void;\n        let result: OperationResult | void;\n\n        function nextResult(value: ExecutionResult) {\n          observer.next(\n            (result = result\n              ? mergeResultPatch(result, value)\n              : makeResult(operation, value))\n          );\n        }\n\n        Promise.resolve().then(() => {\n          if (isComplete) return;\n\n          sub = observableish.subscribe({\n            next: nextResult,\n            error(error) {\n              if (Array.isArray(error)) {\n                // NOTE: This is an exception for transports that deliver `GraphQLError[]`, as part\n                // of the observer’s error callback (may happen as part of `graphql-ws`).\n                // We only check for arrays here, as this is an extremely “unexpected” case as the\n                // shape of `ExecutionResult` is instead strictly defined.\n                nextResult({ errors: error });\n              } else {\n                observer.next(makeErrorResult(operation, error));\n              }\n              observer.complete();\n            },\n            complete() {\n              if (!isComplete) {\n                isComplete = true;\n                if (operation.kind === 'subscription') {\n                  client.reexecuteOperation(\n                    makeOperation('teardown', operation, operation.context)\n                  );\n                }\n                if (result && result.hasNext) {\n                  nextResult({ hasNext: false });\n                }\n                observer.complete();\n              }\n            },\n          });\n        });\n\n        return () => {\n          isComplete = true;\n          if (sub) sub.unsubscribe();\n        };\n      });\n    };\n\n    const isSubscriptionOperationFn =\n      isSubscriptionOperation ||\n      (operation =>\n        operation.kind === 'subscription' ||\n        (!!enableAllOperations &&\n          (operation.kind === 'query' || operation.kind === 'mutation')));\n\n    return ops$ => {\n      const subscriptionResults$ = pipe(\n        ops$,\n        filter(\n          operation =>\n            operation.kind !== 'teardown' &&\n            isSubscriptionOperationFn(operation)\n        ),\n        mergeMap(operation => {\n          const { key } = operation;\n          const teardown$ = pipe(\n            ops$,\n            filter(op => op.kind === 'teardown' && op.key === key)\n          );\n\n          return pipe(\n            createSubscriptionSource(operation),\n            takeUntil(teardown$)\n          );\n        })\n      );\n\n      const forward$ = pipe(\n        ops$,\n        filter(\n          operation =>\n            operation.kind === 'teardown' ||\n            !isSubscriptionOperationFn(operation)\n        ),\n        forward\n      );\n\n      return merge([subscriptionResults$, forward$]);\n    };\n  };\n"
  },
  {
    "path": "packages/core/src/gql.test.ts",
    "content": "import { parse, print } from '@0no-co/graphql.web';\nimport { vi, expect, it, beforeEach, MockInstance } from 'vitest';\n\nimport { gql } from './gql';\nimport { keyDocument } from './utils';\n\nlet warn: MockInstance;\n\nbeforeEach(() => {\n  warn = vi.spyOn(console, 'warn');\n  warn.mockClear();\n});\n\nit('parses GraphQL Documents', () => {\n  const doc = gql`\n    {\n      gql\n      testing\n    }\n  `;\n\n  expect(doc.definitions).toEqual(\n    parse('{ gql testing }', { noLocation: true }).definitions\n  );\n\n  expect(doc).toBe(keyDocument('{\\n  gql\\n  testing\\n}'));\n  expect(doc.loc).toEqual({\n    start: 0,\n    end: 19,\n    source: expect.anything(),\n  });\n});\n\nit('deduplicates fragments', () => {\n  const frag = gql`\n    fragment Test on Test {\n      testField\n    }\n  `;\n\n  const doc = gql`\n    query {\n      ...Test\n    }\n\n    ${frag}\n    ${frag}\n  `;\n\n  expect(doc.definitions.length).toBe(2);\n  expect(warn).not.toHaveBeenCalled();\n});\n\nit('warns on duplicate fragment names with different sources', () => {\n  const frag = gql`\n    fragment Test on Test {\n      testField\n    }\n  `;\n\n  const duplicate = gql`\n    fragment Test on Test {\n      otherField\n    }\n  `;\n\n  const doc = gql`\n    query {\n      ...Test\n    }\n\n    ${frag}\n    ${duplicate}\n  `;\n\n  expect(warn).toHaveBeenCalledTimes(1);\n  expect(doc.definitions.length).toBe(2);\n});\n\nit('interpolates nested GraphQL Documents', () => {\n  expect(\n    print(gql`\n      query {\n        ...Query\n      }\n\n      ${gql`\n        fragment Query on Query {\n          field\n        }\n      `}\n    `)\n  ).toMatchInlineSnapshot(`\n    \"{\n      ...Query\n    }\n\n    fragment Query on Query {\n      field\n    }\"\n  `);\n});\n\nit('interpolates strings', () => {\n  expect(\n    print(\n      gql`\n        query {\n          ${'field'}\n        }\n      `\n    )\n  ).toMatchInlineSnapshot(`\n    \"{\n      field\n    }\"\n  `);\n});\n"
  },
  {
    "path": "packages/core/src/gql.ts",
    "content": "/* eslint-disable prefer-rest-params */\nimport { Kind } from '@0no-co/graphql.web';\nimport type { DocumentNode, DefinitionNode } from './utils/graphql';\nimport type { AnyVariables, TypedDocumentNode } from './types';\nimport { keyDocument, stringifyDocument } from './utils';\n\n/** A GraphQL parse function, which may be called as a tagged template literal, returning a parsed {@link DocumentNode}.\n *\n * @remarks\n * The `gql` tag or function is used to parse a GraphQL query document into a {@link DocumentNode}.\n *\n * When used as a tagged template, `gql` will automatically merge fragment definitions into the resulting\n * document and deduplicate them.\n *\n * It enforces that all fragments have a unique name. When fragments with different definitions share a name,\n * it will log a warning in development.\n *\n * Hint: It’s recommended to use this `gql` function over other GraphQL parse functions, since it puts the parsed\n * results directly into `@urql/core`’s internal caches and prevents further unnecessary work.\n *\n * @example\n * ```ts\n * const AuthorFragment = gql`\n *   fragment AuthorDisplayComponent on Author {\n *     id\n *     name\n *   }\n * `;\n *\n * const BookFragment = gql`\n *   fragment ListBookComponent on Book {\n *     id\n *     title\n *     author {\n *       ...AuthorDisplayComponent\n *     }\n *   }\n *\n *   ${AuthorFragment}\n * `;\n *\n * const BookQuery = gql`\n *   query Book($id: ID!) {\n *     book(id: $id) {\n *       ...BookFragment\n *     }\n *   }\n *\n *   ${BookFragment}\n * `;\n * ```\n */\nfunction gql<Data = any, Variables extends AnyVariables = AnyVariables>(\n  strings: TemplateStringsArray,\n  ...interpolations: Array<TypedDocumentNode | DocumentNode | string>\n): TypedDocumentNode<Data, Variables>;\n\nfunction gql<Data = any, Variables extends AnyVariables = AnyVariables>(\n  string: string\n): TypedDocumentNode<Data, Variables>;\n\nfunction gql(parts: string | TemplateStringsArray /* arguments */) {\n  const fragmentNames = new Map<string, string>();\n  const definitions: DefinitionNode[] = [];\n  const source: DocumentNode[] = [];\n\n  // Apply the entire tagged template body's definitions\n  let body: string = Array.isArray(parts) ? parts[0] : parts || '';\n  for (let i = 1; i < arguments.length; i++) {\n    const value = arguments[i];\n    if (value && value.definitions) {\n      source.push(value);\n    } else {\n      body += value;\n    }\n\n    body += arguments[0][i];\n  }\n\n  source.unshift(keyDocument(body));\n  for (let i = 0; i < source.length; i++) {\n    for (let j = 0; j < source[i].definitions.length; j++) {\n      const definition = source[i].definitions[j];\n      if (definition.kind === Kind.FRAGMENT_DEFINITION) {\n        const name = definition.name.value;\n        const value = stringifyDocument(definition);\n        // Fragments will be deduplicated according to this Map\n        if (!fragmentNames.has(name)) {\n          fragmentNames.set(name, value);\n          definitions.push(definition);\n        } else if (\n          process.env.NODE_ENV !== 'production' &&\n          fragmentNames.get(name) !== value\n        ) {\n          // Fragments with the same names is expected to have the same contents\n          console.warn(\n            '[WARNING: Duplicate Fragment] A fragment with name `' +\n              name +\n              '` already exists in this document.\\n' +\n              'While fragment names may not be unique across your source, each name must be unique per document.'\n          );\n        }\n      } else {\n        definitions.push(definition);\n      }\n    }\n  }\n\n  return keyDocument({\n    kind: Kind.DOCUMENT,\n    definitions,\n  });\n}\n\nexport { gql };\n"
  },
  {
    "path": "packages/core/src/index.ts",
    "content": "export { gql } from './gql';\n\nexport * from './client';\nexport * from './exchanges';\nexport * from './types';\n\nexport {\n  CombinedError,\n  stringifyVariables,\n  stringifyDocument,\n  createRequest,\n  makeResult,\n  makeErrorResult,\n  mergeResultPatch,\n  formatDocument,\n  makeOperation,\n  getOperationName,\n} from './utils';\n"
  },
  {
    "path": "packages/core/src/internal/__snapshots__/fetchSource.test.ts.snap",
    "content": "// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html\n\nexports[`on error > ignores the error when a result is available 1`] = `\n{\n  \"data\": undefined,\n  \"error\": [CombinedError: [Network] Forbidden],\n  \"extensions\": undefined,\n  \"hasNext\": false,\n  \"operation\": {\n    \"context\": {\n      \"fetchOptions\": {\n        \"method\": \"POST\",\n      },\n      \"requestPolicy\": \"cache-first\",\n      \"url\": \"http://localhost:3000/graphql\",\n    },\n    \"key\": 2,\n    \"kind\": \"query\",\n    \"query\": {\n      \"__key\": -2395444236,\n      \"definitions\": [\n        {\n          \"directives\": undefined,\n          \"kind\": \"OperationDefinition\",\n          \"name\": {\n            \"kind\": \"Name\",\n            \"value\": \"getUser\",\n          },\n          \"operation\": \"query\",\n          \"selectionSet\": {\n            \"kind\": \"SelectionSet\",\n            \"selections\": [\n              {\n                \"alias\": undefined,\n                \"arguments\": [\n                  {\n                    \"kind\": \"Argument\",\n                    \"name\": {\n                      \"kind\": \"Name\",\n                      \"value\": \"name\",\n                    },\n                    \"value\": {\n                      \"kind\": \"Variable\",\n                      \"name\": {\n                        \"kind\": \"Name\",\n                        \"value\": \"name\",\n                      },\n                    },\n                  },\n                ],\n                \"directives\": undefined,\n                \"kind\": \"Field\",\n                \"name\": {\n                  \"kind\": \"Name\",\n                  \"value\": \"user\",\n                },\n                \"selectionSet\": {\n                  \"kind\": \"SelectionSet\",\n                  \"selections\": [\n                    {\n                      \"alias\": undefined,\n                      \"arguments\": undefined,\n                      \"directives\": undefined,\n                      \"kind\": \"Field\",\n                      \"name\": {\n                        \"kind\": \"Name\",\n                        \"value\": \"id\",\n                      },\n                      \"selectionSet\": undefined,\n                    },\n                    {\n                      \"alias\": undefined,\n                      \"arguments\": undefined,\n                      \"directives\": undefined,\n                      \"kind\": \"Field\",\n                      \"name\": {\n                        \"kind\": \"Name\",\n                        \"value\": \"firstName\",\n                      },\n                      \"selectionSet\": undefined,\n                    },\n                    {\n                      \"alias\": undefined,\n                      \"arguments\": undefined,\n                      \"directives\": undefined,\n                      \"kind\": \"Field\",\n                      \"name\": {\n                        \"kind\": \"Name\",\n                        \"value\": \"lastName\",\n                      },\n                      \"selectionSet\": undefined,\n                    },\n                  ],\n                },\n              },\n            ],\n          },\n          \"variableDefinitions\": [\n            {\n              \"defaultValue\": undefined,\n              \"directives\": undefined,\n              \"kind\": \"VariableDefinition\",\n              \"type\": {\n                \"kind\": \"NamedType\",\n                \"name\": {\n                  \"kind\": \"Name\",\n                  \"value\": \"String\",\n                },\n              },\n              \"variable\": {\n                \"kind\": \"Variable\",\n                \"name\": {\n                  \"kind\": \"Name\",\n                  \"value\": \"name\",\n                },\n              },\n            },\n          ],\n        },\n      ],\n      \"kind\": \"Document\",\n      \"loc\": {\n        \"end\": 92,\n        \"source\": {\n          \"body\": \"query getUser($name: String) {\n  user(name: $name) {\n    id\n    firstName\n    lastName\n  }\n}\",\n          \"locationOffset\": {\n            \"column\": 1,\n            \"line\": 1,\n          },\n          \"name\": \"gql\",\n        },\n        \"start\": 0,\n      },\n    },\n    \"variables\": {\n      \"name\": \"Clara\",\n    },\n  },\n  \"stale\": false,\n}\n`;\n\nexports[`on error > returns error data 1`] = `\n{\n  \"data\": undefined,\n  \"error\": [CombinedError: [Network] Forbidden],\n  \"extensions\": undefined,\n  \"hasNext\": false,\n  \"operation\": {\n    \"context\": {\n      \"fetchOptions\": {\n        \"method\": \"POST\",\n      },\n      \"requestPolicy\": \"cache-first\",\n      \"url\": \"http://localhost:3000/graphql\",\n    },\n    \"key\": 2,\n    \"kind\": \"query\",\n    \"query\": {\n      \"__key\": -2395444236,\n      \"definitions\": [\n        {\n          \"directives\": undefined,\n          \"kind\": \"OperationDefinition\",\n          \"name\": {\n            \"kind\": \"Name\",\n            \"value\": \"getUser\",\n          },\n          \"operation\": \"query\",\n          \"selectionSet\": {\n            \"kind\": \"SelectionSet\",\n            \"selections\": [\n              {\n                \"alias\": undefined,\n                \"arguments\": [\n                  {\n                    \"kind\": \"Argument\",\n                    \"name\": {\n                      \"kind\": \"Name\",\n                      \"value\": \"name\",\n                    },\n                    \"value\": {\n                      \"kind\": \"Variable\",\n                      \"name\": {\n                        \"kind\": \"Name\",\n                        \"value\": \"name\",\n                      },\n                    },\n                  },\n                ],\n                \"directives\": undefined,\n                \"kind\": \"Field\",\n                \"name\": {\n                  \"kind\": \"Name\",\n                  \"value\": \"user\",\n                },\n                \"selectionSet\": {\n                  \"kind\": \"SelectionSet\",\n                  \"selections\": [\n                    {\n                      \"alias\": undefined,\n                      \"arguments\": undefined,\n                      \"directives\": undefined,\n                      \"kind\": \"Field\",\n                      \"name\": {\n                        \"kind\": \"Name\",\n                        \"value\": \"id\",\n                      },\n                      \"selectionSet\": undefined,\n                    },\n                    {\n                      \"alias\": undefined,\n                      \"arguments\": undefined,\n                      \"directives\": undefined,\n                      \"kind\": \"Field\",\n                      \"name\": {\n                        \"kind\": \"Name\",\n                        \"value\": \"firstName\",\n                      },\n                      \"selectionSet\": undefined,\n                    },\n                    {\n                      \"alias\": undefined,\n                      \"arguments\": undefined,\n                      \"directives\": undefined,\n                      \"kind\": \"Field\",\n                      \"name\": {\n                        \"kind\": \"Name\",\n                        \"value\": \"lastName\",\n                      },\n                      \"selectionSet\": undefined,\n                    },\n                  ],\n                },\n              },\n            ],\n          },\n          \"variableDefinitions\": [\n            {\n              \"defaultValue\": undefined,\n              \"directives\": undefined,\n              \"kind\": \"VariableDefinition\",\n              \"type\": {\n                \"kind\": \"NamedType\",\n                \"name\": {\n                  \"kind\": \"Name\",\n                  \"value\": \"String\",\n                },\n              },\n              \"variable\": {\n                \"kind\": \"Variable\",\n                \"name\": {\n                  \"kind\": \"Name\",\n                  \"value\": \"name\",\n                },\n              },\n            },\n          ],\n        },\n      ],\n      \"kind\": \"Document\",\n      \"loc\": {\n        \"end\": 92,\n        \"source\": {\n          \"body\": \"query getUser($name: String) {\n  user(name: $name) {\n    id\n    firstName\n    lastName\n  }\n}\",\n          \"locationOffset\": {\n            \"column\": 1,\n            \"line\": 1,\n          },\n          \"name\": \"gql\",\n        },\n        \"start\": 0,\n      },\n    },\n    \"variables\": {\n      \"name\": \"Clara\",\n    },\n  },\n  \"stale\": false,\n}\n`;\n\nexports[`on error > returns error data with status 400 and manual redirect mode 1`] = `\n{\n  \"data\": undefined,\n  \"error\": [CombinedError: [Network] Forbidden],\n  \"extensions\": undefined,\n  \"hasNext\": false,\n  \"operation\": {\n    \"context\": {\n      \"fetchOptions\": {\n        \"method\": \"POST\",\n      },\n      \"requestPolicy\": \"cache-first\",\n      \"url\": \"http://localhost:3000/graphql\",\n    },\n    \"key\": 2,\n    \"kind\": \"query\",\n    \"query\": {\n      \"__key\": -2395444236,\n      \"definitions\": [\n        {\n          \"directives\": undefined,\n          \"kind\": \"OperationDefinition\",\n          \"name\": {\n            \"kind\": \"Name\",\n            \"value\": \"getUser\",\n          },\n          \"operation\": \"query\",\n          \"selectionSet\": {\n            \"kind\": \"SelectionSet\",\n            \"selections\": [\n              {\n                \"alias\": undefined,\n                \"arguments\": [\n                  {\n                    \"kind\": \"Argument\",\n                    \"name\": {\n                      \"kind\": \"Name\",\n                      \"value\": \"name\",\n                    },\n                    \"value\": {\n                      \"kind\": \"Variable\",\n                      \"name\": {\n                        \"kind\": \"Name\",\n                        \"value\": \"name\",\n                      },\n                    },\n                  },\n                ],\n                \"directives\": undefined,\n                \"kind\": \"Field\",\n                \"name\": {\n                  \"kind\": \"Name\",\n                  \"value\": \"user\",\n                },\n                \"selectionSet\": {\n                  \"kind\": \"SelectionSet\",\n                  \"selections\": [\n                    {\n                      \"alias\": undefined,\n                      \"arguments\": undefined,\n                      \"directives\": undefined,\n                      \"kind\": \"Field\",\n                      \"name\": {\n                        \"kind\": \"Name\",\n                        \"value\": \"id\",\n                      },\n                      \"selectionSet\": undefined,\n                    },\n                    {\n                      \"alias\": undefined,\n                      \"arguments\": undefined,\n                      \"directives\": undefined,\n                      \"kind\": \"Field\",\n                      \"name\": {\n                        \"kind\": \"Name\",\n                        \"value\": \"firstName\",\n                      },\n                      \"selectionSet\": undefined,\n                    },\n                    {\n                      \"alias\": undefined,\n                      \"arguments\": undefined,\n                      \"directives\": undefined,\n                      \"kind\": \"Field\",\n                      \"name\": {\n                        \"kind\": \"Name\",\n                        \"value\": \"lastName\",\n                      },\n                      \"selectionSet\": undefined,\n                    },\n                  ],\n                },\n              },\n            ],\n          },\n          \"variableDefinitions\": [\n            {\n              \"defaultValue\": undefined,\n              \"directives\": undefined,\n              \"kind\": \"VariableDefinition\",\n              \"type\": {\n                \"kind\": \"NamedType\",\n                \"name\": {\n                  \"kind\": \"Name\",\n                  \"value\": \"String\",\n                },\n              },\n              \"variable\": {\n                \"kind\": \"Variable\",\n                \"name\": {\n                  \"kind\": \"Name\",\n                  \"value\": \"name\",\n                },\n              },\n            },\n          ],\n        },\n      ],\n      \"kind\": \"Document\",\n      \"loc\": {\n        \"end\": 92,\n        \"source\": {\n          \"body\": \"query getUser($name: String) {\n  user(name: $name) {\n    id\n    firstName\n    lastName\n  }\n}\",\n          \"locationOffset\": {\n            \"column\": 1,\n            \"line\": 1,\n          },\n          \"name\": \"gql\",\n        },\n        \"start\": 0,\n      },\n    },\n    \"variables\": {\n      \"name\": \"Clara\",\n    },\n  },\n  \"stale\": false,\n}\n`;\n\nexports[`on error with non spec-compliant body > handles network errors 1`] = `\n{\n  \"data\": undefined,\n  \"error\": [CombinedError: [Network] Forbidden],\n  \"extensions\": undefined,\n  \"hasNext\": false,\n  \"operation\": {\n    \"context\": {\n      \"fetchOptions\": {\n        \"method\": \"POST\",\n      },\n      \"requestPolicy\": \"cache-first\",\n      \"url\": \"http://localhost:3000/graphql\",\n    },\n    \"key\": 2,\n    \"kind\": \"query\",\n    \"query\": {\n      \"__key\": -2395444236,\n      \"definitions\": [\n        {\n          \"directives\": undefined,\n          \"kind\": \"OperationDefinition\",\n          \"name\": {\n            \"kind\": \"Name\",\n            \"value\": \"getUser\",\n          },\n          \"operation\": \"query\",\n          \"selectionSet\": {\n            \"kind\": \"SelectionSet\",\n            \"selections\": [\n              {\n                \"alias\": undefined,\n                \"arguments\": [\n                  {\n                    \"kind\": \"Argument\",\n                    \"name\": {\n                      \"kind\": \"Name\",\n                      \"value\": \"name\",\n                    },\n                    \"value\": {\n                      \"kind\": \"Variable\",\n                      \"name\": {\n                        \"kind\": \"Name\",\n                        \"value\": \"name\",\n                      },\n                    },\n                  },\n                ],\n                \"directives\": undefined,\n                \"kind\": \"Field\",\n                \"name\": {\n                  \"kind\": \"Name\",\n                  \"value\": \"user\",\n                },\n                \"selectionSet\": {\n                  \"kind\": \"SelectionSet\",\n                  \"selections\": [\n                    {\n                      \"alias\": undefined,\n                      \"arguments\": undefined,\n                      \"directives\": undefined,\n                      \"kind\": \"Field\",\n                      \"name\": {\n                        \"kind\": \"Name\",\n                        \"value\": \"id\",\n                      },\n                      \"selectionSet\": undefined,\n                    },\n                    {\n                      \"alias\": undefined,\n                      \"arguments\": undefined,\n                      \"directives\": undefined,\n                      \"kind\": \"Field\",\n                      \"name\": {\n                        \"kind\": \"Name\",\n                        \"value\": \"firstName\",\n                      },\n                      \"selectionSet\": undefined,\n                    },\n                    {\n                      \"alias\": undefined,\n                      \"arguments\": undefined,\n                      \"directives\": undefined,\n                      \"kind\": \"Field\",\n                      \"name\": {\n                        \"kind\": \"Name\",\n                        \"value\": \"lastName\",\n                      },\n                      \"selectionSet\": undefined,\n                    },\n                  ],\n                },\n              },\n            ],\n          },\n          \"variableDefinitions\": [\n            {\n              \"defaultValue\": undefined,\n              \"directives\": undefined,\n              \"kind\": \"VariableDefinition\",\n              \"type\": {\n                \"kind\": \"NamedType\",\n                \"name\": {\n                  \"kind\": \"Name\",\n                  \"value\": \"String\",\n                },\n              },\n              \"variable\": {\n                \"kind\": \"Variable\",\n                \"name\": {\n                  \"kind\": \"Name\",\n                  \"value\": \"name\",\n                },\n              },\n            },\n          ],\n        },\n      ],\n      \"kind\": \"Document\",\n      \"loc\": {\n        \"end\": 92,\n        \"source\": {\n          \"body\": \"query getUser($name: String) {\n  user(name: $name) {\n    id\n    firstName\n    lastName\n  }\n}\",\n          \"locationOffset\": {\n            \"column\": 1,\n            \"line\": 1,\n          },\n          \"name\": \"gql\",\n        },\n        \"start\": 0,\n      },\n    },\n    \"variables\": {\n      \"name\": \"Clara\",\n    },\n  },\n  \"stale\": false,\n}\n`;\n\nexports[`on success > returns response data 1`] = `\n{\n  \"data\": {\n    \"data\": {\n      \"user\": 1200,\n    },\n  },\n  \"error\": undefined,\n  \"extensions\": undefined,\n  \"hasNext\": false,\n  \"operation\": {\n    \"context\": {\n      \"fetchOptions\": {\n        \"method\": \"POST\",\n      },\n      \"requestPolicy\": \"cache-first\",\n      \"url\": \"http://localhost:3000/graphql\",\n    },\n    \"key\": 2,\n    \"kind\": \"query\",\n    \"query\": {\n      \"__key\": -2395444236,\n      \"definitions\": [\n        {\n          \"directives\": undefined,\n          \"kind\": \"OperationDefinition\",\n          \"name\": {\n            \"kind\": \"Name\",\n            \"value\": \"getUser\",\n          },\n          \"operation\": \"query\",\n          \"selectionSet\": {\n            \"kind\": \"SelectionSet\",\n            \"selections\": [\n              {\n                \"alias\": undefined,\n                \"arguments\": [\n                  {\n                    \"kind\": \"Argument\",\n                    \"name\": {\n                      \"kind\": \"Name\",\n                      \"value\": \"name\",\n                    },\n                    \"value\": {\n                      \"kind\": \"Variable\",\n                      \"name\": {\n                        \"kind\": \"Name\",\n                        \"value\": \"name\",\n                      },\n                    },\n                  },\n                ],\n                \"directives\": undefined,\n                \"kind\": \"Field\",\n                \"name\": {\n                  \"kind\": \"Name\",\n                  \"value\": \"user\",\n                },\n                \"selectionSet\": {\n                  \"kind\": \"SelectionSet\",\n                  \"selections\": [\n                    {\n                      \"alias\": undefined,\n                      \"arguments\": undefined,\n                      \"directives\": undefined,\n                      \"kind\": \"Field\",\n                      \"name\": {\n                        \"kind\": \"Name\",\n                        \"value\": \"id\",\n                      },\n                      \"selectionSet\": undefined,\n                    },\n                    {\n                      \"alias\": undefined,\n                      \"arguments\": undefined,\n                      \"directives\": undefined,\n                      \"kind\": \"Field\",\n                      \"name\": {\n                        \"kind\": \"Name\",\n                        \"value\": \"firstName\",\n                      },\n                      \"selectionSet\": undefined,\n                    },\n                    {\n                      \"alias\": undefined,\n                      \"arguments\": undefined,\n                      \"directives\": undefined,\n                      \"kind\": \"Field\",\n                      \"name\": {\n                        \"kind\": \"Name\",\n                        \"value\": \"lastName\",\n                      },\n                      \"selectionSet\": undefined,\n                    },\n                  ],\n                },\n              },\n            ],\n          },\n          \"variableDefinitions\": [\n            {\n              \"defaultValue\": undefined,\n              \"directives\": undefined,\n              \"kind\": \"VariableDefinition\",\n              \"type\": {\n                \"kind\": \"NamedType\",\n                \"name\": {\n                  \"kind\": \"Name\",\n                  \"value\": \"String\",\n                },\n              },\n              \"variable\": {\n                \"kind\": \"Variable\",\n                \"name\": {\n                  \"kind\": \"Name\",\n                  \"value\": \"name\",\n                },\n              },\n            },\n          ],\n        },\n      ],\n      \"kind\": \"Document\",\n      \"loc\": {\n        \"end\": 92,\n        \"source\": {\n          \"body\": \"query getUser($name: String) {\n  user(name: $name) {\n    id\n    firstName\n    lastName\n  }\n}\",\n          \"locationOffset\": {\n            \"column\": 1,\n            \"line\": 1,\n          },\n          \"name\": \"gql\",\n        },\n        \"start\": 0,\n      },\n    },\n    \"variables\": {\n      \"name\": \"Clara\",\n    },\n  },\n  \"stale\": false,\n}\n`;\n\nexports[`on success > uses the mock fetch if given 1`] = `\n{\n  \"data\": {\n    \"data\": {\n      \"user\": 1200,\n    },\n  },\n  \"error\": undefined,\n  \"extensions\": undefined,\n  \"hasNext\": false,\n  \"operation\": {\n    \"context\": {\n      \"fetch\": [MockFunction spy] {\n        \"calls\": [\n          [\n            \"https://test.com/graphql\",\n            {\n              \"signal\": undefined,\n            },\n          ],\n        ],\n        \"results\": [\n          {\n            \"type\": \"return\",\n            \"value\": Promise {},\n          },\n        ],\n      },\n      \"fetchOptions\": {\n        \"method\": \"POST\",\n      },\n      \"requestPolicy\": \"cache-first\",\n      \"url\": \"http://localhost:3000/graphql\",\n    },\n    \"key\": 2,\n    \"kind\": \"query\",\n    \"query\": {\n      \"__key\": -2395444236,\n      \"definitions\": [\n        {\n          \"directives\": undefined,\n          \"kind\": \"OperationDefinition\",\n          \"name\": {\n            \"kind\": \"Name\",\n            \"value\": \"getUser\",\n          },\n          \"operation\": \"query\",\n          \"selectionSet\": {\n            \"kind\": \"SelectionSet\",\n            \"selections\": [\n              {\n                \"alias\": undefined,\n                \"arguments\": [\n                  {\n                    \"kind\": \"Argument\",\n                    \"name\": {\n                      \"kind\": \"Name\",\n                      \"value\": \"name\",\n                    },\n                    \"value\": {\n                      \"kind\": \"Variable\",\n                      \"name\": {\n                        \"kind\": \"Name\",\n                        \"value\": \"name\",\n                      },\n                    },\n                  },\n                ],\n                \"directives\": undefined,\n                \"kind\": \"Field\",\n                \"name\": {\n                  \"kind\": \"Name\",\n                  \"value\": \"user\",\n                },\n                \"selectionSet\": {\n                  \"kind\": \"SelectionSet\",\n                  \"selections\": [\n                    {\n                      \"alias\": undefined,\n                      \"arguments\": undefined,\n                      \"directives\": undefined,\n                      \"kind\": \"Field\",\n                      \"name\": {\n                        \"kind\": \"Name\",\n                        \"value\": \"id\",\n                      },\n                      \"selectionSet\": undefined,\n                    },\n                    {\n                      \"alias\": undefined,\n                      \"arguments\": undefined,\n                      \"directives\": undefined,\n                      \"kind\": \"Field\",\n                      \"name\": {\n                        \"kind\": \"Name\",\n                        \"value\": \"firstName\",\n                      },\n                      \"selectionSet\": undefined,\n                    },\n                    {\n                      \"alias\": undefined,\n                      \"arguments\": undefined,\n                      \"directives\": undefined,\n                      \"kind\": \"Field\",\n                      \"name\": {\n                        \"kind\": \"Name\",\n                        \"value\": \"lastName\",\n                      },\n                      \"selectionSet\": undefined,\n                    },\n                  ],\n                },\n              },\n            ],\n          },\n          \"variableDefinitions\": [\n            {\n              \"defaultValue\": undefined,\n              \"directives\": undefined,\n              \"kind\": \"VariableDefinition\",\n              \"type\": {\n                \"kind\": \"NamedType\",\n                \"name\": {\n                  \"kind\": \"Name\",\n                  \"value\": \"String\",\n                },\n              },\n              \"variable\": {\n                \"kind\": \"Variable\",\n                \"name\": {\n                  \"kind\": \"Name\",\n                  \"value\": \"name\",\n                },\n              },\n            },\n          ],\n        },\n      ],\n      \"kind\": \"Document\",\n      \"loc\": {\n        \"end\": 92,\n        \"source\": {\n          \"body\": \"query getUser($name: String) {\n  user(name: $name) {\n    id\n    firstName\n    lastName\n  }\n}\",\n          \"locationOffset\": {\n            \"column\": 1,\n            \"line\": 1,\n          },\n          \"name\": \"gql\",\n        },\n        \"start\": 0,\n      },\n    },\n    \"variables\": {\n      \"name\": \"Clara\",\n    },\n  },\n  \"stale\": false,\n}\n`;\n"
  },
  {
    "path": "packages/core/src/internal/fetchOptions.test.ts",
    "content": "// @vitest-environment jsdom\n\nimport { expect, describe, it } from 'vitest';\nimport { Kind } from '@0no-co/graphql.web';\nimport { makeOperation } from '../utils/operation';\nimport { queryOperation, mutationOperation } from '../test-utils';\nimport { makeFetchBody, makeFetchURL, makeFetchOptions } from './fetchOptions';\n\ndescribe('makeFetchBody', () => {\n  it('creates a fetch body', () => {\n    const body = makeFetchBody(queryOperation);\n    expect(body).toMatchInlineSnapshot(`\n      {\n        \"documentId\": undefined,\n        \"extensions\": undefined,\n        \"operationName\": \"getUser\",\n        \"query\": \"query getUser($name: String) {\n        user(name: $name) {\n          id\n          firstName\n          lastName\n        }\n      }\",\n        \"variables\": {\n          \"name\": \"Clara\",\n        },\n      }\n    `);\n  });\n\n  it('omits the query property when APQ is set', () => {\n    const apqOperation = makeOperation(queryOperation.kind, queryOperation);\n\n    apqOperation.extensions = {\n      ...apqOperation.extensions,\n      persistedQuery: {\n        version: 1,\n        sha256Hash: '[test]',\n      },\n    };\n\n    expect(makeFetchBody(apqOperation).query).toBe(undefined);\n\n    apqOperation.extensions.persistedQuery!.miss = true;\n    expect(makeFetchBody(apqOperation).query).not.toBe(undefined);\n  });\n\n  it('omits the query property when query is a persisted document', () => {\n    // A persisted documents is one that carries a `documentId` property and\n    // has no definitions\n    const persistedOperation = makeOperation(queryOperation.kind, {\n      ...queryOperation,\n      query: {\n        kind: Kind.DOCUMENT,\n        definitions: [],\n        documentId: 'TestDocumentId',\n      },\n    });\n\n    expect(makeFetchBody(persistedOperation).query).toBe(undefined);\n    expect(makeFetchBody(persistedOperation).documentId).toBe('TestDocumentId');\n  });\n});\n\ndescribe('makeFetchURL', () => {\n  it('returns the URL by default', () => {\n    const body = makeFetchBody(queryOperation);\n    expect(makeFetchURL(queryOperation, body)).toBe(\n      'http://localhost:3000/graphql'\n    );\n  });\n\n  it('returns the URL by default when only a path is provided', () => {\n    const operation = makeOperation(queryOperation.kind, queryOperation, {\n      url: '/graphql',\n    });\n    const body = makeFetchBody(operation);\n    expect(makeFetchURL(operation, body)).toBe('/graphql');\n  });\n\n  it('returns a query parameter URL when GET is preferred', () => {\n    const operation = makeOperation(queryOperation.kind, queryOperation, {\n      ...queryOperation.context,\n      preferGetMethod: true,\n    });\n\n    const body = makeFetchBody(operation);\n    expect(makeFetchURL(operation, body)).toMatchInlineSnapshot(\n      '\"http://localhost:3000/graphql?query=query+getUser%28%24name%3A+String%29+%7B%0A++user%28name%3A+%24name%29+%7B%0A++++id%0A++++firstName%0A++++lastName%0A++%7D%0A%7D&operationName=getUser&variables=%7B%22name%22%3A%22Clara%22%7D\"'\n    );\n  });\n\n  it('returns a query parameter URL when GET is preferred and only a path is provided', () => {\n    const operation = makeOperation(queryOperation.kind, queryOperation, {\n      url: '/graphql',\n      preferGetMethod: true,\n    });\n\n    const body = makeFetchBody(operation);\n    expect(makeFetchURL(operation, body)).toMatchInlineSnapshot(\n      '\"/graphql?query=query+getUser%28%24name%3A+String%29+%7B%0A++user%28name%3A+%24name%29+%7B%0A++++id%0A++++firstName%0A++++lastName%0A++%7D%0A%7D&operationName=getUser&variables=%7B%22name%22%3A%22Clara%22%7D\"'\n    );\n  });\n\n  it('returns the URL without query parameters when it exceeds given length', () => {\n    const operation = makeOperation(queryOperation.kind, queryOperation, {\n      ...queryOperation.context,\n      preferGetMethod: true,\n    });\n\n    operation.variables = {\n      ...operation.variables,\n      test: 'x'.repeat(2048),\n    };\n\n    const body = makeFetchBody(operation);\n    expect(makeFetchURL(operation, body)).toBe('http://localhost:3000/graphql');\n    // Resets the `preferGetMethod` field\n    expect(operation.context.preferGetMethod).toBe(false);\n  });\n\n  it('returns the URL without query parameters for mutations', () => {\n    const operation = makeOperation(mutationOperation.kind, mutationOperation, {\n      ...mutationOperation.context,\n      preferGetMethod: true,\n    });\n\n    const body = makeFetchBody(operation);\n    expect(makeFetchURL(operation, body)).toBe('http://localhost:3000/graphql');\n  });\n});\n\ndescribe('makeFetchOptions', () => {\n  it('creates a JSON request by default', () => {\n    const body = makeFetchBody(queryOperation);\n    expect(makeFetchOptions(queryOperation, body)).toMatchInlineSnapshot(`\n      {\n        \"body\": \"{\"operationName\":\"getUser\",\"query\":\"query getUser($name: String) {\\\\n  user(name: $name) {\\\\n    id\\\\n    firstName\\\\n    lastName\\\\n  }\\\\n}\",\"variables\":{\"name\":\"Clara\"}}\",\n        \"headers\": {\n          \"accept\": \"application/graphql-response+json, application/graphql+json, application/json, text/event-stream, multipart/mixed\",\n          \"content-type\": \"application/json\",\n        },\n        \"method\": \"POST\",\n      }\n    `);\n  });\n\n  it('handles the Headers object', () => {\n    const headers = new Headers();\n    headers.append('x-test', 'true');\n    const operation = makeOperation(queryOperation.kind, queryOperation, {\n      ...queryOperation.context,\n      fetchOptions: {\n        headers,\n      },\n    });\n    const body = makeFetchBody(operation);\n\n    expect(makeFetchOptions(operation, body)).toMatchInlineSnapshot(`\n      {\n        \"body\": \"{\"operationName\":\"getUser\",\"query\":\"query getUser($name: String) {\\\\n  user(name: $name) {\\\\n    id\\\\n    firstName\\\\n    lastName\\\\n  }\\\\n}\",\"variables\":{\"name\":\"Clara\"}}\",\n        \"headers\": {\n          \"accept\": \"application/graphql-response+json, application/graphql+json, application/json, text/event-stream, multipart/mixed\",\n          \"content-type\": \"application/json\",\n          \"x-test\": \"true\",\n        },\n        \"method\": \"POST\",\n      }\n    `);\n  });\n\n  it('handles an Array headers init', () => {\n    const operation = makeOperation(queryOperation.kind, queryOperation, {\n      ...queryOperation.context,\n      fetchOptions: {\n        headers: [['x-test', 'true']],\n      },\n    });\n    const body = makeFetchBody(operation);\n\n    expect(makeFetchOptions(operation, body)).toMatchInlineSnapshot(`\n      {\n        \"body\": \"{\"operationName\":\"getUser\",\"query\":\"query getUser($name: String) {\\\\n  user(name: $name) {\\\\n    id\\\\n    firstName\\\\n    lastName\\\\n  }\\\\n}\",\"variables\":{\"name\":\"Clara\"}}\",\n        \"headers\": {\n          \"accept\": \"application/graphql-response+json, application/graphql+json, application/json, text/event-stream, multipart/mixed\",\n          \"content-type\": \"application/json\",\n          \"x-test\": \"true\",\n        },\n        \"method\": \"POST\",\n      }\n    `);\n  });\n\n  it('creates a GET request when preferred for query operations', () => {\n    const operation = makeOperation(queryOperation.kind, queryOperation, {\n      ...queryOperation.context,\n      preferGetMethod: 'force',\n    });\n\n    const body = makeFetchBody(operation);\n    expect(makeFetchOptions(operation, body)).toMatchInlineSnapshot(`\n      {\n        \"body\": undefined,\n        \"headers\": {\n          \"accept\": \"application/graphql-response+json, application/graphql+json, application/json, text/event-stream, multipart/mixed\",\n        },\n        \"method\": \"GET\",\n      }\n    `);\n  });\n\n  it('creates a POST multipart request when a file is detected', () => {\n    const operation = makeOperation(mutationOperation.kind, mutationOperation);\n    operation.variables = {\n      ...operation.variables,\n      file: new Blob(),\n    };\n\n    const body = makeFetchBody(operation);\n    const options = makeFetchOptions(operation, body);\n    expect(options).toMatchInlineSnapshot(`\n      {\n        \"body\": FormData {},\n        \"headers\": {\n          \"accept\": \"application/graphql-response+json, application/graphql+json, application/json, text/event-stream, multipart/mixed\",\n        },\n        \"method\": \"POST\",\n      }\n    `);\n\n    expect(options.body).toBeInstanceOf(FormData);\n    const form = options.body as FormData;\n\n    expect(JSON.parse(form.get('operations') as string)).toEqual({\n      ...body,\n      variables: {\n        ...body.variables,\n        file: null,\n      },\n    });\n\n    expect(form.get('map')).toMatchInlineSnapshot(`\"{\"0\":[\"variables.file\"]}\"`);\n    expect(form.get('0')).toBeInstanceOf(Blob);\n  });\n});\n"
  },
  {
    "path": "packages/core/src/internal/fetchOptions.ts",
    "content": "import {\n  stringifyDocument,\n  getOperationName,\n  stringifyVariables,\n  extractFiles,\n} from '../utils';\n\nimport type { AnyVariables, GraphQLRequest, Operation } from '../types';\n\n/** Abstract definition of the JSON data sent during GraphQL HTTP POST requests. */\nexport interface FetchBody {\n  query?: string;\n  documentId?: string;\n  operationName: string | undefined;\n  variables: undefined | Record<string, any>;\n  extensions: undefined | Record<string, any>;\n}\n\n/** Creates a GraphQL over HTTP compliant JSON request body.\n * @param request - An object containing a `query` document and `variables`.\n * @returns A {@link FetchBody}\n * @see {@link https://github.com/graphql/graphql-over-http} for the GraphQL over HTTP spec.\n */\nexport function makeFetchBody<\n  Data = any,\n  Variables extends AnyVariables = AnyVariables,\n>(request: Omit<GraphQLRequest<Data, Variables>, 'key'>): FetchBody {\n  const body: FetchBody = {\n    query: undefined,\n    documentId: undefined,\n    operationName: getOperationName(request.query),\n    variables: request.variables || undefined,\n    extensions: request.extensions,\n  };\n\n  if (\n    'documentId' in request.query &&\n    request.query.documentId &&\n    // NOTE: We have to check that the document will definitely be sent\n    // as a persisted document to avoid breaking changes\n    (!request.query.definitions || !request.query.definitions.length)\n  ) {\n    body.documentId = request.query.documentId;\n  } else if (\n    !request.extensions ||\n    !request.extensions.persistedQuery ||\n    !!request.extensions.persistedQuery.miss\n  ) {\n    body.query = stringifyDocument(request.query);\n  }\n\n  return body;\n}\n\n/** Creates a URL that will be called for a GraphQL HTTP request.\n *\n * @param operation - An {@link Operation} for which to make the request.\n * @param body - A {@link FetchBody} which may be replaced with a URL.\n *\n * @remarks\n * Creates the URL that’ll be called as part of a GraphQL HTTP request.\n * Built-in fetch exchanges support sending GET requests, even for\n * non-persisted full requests, which this function supports by being\n * able to serialize GraphQL requests into the URL.\n */\nexport const makeFetchURL = (\n  operation: Operation,\n  body?: FetchBody\n): string => {\n  const useGETMethod =\n    operation.kind === 'query' && operation.context.preferGetMethod;\n  if (!useGETMethod || !body) return operation.context.url;\n\n  const urlParts = splitOutSearchParams(operation.context.url);\n  for (const key in body) {\n    const value = body[key];\n    if (value) {\n      urlParts[1].set(\n        key,\n        typeof value === 'object' ? stringifyVariables(value) : value\n      );\n    }\n  }\n  const finalUrl = urlParts.join('?');\n  if (finalUrl.length > 2047 && useGETMethod !== 'force') {\n    operation.context.preferGetMethod = false;\n    return operation.context.url;\n  }\n\n  return finalUrl;\n};\n\nconst splitOutSearchParams = (\n  url: string\n): readonly [string, URLSearchParams] => {\n  const start = url.indexOf('?');\n  return start > -1\n    ? [url.slice(0, start), new URLSearchParams(url.slice(start + 1))]\n    : [url, new URLSearchParams()];\n};\n\n/** Serializes a {@link FetchBody} into a {@link RequestInit.body} format. */\nconst serializeBody = (\n  operation: Operation,\n  body?: FetchBody\n): FormData | string | undefined => {\n  const omitBody =\n    operation.kind === 'query' && !!operation.context.preferGetMethod;\n  if (body && !omitBody) {\n    const json = stringifyVariables(body);\n    const files = extractFiles(body.variables);\n    if (files.size) {\n      const form = new FormData();\n      form.append('operations', json);\n      form.append(\n        'map',\n        stringifyVariables({\n          ...[...files.keys()].map(value => [value]),\n        })\n      );\n      let index = 0;\n      for (const file of files.values()) form.append(`${index++}`, file);\n      return form;\n    }\n    return json;\n  }\n};\n\nconst isHeaders = (headers: HeadersInit): headers is Headers =>\n  'has' in headers && !Object.keys(headers).length;\n\n/** Creates a `RequestInit` object for a given `Operation`.\n *\n * @param operation - An {@link Operation} for which to make the request.\n * @param body - A {@link FetchBody} which is added to the options, if the request isn’t a GET request.\n *\n * @remarks\n * Creates the fetch options {@link RequestInit} object that’ll be passed to the Fetch API\n * as part of a GraphQL over HTTP request. It automatically sets a default `Content-Type`\n * header.\n *\n * @see {@link https://github.com/graphql/graphql-over-http} for the GraphQL over HTTP spec.\n * @see {@link https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API} for the Fetch API spec.\n */\nexport const makeFetchOptions = (\n  operation: Operation,\n  body?: FetchBody\n): RequestInit => {\n  const headers: HeadersInit = {\n    accept:\n      operation.kind === 'subscription'\n        ? 'text/event-stream, multipart/mixed'\n        : 'application/graphql-response+json, application/graphql+json, application/json, text/event-stream, multipart/mixed',\n  };\n  const extraOptions =\n    (typeof operation.context.fetchOptions === 'function'\n      ? operation.context.fetchOptions()\n      : operation.context.fetchOptions) || {};\n  if (extraOptions.headers) {\n    if (isHeaders(extraOptions.headers)) {\n      extraOptions.headers.forEach((value, key) => {\n        headers[key] = value;\n      });\n    } else if (Array.isArray(extraOptions.headers)) {\n      (extraOptions.headers as Array<[string, string]>).forEach(\n        (value, key) => {\n          if (Array.isArray(value)) {\n            if (headers[value[0]]) {\n              headers[value[0]] = `${headers[value[0]]},${value[1]}`;\n            } else {\n              headers[value[0]] = value[1];\n            }\n          } else {\n            headers[key] = value;\n          }\n        }\n      );\n    } else {\n      for (const key in extraOptions.headers) {\n        headers[key.toLowerCase()] = extraOptions.headers[key];\n      }\n    }\n  }\n\n  const serializedBody = serializeBody(operation, body);\n  if (typeof serializedBody === 'string' && !headers['content-type'])\n    headers['content-type'] = 'application/json';\n  return {\n    ...extraOptions,\n    method: serializedBody ? 'POST' : 'GET',\n    body: serializedBody,\n    headers,\n  };\n};\n"
  },
  {
    "path": "packages/core/src/internal/fetchSource.test.ts",
    "content": "import { pipe, scan, subscribe, toPromise } from 'wonka';\nimport {\n  vi,\n  expect,\n  it,\n  beforeEach,\n  describe,\n  beforeAll,\n  Mock,\n  afterAll,\n} from 'vitest';\n\nimport { queryOperation, context } from '../test-utils';\nimport { makeFetchSource } from './fetchSource';\nimport { gql } from '../gql';\nimport { OperationResult, Operation } from '../types';\nimport { makeOperation } from '../utils';\n\nconst fetch = (globalThis as any).fetch as Mock;\nconst abort = vi.fn();\n\nbeforeAll(() => {\n  (globalThis as any).AbortController = function AbortController() {\n    this.signal = undefined;\n    this.abort = abort;\n  };\n});\n\nbeforeEach(() => {\n  fetch.mockClear();\n  abort.mockClear();\n});\n\nafterAll(() => {\n  (globalThis as any).AbortController = undefined;\n});\n\nconst response = JSON.stringify({\n  status: 200,\n  data: {\n    data: {\n      user: 1200,\n    },\n  },\n});\n\ndescribe('on success', () => {\n  beforeEach(() => {\n    fetch.mockResolvedValue({\n      status: 200,\n      headers: { get: () => 'application/json' },\n      text: vi.fn().mockResolvedValue(response),\n    });\n  });\n\n  it('returns response data', async () => {\n    const fetchOptions = {};\n    const data = await pipe(\n      makeFetchSource(queryOperation, 'https://test.com/graphql', fetchOptions),\n      toPromise\n    );\n\n    expect(data).toMatchSnapshot();\n\n    expect(fetch).toHaveBeenCalled();\n    expect(fetch.mock.calls[0][0]).toBe('https://test.com/graphql');\n    expect(fetch.mock.calls[0][1]).toBe(fetchOptions);\n  });\n\n  it('uses the mock fetch if given', async () => {\n    const fetchOptions = {};\n    const fetcher = vi.fn().mockResolvedValue({\n      status: 200,\n      headers: { get: () => 'application/json' },\n      text: vi.fn().mockResolvedValue(response),\n    });\n\n    const data = await pipe(\n      makeFetchSource(\n        {\n          ...queryOperation,\n          context: {\n            ...queryOperation.context,\n            fetch: fetcher,\n          },\n        },\n        'https://test.com/graphql',\n        fetchOptions\n      ),\n      toPromise\n    );\n\n    expect(data).toMatchSnapshot();\n    expect(fetch).not.toHaveBeenCalled();\n    expect(fetcher).toHaveBeenCalled();\n  });\n});\n\ndescribe('on error', () => {\n  beforeEach(() => {\n    fetch.mockResolvedValue({\n      status: 400,\n      statusText: 'Forbidden',\n      headers: { get: () => 'application/json' },\n      text: vi.fn().mockResolvedValue('{}'),\n    });\n  });\n\n  it('handles network errors', async () => {\n    const error = new Error('test');\n    fetch.mockRejectedValue(error);\n\n    const fetchOptions = {};\n    const data = await pipe(\n      makeFetchSource(queryOperation, 'https://test.com/graphql', fetchOptions),\n      toPromise\n    );\n\n    expect(data).toHaveProperty('error.networkError', error);\n  });\n\n  it('returns error data', async () => {\n    const fetchOptions = {};\n    const data = await pipe(\n      makeFetchSource(queryOperation, 'https://test.com/graphql', fetchOptions),\n      toPromise\n    );\n\n    expect(data).toMatchSnapshot();\n  });\n\n  it('returns error data with status 400 and manual redirect mode', async () => {\n    const data = await pipe(\n      makeFetchSource(queryOperation, 'https://test.com/graphql', {\n        redirect: 'manual',\n      }),\n      toPromise\n    );\n\n    expect(data).toMatchSnapshot();\n  });\n\n  it('ignores the error when a result is available', async () => {\n    const data = await pipe(\n      makeFetchSource(queryOperation, 'https://test.com/graphql', {}),\n      toPromise\n    );\n\n    expect(data).toMatchSnapshot();\n  });\n});\n\ndescribe('on unexpected plain text responses', () => {\n  beforeEach(() => {\n    fetch.mockResolvedValue({\n      status: 200,\n      headers: new Map([['Content-Type', 'text/plain']]),\n      text: vi.fn().mockResolvedValue('Some Error Message'),\n    });\n  });\n\n  it('returns error data', async () => {\n    const fetchOptions = {};\n    const result = await pipe(\n      makeFetchSource(queryOperation, 'https://test.com/graphql', fetchOptions),\n      toPromise\n    );\n\n    expect(result.error).toMatchObject({\n      message: '[Network] Some Error Message',\n    });\n  });\n});\n\ndescribe('on error with non spec-compliant body', () => {\n  beforeEach(() => {\n    fetch.mockResolvedValue({\n      status: 400,\n      statusText: 'Forbidden',\n      headers: { get: () => 'application/json' },\n      text: vi.fn().mockResolvedValue('{\"errors\":{\"detail\":\"Bad Request\"}}'),\n    });\n  });\n\n  it('handles network errors', async () => {\n    const data = await pipe(\n      makeFetchSource(queryOperation, 'https://test.com/graphql', {}),\n      toPromise\n    );\n\n    expect(data).toMatchSnapshot();\n    expect(data).toHaveProperty('error.networkError.message', 'Forbidden');\n  });\n});\n\ndescribe('on teardown', () => {\n  const fail = () => {\n    expect(true).toEqual(false);\n  };\n\n  it('does not start the outgoing request on immediate teardowns', async () => {\n    fetch.mockImplementation(async () => {\n      await new Promise(() => {\n        /*noop*/\n      });\n    });\n\n    const { unsubscribe } = pipe(\n      makeFetchSource(queryOperation, 'https://test.com/graphql', {}),\n      subscribe(fail)\n    );\n\n    unsubscribe();\n\n    // NOTE: We can only observe the async iterator's final run after a macro tick\n\n    await new Promise(resolve => setTimeout(resolve));\n    expect(fetch).toHaveBeenCalledTimes(0);\n    expect(abort).toHaveBeenCalledTimes(1);\n  });\n\n  it('aborts the outgoing request', async () => {\n    fetch.mockResolvedValue({\n      status: 200,\n      headers: new Map([['Content-Type', 'application/json']]),\n      text: vi.fn().mockResolvedValue('{ \"data\": null }'),\n    });\n\n    const { unsubscribe } = pipe(\n      makeFetchSource(queryOperation, 'https://test.com/graphql', {}),\n      subscribe(() => {\n        /*noop*/\n      })\n    );\n\n    await new Promise(resolve => setTimeout(resolve));\n    unsubscribe();\n\n    // NOTE: We can only observe the async iterator's final run after a macro tick\n    await new Promise(resolve => setTimeout(resolve));\n    expect(fetch).toHaveBeenCalledTimes(1);\n    expect(abort).toHaveBeenCalledTimes(1);\n  });\n});\n\ndescribe('on multipart/mixed', () => {\n  const wrap = (json: object) =>\n    '\\r\\n' +\n    'Content-Type: application/json; charset=utf-8\\r\\n\\r\\n' +\n    JSON.stringify(json) +\n    '\\r\\n---';\n\n  it('listens for more streamed responses', async () => {\n    fetch.mockResolvedValue({\n      status: 200,\n      headers: {\n        get() {\n          return 'multipart/mixed';\n        },\n      },\n      body: {\n        getReader: function () {\n          let cancelled = false;\n          const results = [\n            {\n              done: false,\n              value: Buffer.from('\\r\\n---'),\n            },\n            {\n              done: false,\n              value: Buffer.from(\n                wrap({\n                  hasNext: true,\n                  data: {\n                    author: {\n                      id: '1',\n                      __typename: 'Author',\n                    },\n                  },\n                })\n              ),\n            },\n            {\n              done: false,\n              value: Buffer.from(\n                wrap({\n                  incremental: [\n                    {\n                      path: ['author'],\n                      data: { name: 'Steve' },\n                    },\n                  ],\n                  hasNext: true,\n                })\n              ),\n            },\n            {\n              done: false,\n              value: Buffer.from(wrap({ hasNext: false }) + '--'),\n            },\n            { done: true },\n          ];\n          let count = 0;\n          return {\n            cancel: function () {\n              cancelled = true;\n            },\n            read: function () {\n              if (cancelled) throw new Error('No');\n\n              return Promise.resolve(results[count++]);\n            },\n          };\n        },\n      },\n    });\n\n    const AuthorFragment = gql`\n      fragment authorFields on Author {\n        name\n      }\n    `;\n\n    const streamedQueryOperation: Operation = makeOperation(\n      'query',\n      {\n        query: gql`\n          query {\n            author {\n              id\n              ...authorFields @defer\n            }\n          }\n\n          ${AuthorFragment}\n        `,\n        variables: {},\n        key: 1,\n      },\n      context\n    );\n\n    const chunks: OperationResult[] = await pipe(\n      makeFetchSource(streamedQueryOperation, 'https://test.com/graphql', {}),\n      scan((prev: OperationResult[], item) => [...prev, item], []),\n      toPromise\n    );\n\n    expect(chunks.length).toEqual(3);\n\n    expect(chunks[0].data).toEqual({\n      author: {\n        id: '1',\n        __typename: 'Author',\n      },\n    });\n\n    expect(chunks[1].data).toEqual({\n      author: {\n        id: '1',\n        name: 'Steve',\n        __typename: 'Author',\n      },\n    });\n\n    expect(chunks[2].data).toEqual({\n      author: {\n        id: '1',\n        name: 'Steve',\n        __typename: 'Author',\n      },\n    });\n  });\n});\n\ndescribe('on text/event-stream', () => {\n  const wrap = (json: object) => 'data: ' + JSON.stringify(json) + '\\n\\n';\n\n  it('listens for streamed responses', async () => {\n    fetch.mockResolvedValue({\n      status: 200,\n      headers: {\n        get() {\n          return 'text/event-stream';\n        },\n      },\n      body: {\n        getReader: function () {\n          let cancelled = false;\n          const results = [\n            {\n              done: false,\n              value: Buffer.from(\n                wrap({\n                  hasNext: true,\n                  data: {\n                    author: {\n                      id: '1',\n                      __typename: 'Author',\n                    },\n                  },\n                })\n              ),\n            },\n            {\n              done: false,\n              value: Buffer.from(\n                wrap({\n                  incremental: [\n                    {\n                      path: ['author'],\n                      data: { name: 'Steve' },\n                    },\n                  ],\n                  hasNext: true,\n                })\n              ),\n            },\n            {\n              done: false,\n              value: Buffer.from(wrap({ hasNext: false })),\n            },\n            { done: true },\n          ];\n          let count = 0;\n          return {\n            cancel: function () {\n              cancelled = true;\n            },\n            read: function () {\n              if (cancelled) throw new Error('No');\n\n              return Promise.resolve(results[count++]);\n            },\n          };\n        },\n      },\n    });\n\n    const AuthorFragment = gql`\n      fragment authorFields on Author {\n        name\n      }\n    `;\n\n    const streamedQueryOperation: Operation = makeOperation(\n      'query',\n      {\n        query: gql`\n          query {\n            author {\n              id\n              ...authorFields @defer\n            }\n          }\n\n          ${AuthorFragment}\n        `,\n        variables: {},\n        key: 1,\n      },\n      context\n    );\n\n    const chunks: OperationResult[] = await pipe(\n      makeFetchSource(streamedQueryOperation, 'https://test.com/graphql', {}),\n      scan((prev: OperationResult[], item) => [...prev, item], []),\n      toPromise\n    );\n\n    expect(chunks.length).toEqual(3);\n\n    expect(chunks[0].data).toEqual({\n      author: {\n        id: '1',\n        __typename: 'Author',\n      },\n    });\n\n    expect(chunks[1].data).toEqual({\n      author: {\n        id: '1',\n        name: 'Steve',\n        __typename: 'Author',\n      },\n    });\n\n    expect(chunks[2].data).toEqual({\n      author: {\n        id: '1',\n        name: 'Steve',\n        __typename: 'Author',\n      },\n    });\n  });\n\n  it('merges deferred results on the root-type', async () => {\n    fetch.mockResolvedValue({\n      status: 200,\n      headers: {\n        get() {\n          return 'text/event-stream';\n        },\n      },\n      body: {\n        getReader: function () {\n          let cancelled = false;\n          const results = [\n            {\n              done: false,\n              value: Buffer.from(\n                wrap({\n                  hasNext: true,\n                  data: {\n                    author: {\n                      id: '1',\n                      __typename: 'Author',\n                    },\n                  },\n                })\n              ),\n            },\n            {\n              done: false,\n              value: Buffer.from(\n                wrap({\n                  incremental: [\n                    {\n                      path: [],\n                      data: { author: { name: 'Steve' } },\n                    },\n                  ],\n                  hasNext: true,\n                })\n              ),\n            },\n            {\n              done: false,\n              value: Buffer.from(wrap({ hasNext: false })),\n            },\n            { done: true },\n          ];\n          let count = 0;\n          return {\n            cancel: function () {\n              cancelled = true;\n            },\n            read: function () {\n              if (cancelled) throw new Error('No');\n\n              return Promise.resolve(results[count++]);\n            },\n          };\n        },\n      },\n    });\n\n    const AuthorFragment = gql`\n      fragment authorFields on Query {\n        author {\n          name\n        }\n      }\n    `;\n\n    const streamedQueryOperation: Operation = makeOperation(\n      'query',\n      {\n        query: gql`\n          query {\n            author {\n              id\n              ...authorFields @defer\n            }\n          }\n\n          ${AuthorFragment}\n        `,\n        variables: {},\n        key: 1,\n      },\n      context\n    );\n\n    const chunks: OperationResult[] = await pipe(\n      makeFetchSource(streamedQueryOperation, 'https://test.com/graphql', {}),\n      scan((prev: OperationResult[], item) => [...prev, item], []),\n      toPromise\n    );\n\n    expect(chunks.length).toEqual(3);\n\n    expect(chunks[0].data).toEqual({\n      author: {\n        id: '1',\n        __typename: 'Author',\n      },\n    });\n\n    expect(chunks[1].data).toEqual({\n      author: {\n        id: '1',\n        name: 'Steve',\n        __typename: 'Author',\n      },\n    });\n\n    expect(chunks[2].data).toEqual({\n      author: {\n        id: '1',\n        name: 'Steve',\n        __typename: 'Author',\n      },\n    });\n  });\n});\n"
  },
  {
    "path": "packages/core/src/internal/fetchSource.ts",
    "content": "/* Summary: This file handles the HTTP transport via GraphQL over HTTP\n * See: https://graphql.github.io/graphql-over-http/draft/\n *\n * `@urql/core`, by default, implements several RFC'd protocol extensions\n * on top of this. As such, this implementation supports:\n * - [Incremental Delivery](https://github.com/graphql/graphql-over-http/blob/main/rfcs/IncrementalDelivery.md)\n * - [GraphQL over SSE](https://github.com/graphql/graphql-over-http/blob/main/rfcs/GraphQLOverSSE.md)\n *\n * This also supports the \"Defer Stream\" payload format.\n * See: https://github.com/graphql/graphql-wg/blob/main/rfcs/DeferStream.md\n * Implementation for this is located in `../utils/result.ts` in `mergeResultPatch`\n *\n * And; this also supports the GraphQL Multipart spec for file uploads.\n * See: https://github.com/jaydenseric/graphql-multipart-request-spec\n * Implementation for this is located in `../utils/variables.ts` in `extractFiles`,\n * and `./fetchOptions.ts` in `serializeBody`.\n *\n * And; this also supports GET requests (and hence; automatic persisted queries)\n * via the `@urql/exchange-persisted` package.\n *\n * This implementation DOES NOT support Batching.\n * See: https://github.com/graphql/graphql-over-http/blob/main/rfcs/Batching.md\n * Which is deemed out-of-scope, as it's sufficiently unnecessary given\n * modern handling of HTTP requests being in parallel.\n *\n * The implementation in this file needs to make certain accommodations for:\n * - The Web Fetch API\n * - Non-browser or polyfill Fetch APIs\n * - Node.js-like Fetch implementations\n *\n * GraphQL over SSE has a reference implementation, which supports non-HTTP/2\n * modes and is a faithful implementation of the spec.\n * See: https://github.com/enisdenjo/graphql-sse\n *\n * GraphQL Inremental Delivery (aka “GraphQL Multipart Responses”) has a\n * reference implementation, which a prior implementation of this file heavily\n * leaned on (See prior attribution comments)\n * See: https://github.com/maraisr/meros\n *\n * This file merges support for all three GraphQL over HTTP response formats\n * via async generators and Wonka’s `fromAsyncIterable`. As part of this, `streamBody`\n * and `split` are the common, cross-compatible base implementations.\n */\n\nimport type { Source } from 'wonka';\nimport { fromAsyncIterable, onEnd, filter, pipe } from 'wonka';\nimport type { Operation, OperationResult, ExecutionResult } from '../types';\nimport { makeResult, makeErrorResult, mergeResultPatch } from '../utils';\n\nconst boundaryHeaderRe = /boundary=\"?([^=\";]+)\"?/i;\nconst eventStreamRe = /data: ?([^\\n]+)/;\n\ntype ChunkData = Buffer | Uint8Array;\n\nasync function* streamBody(\n  response: Response\n): AsyncIterableIterator<ChunkData> {\n  if (response.body![Symbol.asyncIterator]) {\n    for await (const chunk of response.body! as any) yield chunk as ChunkData;\n  } else {\n    const reader = response.body!.getReader();\n    let result: ReadableStreamReadResult<ChunkData>;\n    try {\n      while (!(result = await reader.read()).done) yield result.value;\n    } finally {\n      reader.cancel();\n    }\n  }\n}\n\nasync function* streamToBoundedChunks(\n  chunks: AsyncIterableIterator<ChunkData>,\n  boundary: string\n): AsyncIterableIterator<string> {\n  const decoder = typeof TextDecoder !== 'undefined' ? new TextDecoder() : null;\n  let buffer = '';\n  let boundaryIndex: number;\n  for await (const chunk of chunks) {\n    // NOTE: We're avoiding referencing the `Buffer` global here to prevent\n    // auto-polyfilling in Webpack\n    buffer +=\n      chunk.constructor.name === 'Buffer'\n        ? (chunk as Buffer).toString()\n        : decoder!.decode(chunk as ArrayBuffer, { stream: true });\n    while ((boundaryIndex = buffer.indexOf(boundary)) > -1) {\n      yield buffer.slice(0, boundaryIndex);\n      buffer = buffer.slice(boundaryIndex + boundary.length);\n    }\n  }\n}\n\nasync function* parseJSON(\n  response: Response\n): AsyncIterableIterator<ExecutionResult> {\n  yield JSON.parse(await response.text());\n}\n\nasync function* parseEventStream(\n  response: Response\n): AsyncIterableIterator<ExecutionResult> {\n  let payload: any;\n  for await (const chunk of streamToBoundedChunks(\n    streamBody(response),\n    '\\n\\n'\n  )) {\n    const match = chunk.match(eventStreamRe);\n    if (match) {\n      const chunk = match[1];\n      try {\n        yield (payload = JSON.parse(chunk));\n      } catch (error) {\n        if (!payload) throw error;\n      }\n      if (payload && payload.hasNext === false) break;\n    }\n  }\n  if (payload && payload.hasNext !== false) {\n    yield { hasNext: false };\n  }\n}\n\nasync function* parseMultipartMixed(\n  contentType: string,\n  response: Response\n): AsyncIterableIterator<ExecutionResult> {\n  const boundaryHeader = contentType.match(boundaryHeaderRe);\n  const boundary = '--' + (boundaryHeader ? boundaryHeader[1] : '-');\n  let isPreamble = true;\n  let payload: any;\n  for await (let chunk of streamToBoundedChunks(\n    streamBody(response),\n    '\\r\\n' + boundary\n  )) {\n    if (isPreamble) {\n      isPreamble = false;\n      const preambleIndex = chunk.indexOf(boundary);\n      if (preambleIndex > -1) {\n        chunk = chunk.slice(preambleIndex + boundary.length);\n      } else {\n        continue;\n      }\n    }\n    try {\n      yield (payload = JSON.parse(chunk.slice(chunk.indexOf('\\r\\n\\r\\n') + 4)));\n    } catch (error) {\n      if (!payload) throw error;\n    }\n    if (payload && payload.hasNext === false) break;\n  }\n  if (payload && payload.hasNext !== false) {\n    yield { hasNext: false };\n  }\n}\n\nasync function* parseMaybeJSON(\n  response: Response\n): AsyncIterableIterator<ExecutionResult> {\n  const text = await response.text();\n  try {\n    const result = JSON.parse(text);\n    if (process.env.NODE_ENV !== 'production') {\n      console.warn(\n        `Found response with content-type \"text/plain\" but it had a valid \"application/json\" response.`\n      );\n    }\n    yield result;\n  } catch (e) {\n    throw new Error(text);\n  }\n}\n\nasync function* fetchOperation(\n  operation: Operation,\n  url: string,\n  fetchOptions: RequestInit\n) {\n  let networkMode = true;\n  let result: OperationResult | null = null;\n  let response: Response | undefined;\n\n  try {\n    // Delay for a tick to give the Client a chance to cancel the request\n    // if a teardown comes in immediately\n    yield await Promise.resolve();\n\n    response = await (operation.context.fetch || fetch)(url, fetchOptions);\n    const contentType = response.headers.get('Content-Type') || '';\n\n    let results: AsyncIterable<ExecutionResult>;\n    if (/multipart\\/mixed/i.test(contentType)) {\n      results = parseMultipartMixed(contentType, response);\n    } else if (/text\\/event-stream/i.test(contentType)) {\n      results = parseEventStream(response);\n    } else if (!/text\\//i.test(contentType)) {\n      results = parseJSON(response);\n    } else {\n      results = parseMaybeJSON(response);\n    }\n\n    let pending: ExecutionResult['pending'];\n    for await (const payload of results) {\n      if (payload.pending && !result) {\n        pending = payload.pending;\n      } else if (payload.pending) {\n        pending = [...pending!, ...payload.pending];\n      }\n      result = result\n        ? mergeResultPatch(result, payload, response, pending)\n        : makeResult(operation, payload, response);\n      networkMode = false;\n      yield result;\n      networkMode = true;\n    }\n\n    if (!result) {\n      yield (result = makeResult(operation, {}, response));\n    }\n  } catch (error: any) {\n    if (!networkMode) {\n      throw error;\n    }\n\n    yield makeErrorResult(\n      operation,\n      response &&\n        (response.status < 200 || response.status >= 300) &&\n        response.statusText\n        ? new Error(response.statusText)\n        : error,\n      response\n    );\n  }\n}\n\n/** Makes a GraphQL HTTP request to a given API by wrapping around the Fetch API.\n *\n * @param operation - The {@link Operation} that should be sent via GraphQL over HTTP.\n * @param url - The endpoint URL for the GraphQL HTTP API.\n * @param fetchOptions - The {@link RequestInit} fetch options for the request.\n * @returns A Wonka {@link Source} of {@link OperationResult | OperationResults}.\n *\n * @remarks\n * This utility defines how all built-in fetch exchanges make GraphQL HTTP requests,\n * supporting multipart incremental responses, cancellation and other smaller\n * implementation details.\n *\n * If you’re implementing a modified fetch exchange for a GraphQL over HTTP API\n * it’s recommended you use this utility.\n *\n * Hint: This function does not use the passed `operation` to create or modify the\n * `fetchOptions` and instead expects that the options have already been created\n * using {@link makeFetchOptions} and modified as needed.\n *\n * @throws\n * If the `fetch` polyfill or globally available `fetch` function doesn’t support\n * streamed multipart responses while trying to handle a `multipart/mixed` GraphQL response,\n * the source will throw “Streaming requests unsupported”.\n * This shouldn’t happen in modern browsers and Node.js.\n *\n * @see {@link https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API} for the Fetch API spec.\n */\nexport function makeFetchSource(\n  operation: Operation,\n  url: string,\n  fetchOptions: RequestInit\n): Source<OperationResult> {\n  let abortController: AbortController | void;\n  if (typeof AbortController !== 'undefined') {\n    fetchOptions.signal = (abortController = new AbortController()).signal;\n  }\n  return pipe(\n    fromAsyncIterable(fetchOperation(operation, url, fetchOptions)),\n    filter((result): result is OperationResult => !!result),\n    onEnd(() => {\n      if (abortController) abortController.abort();\n    })\n  );\n}\n"
  },
  {
    "path": "packages/core/src/internal/index.ts",
    "content": "export * from './fetchOptions';\nexport * from './fetchSource';\n"
  },
  {
    "path": "packages/core/src/test-utils/index.ts",
    "content": "export * from './samples';\n"
  },
  {
    "path": "packages/core/src/test-utils/samples.ts",
    "content": "import { gql } from '../gql';\n\nimport type {\n  ExecutionResult,\n  GraphQLRequest,\n  Operation,\n  OperationContext,\n  OperationResult,\n} from '../types';\nimport { makeOperation } from '../utils';\n\nexport const context: OperationContext = {\n  fetchOptions: {\n    method: 'POST',\n  },\n  requestPolicy: 'cache-first',\n  url: 'http://localhost:3000/graphql',\n};\n\nexport const queryGql: GraphQLRequest = {\n  key: 2,\n  query: gql`\n    query getUser($name: String) {\n      user(name: $name) {\n        id\n        firstName\n        lastName\n      }\n    }\n  `,\n  variables: {\n    name: 'Clara',\n  },\n};\n\nexport const mutationGql: GraphQLRequest = {\n  key: 3,\n  query: gql`\n    mutation AddUser($name: String) {\n      addUser(name: $name) {\n        name\n      }\n    }\n  `,\n  variables: {\n    name: 'Clara',\n  },\n};\n\nexport const subscriptionGql: GraphQLRequest = {\n  key: 4,\n  query: gql`\n    subscription subscribeToUser($user: String) {\n      user(user: $user) {\n        name\n      }\n    }\n  `,\n  variables: {\n    user: 'colin',\n  },\n};\n\nexport const queryOperation: Operation = makeOperation(\n  'query',\n  {\n    query: queryGql.query,\n    variables: queryGql.variables,\n    key: queryGql.key,\n  },\n  context\n);\n\nexport const teardownOperation: Operation = makeOperation(\n  'teardown',\n  {\n    query: queryOperation.query,\n    variables: queryOperation.variables,\n    key: queryOperation.key,\n  },\n  context\n);\n\nexport const mutationOperation: Operation = makeOperation(\n  'mutation',\n  {\n    query: mutationGql.query,\n    variables: mutationGql.variables,\n    key: mutationGql.key,\n  },\n  context\n);\n\nexport const subscriptionOperation: Operation = makeOperation(\n  'subscription',\n  {\n    query: subscriptionGql.query,\n    variables: subscriptionGql.variables,\n    key: subscriptionGql.key,\n  },\n  context\n);\n\nexport const undefinedQueryResponse: OperationResult = {\n  operation: queryOperation,\n  stale: false,\n  hasNext: false,\n};\n\nexport const queryResponse: OperationResult = {\n  operation: queryOperation,\n  data: {\n    user: {\n      name: 'Clive',\n    },\n  },\n  stale: false,\n  hasNext: false,\n};\n\nexport const mutationResponse: OperationResult = {\n  operation: mutationOperation,\n  data: {},\n  stale: false,\n  hasNext: false,\n};\n\nexport const subscriptionResult: ExecutionResult = {\n  data: {},\n};\n"
  },
  {
    "path": "packages/core/src/types.ts",
    "content": "import type { GraphQLError, DocumentNode } from './utils/graphql';\nimport type {\n  Kind,\n  DirectiveNode,\n  ValueNode,\n  TypeNode,\n} from '@0no-co/graphql.web';\nimport type { Subscription, Source } from 'wonka';\nimport type { Client } from './client';\nimport type { CombinedError } from './utils/error';\n\n/** A GraphQL persisted document will contain `documentId` that replaces its definitions */\nexport interface PersistedDocument extends DocumentNode {\n  documentId?: string;\n}\n\n/** A GraphQL `DocumentNode` with attached generics for its result data and variables.\n *\n * @remarks\n * A GraphQL {@link DocumentNode} defines both the variables it accepts on request and the `data`\n * shape it delivers on a response in the GraphQL query language.\n *\n * To bridge the gap to TypeScript, tools may be used to generate TypeScript types that define the shape\n * of `data` and `variables` ahead of time. These types are then attached to GraphQL documents using this\n * `TypedDocumentNode` type.\n *\n * Using a `DocumentNode` that is typed like this will cause any `urql` API to type its input `variables`\n * and resulting `data` using the types provided.\n *\n * @privateRemarks\n * For compatibility reasons this type has been copied and internalized from:\n * https://github.com/dotansimha/graphql-typed-document-node/blob/3711b12/packages/core/src/index.ts#L3-L10\n *\n * @see {@link https://github.com/dotansimha/graphql-typed-document-node} for more information.\n */\nexport type TypedDocumentNode<\n  Result = { [key: string]: any },\n  Variables = { [key: string]: any },\n> = DocumentNode & {\n  /** Type to support `@graphql-typed-document-node/core`\n   * @internal\n   */\n  __apiType?: (variables: Variables) => Result;\n  /** Type to support `TypedQueryDocumentNode` from `graphql`\n   * @internal\n   */\n  __ensureTypesOfVariablesAndResultMatching?: (variables: Variables) => Result;\n};\n\n/** GraphQL nodes with added `_directives` dictionary on nodes with directives.\n *\n * @remarks\n * The {@link formatDocument} utility processes documents to add `__typename`\n * fields to them. It additionally provides additional directives processing\n * and outputs this type.\n *\n * When applied, every node with non-const directives, will have an additional\n * `_directives` dictionary added to it, and filter directives starting with\n * a leading `_` underscore from the directives array.\n */\nexport type FormattedNode<Node> = Node extends readonly (infer Child)[]\n  ? readonly FormattedNode<Child>[]\n  : Node extends ValueNode | TypeNode\n    ? Node\n    : Node extends { kind: Kind }\n      ? {\n          [K in Exclude<keyof Node, 'directives' | 'loc'>]: FormattedNode<\n            Node[K]\n          >;\n        } extends infer Node\n        ? Node extends {\n            kind: Kind.FIELD | Kind.INLINE_FRAGMENT | Kind.FRAGMENT_SPREAD;\n          }\n          ? Node & {\n              _generated?: boolean;\n              _directives?: Record<string, DirectiveNode> | undefined;\n            }\n          : Node\n        : Node\n      : Node;\n\n/** Any GraphQL `DocumentNode` or query string input.\n *\n * @remarks\n * Wherever any `urql` bindings or API expect a query, it accepts either a query string,\n * a `DocumentNode`, or a {@link TypedDocumentNode}.\n */\nexport type DocumentInput<\n  Result = { [key: string]: any },\n  Variables = { [key: string]: any },\n> = string | DocumentNode | TypedDocumentNode<Result, Variables>;\n\n/** A list of errors on {@link ExecutionResult | ExecutionResults}.\n * @see {@link https://spec.graphql.org/draft/#sec-Errors.Error-Result-Format} for the GraphQL Error Result format spec.\n */\nexport type ErrorLike = Partial<GraphQLError> | Error;\n\n/** Extensions which may be placed on {@link ExecutionResult | ExecutionResults}.\n * @see {@link https://spec.graphql.org/draft/#sel-EAPHJCAACCoGu9J} for the GraphQL Error Result format spec.\n */\ntype Extensions = Record<string, any>;\n\n/** Extensions sub-property on `persistedQuery` for Automatic Persisted Queries.\n *\n * @remarks\n * This is part of the Automatic Persisted Query defacto standard and allows an API\n * request to omit the `query`, instead sending this `sha256Hash`.\n */\nexport interface PersistedRequestExtensions {\n  version?: 1;\n  sha256Hash: string;\n  /** Set when a `sha256Hash` previously experienced a miss which will force `query` to be sent. */\n  miss?: boolean;\n}\n\n/** Extensions which may be palced on {@link GraphQLRequest | GraphQLRequests}.\n * @see {@link https://github.com/graphql/graphql-over-http/blob/1928447/spec/GraphQLOverHTTP.md#request-parameters} for the GraphQL over HTTP spec\n */\nexport interface RequestExtensions {\n  persistedQuery?: PersistedRequestExtensions;\n  [extension: string]: any;\n}\n\ntype Path = readonly (string | number)[];\n\n/** Incremental Payloads sent as part of \"Incremental Delivery\" patching prior result data.\n *\n * @remarks\n * \"Incremental Delivery\" works by allowing APIs to stream patches to the client, whih update\n * prior results at the specified `path`.\n *\n * @see {@link https://github.com/graphql/graphql-spec/blob/94363c9/spec/Section%207%20--%20Response.md#incremental} for the incremental payload spec\n */\nexport interface IncrementalPayload {\n  /** Optional label for the incremental payload that corresponds to directives' labels.\n   *\n   * @remarks\n   * All incremental payloads are labelled by the label that `@stream` or `@defer` directives\n   * specified, to identify which directive they originally belonged to.\n   */\n  label?: string | null;\n  /** JSON patch at which to apply the `data` patch or append the `items`.\n   *\n   * @remarks\n   * The `path` indicates the JSON path of a prior result’s `data` structure at which\n   * to insert the patch’s data.\n   * When `items` is set instead, which represents a list of items to insert, the last\n   * entry of the `path` will be an index number at which to start setting the range of\n   * items.\n   */\n  path?: Path;\n  /** An id pointing at an entry in the \"pending\" set of deferred results\n   *\n   * @remarks\n   * When we resolve this id it will give us the path to the deferred Fragment, this\n   * can be afterwards combined with the subPath to get the eventual location of the data.\n   */\n  id?: string;\n  /** A path array from the defer/stream fragment to the location of our data. */\n  subPath?: Path;\n  /** Data to patch into the result data at the given `path`.\n   *\n   * @remarks\n   * This `data`, when set, is merged into the object at the given `path` of the last\n   * result that has been delivered.\n   * This isn't set when `items` is set.\n   */\n  data?: Record<string, unknown> | null;\n  /** List of items to patch into the result data at the given `path`.\n   *\n   * @remarks\n   * The `items`, when provided, is set onto a range in an array, at the given JSON\n   * `path`. The start index is the last entry of the `path` and the end index is\n   * the length of the `items` list added to this index.\n   * This isn't set when `data` is set.\n   */\n  items?: readonly unknown[] | null;\n  /** Contains a list of errors raised by incremental payloads.\n   *\n   * @remarks\n   * The list of `errors` on `incremental` payloads is merged into the list of prior\n   * results’ errors.\n   *\n   * @see {@link https://spec.graphql.org/October2021/#sec-Errors} for the GraphQL Errors Response spec\n   */\n  errors?: ErrorLike[] | readonly ErrorLike[];\n  /** Additional metadata that a GraphQL API may choose to send that is out of spec.\n   * @see {@link https://spec.graphql.org/October2021/#sel-EAPHJCAACCoGu9J} for the GraphQL Response spec\n   */\n  extensions?: Extensions;\n}\n\ntype PendingIncrementalResult = {\n  path: Path;\n  id: string;\n  label?: string;\n};\n\nexport interface ExecutionResult {\n  /** Payloads we are still waiting for from the server.\n   *\n   * @remarks\n   * This was nely introduced in the defer/stream spec iteration of June 2023 https://github.com/graphql/defer-stream-wg/discussions/69\n   * Pending can be present on both Incremental as well as normal execution results, the presence of pending on an incremental\n   * result points at a nested deferred/streamed fragment.\n   */\n  pending?: readonly PendingIncrementalResult[];\n  /** Incremental patches to be applied to a previous result as part of \"Incremental Delivery\".\n   *\n   * @remarks\n   * When this is set `data` and `errors` is typically not set on the result. Instead, the incremental payloads\n   * are applied as patches to a prior result's `data`.\n   *\n   * @see {@link https://github.com/graphql/graphql-spec/blob/94363c9/spec/Section%207%20--%20Response.md#incremental} for the incremental payload spec\n   */\n  incremental?: IncrementalPayload[];\n  /** The result of the execution of the GraphQL operation.\n   * @see {@link https://spec.graphql.org/October2021/#sec-Data} for the GraphQL Data Response spec\n   */\n  data?: null | Record<string, any>;\n  /** Contains a list of errors raised by fields or the request itself.\n   * @see {@link https://spec.graphql.org/October2021/#sec-Errors} for the GraphQL Errors Response spec\n   */\n  errors?: ErrorLike[] | readonly ErrorLike[];\n  /** Additional metadata that a GraphQL API may choose to send that is out of spec.\n   * @see {@link https://spec.graphql.org/October2021/#sel-EAPHJCAACCoGu9J} for the GraphQL Response spec\n   */\n  extensions?: Extensions;\n  /** Flag indicating whether a future, incremental response may update this response.\n   * @see {@link https://github.com/graphql/graphql-wg/blob/main/rfcs/DeferStream.md#payload-format} for the DeferStream spec\n   */\n  hasNext?: boolean;\n  payload?: Omit<ExecutionResult, 'payload'>;\n}\n\n/** A source of {@link OperationResult | OperationResults}, convertable to a promise, subscribable, or Wonka Source.\n *\n * @remarks\n * The {@link Client} will often return a `OperationResultSource` to provide a more flexible Wonka {@link Source}.\n *\n * While a {@link Source} may require you to import helpers to convert it to a `Promise` for a single result, or\n * to subscribe to it, the `OperationResultSource` is a `PromiseLike` and has methods to convert it to a promise,\n * or to subscribe to it with a single method call.\n */\nexport type OperationResultSource<T extends OperationResult> = Source<T> &\n  PromiseLike<T> & {\n    /** Returns the first non-stale, settled results of the source.\n     * @remarks\n     * The `toPromise` method gives you the first result of an `OperationResultSource`\n     * that has `hasNext: false` and `stale: false` set as a `Promise`.\n     *\n     * Hint: If you're trying to get updates for your results, this won't work.\n     * This gives you only a single, promisified result, so it won't receive\n     * cache or other updates.\n     */\n    toPromise(): Promise<T>;\n    /** Alias for Wonka's `subscribe` and calls `onResult` when subscribed to for each new `OperationResult`. */\n    subscribe(onResult: (value: T) => void): Subscription;\n  };\n\n/** A type of Operation, either a GraphQL `query`, `mutation`, or `subscription`; or a `teardown` signal.\n *\n * @remarks\n * Internally, {@link Operation | Operations} instruct the {@link Client} to perform a certain action on its exchanges.\n * Any of the three GraphQL operations tell it to execute these operations, and the `teardown` signal instructs it that\n * the operations are cancelled and/or have ended.\n *\n * The `teardown` signal is sent when nothing is subscribed to an operation anymore and no longer interested in its results\n * or any updates.\n */\nexport type OperationType = 'subscription' | 'query' | 'mutation' | 'teardown';\n\n/** The request and caching strategy that is used by exchanges to retrive cached results.\n *\n * @remarks\n * The `RequestPolicy` is used by cache exchanges to decide how a query operation may be resolved with cached results.h\n * A cache exchange may behave differently depending on which policy is returned.\n *\n * - `cache-first` (the default) prefers cached results and falls back to sending an API request.\n * - `cache-and-network` returns cached results but also always sends an API request in the background.\n * - `network-only` will ignore any cached results and send an API request.\n * - `cache-only` will always return cached results and prevent API requests.\n */\nexport type RequestPolicy =\n  | 'cache-first'\n  | 'cache-and-network'\n  | 'network-only'\n  | 'cache-only';\n\n/** A metadata flag set by cache exchanges to indicate whether a cache miss, a cache hit, or a partial cache hit has occurred.\n *\n * @remarks\n * A cache exchange may update {@link OperationDebugMeta.cacheOutcome} on {@link OperationContext.meta} to indicate whether\n * an operation has been resolved from the cache.\n *\n * A cache hit is considered a result that has fully come from a cache. A partial result is a result that has come from a cache\n * but is incomplete, which may trigger another API request. A cache miss means a result must be requested from the API as no\n * cache result has been delivered.\n */\nexport type CacheOutcome = 'miss' | 'partial' | 'hit';\n\n/** A default type for variables.\n *\n * @remarks\n * While {@link TypedDocumentNode} can be used by generators to add TypeScript types for a GraphQL operation’s\n * variables and result, when this isn’t the case this type is used as a fallback for the `Variables` generic.\n */\nexport type AnyVariables = { [prop: string]: any } | void | undefined;\n\n/** A GraphQL request representing a single execution in GraphQL.\n *\n * @remarks\n * A `GraphQLRequest` is a single executable request that may be used by a cache or a GraphQL API to deliver a result.\n * A request contains a `DocumentNode` for the query document of a GraphQL operation and the `variables` for the given\n * request.\n *\n * A unique `key` is generated to identify the request internally by `urql`. Two requests with the same query and\n * variables will share the same `key`.\n *\n * The `Data` and `Variables` generics may be provided by a {@link TypedDocumentNode}, adding TypeScript types for what\n * the result shape and variables shape are.\n *\n * @see {@link https://spec.graphql.org/October2021/#sec-Executing-Requests} for more information on GraphQL reuqests.\n */\nexport interface GraphQLRequest<\n  Data = any,\n  Variables extends AnyVariables = AnyVariables,\n> {\n  /** Unique identifier for the `GraphQLRequest`.\n   *\n   * @remarks\n   * This is a key that combines the unique key of the `query` and the `variables` into a unique\n   * `key` for the `GraphQLRequest`. Any request with the same query and variables will have a unique\n   * `key` by which results and requests can be identified as identical.\n   *\n   * Internally, a stable, cached `key` is generated for the `DocumentNode` and for the `variables` and\n   * both will be combined into a combined `key` which is set here, based on a DJB2 hash,\n   *\n   * The `variables` will change the key even if they contain a non-JSON reference. If you pass a custom\n   * class instance to `variables` that doesn't contain a `toString` or `toJSON` method, a stable but random\n   * identifier will replace this class to generate a key.\n   */\n  key: number;\n  /** A GraphQL document to execute against a cache or API.\n   *\n   * @remarks\n   * A `GraphQLRequest` is executed against an operation in a GraphQL document.\n   * In `urql`, we expect a document to only contain a single operation that is executed rather than\n   * multiple ones by convention.\n   */\n  query: DocumentNode | PersistedDocument | TypedDocumentNode<Data, Variables>;\n  /** Variables used to execute the `query` document.\n   *\n   * @remarks\n   * The `variables`, based either on the {@link AnyVariables} type or the {@link TypedDocumentNode}'s provided\n   * generic, are sent to the GraphQL API to execute a request.\n   */\n  variables: Variables;\n  /** Additional metadata that a GraphQL API may accept for spec extensions.\n   * @see {@link https://github.com/graphql/graphql-over-http/blob/1928447/spec/GraphQLOverHTTP.md#request-parameters} for the GraphQL over HTTP spec\n   */\n  extensions?: RequestExtensions | undefined;\n}\n\n/** Parameters from which {@link GraphQLRequest | GraphQLRequests} are created from.\n *\n * @remarks\n * A `GraphQLRequest` is a single executable request with a generated `key` to identify\n * their results, whereas `GraphQLRequestParams` is a utility type used to generate\n * inputs for `urql` to create requests from, i.e. it only contains a `query` and\n * `variables`. The type conditionally makes the `variables` property completely\n * optional.\n *\n * @privateRemarks\n * The wrapping union type is needed for passthrough or wrapper utilities that wrap\n * functions like `useQuery` with generics.\n */\nexport type GraphQLRequestParams<\n  Data = any,\n  Variables extends AnyVariables = AnyVariables,\n> =\n  | ({\n      query: DocumentInput<Data, Variables>;\n    } & (Variables extends void\n      ? {\n          variables?: Variables;\n        }\n      : Variables extends {\n            [P in keyof Variables]: undefined extends Variables[P]\n              ? unknown\n              : null extends Variables[P]\n                ? unknown\n                : void extends Variables[P]\n                  ? unknown\n                  : never;\n          }\n        ? {\n            variables?: Variables;\n          }\n        : {\n            variables: Variables;\n          }))\n  | {\n      query: DocumentInput<Data, Variables>;\n      variables: Variables;\n    };\n\n/** Metadata used to annotate an `Operation` in development for the `urql-devtools`.\n *\n * @remarks\n * The `OperationDebugMeta` is found on {@link OperationContext.meta} only in development,\n * and is used to send additional metadata to the `urql-devtools` about the {@link Operation}.\n *\n * In production, most of this metadata will be missing, and it must not be used outside\n * of development, and should only be used by the `urql-devtools`.\n */\nexport interface OperationDebugMeta {\n  /** A label for the source of the `Operation`.\n   *\n   * @remarks\n   * The `source` string indicates a human readable originator for the `Operation`.\n   * This may be set to a component name or function name to indicate what originally\n   * triggered the `Operation`.\n   */\n  source?: string;\n  /** A type of caching outcome set by cache exchanges on `OperationResult`s.\n   *\n   * @remarks\n   * The `cacheOutcome` flag is set to a {@link CacheOutcome} on {@link Operation | Operations}\n   * after they passed through the cache exchange. This flag indicates whether a cache hit, miss,\n   * or partial cache hit has occurred.\n   */\n  cacheOutcome?: CacheOutcome;\n  /** Reserved to indicate the time it took for a GraphQL request to receive a response from a GraphQL API.\n   *\n   * @remarks\n   * The `networkLatency` may be set to the time it took (in ms) for a GraphQL API to respond to a request\n   * and deliver a result.\n   * @internal\n   */\n  networkLatency?: number;\n  /** Reserved to indicate the timestamp at which a GraphQL request was sent to a GraphQL API.\n   *\n   * @remarks\n   * The `startTime` is set to an epoch timestamp (in ms) at which a GraphQL request was started\n   * and sent to a GraphQL API.\n   * @internal\n   */\n  startTime?: number;\n}\n\n/** A unique identity for GraphQL mutations.\n *\n * @remarks\n * GraphQL mutations not only use {@link GraphQLRequest.key} to identify a result, but instead use\n * an identity to mark which result belongs to them.\n *\n * While two GraphQL queries and subscriptions sharing the same variables and the same operation\n * (i.e. `DocumentNode`) are considered identical, two mutations are not.\n * Two GraphQL queries or subscription results with the same {@link GraphQLRequest.key} can be used\n * to resolve any {@link GraphQLRequest} with this same `key`.\n * This is because identical queries and subscriptions are idempotent.\n *\n * However, two mutations with the same variables may receive different results from a GraphQL API,\n * since they may trigger side-effects.\n * This means that `urql` needs an additional identifier to differentiate between two mutations with\n * the same `DocumentNode`s and `variables`.\n */\nexport type OperationInstance = number & {\n  /** Marker to indicate that an `OperationInstance` may not be created by a user.\n   *\n   * @remarks\n   * The {@link Client} creates `OperationInstance` indentities automatically and uses them internally\n   * to identify mutations results as belonging to mutation operations. These are just integers (numbers),\n   * however, they're used as if they are objects (e.g. `{}`). However, since instances of arrays and\n   * objects are not serialisable numbers are used instead.\n   *\n   * Because these are internal, the TypeScript type is marked using a `unique symbol` because they're\n   * created opaquely and privately.\n   *\n   * @internal\n   */\n  readonly _opaque: unique symbol;\n};\n\n/** Additional metadata for an `Operation` used to execute it.\n *\n * @remarks\n * The `OperationContext` is found on {@link Operation.context} and gives exchanges additional metadata\n * and options used to execute the operation.\n *\n * The context can often be changed on a per-operation basis, meaning, APIs on the {@link Client} or\n * bindings can pass a partial context that alters these options for a single operation.\n *\n * The `OperationContext` is populated mostly from the initial options passed to the `Client` at its\n * time of creation, but may also be modified by exchanges when an {@link Operation} is passed through\n * to the next exchange or when a result is returned.\n */\nexport interface OperationContext {\n  /** A unique identity for GraphQL mutations.\n   *\n   * @remarks\n   * This is an internal property set by the `Client` to an identity of type {@link OperationInstance}.\n   * An `OperationInstance` is an identifier that's used to tell two mutation operations with identical\n   * `query` documents and `variables` apart from one another.\n   * @internal\n   */\n  readonly _instance?: OperationInstance | undefined;\n  /** Additional cache tags for `@urql/core`'s document `cacheExchange`.\n   *\n   * @remarks\n   * The built-in {@link cacheExchange} in `@urql/core` is a document cache that uses `__typename`s in\n   * mutation results to invalidate past, cached queries.\n   * The `additionalTypenames` array may be set to the list of custom typenames whenever a result may\n   * not deliver `__typename` properties, e.g. when an empty array may be sent.\n   *\n   * By providing a list of custom typenames you may \"tag\" a result as containing a certain type, which\n   * helps the document cache associate mutations with queries when either don't actually contain a\n   * `__typename` in the JSON result.\n   */\n  additionalTypenames?: string[];\n  /** The `fetch` function used to make API calls.\n   *\n   * @remarks\n   * This is the fetch polyfill used by any fetch exchange to make an API request. By default, when this\n   * option isn't set, any fetch exchange will attempt to use the globally available `fetch` function\n   * to make a request instead.\n   *\n   * @see {@link https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API} for the Fetch API spec.\n   */\n  fetch?: typeof fetch;\n  /** The `url` passed to the `fetch` call on API requests.\n   * @see {@link https://developer.mozilla.org/en-US/docs/Web/API/fetch} for a description of the `fetch` calls.\n   */\n  url: string;\n  /** Additional options passed to the `fetch` call on API requests.\n   *\n   * @remarks\n   * The options in this object or an object returned by a callback function will be merged into the\n   * {@link RequestInit} options passed to the `fetch` call.\n   *\n   * @see {@link https://developer.mozilla.org/en-US/docs/Web/API/fetch} for a description of this object.\n   */\n  fetchOptions?: RequestInit | (() => RequestInit);\n  /** Allows the `fetchExchange` to handle subscriptions.\n   *\n   * @remarks\n   * When set to `true`, subscriptions are allowed to be handled by the {@link fetchExchange} and will\n   * be sent using a `fetch` call as GraphQL over HTTP requests.\n   * This may be enabled on {@link ClientOptions.fetchSubscriptions} when your API supports the\n   * `text/event-stream` and `multipart/mixed` response protocols and is able to use them to\n   * respond with subscription results.\n   */\n  fetchSubscriptions?: boolean;\n  /** The request and caching strategy instructing cache exchanges how to treat cached results.\n   *\n   * @remarks\n   * The {@link RequestPolicy} instructing cache exchanges how to use and treat their cached results.\n   * By default `cache-first` is set and used, which will use cache results, and only make an API request\n   * on a cache miss.\n   */\n  requestPolicy: RequestPolicy;\n  /** Metadata that annotates an `Operation` in development for the `urql-devtools`.\n   *\n   * @remarks\n   * This is metadata that is used by the `urql-devtools` to get more information about `Operation`s and\n   * `OperationResult`s and is filled in by exchanges across the codebase in development.\n   *\n   * This data is not for production use and hence shouldn't be used or relied upon directly.\n   * In production, this may not be set by default exchanges.\n   */\n  meta?: OperationDebugMeta;\n  /** Instructs fetch exchanges to use a GET request.\n   *\n   * @remarks\n   * By default, GraphQL over HTTP requests are always sent as POST requests with a JSON body.\n   * However, sometimes it's preferable to send a GET request instead, for instance, for caching with or\n   * without persisted queries.\n   *\n   * When set to `true`, the `preferGetMethod` instructs fetch exchanges to instead send a GET request\n   * for query operations.\n   *\n   * Additionally, `urql`'s built-in fetch exchanges will default to `'within-url-limit'` and not send a GET request\n   * when the resulting URL would be 2,048 characters or longer. This can be forced and circumvented by setting\n   * this option to `'force'`.\n   */\n  preferGetMethod?: boolean | 'force' | 'within-url-limit';\n  /** A configuration flag indicating whether this operation may trigger \"Suspense\".\n   *\n   * @remarks\n   * This configuration flag is reserved for `urql` (`react-urql`) and `@urql/preact` to activate or\n   * deactivate support for Suspense, and is ignored in other bindings.\n   * When activated here and on {@link `Client.suspense`} it allows the bindings to \"suspend\" instead\n   * of returning a loading state, which will stop updates in a querying component and instead cascade\n   * to a higher suspense boundary for a loading state.\n   *\n   * @see {@link https://beta.reactjs.org/blog/2022/03/29/react-v18#new-suspense-features} for more information on React Suspense.\n   */\n  suspense?: boolean;\n  /** A metdata flag indicating whether this operation triggered optimistic updates.\n   *\n   * @remarks\n   * This configuration flag is reserved for `@urql/exchange-graphcache` and is flipped\n   * when an operation triggerd optimistic updates.\n   */\n  optimistic?: boolean;\n  [key: string]: any;\n}\n\n/** The inputs to `urql`'s Exchange pipeline to instruct them to execute a GraphQL operation.\n *\n * @remarks\n * An `Operation`, in `urql`, starts a {@link GraphQLRequest} and are events. The `kind` of an `Operation` can\n * be set to any operation kind of GraphQL, namely `query`, `mutation`, or `subscription`. To terminate an\n * operation, once it's cancelled, a `teardown` kind event is sent.\n *\n * The {@link ExchangeIO} type describes how {@link Exchange | Exchanges} receive `Operation`s and return\n * `OperationResults`, using `teardown` `Operation`s to cancel ongoing operations.\n *\n * @see {@link https://urql.dev/goto/docs/architecture/#the-client-and-exchanges} for more information\n * on the flow of Exchanges.\n */\nexport interface Operation<\n  Data = any,\n  Variables extends AnyVariables = AnyVariables,\n> extends GraphQLRequest<Data, Variables> {\n  /** The `OperationType` describing the kind of `Operation`.\n   *\n   * @remarks\n   * This is used to describe what to do with the {@link GraphQLRequest} of an {@link Operation} and is set\n   * to a GraphQL operation type (`query`, `mutation`, or `subscription`) to start an `Operation`; and to\n   * `teardown` to cancel an operation, which either terminates it early or lets exchanges know that no\n   * consumer is interested in this operation any longer.\n   */\n  readonly kind: OperationType;\n  /** Holds additional metadata for an `Operation` used to execute it.\n   *\n   * @remarks\n   * The {@link OperationContext} is created by the {@link Client} but may also be modified by\n   * {@link Exchange | Exchanges} and is used as metadata by them.\n   */\n  context: OperationContext;\n}\n\n/** A result for an `Operation` carrying a full GraphQL response.\n *\n * @remarks\n * An `OperationResult` is the result of an {@link Operation} and carry a description of the full response\n * on them. The {@link OperationResult.operation} is set to the `Operation` that this result fulfils.\n *\n * Unlike {@link ExecutionResult}, an `OperationResult` will never be an incremental result and will\n * always match the fully merged type of a GraphQL request. It essentially is a postprocessed version\n * of a GraphQL API response.\n */\nexport interface OperationResult<\n  Data = any,\n  Variables extends AnyVariables = AnyVariables,\n> {\n  /** The [operation]{@link Operation} which has been executed. */\n  /** The `Operation` which this `OperationResult` is for.\n   *\n   * @remarks\n   * The `operation` property is set to the {@link Operation} that this result is. At the time the\n   * {@link OperationResult} is constructed (either from the cache or an API response) the original\n   * `Operation` that the exchange delivering this result has received will be added.\n   *\n   * The {@link Client} uses this to identify which {@link Operation} this {@link OperationResult} is\n   * for and to filter and deliver this result to the right place and consumers.\n   */\n  operation: Operation<Data, Variables>;\n  /** The result of the execution of the GraphQL operation.\n   * @see {@link https://spec.graphql.org/October2021/#sec-Data} for the GraphQL Data Response spec\n   */\n  data?: Data;\n  /** Contains a description of errors raised by GraphQL fields or the request itself by the API.\n   *\n   * @remarks\n   * The `error` of an `OperationResult` is set to a {@link CombinedError} if the GraphQL API response\n   * contained any GraphQL errors.\n   *\n   * GraphQL errors occur when either a GraphQL request was prevented from executing entirely\n   * (at which point `data: undefined` is set) or when one or more fields of a GraphQL request\n   * failed to execute. Due to the latter, you may receive partial data when a GraphQL request\n   * partially failed.\n   */\n  error?: CombinedError;\n  /** Additional metadata that a GraphQL API may choose to send that is out of spec.\n   * @see {@link https://spec.graphql.org/October2021/#sel-EAPHJCAACCoGu9J} for the GraphQL Response spec\n   */\n  extensions?: Record<string, any>;\n  /** Indicates that an `OperationResult` is not fresh and a new result will follow.\n   *\n   * @remarks\n   * The `stale` flag indicates whether a result is expected to be superseded by a new result soon.\n   * This flag is set whenever a new result is being awaited and will be deliverd as soon as the API responds.\n   *\n   * It may be set by the {@link Client} when the `Operation` was already active, at which point\n   * the {@link Client} asks the {@link Exchange | Exchanges} to request a new API response, or\n   * by cache exchanges when a temporary, incomplete, or initial cache result has been deliverd, and\n   * a new API request has been started in the background. (For partial cache results)\n   *\n   * Most commonly, this flag is set for a cached result when the operation is executed using the\n   * `cache-and-network` {@link RequestPolicy}.\n   */\n  stale: boolean;\n  /** Indicates that the GraphQL response is streamed and updated results will follow.\n   *\n   * @remarks\n   * Due to incremental delivery, an API may deliver multiple {@link ExecutionResult | ExecutionResults} for a\n   * single GraphQL request. This can happen for `@defer`, `@stream`, or `@live` queries, which allow an API\n   * to update an initial GraphQL response over time, like a subscription.\n   *\n   * For GraphQL subscriptions, this flag will always be set to `true`.\n   */\n  hasNext: boolean;\n}\n\n/** The input parameters a `Client` passes to an `Exchange` when it's created.\n *\n * @remarks\n * When instantiated, a {@link Client} passes these inputs parameters to an {@link Exchange}.\n *\n * This input contains the `Client` itself, a `dispatchDebug` function for the `urql-devtools`, and\n * `forward`, which is set to the next exchange's {@link ExchangeIO} function in the exchange pipeline.\n */\nexport interface ExchangeInput {\n  /** The `Client` that is using this `Exchange`.\n   *\n   * @remarks\n   * The {@link Client} instantiating the {@link Exchange} will call it with the `ExchangeInput` object,\n   * while setting `client` to itself.\n   *\n   * Exchanges use methods like {@link Client.reexecuteOperation} to issue {@link Operation | Operations}\n   * themselves, and communicate with the exchange pipeline as a whole.\n   */\n  client: Client;\n  /** The next `Exchange`'s {@link ExchangeIO} function in the pipeline.\n   *\n   * @remarks\n   * `Exchange`s are like middleware function, and are henced composed like a recursive pipeline.\n   * Each `Exchange` will receive the next `Exchange`'s {@link ExchangeIO} function which they\n   * then call to compose each other.\n   *\n   * Since each `Exchange` calls the next, this creates a pipeline where operations are forwarded\n   * in sequence and `OperationResult`s from the next `Exchange` are combined with the current.\n   */\n  forward: ExchangeIO;\n  /** Issues a debug event to the `urql-devtools`.\n   *\n   * @remarks\n   * If `@urql/devtools` are set up, this dispatch function issues events to the `urql-devtools`.\n   * These events give the devtools more granular insights on what's going on in exchanges asynchronously,\n   * since `Operation`s and `OperationResult`s only signify the “start” and “end” of a request.\n   */\n  dispatchDebug<T extends keyof DebugEventTypes | string>(\n    t: DebugEventArg<T>\n  ): void;\n}\n\n/** `Exchange`s are both extensions for a `Client` and part of the control-flow executing `Operation`s.\n *\n * @remarks\n * `Exchange`s are responsible for the pipeline in `urql` that accepts {@link Operation | Operations} and\n * returns {@link OperationResult | OperationResults}. They take care of adding functionality to a {@link Client},\n * like deduplication, caching, and fetching (i.e. making GraphQL requests).\n *\n * When passed to the `Client`, they're instantiated with the {@link ExchangeInput} object and return an {@link ExchangeIO}\n * function, which is a mapping function that receives a stream of `Operation`s and returns a stream of `OperationResult`s.\n *\n * Like middleware, exchanges are composed, calling each other in a pipeline-like fashion, which is facilitated by exchanges\n * calling {@link ExchangeInput.forward}, which is set to the next exchange's {@link ExchangeIO} function in the pipeline.\n *\n * @see {@link https://urql.dev/goto/docs/architecture/#the-client-and-exchanges} for more information on Exchanges.\n * @see {@link https://urql.dev/goto/docs/advanced/authoring-exchanges} on how Exchanges are authored.\n *\n * @example\n * ```ts\n * import { pipe, onPush } from 'wonka';\n * import { Exchange } from '@urql/core';\n *\n * const debugExchange: Exchange => {\n *   return ops$ => pipe(\n *     ops$,\n *     onPush(operation => console.log(operation)),\n *     forward,\n *     onPush(result => console.log(result)),\n *   );\n * };\n * ```\n */\nexport type Exchange = (input: ExchangeInput) => ExchangeIO;\n\n/** Returned by `Exchange`s, the `ExchangeIO` function are the composed pipeline functions.\n *\n * @remarks\n * An {@link Exchange} must return an `ExchangeIO` function, which accepts a stream of {@link Operation | Operations} which\n * this exchange handles and returns a stream of {@link OperationResult | OperationResults}. These streams are Wonka {@link Source | Sources}.\n *\n * An exchange may enhance the incoming stream of `Operation`s to add, filter, map (change), or remove `Operation`s, before\n * forwarding those to {@link ExchangeInput.forward}, using Wonka's operators, and may add or remove `OperationResult`s from\n * the returned stream.\n *\n * Generally, the stream of `OperationResult` returned by {@link ExchangeInput.forward} is always merged and combined with\n * the `Exchange`'s own stream of results if the `Exchange` creates and delivers results of its own.\n *\n * @see {@link https://urql.dev/goto/docs/advanced/authoring-exchanges} on how Exchanges are authored.\n */\nexport type ExchangeIO = (ops$: Source<Operation>) => Source<OperationResult>;\n\n/** A mapping type of debug event types to their payloads.\n *\n * @remarks\n * These are the debug events that {@link ExchangeInput.dispatchDebug} accepts mapped to the payloads these events carry.\n * Debug events are only used in development and only consumed by the `urql-devtools`.\n */\nexport interface DebugEventTypes {\n  /** Signals to the devtools that a cache exchange will deliver a cached result. */\n  cacheHit: { value: any };\n  /** Signals to the devtools that a cache exchange will invalidate a cached result. */\n  cacheInvalidation: {\n    typenames: string[];\n    response: OperationResult;\n  };\n  /** Signals to the devtools that a fetch exchange will make a GraphQL API request. */\n  fetchRequest: {\n    url: string;\n    fetchOptions: RequestInit;\n  };\n  /** Signals to the devtools that a fetch exchange has received a GraphQL API response successfully. */\n  fetchSuccess: {\n    url: string;\n    fetchOptions: RequestInit;\n    value: object;\n  };\n  /** Signals to the devtools that a fetch exchange has failed to execute a GraphQL API request. */\n  fetchError: {\n    url: string;\n    fetchOptions: RequestInit;\n    value: Error;\n  };\n  /** Signals to the devtools that a retry exchange will retry an Operation. */\n  retryRetrying: {\n    retryCount: number;\n  };\n}\n\n/** Utility type that maps a debug event type to its payload.\n *\n * @remarks\n * This is a utility type that determines the required payload for a given debug event, which is\n * sent to the `urql-devtools`.\n *\n * The payloads for known debug events are defined by the {@link DebugEventTypes} type, and\n * each event additionally carries a human readable `message` with it, and the {@link Operation}\n * for which the event is.\n *\n * @internal\n */\nexport type DebugEventArg<T extends keyof DebugEventTypes | string> = {\n  type: T;\n  message: string;\n  operation: Operation;\n} & (T extends keyof DebugEventTypes\n  ? { data: DebugEventTypes[T] }\n  : { data?: any });\n\n/** Utility type of the full payload that is sent to the `urql-devtools`.\n *\n * @remarks\n * While the {@link DebugEventArg} defines the payload that {@link ExchangeInput.dispatchDebug}\n * accepts, each debug event then receives additional properties which are sent to the `urql-devtools`,\n * which this type defines.\n * @internal\n */\nexport type DebugEvent<T extends keyof DebugEventTypes | string = string> =\n  DebugEventArg<T> & {\n    timestamp: number;\n    source: string;\n  };\n"
  },
  {
    "path": "packages/core/src/utils/__snapshots__/error.test.ts.snap",
    "content": "// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html\n\nexports[`CombinedError > behaves like a normal Error 1`] = `\"[Network] test\"`;\n"
  },
  {
    "path": "packages/core/src/utils/collectTypenames.test.ts",
    "content": "import { describe, it, expect } from 'vitest';\nimport { collectTypenames } from './collectTypenames';\n\ndescribe('collectTypenames', () => {\n  it('returns all typenames included in a response as an array', () => {\n    const typeNames = collectTypenames({\n      todos: [\n        {\n          id: 1,\n          __typename: 'Todo',\n        },\n      ],\n    });\n    expect(typeNames).toEqual(['Todo']);\n  });\n\n  it('does not duplicate typenames', () => {\n    const typeNames = collectTypenames({\n      todos: [\n        {\n          id: 1,\n          __typename: 'Todo',\n        },\n        {\n          id: 3,\n          __typename: 'Todo',\n        },\n      ],\n    });\n    expect(typeNames).toEqual(['Todo']);\n  });\n\n  it('returns multiple different typenames', () => {\n    const typeNames = collectTypenames({\n      todos: [\n        {\n          id: 1,\n          __typename: 'Todo',\n        },\n        {\n          id: 3,\n          __typename: 'Avocado',\n        },\n      ],\n    });\n    expect(typeNames).toEqual(['Todo', 'Avocado']);\n  });\n\n  it('works on nested objects', () => {\n    const typeNames = collectTypenames({\n      todos: [\n        {\n          id: 1,\n          __typename: 'Todo',\n        },\n        {\n          id: 2,\n          subTask: {\n            id: 3,\n            __typename: 'SubTask',\n          },\n        },\n      ],\n    });\n    expect(typeNames).toEqual(['Todo', 'SubTask']);\n  });\n\n  it('traverses nested arrays of objects', () => {\n    const typenames = collectTypenames({\n      todos: [\n        {\n          id: 1,\n          authors: [\n            [\n              {\n                name: 'Phil',\n                __typename: 'Author',\n              },\n            ],\n          ],\n          __typename: 'Todo',\n        },\n      ],\n    });\n\n    expect(typenames).toEqual(['Author', 'Todo']);\n  });\n});\n"
  },
  {
    "path": "packages/core/src/utils/collectTypenames.ts",
    "content": "interface EntityLike {\n  [key: string]: EntityLike | EntityLike[] | any;\n  __typename: string | null | void;\n}\n\nconst collectTypes = (obj: EntityLike | EntityLike[], types: Set<string>) => {\n  if (Array.isArray(obj)) {\n    for (let i = 0, l = obj.length; i < l; i++) {\n      collectTypes(obj[i], types);\n    }\n  } else if (typeof obj === 'object' && obj !== null) {\n    for (const key in obj) {\n      if (key === '__typename' && typeof obj[key] === 'string') {\n        types.add(obj[key] as string);\n      } else {\n        collectTypes(obj[key], types);\n      }\n    }\n  }\n\n  return types;\n};\n\n/** Finds and returns a list of `__typename` fields found in response data.\n *\n * @privateRemarks\n * This is used by `@urql/core`’s document `cacheExchange` to find typenames\n * in a given GraphQL response’s data.\n */\nexport const collectTypenames = (response: object): string[] => [\n  ...collectTypes(response as EntityLike, new Set()),\n];\n"
  },
  {
    "path": "packages/core/src/utils/error.test.ts",
    "content": "import { describe, it, expect } from 'vitest';\nimport { CombinedError } from './error';\n\ndescribe('CombinedError', () => {\n  it('can be instantiated with graphQLErrors', () => {\n    const err = new CombinedError({\n      graphQLErrors: [],\n    });\n\n    expect(err.name).toBe('CombinedError');\n  });\n\n  it('behaves like a normal Error', () => {\n    const err = new CombinedError({\n      networkError: new Error('test'),\n    });\n\n    expect(err).toBeInstanceOf(CombinedError);\n    expect(err).toBeInstanceOf(Error);\n    expect('' + err).toMatchSnapshot();\n  });\n\n  it('accepts graphQLError messages and generates a single message from them', () => {\n    const graphQLErrors = ['Error Message A', 'Error Message B'];\n\n    const err = new CombinedError({ graphQLErrors });\n\n    expect(err.message).toBe(\n      `\n[GraphQL] Error Message A\n[GraphQL] Error Message B\n    `.trim()\n    );\n\n    expect(err.graphQLErrors).toEqual(graphQLErrors.map(x => new Error(x)));\n  });\n\n  it('accepts a network error and generates a message from it', () => {\n    const networkError = new Error('Network Shenanigans');\n    const err = new CombinedError({ networkError });\n\n    expect(err.message).toBe(`[Network] ${networkError.message}`);\n  });\n\n  it('accepts actual errors for graphQLError', () => {\n    const graphQLErrors = [\n      new Error('Error Message A'),\n      new Error('Error Message B'),\n    ];\n\n    const err = new CombinedError({ graphQLErrors });\n\n    expect(err.message).toBe(\n      `\n[GraphQL] Error Message A\n[GraphQL] Error Message B\n    `.trim()\n    );\n\n    expect(err.graphQLErrors).toEqual(graphQLErrors);\n  });\n\n  it('accepts empty string errors for graphQLError', () => {\n    const graphQLErrors = [new Error('')];\n\n    const err = new CombinedError({ graphQLErrors });\n\n    expect(err.message).toBe('[GraphQL] ');\n\n    expect(err.graphQLErrors).toEqual(graphQLErrors);\n  });\n\n  it('accepts a response that is attached to the resulting error', () => {\n    const response = {};\n    const err = new CombinedError({\n      graphQLErrors: [],\n      response,\n    });\n\n    expect(err.response).toBe(response);\n  });\n});\n"
  },
  {
    "path": "packages/core/src/utils/error.ts",
    "content": "import { GraphQLError } from '@0no-co/graphql.web';\nimport type { ErrorLike } from '../types';\n\nconst generateErrorMessage = (\n  networkErr?: Error,\n  graphQlErrs?: GraphQLError[]\n) => {\n  let error = '';\n  if (networkErr) return `[Network] ${networkErr.message}`;\n  if (graphQlErrs) {\n    for (let i = 0, l = graphQlErrs.length; i < l; i++) {\n      if (error) error += '\\n';\n      error += `[GraphQL] ${graphQlErrs[i].message}`;\n    }\n  }\n  return error;\n};\n\nconst rehydrateGraphQlError = (error: any): GraphQLError => {\n  if (\n    error &&\n    typeof error.message === 'string' &&\n    (error.extensions || error.name === 'GraphQLError')\n  ) {\n    return error;\n  } else if (typeof error === 'object' && typeof error.message === 'string') {\n    return new GraphQLError(\n      error.message,\n      error.nodes,\n      error.source,\n      error.positions,\n      error.path,\n      error,\n      error.extensions || {}\n    );\n  } else {\n    return new GraphQLError(error as any);\n  }\n};\n\n/** An abstracted `Error` that provides either a `networkError` or `graphQLErrors`.\n *\n * @remarks\n * During a GraphQL request, either the request can fail entirely, causing a network error,\n * or the GraphQL execution or fields can fail, which will cause an {@link ExecutionResult}\n * to contain an array of GraphQL errors.\n *\n * The `CombinedError` abstracts and normalizes both failure cases. When {@link OperationResult.error}\n * is set to this error, the `CombinedError` abstracts all errors, making it easier to handle only\n * a subset of error cases.\n *\n * @see {@link https://urql.dev/goto/docs/basics/errors} for more information on handling\n * GraphQL errors and the `CombinedError`.\n */\nexport class CombinedError extends Error {\n  public name: string;\n  public message: string;\n\n  /** A list of GraphQL errors rehydrated from a {@link ExecutionResult}.\n   *\n   * @remarks\n   * If an {@link ExecutionResult} received from the API contains a list of errors,\n   * the `CombinedError` will rehydrate them, normalize them to\n   * {@link GraphQLError | GraphQLErrors} and list them here.\n   * An empty list indicates that no GraphQL error has been sent by the API.\n   */\n  public graphQLErrors: GraphQLError[];\n\n  /** Set to an error, if a GraphQL request has failed outright.\n   *\n   * @remarks\n   * A GraphQL over HTTP request may fail and not reach the API. Any error that\n   * prevents a GraphQl request outright, will be considered a “network error” and\n   * set here.\n   */\n  public networkError?: Error;\n\n  /** Set to the {@link Response} object a fetch exchange received.\n   *\n   * @remarks\n   * If a built-in fetch {@link Exchange} is used in `urql`, this may\n   * be set to the {@link Response} object of the Fetch API response.\n   * However, since `urql` doesn’t assume that all users will use HTTP\n   * as the only or exclusive transport for GraphQL this property is\n   * neither typed nor guaranteed and may be re-used for other purposes\n   * by non-fetch exchanges.\n   *\n   * Hint: It can be useful to use `response.status` here, however, if\n   * you plan on relying on this being a {@link Response} in your app,\n   * which it is by default, then make sure you add some extra checks\n   * before blindly assuming so!\n   */\n  public response?: any;\n\n  constructor(input: {\n    networkError?: Error;\n    graphQLErrors?: Array<string | ErrorLike>;\n    response?: any;\n  }) {\n    const normalizedGraphQLErrors = (input.graphQLErrors || []).map(\n      rehydrateGraphQlError\n    );\n    const message = generateErrorMessage(\n      input.networkError,\n      normalizedGraphQLErrors\n    );\n\n    super(message);\n\n    this.name = 'CombinedError';\n    this.message = message;\n    this.graphQLErrors = normalizedGraphQLErrors;\n    this.networkError = input.networkError;\n    this.response = input.response;\n  }\n\n  toString(): string {\n    return this.message;\n  }\n}\n"
  },
  {
    "path": "packages/core/src/utils/formatDocument.test.ts",
    "content": "import { Kind, parse, print } from '@0no-co/graphql.web';\nimport { describe, it, expect } from 'vitest';\nimport { createRequest } from './request';\nimport { formatDocument } from './formatDocument';\n\nconst formatTypeNames = (query: string) => {\n  const typedNode = formatDocument(parse(query));\n  return print(typedNode);\n};\n\ndescribe('formatDocument', () => {\n  it('creates a new instance when adding typenames', () => {\n    const doc = parse(`{ id todos { id } }`) as any;\n    const newDoc = formatDocument(doc) as any;\n    expect(doc).not.toBe(newDoc);\n    expect(doc.definitions).not.toBe(newDoc.definitions);\n    expect(doc.definitions[0]).not.toBe(newDoc.definitions[0]);\n    expect(doc.definitions[0].selectionSet).not.toBe(\n      newDoc.definitions[0].selectionSet\n    );\n    expect(doc.definitions[0].selectionSet.selections).not.toBe(\n      newDoc.definitions[0].selectionSet.selections\n    );\n    // Here we're equal again:\n    expect(doc.definitions[0].selectionSet.selections[0]).toBe(\n      newDoc.definitions[0].selectionSet.selections[0]\n    );\n    // Not equal again:\n    expect(doc.definitions[0].selectionSet.selections[1]).not.toBe(\n      newDoc.definitions[0].selectionSet.selections[1]\n    );\n    expect(doc.definitions[0].selectionSet.selections[1].selectionSet).not.toBe(\n      newDoc.definitions[0].selectionSet.selections[1].selectionSet\n    );\n    // Equal again:\n    expect(\n      doc.definitions[0].selectionSet.selections[1].selectionSet.selections[0]\n    ).toBe(\n      newDoc.definitions[0].selectionSet.selections[1].selectionSet\n        .selections[0]\n    );\n  });\n\n  it('preserves the hashed key of the resulting query', () => {\n    const doc = parse(`{ id todos { id } }`) as any;\n    const expectedKey = createRequest(doc, undefined).key;\n    const formattedDoc = formatDocument(doc);\n    expect(formattedDoc).not.toBe(doc);\n    const actualKey = createRequest(formattedDoc, undefined).key;\n    expect(expectedKey).toBe(actualKey);\n  });\n\n  it('does not preserve the referential integrity with a cloned object', () => {\n    const doc = parse(`{ id todos { id } }`);\n    const formattedDoc = formatDocument(doc);\n    expect(formattedDoc).not.toBe(doc);\n    const query = { ...formattedDoc };\n    const reformattedDoc = formatDocument(query);\n    expect(reformattedDoc).not.toBe(doc);\n  });\n\n  it('preserves custom properties', () => {\n    const doc = parse(`{ todos { id } }`) as any;\n    doc.documentId = '123';\n    expect((formatDocument(doc) as any).documentId).toBe(doc.documentId);\n  });\n\n  it('adds typenames to a query string', () => {\n    expect(formatTypeNames(`{ todos { id } }`)).toMatchInlineSnapshot(`\n      \"{\n        todos {\n          id\n          __typename\n        }\n      }\"\n    `);\n  });\n\n  it('does not duplicate typenames', () => {\n    expect(\n      formatTypeNames(`{\n      todos {\n        id\n        __typename\n      }\n    }`)\n    ).toMatchInlineSnapshot(`\n      \"{\n        todos {\n          id\n          __typename\n        }\n      }\"\n    `);\n  });\n\n  it('does add typenames when it is aliased', () => {\n    expect(\n      formatTypeNames(`{\n      todos {\n        id\n        typename: __typename\n      }\n    }`)\n    ).toMatchInlineSnapshot(`\n      \"{\n        todos {\n          id\n          typename: __typename\n          __typename\n        }\n      }\"\n    `);\n  });\n\n  it('processes directives', () => {\n    const document = `\n      {\n        todos @skip {\n          id @_test\n        }\n      }\n   `;\n\n    const node = formatDocument(parse(document));\n\n    expect(node).toHaveProperty(\n      'definitions.0.selectionSet.selections.0.selectionSet.selections.0._directives',\n      {\n        test: {\n          kind: Kind.DIRECTIVE,\n          arguments: undefined,\n          name: {\n            kind: Kind.NAME,\n            value: '_test',\n          },\n        },\n      }\n    );\n\n    expect(formatTypeNames(document)).toMatchInlineSnapshot(`\n     \"{\n       todos @skip {\n         id\n         __typename\n       }\n     }\"\n   `);\n  });\n});\n"
  },
  {
    "path": "packages/core/src/utils/formatDocument.ts",
    "content": "import type {\n  FieldNode,\n  SelectionNode,\n  DefinitionNode,\n  DirectiveNode,\n} from '@0no-co/graphql.web';\nimport { Kind } from '@0no-co/graphql.web';\nimport type { KeyedDocumentNode } from './request';\nimport { keyDocument } from './request';\nimport type { FormattedNode, TypedDocumentNode } from '../types';\n\nconst formatNode = <\n  T extends SelectionNode | DefinitionNode | TypedDocumentNode<any, any>,\n>(\n  node: T\n): FormattedNode<T> => {\n  if ('definitions' in node) {\n    const definitions: FormattedNode<DefinitionNode>[] = [];\n    for (let i = 0, l = node.definitions.length; i < l; i++) {\n      const newDefinition = formatNode(node.definitions[i]);\n      definitions.push(newDefinition);\n    }\n\n    return { ...node, definitions } as FormattedNode<T>;\n  }\n\n  if ('directives' in node && node.directives && node.directives.length) {\n    const directives: DirectiveNode[] = [];\n    const _directives = {};\n    for (let i = 0, l = node.directives.length; i < l; i++) {\n      const directive = node.directives[i];\n      let name = directive.name.value;\n      if (name[0] !== '_') {\n        directives.push(directive);\n      } else {\n        name = name.slice(1);\n      }\n      _directives[name] = directive;\n    }\n    node = { ...node, directives, _directives };\n  }\n\n  if ('selectionSet' in node) {\n    const selections: FormattedNode<SelectionNode>[] = [];\n    let hasTypename = node.kind === Kind.OPERATION_DEFINITION;\n    if (node.selectionSet) {\n      for (let i = 0, l = node.selectionSet.selections.length; i < l; i++) {\n        const selection = node.selectionSet.selections[i];\n        hasTypename =\n          hasTypename ||\n          (selection.kind === Kind.FIELD &&\n            selection.name.value === '__typename' &&\n            !selection.alias);\n        const newSelection = formatNode(selection);\n        selections.push(newSelection);\n      }\n\n      if (!hasTypename) {\n        selections.push({\n          kind: Kind.FIELD,\n          name: {\n            kind: Kind.NAME,\n            value: '__typename',\n          },\n          _generated: true,\n        } as FormattedNode<FieldNode>);\n      }\n\n      return {\n        ...node,\n        selectionSet: { ...node.selectionSet, selections },\n      } as FormattedNode<T>;\n    }\n  }\n\n  return node as FormattedNode<T>;\n};\n\nconst formattedDocs: Map<number, KeyedDocumentNode> = new Map<\n  number,\n  KeyedDocumentNode\n>();\n\n/** Formats a GraphQL document to add `__typename` fields and process client-side directives.\n *\n * @param node - a {@link DocumentNode}.\n * @returns a {@link FormattedDocument}\n *\n * @remarks\n * Cache {@link Exchange | Exchanges} will require typename introspection to\n * recognize types in a GraphQL response. To retrieve these typenames,\n * this function is used to add the `__typename` fields to non-root\n * selection sets of a GraphQL document.\n *\n * Additionally, this utility will process directives, filter out client-side\n * directives starting with an `_` underscore, and place a `_directives` dictionary\n * on selection nodes.\n *\n * This utility also preserves the internally computed key of the\n * document as created by {@link createRequest} to avoid any\n * formatting from being duplicated.\n *\n * @see {@link https://spec.graphql.org/October2021/#sec-Type-Name-Introspection} for more information\n * on typename introspection via the `__typename` field.\n */\nexport const formatDocument = <T extends TypedDocumentNode<any, any>>(\n  node: T\n): FormattedNode<T> => {\n  const query = keyDocument(node);\n\n  let result = formattedDocs.get(query.__key);\n  if (!result) {\n    formattedDocs.set(\n      query.__key,\n      (result = formatNode(query) as KeyedDocumentNode)\n    );\n    // Ensure that the hash of the resulting document won't suddenly change\n    // we are marking __key as non-enumerable so when external exchanges use visit\n    // to manipulate a document we won't restore the previous query due to the __key\n    // property.\n    Object.defineProperty(result, '__key', {\n      value: query.__key,\n      enumerable: false,\n    });\n  }\n\n  return result as FormattedNode<T>;\n};\n"
  },
  {
    "path": "packages/core/src/utils/graphql.ts",
    "content": "import type * as GraphQLWeb from '@0no-co/graphql.web';\nimport type * as GraphQL from 'graphql';\n\ntype OrNever<T> = void extends T ? never : T;\n\nexport type GraphQLError =\n  | GraphQLWeb.GraphQLError\n  | OrNever<GraphQL.GraphQLError>;\n\nexport type DocumentNode =\n  | GraphQLWeb.DocumentNode\n  | OrNever<GraphQL.DocumentNode>;\n\nexport type DefinitionNode =\n  | GraphQLWeb.DefinitionNode\n  | OrNever<GraphQL.DefinitionNode>;\n"
  },
  {
    "path": "packages/core/src/utils/hash.test.ts",
    "content": "import { HashValue, phash } from './hash';\nimport { expect, it } from 'vitest';\n\nit('hashes given strings', () => {\n  expect(phash('hello')).toMatchInlineSnapshot('261238937');\n});\n\nit('hashes given strings and seeds', () => {\n  let hash: HashValue;\n  expect((hash = phash('hello'))).toMatchInlineSnapshot('261238937');\n  expect((hash = phash('world', hash))).toMatchInlineSnapshot('-152191');\n  expect((hash = phash('!', hash))).toMatchInlineSnapshot('-5022270');\n  expect(typeof hash).toBe('number');\n});\n"
  },
  {
    "path": "packages/core/src/utils/hash.ts",
    "content": "/** A hash value as computed by {@link phash}.\n *\n * @remarks\n * Typically `HashValue`s are used as hashes and keys of GraphQL documents,\n * variables, and combined, for GraphQL requests.\n */\nexport type HashValue = number & {\n  /** Marker to indicate that a `HashValue` may not be created by a user.\n   *\n   * @remarks\n   * `HashValue`s are created by {@link phash} and are marked as such to not mix them\n   * up with other numbers and prevent them from being created or used outside of this\n   * hashing function.\n   *\n   * @internal\n   */\n  readonly _opaque: unique symbol;\n};\n\n/** Computes a djb2 hash of the given string.\n *\n * @param x - the string to be hashed\n * @param seed - optionally a prior hash for progressive hashing\n * @returns a hash value, i.e. a number\n *\n * @remark\n * This is the hashing function used throughout `urql`, primarily to compute\n * {@link Operation.key}.\n *\n * @see {@link http://www.cse.yorku.ca/~oz/hash.html#djb2} for a further description of djb2.\n */\nexport const phash = (x: string, seed?: HashValue): HashValue => {\n  let h = (seed || 5381) | 0;\n  for (let i = 0, l = x.length | 0; i < l; i++)\n    h = (h << 5) + h + x.charCodeAt(i);\n  return h as HashValue;\n};\n"
  },
  {
    "path": "packages/core/src/utils/index.ts",
    "content": "export * from './error';\nexport * from './request';\nexport * from './result';\nexport * from './variables';\nexport * from './collectTypenames';\nexport * from './formatDocument';\nexport * from './streamUtils';\nexport * from './operation';\n\nexport const noop = () => {\n  /* noop */\n};\n"
  },
  {
    "path": "packages/core/src/utils/operation.ts",
    "content": "import type {\n  AnyVariables,\n  GraphQLRequest,\n  Operation,\n  OperationContext,\n  OperationType,\n} from '../types';\n\n/** Creates a {@link Operation} from the given parameters.\n *\n * @param kind - The {@link OperationType} of GraphQL operation, i.e. `query`, `mutation`, or `subscription`.\n * @param request - The {@link GraphQLRequest} or {@link Operation} used as a template for the new `Operation`.\n * @param context - The {@link OperationContext} `context` data for the `Operation`.\n * @returns A new {@link Operation}.\n *\n * @remarks\n * This method is both used to create new {@link Operation | Operations} as well as copy and modify existing\n * operations. While it’s not required to use this function to copy an `Operation`, it is recommended, in case\n * additional dynamic logic is added to them in the future.\n *\n * Hint: When an {@link Operation} is passed to the `request` argument, the `context` argument does not have to be\n * a complete {@link OperationContext} and will instead be combined with passed {@link Operation.context}.\n *\n * @example\n * An example of copying an existing `Operation` to modify its `context`:\n *\n * ```ts\n * makeOperation(\n *   operation.kind,\n *   operation,\n *   { requestPolicy: 'cache-first' },\n * );\n * ```\n */\nfunction makeOperation<\n  Data = any,\n  Variables extends AnyVariables = AnyVariables,\n>(\n  kind: OperationType,\n  request: GraphQLRequest<Data, Variables>,\n  context: OperationContext\n): Operation<Data, Variables>;\n\nfunction makeOperation<\n  Data = any,\n  Variables extends AnyVariables = AnyVariables,\n>(\n  kind: OperationType,\n  request: Operation<Data, Variables>,\n  context?: Partial<OperationContext>\n): Operation<Data, Variables>;\n\nfunction makeOperation(kind, request, context) {\n  return {\n    ...request,\n    kind,\n    context: request.context\n      ? {\n          ...request.context,\n          ...context,\n        }\n      : context || request.context,\n  };\n}\n\nexport { makeOperation };\n\n/** Adds additional metadata to an `Operation`'s `context.meta` property while copying it.\n * @see {@link OperationDebugMeta} for more information on the {@link OperationContext.meta} property.\n */\nexport const addMetadata = (\n  operation: Operation,\n  meta: OperationContext['meta']\n) => {\n  return makeOperation(operation.kind, operation, {\n    meta: {\n      ...operation.context.meta,\n      ...meta,\n    },\n  });\n};\n"
  },
  {
    "path": "packages/core/src/utils/request.test.ts",
    "content": "import { expect, it, describe } from 'vitest';\n\nimport { parse, print } from '@0no-co/graphql.web';\nimport { gql } from '../gql';\nimport { createRequest, stringifyDocument } from './request';\nimport { formatDocument } from './formatDocument';\n\ndescribe('createRequest', () => {\n  it('should hash identical queries identically', () => {\n    const reqA = createRequest('{ test }', undefined);\n    const reqB = createRequest('{ test }', undefined);\n    expect(reqA.key).toBe(reqB.key);\n  });\n\n  it('should hash identical queries identically', () => {\n    const reqA = createRequest('{ test }', undefined);\n    const reqB = createRequest('{ test }', undefined);\n    expect(reqA.key).toBe(reqB.key);\n  });\n\n  it('should hash identical DocumentNodes identically', () => {\n    const reqA = createRequest(parse('{ testB }'), undefined);\n    const reqB = createRequest(parse('{ testB }'), undefined);\n    expect(reqA.key).toBe(reqB.key);\n    expect(reqA.query).toBe(reqB.query);\n  });\n\n  it('should use the hash from a key if available', () => {\n    const doc = parse('{ testC }');\n    (doc as any).__key = 1234;\n    const req = createRequest(doc, undefined);\n    expect(req.key).toBe(1234);\n  });\n\n  it('should hash DocumentNodes and strings identically', () => {\n    const docA = parse('{ field }');\n    const docB = print(docA);\n    const reqA = createRequest(docA, undefined);\n    const reqB = createRequest(docB, undefined);\n    expect(reqA.key).toBe(reqB.key);\n    expect(reqA.query).toBe(reqB.query);\n  });\n\n  it('should hash graphql-tag documents correctly', () => {\n    const doc = gql`\n      {\n        testD\n      }\n    `;\n    createRequest(doc, undefined);\n    expect((doc as any).__key).not.toBe(undefined);\n  });\n\n  it('should return a valid query object', () => {\n    const doc = gql`\n      {\n        testE\n      }\n    `;\n    const val = createRequest(doc, undefined);\n\n    expect(val).toMatchObject({\n      key: expect.any(Number),\n      query: expect.any(Object),\n      variables: {},\n    });\n  });\n\n  it('should return a valid query object with variables', () => {\n    const doc = print(gql`\n      {\n        testF\n      }\n    `);\n    const val = createRequest(doc, { test: 5 });\n\n    expect(print(val.query)).toBe(doc);\n    expect(val).toMatchObject({\n      key: expect.any(Number),\n      query: expect.any(Object),\n      variables: { test: 5 },\n    });\n  });\n\n  it('should hash persisted documents consistently', () => {\n    const doc = parse('{ testG }');\n    const docPersisted = parse('{ testG }');\n    (docPersisted as any).documentId = 'testG';\n\n    const req = createRequest(doc, undefined);\n    const reqPersisted = createRequest(docPersisted, undefined);\n    expect(req.key).not.toBe(reqPersisted.key);\n  });\n});\n\ndescribe('stringifyDocument ', () => {\n  it('should reprint formatted documents', () => {\n    const doc = parse('{ test { field } }');\n    const formatted = formatDocument(doc);\n    expect(stringifyDocument(formatted)).toBe(print(formatted));\n  });\n\n  it('should reprint request documents', () => {\n    const request = createRequest(`query { test { field } }`, {});\n    const formatted = formatDocument(request.query);\n    expect(print(formatted)).toMatchInlineSnapshot(`\n      \"{\n        test {\n          field\n          __typename\n        }\n      }\"\n    `);\n    expect(stringifyDocument(formatted)).toBe(print(formatted));\n  });\n\n  it('should reprint gql documents', () => {\n    const request = createRequest(\n      gql`\n        query {\n          test {\n            field\n          }\n        }\n      `,\n      {}\n    );\n    const formatted = formatDocument(request.query);\n    expect(print(formatted)).toMatchInlineSnapshot(`\n      \"{\n        test {\n          field\n          __typename\n        }\n      }\"\n    `);\n    expect(stringifyDocument(formatted)).toBe(print(formatted));\n  });\n\n  it('should remove comments', () => {\n    const doc = `\n      { #query\n        # broken\n        test\n      }\n    `;\n    expect(stringifyDocument(createRequest(doc, undefined).query))\n      .toMatchInlineSnapshot(`\n      \"{\n        test\n      }\"\n    `);\n  });\n\n  it('should remove duplicate spaces', () => {\n    const doc = `\n      {\n        abc          ,, test\n      }\n    `;\n    expect(stringifyDocument(createRequest(doc, undefined).query))\n      .toMatchInlineSnapshot(`\n      \"{\n        abc\n        test\n      }\"\n    `);\n  });\n\n  it('should not sanitize within strings', () => {\n    const doc = `\n      {\n        field(arg: \"test #1\")\n      }\n    `;\n    expect(stringifyDocument(createRequest(doc, undefined).query))\n      .toMatchInlineSnapshot(`\n        \"{\n          field(arg: \n        \"test #1\")\n        }\"\n      `);\n  });\n\n  it('should not sanitize within block strings', () => {\n    const doc = `\n      {\n        field(\n          arg: \"\"\"\n          hello\n          #hello\n          \"\"\"\n        )\n      }\n    `;\n    expect(stringifyDocument(createRequest(doc, undefined).query))\n      .toMatchInlineSnapshot(`\n        \"{\n          field(arg: \n        \"\"\"\n          hello\n          #hello\n          \"\"\")\n        }\"\n      `);\n  });\n});\n"
  },
  {
    "path": "packages/core/src/utils/request.ts",
    "content": "import { Kind, parse, print } from '@0no-co/graphql.web';\nimport type { DocumentNode, DefinitionNode } from './graphql';\nimport type { HashValue } from './hash';\nimport { phash } from './hash';\nimport { stringifyVariables } from './variables';\n\nimport type {\n  DocumentInput,\n  TypedDocumentNode,\n  AnyVariables,\n  GraphQLRequest,\n  RequestExtensions,\n} from '../types';\n\ntype PersistedDocumentNode = TypedDocumentNode & {\n  documentId?: string;\n};\n\n/** A `DocumentNode` annotated with its hashed key.\n * @internal\n */\nexport type KeyedDocumentNode = TypedDocumentNode & {\n  __key: HashValue;\n};\n\nconst SOURCE_NAME = 'gql';\nconst GRAPHQL_STRING_RE = /(\"{3}[\\s\\S]*\"{3}|\"(?:\\\\.|[^\"])*\")/g;\nconst REPLACE_CHAR_RE = /(?:#[^\\n\\r]+)?(?:[\\r\\n]+|$)/g;\n\nconst replaceOutsideStrings = (str: string, idx: number): string =>\n  idx % 2 === 0 ? str.replace(REPLACE_CHAR_RE, '\\n') : str;\n\n/** Sanitizes a GraphQL document string by replacing comments and redundant newlines in it. */\nconst sanitizeDocument = (node: string): string =>\n  node.split(GRAPHQL_STRING_RE).map(replaceOutsideStrings).join('').trim();\n\nconst prints: Map<DocumentNode | DefinitionNode, string> = new Map<\n  DocumentNode | DefinitionNode,\n  string\n>();\nconst docs: Map<HashValue, KeyedDocumentNode> = new Map<\n  HashValue,\n  KeyedDocumentNode\n>();\n\n/** A cached printing function for GraphQL documents.\n *\n * @param node - A string of a document or a {@link DocumentNode}\n * @returns A normalized printed string of the passed GraphQL document.\n *\n * @remarks\n * This function accepts a GraphQL query string or {@link DocumentNode},\n * then prints and sanitizes it. The sanitizer takes care of removing\n * comments, which otherwise alter the key of the document although the\n * document is otherwise equivalent to another.\n *\n * When a {@link DocumentNode} is passed to this function, it caches its\n * output by modifying the `loc.source.body` property on the GraphQL node.\n */\nexport const stringifyDocument = (\n  node: string | DefinitionNode | DocumentNode\n): string => {\n  let printed: string;\n  if (typeof node === 'string') {\n    printed = sanitizeDocument(node);\n  } else if (node.loc && docs.get((node as KeyedDocumentNode).__key) === node) {\n    printed = node.loc.source.body;\n  } else {\n    printed = prints.get(node) || sanitizeDocument(print(node));\n    prints.set(node, printed);\n  }\n\n  if (typeof node !== 'string' && !node.loc) {\n    (node as any).loc = {\n      start: 0,\n      end: printed.length,\n      source: {\n        body: printed,\n        name: SOURCE_NAME,\n        locationOffset: { line: 1, column: 1 },\n      },\n    };\n  }\n\n  return printed;\n};\n\n/** Computes the hash for a document's string using {@link stringifyDocument}'s output.\n *\n * @param node - A string of a document or a {@link DocumentNode}\n * @returns A {@link HashValue}\n *\n * @privateRemarks\n * This function adds the operation name of the document to the hash, since sometimes\n * a merged document with multiple operations may be used. Although `urql` requires a\n * `DocumentNode` to only contain a single operation, when the cached `loc.source.body`\n * of a `DocumentNode` is used, this string may still contain multiple operations and\n * the resulting hash should account for only one at a time.\n */\nconst hashDocument = (\n  node: string | DefinitionNode | DocumentNode\n): HashValue => {\n  let key: HashValue;\n  if ((node as PersistedDocumentNode).documentId) {\n    key = phash((node as PersistedDocumentNode).documentId!);\n  } else {\n    key = phash(stringifyDocument(node));\n    // Add the operation name to the produced hash\n    if ((node as DocumentNode).definitions) {\n      const operationName = getOperationName(node as DocumentNode);\n      if (operationName) key = phash(`\\n# ${operationName}`, key);\n    }\n  }\n  return key;\n};\n\n/** Returns a canonical version of the passed `DocumentNode` with an added hash key.\n *\n * @param node - A string of a document or a {@link DocumentNode}\n * @returns A {@link KeyedDocumentNode}\n *\n * @remarks\n * `urql` will always avoid unnecessary work, no matter whether a user passes `DocumentNode`s\n * or strings of GraphQL documents to its APIs.\n *\n * This function will return a canonical version of a {@link KeyedDocumentNode} no matter\n * which kind of input is passed, avoiding parsing or hashing of passed data as needed.\n */\nexport const keyDocument = (node: string | DocumentNode): KeyedDocumentNode => {\n  let key: HashValue;\n  let query: DocumentNode;\n  if (typeof node === 'string') {\n    key = hashDocument(node);\n    query = docs.get(key) || parse(node, { noLocation: true });\n  } else {\n    key = (node as KeyedDocumentNode).__key || hashDocument(node);\n    query = docs.get(key) || node;\n  }\n\n  // Add location information if it's missing\n  if (!query.loc) stringifyDocument(query);\n\n  (query as KeyedDocumentNode).__key = key;\n  docs.set(key, query as KeyedDocumentNode);\n  return query as KeyedDocumentNode;\n};\n\n/** Creates a `GraphQLRequest` from the passed parameters.\n *\n * @param q - A string of a document or a {@link DocumentNode}\n * @param variables - A variables object for the defined GraphQL operation.\n * @returns A {@link GraphQLRequest}\n *\n * @remarks\n * `createRequest` creates a {@link GraphQLRequest} from the passed parameters,\n * while replacing the document as needed with a canonical version of itself,\n * to avoid parsing, printing, or hashing the same input multiple times.\n *\n * If no variables are passed, canonically it'll default to an empty object,\n * which is removed from the resulting hash key.\n */\nexport const createRequest = <\n  Data = any,\n  Variables extends AnyVariables = AnyVariables,\n>(\n  _query: DocumentInput<Data, Variables>,\n  _variables: Variables,\n  extensions?: RequestExtensions | undefined\n): GraphQLRequest<Data, Variables> => {\n  const variables = _variables || ({} as Variables);\n  const query = keyDocument(_query);\n  const printedVars = stringifyVariables(variables, true);\n  let key = query.__key;\n  if (printedVars !== '{}') key = phash(printedVars, key);\n  return { key, query, variables, extensions };\n};\n\n/** Returns the name of the `DocumentNode`'s operation, if any.\n * @param query - A {@link DocumentNode}\n * @returns the operation's name contained within the document, or `undefined`\n */\nexport const getOperationName = (query: DocumentNode): string | undefined => {\n  for (let i = 0, l = query.definitions.length; i < l; i++) {\n    const node = query.definitions[i];\n    if (node.kind === Kind.OPERATION_DEFINITION) {\n      return node.name ? node.name.value : undefined;\n    }\n  }\n};\n\n/** Returns the type of the `DocumentNode`'s operation, if any.\n * @param query - A {@link DocumentNode}\n * @returns the operation's type contained within the document, or `undefined`\n */\nexport const getOperationType = (query: DocumentNode): string | undefined => {\n  for (let i = 0, l = query.definitions.length; i < l; i++) {\n    const node = query.definitions[i];\n    if (node.kind === Kind.OPERATION_DEFINITION) {\n      return node.operation;\n    }\n  }\n};\n"
  },
  {
    "path": "packages/core/src/utils/result.test.ts",
    "content": "import { describe, it, expect } from 'vitest';\nimport { OperationResult } from '../types';\nimport { queryOperation, subscriptionOperation } from '../test-utils';\nimport { makeResult, mergeResultPatch } from './result';\nimport { GraphQLError } from '@0no-co/graphql.web';\nimport { CombinedError } from './error';\n\ndescribe('makeResult', () => {\n  it('adds extensions and errors correctly', () => {\n    const origResult = {\n      data: undefined,\n      errors: ['error message'],\n      extensions: {\n        extensionKey: 'extensionValue',\n      },\n    };\n\n    const result = makeResult(queryOperation, origResult);\n\n    expect(result.hasNext).toBe(false);\n    expect(result.operation).toBe(queryOperation);\n    expect(result.data).toBe(undefined);\n    expect(result.extensions).toEqual(origResult.extensions);\n    expect(result.error).toMatchInlineSnapshot(\n      `[CombinedError: [GraphQL] error message]`\n    );\n  });\n\n  it('default hasNext to true for subscriptions', () => {\n    const origResult = {\n      data: undefined,\n      errors: ['error message'],\n      extensions: {\n        extensionKey: 'extensionValue',\n      },\n    };\n\n    const result = makeResult(subscriptionOperation, origResult);\n    expect(result.hasNext).toBe(true);\n  });\n});\n\ndescribe('mergeResultPatch (defer/stream latest', () => {\n  it('should read pending and append the result', () => {\n    const pending = [{ id: '0', path: [] }];\n    const prevResult: OperationResult = {\n      operation: queryOperation,\n      stale: false,\n      hasNext: true,\n      data: {\n        f2: {\n          a: 'a',\n          b: 'b',\n          c: {\n            d: 'd',\n            e: 'e',\n            f: { h: 'h', i: 'i' },\n          },\n        },\n      },\n    };\n\n    const merged = mergeResultPatch(\n      prevResult,\n      {\n        incremental: [\n          { id: '0', data: { MyFragment: 'Query' } },\n          { id: '0', subPath: ['f2', 'c', 'f'], data: { j: 'j' } },\n        ],\n        // TODO: not sure if we need this but it's part of the spec\n        // completed: [{ id: '0' }],\n        hasNext: false,\n      },\n      undefined,\n      pending\n    );\n\n    expect(merged.data).toEqual({\n      MyFragment: 'Query',\n      f2: {\n        a: 'a',\n        b: 'b',\n        c: {\n          d: 'd',\n          e: 'e',\n          f: { h: 'h', i: 'i', j: 'j' },\n        },\n      },\n    });\n  });\n\n  it('should read pending and append the result w/ overlapping fields', () => {\n    const pending = [\n      { id: '0', path: [], label: 'D1' },\n      { id: '1', path: ['f2', 'c', 'f'], label: 'D2' },\n    ];\n    const prevResult: OperationResult = {\n      operation: queryOperation,\n      stale: false,\n      hasNext: true,\n      data: {\n        f2: {\n          a: 'A',\n          b: 'B',\n          c: {\n            d: 'D',\n            e: 'E',\n            f: {\n              h: 'H',\n              i: 'I',\n            },\n          },\n        },\n      },\n    };\n\n    const merged = mergeResultPatch(\n      prevResult,\n      {\n        incremental: [\n          { id: '0', subPath: ['f2', 'c', 'f'], data: { j: 'J', k: 'K' } },\n        ],\n        pending: [{ id: '1', path: ['f2', 'c', 'f'], label: 'D2' }],\n        hasNext: true,\n      },\n      undefined,\n      pending\n    );\n\n    const merged2 = mergeResultPatch(\n      merged,\n      {\n        incremental: [{ id: '1', data: { l: 'L', m: 'M' } }],\n        hasNext: false,\n      },\n      undefined,\n      pending\n    );\n\n    expect(merged2.data).toEqual({\n      f2: {\n        a: 'A',\n        b: 'B',\n        c: {\n          d: 'D',\n          e: 'E',\n          f: {\n            h: 'H',\n            i: 'I',\n            j: 'J',\n            k: 'K',\n            l: 'L',\n            m: 'M',\n          },\n        },\n      },\n    });\n  });\n});\n\ndescribe('mergeResultPatch (defer/stream pre June-2023)', () => {\n  it('should default hasNext to true if the last result was set to true', () => {\n    const prevResult: OperationResult = {\n      operation: subscriptionOperation,\n      data: {\n        __typename: 'Subscription',\n        event: 1,\n      },\n      stale: false,\n      hasNext: true,\n    };\n\n    const merged = mergeResultPatch(prevResult, {\n      data: {\n        __typename: 'Subscription',\n        event: 2,\n      },\n    });\n\n    expect(merged.data).not.toBe(prevResult.data);\n    expect(merged.data.event).toBe(2);\n    expect(merged.hasNext).toBe(true);\n  });\n\n  it('should work with the payload property', () => {\n    const prevResult: OperationResult = {\n      operation: subscriptionOperation,\n      data: {\n        __typename: 'Subscription',\n        event: 1,\n      },\n      stale: false,\n      hasNext: true,\n    };\n\n    const merged = mergeResultPatch(prevResult, {\n      payload: {\n        data: {\n          __typename: 'Subscription',\n          event: 2,\n        },\n      },\n    });\n\n    expect(merged.data).not.toBe(prevResult.data);\n    expect(merged.data.event).toBe(2);\n    expect(merged.hasNext).toBe(true);\n  });\n\n  it('should work with the payload property and errors', () => {\n    const prevResult: OperationResult = {\n      operation: subscriptionOperation,\n      data: {\n        __typename: 'Subscription',\n        event: 1,\n      },\n      stale: false,\n      hasNext: true,\n    };\n\n    const merged = mergeResultPatch(prevResult, {\n      payload: {\n        data: {\n          __typename: 'Subscription',\n          event: 2,\n        },\n      },\n      errors: [new GraphQLError('Something went horribly wrong')],\n    });\n\n    expect(merged.data).not.toBe(prevResult.data);\n    expect(merged.data.event).toBe(2);\n    expect(merged.error).toEqual(\n      new CombinedError({\n        graphQLErrors: [new GraphQLError('Something went horribly wrong')],\n      })\n    );\n    expect(merged.hasNext).toBe(true);\n  });\n\n  it('should ignore invalid patches', () => {\n    const prevResult: OperationResult = {\n      operation: queryOperation,\n      data: {\n        __typename: 'Query',\n        items: [\n          {\n            __typename: 'Item',\n            id: 'id',\n          },\n        ],\n      },\n      stale: false,\n      hasNext: true,\n    };\n\n    const merged = mergeResultPatch(prevResult, {\n      incremental: [\n        {\n          data: undefined,\n          path: ['a'],\n        },\n        {\n          items: null,\n          path: ['b'],\n        },\n      ],\n    });\n\n    expect(merged.data).toStrictEqual({\n      __typename: 'Query',\n      items: [\n        {\n          __typename: 'Item',\n          id: 'id',\n        },\n      ],\n    });\n  });\n\n  it('should apply incremental defer patches', () => {\n    const prevResult: OperationResult = {\n      operation: queryOperation,\n      data: {\n        __typename: 'Query',\n        items: [\n          {\n            __typename: 'Item',\n            id: 'id',\n            child: undefined,\n          },\n        ],\n      },\n      stale: false,\n      hasNext: true,\n    };\n\n    const patch = { __typename: 'Child' };\n\n    const merged = mergeResultPatch(prevResult, {\n      incremental: [\n        {\n          data: patch,\n          path: ['items', 0, 'child'],\n        },\n      ],\n    });\n\n    expect(merged.data.items[0]).not.toBe(prevResult.data.items[0]);\n    expect(merged.data.items[0].child).toBe(patch);\n    expect(merged.data).toStrictEqual({\n      __typename: 'Query',\n      items: [\n        {\n          __typename: 'Item',\n          id: 'id',\n          child: patch,\n        },\n      ],\n    });\n  });\n\n  it('should handle null incremental defer patches', () => {\n    const prevResult: OperationResult = {\n      operation: queryOperation,\n      data: {\n        __typename: 'Query',\n        item: undefined,\n      },\n      stale: false,\n      hasNext: true,\n    };\n\n    const merged = mergeResultPatch(prevResult, {\n      incremental: [\n        {\n          data: null,\n          path: ['item'],\n        },\n      ],\n    });\n\n    expect(merged.data).not.toBe(prevResult.data);\n    expect(merged.data.item).toBe(null);\n  });\n\n  it('should apply incremental stream patches', () => {\n    const prevResult: OperationResult = {\n      operation: queryOperation,\n      data: {\n        __typename: 'Query',\n        items: [{ __typename: 'Item' }],\n      },\n      stale: false,\n      hasNext: true,\n    };\n\n    const patch = { __typename: 'Item' };\n\n    const merged = mergeResultPatch(prevResult, {\n      incremental: [\n        {\n          items: [patch],\n          path: ['items', 1],\n        },\n      ],\n    });\n\n    expect(merged.data.items).not.toBe(prevResult.data.items);\n    expect(merged.data.items[0]).toBe(prevResult.data.items[0]);\n    expect(merged.data.items[1]).toBe(patch);\n    expect(merged.data).toStrictEqual({\n      __typename: 'Query',\n      items: [{ __typename: 'Item' }, { __typename: 'Item' }],\n    });\n  });\n\n  it('should apply incremental stream patches deeply', () => {\n    const prevResult: OperationResult = {\n      operation: queryOperation,\n      data: {\n        __typename: 'Query',\n        test: [\n          {\n            __typename: 'Test',\n          },\n        ],\n      },\n      stale: false,\n      hasNext: true,\n    };\n\n    const patch = { name: 'Test' };\n\n    const merged = mergeResultPatch(prevResult, {\n      incremental: [\n        {\n          items: [patch],\n          path: ['test', 0],\n        },\n      ],\n    });\n\n    expect(merged.data).toStrictEqual({\n      __typename: 'Query',\n      test: [\n        {\n          __typename: 'Test',\n          name: 'Test',\n        },\n      ],\n    });\n  });\n\n  it('should handle null incremental stream patches', () => {\n    const prevResult: OperationResult = {\n      operation: queryOperation,\n      data: {\n        __typename: 'Query',\n        items: [{ __typename: 'Item' }],\n      },\n      stale: false,\n      hasNext: true,\n    };\n\n    const merged = mergeResultPatch(prevResult, {\n      incremental: [\n        {\n          items: null,\n          path: ['items', 1],\n        },\n      ],\n    });\n\n    expect(merged.data.items).not.toBe(prevResult.data.items);\n    expect(merged.data.items[0]).toBe(prevResult.data.items[0]);\n    expect(merged.data).toStrictEqual({\n      __typename: 'Query',\n      items: [{ __typename: 'Item' }],\n    });\n  });\n\n  it('should handle root incremental stream patches', () => {\n    const prevResult: OperationResult = {\n      operation: queryOperation,\n      data: {\n        __typename: 'Query',\n        item: {\n          test: true,\n        },\n      },\n      stale: false,\n      hasNext: true,\n    };\n\n    const merged = mergeResultPatch(prevResult, {\n      incremental: [\n        {\n          data: { item: { test2: false } },\n          path: [],\n        },\n      ],\n    });\n\n    expect(merged.data).toStrictEqual({\n      __typename: 'Query',\n      item: {\n        test: true,\n        test2: false,\n      },\n    });\n  });\n\n  it('should merge extensions from each patch', () => {\n    const prevResult: OperationResult = {\n      operation: queryOperation,\n      data: {\n        __typename: 'Query',\n      },\n      extensions: {\n        base: true,\n      },\n      stale: false,\n      hasNext: true,\n    };\n\n    const merged = mergeResultPatch(prevResult, {\n      incremental: [\n        {\n          data: null,\n          path: ['item'],\n          extensions: {\n            patch: true,\n          },\n        },\n      ],\n    });\n\n    expect(merged.extensions).toStrictEqual({\n      base: true,\n      patch: true,\n    });\n  });\n\n  it('should combine errors from each patch', () => {\n    const prevResult: OperationResult = makeResult(queryOperation, {\n      errors: ['base'],\n    });\n\n    const merged = mergeResultPatch(prevResult, {\n      incremental: [\n        {\n          data: null,\n          path: ['item'],\n          errors: ['patch'],\n        },\n      ],\n    });\n\n    expect(merged.error).toMatchInlineSnapshot(`\n      [CombinedError: [GraphQL] base\n      [GraphQL] patch]\n    `);\n  });\n\n  it('should preserve all data for noop patches', () => {\n    const prevResult: OperationResult = {\n      operation: queryOperation,\n      data: {\n        __typename: 'Query',\n      },\n      extensions: {\n        base: true,\n      },\n      stale: false,\n      hasNext: true,\n    };\n\n    const merged = mergeResultPatch(prevResult, {\n      hasNext: false,\n    });\n\n    expect(merged.data).toStrictEqual({\n      __typename: 'Query',\n    });\n  });\n\n  it('handles the old version of the incremental payload spec (DEPRECATED)', () => {\n    const prevResult: OperationResult = {\n      operation: queryOperation,\n      data: {\n        __typename: 'Query',\n        items: [\n          {\n            __typename: 'Item',\n            id: 'id',\n            child: undefined,\n          },\n        ],\n      },\n      stale: false,\n      hasNext: true,\n    };\n\n    const patch = { __typename: 'Child' };\n\n    const merged = mergeResultPatch(prevResult, {\n      data: patch,\n      path: ['items', 0, 'child'],\n    } as any);\n\n    expect(merged.data.items[0]).not.toBe(prevResult.data.items[0]);\n    expect(merged.data.items[0].child).toBe(patch);\n    expect(merged.data).toStrictEqual({\n      __typename: 'Query',\n      items: [\n        {\n          __typename: 'Item',\n          id: 'id',\n          child: patch,\n        },\n      ],\n    });\n  });\n});\n"
  },
  {
    "path": "packages/core/src/utils/result.ts",
    "content": "import type {\n  ExecutionResult,\n  Operation,\n  OperationResult,\n  IncrementalPayload,\n} from '../types';\nimport { CombinedError } from './error';\n\n/** Converts the `ExecutionResult` received for a given `Operation` to an `OperationResult`.\n *\n * @param operation - The {@link Operation} for which the API’s result is for.\n * @param result - The GraphQL API’s {@link ExecutionResult}.\n * @param response - Optionally, a raw object representing the API’s result (Typically a {@link Response}).\n * @returns An {@link OperationResult}.\n *\n * @remarks\n * This utility can be used to create {@link OperationResult | OperationResults} in the shape\n * that `urql` expects and defines, and should be used rather than creating the results manually.\n *\n * @throws\n * If no data, or errors are contained within the result, or the result is instead an incremental\n * response containing a `path` property, a “No Content” error is thrown.\n *\n * @see {@link ExecutionResult} for the type definition of GraphQL API results.\n */\nexport const makeResult = (\n  operation: Operation,\n  result: ExecutionResult,\n  response?: any\n): OperationResult => {\n  if (\n    !('data' in result) &&\n    (!('errors' in result) || !Array.isArray(result.errors))\n  ) {\n    throw new Error('No Content');\n  }\n\n  const defaultHasNext = operation.kind === 'subscription';\n  return {\n    operation,\n    data: result.data,\n    error: Array.isArray(result.errors)\n      ? new CombinedError({\n          graphQLErrors: result.errors,\n          response,\n        })\n      : undefined,\n    extensions: result.extensions ? { ...result.extensions } : undefined,\n    hasNext: result.hasNext == null ? defaultHasNext : result.hasNext,\n    stale: false,\n  };\n};\n\nconst deepMerge = (target: any, source: any): any => {\n  if (typeof target === 'object' && target != null) {\n    if (Array.isArray(target)) {\n      target = [...target];\n      for (let i = 0, l = source.length; i < l; i++)\n        target[i] = deepMerge(target[i], source[i]);\n\n      return target;\n    }\n    if (!target.constructor || target.constructor === Object) {\n      target = { ...target };\n      for (const key in source)\n        target[key] = deepMerge(target[key], source[key]);\n      return target;\n    }\n  }\n  return source;\n};\n\n/** Merges an incrementally delivered `ExecutionResult` into a previous `OperationResult`.\n *\n * @param prevResult - The {@link OperationResult} that preceded this result.\n * @param path - The GraphQL API’s {@link ExecutionResult} that should be patching the `prevResult`.\n * @param response - Optionally, a raw object representing the API’s result (Typically a {@link Response}).\n * @returns A new {@link OperationResult} patched with the incremental result.\n *\n * @remarks\n * This utility should be used to merge subsequent {@link ExecutionResult | ExecutionResults} of\n * incremental responses into a prior {@link OperationResult}.\n *\n * When directives like `@defer`, `@stream`, and `@live` are used, GraphQL may deliver new\n * results that modify previous results. In these cases, it'll set a `path` property to modify\n * the result it sent last. This utility is built to handle these cases and merge these payloads\n * into existing {@link OperationResult | OperationResults}.\n *\n * @see {@link ExecutionResult} for the type definition of GraphQL API results.\n */\nexport const mergeResultPatch = (\n  prevResult: OperationResult,\n  nextResult: ExecutionResult,\n  response?: any,\n  pending?: ExecutionResult['pending']\n): OperationResult => {\n  let errors = prevResult.error ? prevResult.error.graphQLErrors : [];\n  let hasExtensions =\n    !!prevResult.extensions || !!(nextResult.payload || nextResult).extensions;\n  const extensions = {\n    ...prevResult.extensions,\n    ...(nextResult.payload || nextResult).extensions,\n  };\n\n  let incremental = nextResult.incremental;\n\n  // NOTE: We handle the old version of the incremental delivery payloads as well\n  if ('path' in nextResult) {\n    incremental = [nextResult as IncrementalPayload];\n  }\n\n  const withData = { data: prevResult.data };\n  if (incremental) {\n    for (let i = 0, l = incremental.length; i < l; i++) {\n      const patch = incremental[i];\n      if (Array.isArray(patch.errors)) {\n        errors.push(...(patch.errors as any));\n      }\n\n      if (patch.extensions) {\n        Object.assign(extensions, patch.extensions);\n        hasExtensions = true;\n      }\n\n      let prop: string | number = 'data';\n      let part: Record<string, any> | Array<any> = withData;\n      let path: readonly (string | number)[] = [];\n      if (patch.path) {\n        path = patch.path;\n      } else if (pending) {\n        const res = pending.find(pendingRes => pendingRes.id === patch.id);\n        if (patch.subPath) {\n          path = [...res!.path, ...patch.subPath];\n        } else {\n          path = res!.path;\n        }\n      }\n\n      for (let i = 0, l = path.length; i < l; prop = path[i++]) {\n        part = part[prop] = Array.isArray(part[prop])\n          ? [...part[prop]]\n          : { ...part[prop] };\n      }\n\n      if (patch.items) {\n        const startIndex = +prop >= 0 ? (prop as number) : 0;\n        for (let i = 0, l = patch.items.length; i < l; i++)\n          part[startIndex + i] = deepMerge(\n            part[startIndex + i],\n            patch.items[i]\n          );\n      } else if (patch.data !== undefined) {\n        part[prop] = deepMerge(part[prop], patch.data);\n      }\n    }\n  } else {\n    withData.data = (nextResult.payload || nextResult).data || prevResult.data;\n    errors =\n      (nextResult.errors as any[]) ||\n      (nextResult.payload && nextResult.payload.errors) ||\n      errors;\n  }\n\n  return {\n    operation: prevResult.operation,\n    data: withData.data,\n    error: errors.length\n      ? new CombinedError({ graphQLErrors: errors, response })\n      : undefined,\n    extensions: hasExtensions ? extensions : undefined,\n    hasNext:\n      nextResult.hasNext != null ? nextResult.hasNext : prevResult.hasNext,\n    stale: false,\n  };\n};\n\n/** Creates an `OperationResult` containing a network error for requests that encountered unexpected errors.\n *\n * @param operation - The {@link Operation} for which the API’s result is for.\n * @param error - The network-like error that prevented an API result from being delivered.\n * @param response - Optionally, a raw object representing the API’s result (Typically a {@link Response}).\n * @returns An {@link OperationResult} containing only a {@link CombinedError}.\n *\n * @remarks\n * This utility can be used to create {@link OperationResult | OperationResults} in the shape\n * that `urql` expects and defines, and should be used rather than creating the results manually.\n * This function should be used for when the {@link CombinedError.networkError} property is\n * populated and no GraphQL execution actually occurred.\n */\nexport const makeErrorResult = (\n  operation: Operation,\n  error: Error,\n  response?: any\n): OperationResult => ({\n  operation,\n  data: undefined,\n  error: new CombinedError({\n    networkError: error,\n    response,\n  }),\n  extensions: undefined,\n  hasNext: false,\n  stale: false,\n});\n"
  },
  {
    "path": "packages/core/src/utils/streamUtils.ts",
    "content": "import type { Sink, Source } from 'wonka';\nimport { subscribe, take, filter, toPromise, pipe } from 'wonka';\nimport type { OperationResult, OperationResultSource } from '../types';\n\n/** Patches a `toPromise` method onto the `Source` passed to it.\n * @param source$ - the Wonka {@link Source} to patch.\n * @returns The passed `source$` with a patched `toPromise` method as a {@link PromisifiedSource}.\n * @internal\n */\nexport function withPromise<T extends OperationResult>(\n  _source$: Source<T>\n): OperationResultSource<T> {\n  const source$ = ((sink: Sink<T>) =>\n    _source$(sink)) as OperationResultSource<T>;\n  source$.toPromise = () =>\n    pipe(\n      source$,\n      filter(result => !result.stale && !result.hasNext),\n      take(1),\n      toPromise\n    );\n  source$.then = (onResolve, onReject) =>\n    source$.toPromise().then(onResolve, onReject);\n  source$.subscribe = onResult => subscribe(onResult)(source$);\n  return source$;\n}\n"
  },
  {
    "path": "packages/core/src/utils/variables.test.ts",
    "content": "// @vitest-environment jsdom\n\nimport { stringifyVariables, extractFiles } from './variables';\nimport { describe, it, expect } from 'vitest';\nimport { Script } from 'vm';\n\ndescribe('stringifyVariables', () => {\n  it('stringifies objects stabily', () => {\n    expect(stringifyVariables({ b: 'b', a: 'a' })).toBe('{\"a\":\"a\",\"b\":\"b\"}');\n    expect(stringifyVariables({ x: { b: 'b', a: 'a' } })).toBe(\n      '{\"x\":{\"a\":\"a\",\"b\":\"b\"}}'\n    );\n  });\n\n  it('stringifies arrays', () => {\n    expect(stringifyVariables([1, 2])).toBe('[1,2]');\n    expect(stringifyVariables({ x: [1, 2] })).toBe('{\"x\":[1,2]}');\n  });\n\n  it('stringifies scalars', () => {\n    expect(stringifyVariables(1)).toBe('1');\n    expect(stringifyVariables('test')).toBe('\"test\"');\n    expect(stringifyVariables(null)).toBe('null');\n    expect(stringifyVariables(undefined)).toBe('');\n    expect(stringifyVariables(Infinity)).toBe('null');\n    expect(stringifyVariables(1 / 0)).toBe('null');\n  });\n\n  it('returns null for circular structures', () => {\n    const x = { x: null } as any;\n    x.x = x;\n    expect(stringifyVariables(x)).toBe('{\"x\":null}');\n  });\n\n  it('stringifies dates correctly', () => {\n    const date = new Date('2019-12-11T04:20:00');\n    expect(stringifyVariables(date)).toBe(`\"${date.toJSON()}\"`);\n  });\n\n  it('stringifies dictionaries (Object.create(null)) correctly', () => {\n    expect(stringifyVariables(Object.create(null))).toBe('{}');\n  });\n\n  it('recovers if the root object is a dictionary (Object.create(null)) and nests a plain object', () => {\n    const root = Object.create(null);\n    root.data = { test: true };\n    expect(stringifyVariables(root)).toBe('{\"data\":{\"test\":true}}');\n  });\n\n  it('recovers if the root object contains a dictionary (Object.create(null))', () => {\n    const data = Object.create(null);\n    data.test = true;\n    const root = { data };\n    expect(stringifyVariables(root)).toBe('{\"data\":{\"test\":true}}');\n  });\n\n  it('replaces non-plain objects at the root with keyed replacements', () => {\n    expect(stringifyVariables(new (class Test {})())).toMatch(\n      /^{\"__key\":\"\\w+\"}$/\n    );\n    expect(stringifyVariables(new Map())).toMatch(/^{\"__key\":\"\\w+\"}$/);\n  });\n\n  it('stringifies files correctly', () => {\n    const file = new File([0] as any, 'test.js');\n    const str = stringifyVariables(file);\n    expect(str).toBe('null');\n  });\n\n  it('stringifies plain objects from foreign JS contexts correctly', () => {\n    const scriptGlobal: typeof globalThis = new Script(\n      'exports = globalThis'\n    ).runInNewContext({}).exports;\n\n    const plain = new scriptGlobal.Function('return { test: true }')();\n    expect(stringifyVariables(plain)).toBe('{\"test\":true}');\n\n    const data = new scriptGlobal.Function('return new (class Test {})')();\n    expect(stringifyVariables(data)).toMatch(/^{\"__key\":\"\\w+\"}$/);\n  });\n});\n\ndescribe('extractFiles', () => {\n  it('extracts files from nested objects', () => {\n    const file = new Blob();\n    expect(extractFiles({ files: { a: file } })).toEqual(\n      new Map([['variables.files.a', file]])\n    );\n  });\n\n  it('extracts files from nested arrays', () => {\n    const file = new Blob();\n    expect(extractFiles({ files: [file] })).toEqual(\n      new Map([['variables.files.0', file]])\n    );\n  });\n});\n"
  },
  {
    "path": "packages/core/src/utils/variables.ts",
    "content": "export type FileMap = Map<string, File | Blob>;\n\nconst seen: Set<any> = new Set();\nconst cache: WeakMap<any, any> = new WeakMap();\n\nconst stringify = (x: any, includeFiles: boolean): string => {\n  if (x === null || seen.has(x)) {\n    return 'null';\n  } else if (typeof x !== 'object') {\n    return JSON.stringify(x) || '';\n  } else if (x.toJSON) {\n    return stringify(x.toJSON(), includeFiles);\n  } else if (Array.isArray(x)) {\n    let out = '[';\n    for (let i = 0, l = x.length; i < l; i++) {\n      if (out.length > 1) out += ',';\n      out += stringify(x[i], includeFiles) || 'null';\n    }\n    out += ']';\n    return out;\n  } else if (\n    !includeFiles &&\n    ((FileConstructor !== NoopConstructor && x instanceof FileConstructor) ||\n      (BlobConstructor !== NoopConstructor && x instanceof BlobConstructor))\n  ) {\n    return 'null';\n  }\n\n  const keys = Object.keys(x).sort();\n  if (\n    !keys.length &&\n    x.constructor &&\n    Object.getPrototypeOf(x).constructor !== Object.prototype.constructor\n  ) {\n    const key = cache.get(x) || Math.random().toString(36).slice(2);\n    cache.set(x, key);\n    return stringify({ __key: key }, includeFiles);\n  }\n\n  seen.add(x);\n  let out = '{';\n  for (let i = 0, l = keys.length; i < l; i++) {\n    const value = stringify(x[keys[i]], includeFiles);\n    if (value) {\n      if (out.length > 1) out += ',';\n      out += stringify(keys[i], includeFiles) + ':' + value;\n    }\n  }\n\n  seen.delete(x);\n  out += '}';\n  return out;\n};\n\nconst extract = (map: FileMap, path: string, x: any): void => {\n  if (x == null || typeof x !== 'object' || x.toJSON || seen.has(x)) {\n    /*noop*/\n  } else if (Array.isArray(x)) {\n    for (let i = 0, l = x.length; i < l; i++)\n      extract(map, `${path}.${i}`, x[i]);\n  } else if (x instanceof FileConstructor || x instanceof BlobConstructor) {\n    map.set(path, x as File | Blob);\n  } else {\n    seen.add(x);\n    for (const key in x) extract(map, `${path}.${key}`, x[key]);\n  }\n};\n\n/** A stable stringifier for GraphQL variables objects.\n *\n * @param x - any JSON-like data.\n * @return A JSON string.\n *\n * @remarks\n * This utility creates a stable JSON string from any passed data,\n * and protects itself from throwing.\n *\n * The JSON string is stable insofar as objects’ keys are sorted,\n * and instances of non-plain objects are replaced with random keys\n * replacing their values, which remain stable for the objects’\n * instance.\n */\nexport const stringifyVariables = (x: any, includeFiles?: boolean): string => {\n  seen.clear();\n  return stringify(x, includeFiles || false);\n};\n\nclass NoopConstructor {}\nconst FileConstructor = typeof File !== 'undefined' ? File : NoopConstructor;\nconst BlobConstructor = typeof Blob !== 'undefined' ? Blob : NoopConstructor;\n\nexport const extractFiles = (x: any): FileMap => {\n  const map: FileMap = new Map();\n  if (\n    FileConstructor !== NoopConstructor ||\n    BlobConstructor !== NoopConstructor\n  ) {\n    seen.clear();\n    extract(map, 'variables', x);\n  }\n  return map;\n};\n"
  },
  {
    "path": "packages/core/tsconfig.json",
    "content": "{\n  \"extends\": \"../../tsconfig.json\",\n  \"include\": [\"src\"]\n}\n"
  },
  {
    "path": "packages/core/vitest.config.ts",
    "content": "import { mergeConfig } from 'vitest/config';\nimport baseConfig from '../../vitest.config';\n\nexport default mergeConfig(baseConfig, {});\n"
  },
  {
    "path": "packages/introspection/CHANGELOG.md",
    "content": "# @urql/introspection\n\n## 1.2.1\n\n### Patch Changes\n\n- Omit minified files and sourcemaps' `sourcesContent` in published packages\n  Submitted by [@kitten](https://github.com/kitten) (See [#3755](https://github.com/urql-graphql/urql/pull/3755))\n\n## 1.2.0\n\n### Minor Changes\n\n- Add oneOf support\n  Submitted by [@JoviDeCroock](https://github.com/JoviDeCroock) (See [#3743](https://github.com/urql-graphql/urql/pull/3743))\n\n## 1.1.0\n\n### Minor Changes\n\n- Mark `@urql/core` as a peer dependency as well as a regular dependency\n  Submitted by [@kitten](https://github.com/kitten) (See [#3579](https://github.com/urql-graphql/urql/pull/3579))\n\n## 1.0.3\n\n### Patch Changes\n\n- ⚠️ Fix `Any` type being included, even when it isn’t needed\n  Submitted by [@kitten](https://github.com/kitten) (See [#3481](https://github.com/urql-graphql/urql/pull/3481))\n\n## 1.0.2\n\n### Patch Changes\n\n- Publish with npm provenance\n  Submitted by [@kitten](https://github.com/kitten) (See [#3180](https://github.com/urql-graphql/urql/pull/3180))\n\n## 1.0.1\n\n### Patch Changes\n\n- Add TSDocs to `@urql/*` packages\n  Submitted by [@kitten](https://github.com/kitten) (See [#3079](https://github.com/urql-graphql/urql/pull/3079))\n\n## 1.0.0\n\n### Major Changes\n\n- **Goodbye IE11!** 👋 This major release removes support for IE11. All code that is shipped will be transpiled much less and will _not_ be ES5-compatible anymore, by [@kitten](https://github.com/kitten) (See [#2504](https://github.com/FormidableLabs/urql/pull/2504))\n\n## 0.3.3\n\n### Patch Changes\n\n- Avoid making the imports of `@urql/introspection` more specific than they need to be, this because we aren't optimizing for bundle size and in pure node usage this can confuse Node as `import x from 'graphql'` won't share the same module scope as `import x from 'graphql/x/y.mjs'`, by [@JoviDeCroock](https://github.com/JoviDeCroock) (See [#2529](https://github.com/FormidableLabs/urql/pull/2529))\n\n## 0.3.2\n\n### Patch Changes\n\n- ⚠️ Fix import of `executeSync` rather than `execute` causing an incompatibility when several `.mjs` imports and a main `import { executeSync } from 'graphql'` are causing two different modules to be instantiated, by [@kitten](https://github.com/kitten) (See [#2251](https://github.com/FormidableLabs/urql/pull/2251))\n\n## 0.3.1\n\n### Patch Changes\n\n- Extend peer dependency range of `graphql` to include `^16.0.0`.\n  As always when upgrading across many packages of `urql`, especially including `@urql/core` we recommend you to deduplicate dependencies after upgrading, using `npm dedupe` or `npx yarn-deduplicate`, by [@kitten](https://github.com/kitten) (See [#2133](https://github.com/FormidableLabs/urql/pull/2133))\n\n## 0.3.0\n\n### Minor Changes\n\n- Add options to `@urql/introspection`'s `minifyIntrospectionQuery` allowing the inclusion of more\n  information into the minified schema as needed, namely `includeScalars`, `includeEnums`,\n  `includeInputs`, and `includeDirectives`, by [@kitten](https://github.com/kitten) (See [#1578](https://github.com/FormidableLabs/urql/pull/1578))\n\n### Patch Changes\n\n- Remove closure-compiler from the build step (See [#1570](https://github.com/FormidableLabs/urql/pull/1570))\n\n## 0.2.0\n\n### Minor Changes\n\n- Update `minifyIntrospectionQuery` utility to remove additional information on arguments and to filter out schema metadata types, like `__Field` and others, by [@kitten](https://github.com/kitten) (See [#1351](https://github.com/FormidableLabs/urql/pull/1351))\n\n## 0.1.2\n\n### Patch Changes\n\n- ⚠️ Fix the `graphql` dependency being postfixed with `.mjs` when building the package, by [@JoviDeCroock](https://github.com/JoviDeCroock) (See [#1204](https://github.com/FormidableLabs/urql/pull/1204))\n\n## 0.1.1\n\n### Patch Changes\n\n- Add missing `.mjs` extension to all imports from `graphql` to fix Webpack 5 builds, which require extension-specific import paths for ESM bundles and packages. **This change allows you to safely upgrade to Webpack 5.**, by [@kitten](https://github.com/kitten) (See [#1094](https://github.com/FormidableLabs/urql/pull/1094))\n\n## 0.1.0\n\n**Initial Release**\n"
  },
  {
    "path": "packages/introspection/README.md",
    "content": "<h2 align=\"center\">@urql/introspection</h2>\n\n<p align=\"center\"><strong>Utilities for dealing with Introspection Queries and Client Schemas</strong></p>\n"
  },
  {
    "path": "packages/introspection/jsr.json",
    "content": "{\n  \"name\": \"@urql/introspection\",\n  \"version\": \"1.2.1\",\n  \"exports\": {\n    \".\": \"./src/index.ts\"\n  },\n  \"exclude\": [\n    \"node_modules\",\n    \"cypress\",\n    \"**/*.test.*\",\n    \"**/*.spec.*\",\n    \"**/*.test.*.snap\",\n    \"**/*.spec.*.snap\"\n  ]\n}"
  },
  {
    "path": "packages/introspection/package.json",
    "content": "{\n  \"name\": \"@urql/introspection\",\n  \"version\": \"1.2.1\",\n  \"description\": \"Utilities for dealing with Introspection Queries and Client Schemas\",\n  \"sideEffects\": false,\n  \"homepage\": \"https://formidable.com/open-source/urql/docs/\",\n  \"bugs\": \"https://github.com/urql-graphql/urql/issues\",\n  \"license\": \"MIT\",\n  \"author\": \"urql GraphQL Contributors\",\n  \"repository\": {\n    \"type\": \"git\",\n    \"url\": \"https://github.com/urql-graphql/urql.git\",\n    \"directory\": \"packages/introspection\"\n  },\n  \"keywords\": [\n    \"graphql\",\n    \"graphql client\",\n    \"graphql schema\",\n    \"schema\"\n  ],\n  \"main\": \"dist/urql-introspection\",\n  \"module\": \"dist/urql-introspection.mjs\",\n  \"types\": \"dist/urql-introspection.d.ts\",\n  \"source\": \"src/index.ts\",\n  \"exports\": {\n    \".\": {\n      \"types\": \"./dist/urql-introspection.d.ts\",\n      \"import\": \"./dist/urql-introspection.mjs\",\n      \"require\": \"./dist/urql-introspection.js\",\n      \"source\": \"./src/index.ts\"\n    },\n    \"./package.json\": \"./package.json\"\n  },\n  \"files\": [\n    \"LICENSE\",\n    \"README.md\",\n    \"dist/\"\n  ],\n  \"scripts\": {\n    \"clean\": \"rimraf dist\",\n    \"check\": \"tsc --noEmit\",\n    \"lint\": \"eslint --ext=js,jsx,ts,tsx .\",\n    \"build\": \"rollup -c ../../scripts/rollup/config.mjs\",\n    \"prepare\": \"node ../../scripts/prepare/index.js\",\n    \"prepublishOnly\": \"run-s clean build\"\n  },\n  \"devDependencies\": {\n    \"graphql\": \"^16.0.0\"\n  },\n  \"peerDependencies\": {\n    \"graphql\": \"^14.0.0 || ^15.0.0 || ^16.0.0 || ^17.0.0\"\n  },\n  \"publishConfig\": {\n    \"access\": \"public\",\n    \"provenance\": true\n  }\n}\n"
  },
  {
    "path": "packages/introspection/src/getIntrospectedSchema.ts",
    "content": "import type { IntrospectionQuery, GraphQLSchema } from 'graphql';\nimport { parse, buildSchema, execute, getIntrospectionQuery } from 'graphql';\n\n/** Returns an {@link IntrospectionQuery} result for a given GraphQL schema.\n *\n * @param input - A GraphQL schema, either as an SDL string, or a {@link GraphQLSchema} object.\n * @returns an {@link IntrospectionQuery} result.\n *\n * @remarks\n * `getIntrospectedSchema` can be used to get a Schema Introspection result from\n * a given GraphQL schema. The schema can be passed as an SDL string or a\n * {@link GraphQLSchema} object. If an {@link IntrospectionQuery} object is\n * passed, it'll be passed through.\n *\n * @throws\n * If `input` cannot be parsed or converted into a {@link GraphQLSchema} then\n * a {@link TypeError} will be thrown.\n */\nexport const getIntrospectedSchema = (\n  input: string | IntrospectionQuery | GraphQLSchema\n): IntrospectionQuery => {\n  if (typeof input === 'string') {\n    try {\n      input = JSON.parse(input);\n    } catch (_error) {\n      input = buildSchema(input as string);\n    }\n  }\n\n  if (typeof input === 'object' && '__schema' in input) {\n    return input;\n  }\n\n  const initialIntrospection: any = execute({\n    document: parse(getIntrospectionQuery({ descriptions: false })),\n    schema: input as GraphQLSchema,\n  });\n\n  if (!initialIntrospection.data || !initialIntrospection.data.__schema) {\n    throw new TypeError(\n      'GraphQL could not generate an IntrospectionQuery from the given schema.'\n    );\n  }\n\n  return initialIntrospection.data as IntrospectionQuery;\n};\n"
  },
  {
    "path": "packages/introspection/src/index.ts",
    "content": "export * from './getIntrospectedSchema';\nexport * from './minifyIntrospectionQuery';\n"
  },
  {
    "path": "packages/introspection/src/minifyIntrospectionQuery.ts",
    "content": "import type {\n  IntrospectionQuery,\n  IntrospectionType,\n  IntrospectionTypeRef,\n  IntrospectionInputValue,\n  IntrospectionDirective,\n} from 'graphql';\n\nlet _includeScalars = false;\nlet _includeEnums = false;\nlet _includeInputs = false;\nlet _hasAnyType = false;\n\nconst anyType: IntrospectionTypeRef = {\n  kind: 'SCALAR',\n  name: 'Any',\n};\n\nconst mapType = (fromType: any): IntrospectionTypeRef => {\n  switch (fromType.kind) {\n    case 'NON_NULL':\n    case 'LIST':\n      return {\n        kind: fromType.kind,\n        ofType: mapType(fromType.ofType),\n      };\n\n    case 'SCALAR':\n      if (_includeScalars) {\n        return fromType;\n      } else {\n        _hasAnyType = true;\n        return anyType;\n      }\n\n    case 'INPUT_OBJECT':\n      if (_includeInputs) {\n        return fromType;\n      } else {\n        _hasAnyType = true;\n        return anyType;\n      }\n\n    case 'ENUM':\n      if (_includeEnums) {\n        return fromType;\n      } else {\n        _hasAnyType = true;\n        return anyType;\n      }\n\n    case 'OBJECT':\n    case 'INTERFACE':\n    case 'UNION':\n      return fromType;\n\n    default:\n      throw new TypeError(\n        `Unrecognized type reference of type: ${(fromType as any).kind}.`\n      );\n  }\n};\n\nconst minifyIntrospectionType = (\n  type: IntrospectionType\n): IntrospectionType => {\n  switch (type.kind) {\n    case 'SCALAR':\n      return {\n        kind: 'SCALAR',\n        name: type.name,\n      };\n\n    case 'ENUM':\n      return {\n        kind: 'ENUM',\n        name: type.name,\n        enumValues: type.enumValues.map(\n          value =>\n            ({\n              name: value.name,\n            }) as any\n        ),\n      };\n\n    case 'INPUT_OBJECT': {\n      return {\n        kind: 'INPUT_OBJECT',\n        name: type.name,\n        isOneOf: type.isOneOf,\n        inputFields: type.inputFields.map(\n          field =>\n            ({\n              name: field.name,\n              type: mapType(field.type),\n              defaultValue: field.defaultValue || undefined,\n            }) as IntrospectionInputValue\n        ),\n      };\n    }\n\n    case 'OBJECT':\n      return {\n        kind: 'OBJECT',\n        name: type.name,\n        fields: type.fields.map(\n          field =>\n            ({\n              name: field.name,\n              type: field.type && mapType(field.type),\n              args:\n                field.args &&\n                field.args.map(arg => ({\n                  name: arg.name,\n                  type: mapType(arg.type),\n                })),\n            }) as any\n        ),\n        interfaces:\n          type.interfaces &&\n          type.interfaces.map(int => ({\n            kind: 'INTERFACE',\n            name: int.name,\n          })),\n      };\n\n    case 'INTERFACE':\n      return {\n        kind: 'INTERFACE',\n        name: type.name,\n        fields: type.fields.map(\n          field =>\n            ({\n              name: field.name,\n              type: field.type && mapType(field.type),\n              args:\n                field.args &&\n                field.args.map(arg => ({\n                  name: arg.name,\n                  type: mapType(arg.type),\n                })),\n            }) as any\n        ),\n        interfaces:\n          type.interfaces &&\n          type.interfaces.map(int => ({\n            kind: 'INTERFACE',\n            name: int.name,\n          })),\n        possibleTypes:\n          type.possibleTypes &&\n          type.possibleTypes.map(type => ({\n            kind: type.kind,\n            name: type.name,\n          })),\n      };\n\n    case 'UNION':\n      return {\n        kind: 'UNION',\n        name: type.name,\n        possibleTypes: type.possibleTypes.map(type => ({\n          kind: type.kind,\n          name: type.name,\n        })),\n      };\n\n    default:\n      return type;\n  }\n};\n\n/** Input parameters for the {@link minifyIntrospectionQuery} function. */\nexport interface MinifySchemaOptions {\n  /** Includes scalars instead of removing them.\n   *\n   * @remarks\n   * By default, all scalars will be replaced by a single scalar called `Any`\n   * in the output, unless this option is set to `true`.\n   */\n  includeScalars?: boolean;\n  /** Includes enums instead of removing them.\n   *\n   * @remarks\n   * By default, all enums will be replaced by a single scalar called `Any`\n   * in the output, unless this option is set to `true`.\n   */\n  includeEnums?: boolean;\n  /** Includes inputs instead of removing them.\n   *\n   * @remarks\n   * By default, all inputs will be replaced by a single scalar called `Any`\n   * in the output, unless this option is set to `true`.\n   */\n  includeInputs?: boolean;\n  /** Includes directives instead of removing them. */\n  includeDirectives?: boolean;\n}\n\n/** Minifies an {@link IntrospectionQuery} for use with Graphcache or the `populateExchange`.\n *\n * @param schema - An {@link IntrospectionQuery} object to be minified.\n * @param opts - An optional {@link MinifySchemaOptions} configuration object.\n * @returns the minified {@link IntrospectionQuery} object.\n *\n * @remarks\n * `minifyIntrospectionQuery` reduces the size of an {@link IntrospectionQuery} by\n * removing data and information that a client-side consumer, like Graphcache or the\n * `populateExchange`, may not require.\n *\n * At the very least, it will remove system types, descriptions, depreactions,\n * and source locations. Unless disabled via the options passed, it will also\n * by default remove all scalars, enums, inputs, and directives.\n *\n * @throws\n * If `schema` receives an object that isn’t an {@link IntrospectionQuery}, a\n * {@link TypeError} will be thrown.\n */\nexport const minifyIntrospectionQuery = (\n  schema: IntrospectionQuery,\n  opts: MinifySchemaOptions = {}\n): IntrospectionQuery => {\n  if (!schema || !('__schema' in schema)) {\n    throw new TypeError('Expected to receive an IntrospectionQuery.');\n  }\n\n  _hasAnyType = false;\n  _includeScalars = !!opts.includeScalars;\n  _includeEnums = !!opts.includeEnums;\n  _includeInputs = !!opts.includeInputs;\n\n  const {\n    __schema: { queryType, mutationType, subscriptionType, types, directives },\n  } = schema;\n\n  const minifiedTypes = types\n    .filter(type => {\n      switch (type.name) {\n        case '__Directive':\n        case '__DirectiveLocation':\n        case '__EnumValue':\n        case '__InputValue':\n        case '__Field':\n        case '__Type':\n        case '__TypeKind':\n        case '__Schema':\n          return false;\n        default:\n          return (\n            (_includeScalars && type.kind === 'SCALAR') ||\n            (_includeEnums && type.kind === 'ENUM') ||\n            (_includeInputs && type.kind === 'INPUT_OBJECT') ||\n            type.kind === 'OBJECT' ||\n            type.kind === 'INTERFACE' ||\n            type.kind === 'UNION'\n          );\n      }\n    })\n    .map(minifyIntrospectionType);\n\n  if (_hasAnyType) {\n    minifiedTypes.push({ kind: 'SCALAR', name: anyType.name });\n  }\n\n  let minifiedDirectives: IntrospectionDirective[] = [];\n  if (opts.includeDirectives) {\n    minifiedDirectives = (directives || []).map(directive => ({\n      name: directive.name,\n      isRepeatable: directive.isRepeatable ? true : undefined,\n      locations: directive.locations,\n      args: directive.args.map(\n        arg =>\n          ({\n            name: arg.name,\n            type: mapType(arg.type),\n            defaultValue: arg.defaultValue || undefined,\n          }) as IntrospectionInputValue\n      ),\n    }));\n  }\n\n  return {\n    __schema: {\n      queryType,\n      mutationType,\n      subscriptionType,\n      types: minifiedTypes,\n      directives: minifiedDirectives,\n    },\n  };\n};\n"
  },
  {
    "path": "packages/introspection/tsconfig.json",
    "content": "{\n  \"extends\": \"../../tsconfig.json\",\n  \"include\": [\"src\"]\n}\n"
  },
  {
    "path": "packages/next-urql/.gitignore",
    "content": "/rsc\n"
  },
  {
    "path": "packages/next-urql/CHANGELOG.md",
    "content": "# Changelog\n\n## 2.0.0\n\n### Patch Changes\n\n- Updated dependencies\n  - urql@5.0.0\n\n## 1.1.5\n\n### Patch Changes\n\n- Omit minified files and sourcemaps' `sourcesContent` in published packages\n  Submitted by [@kitten](https://github.com/kitten) (See [#3755](https://github.com/urql-graphql/urql/pull/3755))\n\n## 1.1.4\n\n### Patch Changes\n\n- Update Provider TSDoc to reflect our advice on\n  instantiating the client within a React component\n  Submitted by [@y-hsgw](https://github.com/y-hsgw) (See [#3748](https://github.com/urql-graphql/urql/pull/3748))\n\n## 1.1.3\n\n### Patch Changes\n\n- Add type for hasNext to the query-state in urql-next\n  Submitted by [@isy](https://github.com/isy) (See [#3707](https://github.com/urql-graphql/urql/pull/3707))\n\n## 1.1.2\n\n### Patch Changes\n\n- export SSRContext from provider\n  Submitted by [@ccummings](https://github.com/ccummings) (See [#3659](https://github.com/urql-graphql/urql/pull/3659))\n\n## 1.1.1\n\n### Patch Changes\n\n- ⚠️ Fix `CVE-2024-24556`, addressing an XSS vulnerability, where `@urql/next` failed to escape HTML characters in JSON payloads injected into RSC hydration bodies. When an attacker is able to manipulate strings in the JSON response in RSC payloads, this could cause HTML to be evaluated via a typical XSS vulnerability (See [`GHSA-qhjf-hm5j-335w`](https://github.com/urql-graphql/urql/security/advisories/GHSA-qhjf-hm5j-335w) for details.)\n  Submitted by [@JoviDeCroock](https://github.com/JoviDeCroock) (See [`4b7011b7`](https://github.com/urql-graphql/urql/commit/4b7011b70d5718728ff912d02a4dbdc7f703540d))\n\n## 1.1.0\n\n### Minor Changes\n\n- Support a `nonce` prop on `DataHydrationContextProvider` that passes it onto its script tags' attributes\n  Submitted by [@Enalmada](https://github.com/Enalmada) (See [#3398](https://github.com/urql-graphql/urql/pull/3398))\n\n### Patch Changes\n\n- ⚠️ Fix invalid CJS by importing react with import-all semantics\n  Submitted by [@JoviDeCroock](https://github.com/JoviDeCroock) (See [#3405](https://github.com/urql-graphql/urql/pull/3405))\n\n## 1.0.0\n\n### Major Changes\n\n- Create `@urql/next` which is a package meant to support Next 13 and\n  the React 18 features contained within.\n  For server components we have `@urql/next/rsc` and for client components\n  just `@urql/next`\n  Submitted by [@JoviDeCroock](https://github.com/JoviDeCroock) (See [#3214](https://github.com/urql-graphql/urql/pull/3214))\n\n## 5.0.2\n\n### Patch Changes\n\n- Switch `react` imports to namespace imports, and update build process for CommonJS outputs to interoperate with `__esModule` marked modules again\n  Submitted by [@kitten](https://github.com/kitten) (See [#3251](https://github.com/urql-graphql/urql/pull/3251))\n\n## 5.0.1\n\n### Patch Changes\n\n- Publish with npm provenance\n  Submitted by [@kitten](https://github.com/kitten) (See [#3180](https://github.com/urql-graphql/urql/pull/3180))\n\n## 5.0.0\n\n### Patch Changes\n\n- Add TSDocs to `@urql/*` packages\n  Submitted by [@kitten](https://github.com/kitten) (See [#3079](https://github.com/urql-graphql/urql/pull/3079))\n- Updated dependencies (See [#3053](https://github.com/urql-graphql/urql/pull/3053), [#3104](https://github.com/urql-graphql/urql/pull/3104), [#3095](https://github.com/urql-graphql/urql/pull/3095), [#3033](https://github.com/urql-graphql/urql/pull/3033), [#3103](https://github.com/urql-graphql/urql/pull/3103), and [#3079](https://github.com/urql-graphql/urql/pull/3079))\n  - urql@4.0.0\n\n## 4.0.3\n\n### Patch Changes\n\n- Add `pageProps: {}` entry to props on app components, by [@JoviDeCroock](https://github.com/JoviDeCroock) (See [#2909](https://github.com/urql-graphql/urql/pull/2909))\n\n## 4.0.2\n\n### Patch Changes\n\n- ⚠️ Fix type-generation, with a change in TS/Rollup the type generation took the paths as src and resolved them into the types dir, by [@JoviDeCroock](https://github.com/JoviDeCroock) (See [#2870](https://github.com/urql-graphql/urql/pull/2870))\n\n## 4.0.1\n\n### Patch Changes\n\n- Change import for `createClient` to `@urql/core`, which helps Next not depend on `urql` and hence not cause `createContext` to be called when the import is treeshaken away, by [@SleeplessOne1917](https://github.com/SleeplessOne1917) (See [#2833](https://github.com/urql-graphql/urql/pull/2833))\n\n## 4.0.0\n\n### Major Changes\n\n- **Goodbye IE11!** 👋 This major release removes support for IE11. All code that is shipped will be transpiled much less and will _not_ be ES5-compatible anymore, by [@kitten](https://github.com/kitten) (See [#2504](https://github.com/FormidableLabs/urql/pull/2504))\n\n### Patch Changes\n\n- Updated dependencies (See [#2504](https://github.com/FormidableLabs/urql/pull/2504), [#2607](https://github.com/FormidableLabs/urql/pull/2607), and [#2504](https://github.com/FormidableLabs/urql/pull/2504))\n  - urql@3.0.0\n\n## 3.3.3\n\n### Patch Changes\n\n- ⚠️ Fix Node.js ESM re-export detection for `@urql/core` in `urql` package and CommonJS output for all other CommonJS-first packages. This ensures that Node.js' `cjs-module-lexer` can correctly identify re-exports and report them properly. Otherwise, this will lead to a runtime error, by [@kitten](https://github.com/kitten) (See [#2485](https://github.com/FormidableLabs/urql/pull/2485))\n\n## 3.3.2\n\n### Patch Changes\n\n- Extend peer dependency range of `graphql` to include `^16.0.0`.\n  As always when upgrading across many packages of `urql`, especially including `@urql/core` we recommend you to deduplicate dependencies after upgrading, using `npm dedupe` or `npx yarn-deduplicate`, by [@kitten](https://github.com/kitten) (See [#2133](https://github.com/FormidableLabs/urql/pull/2133))\n\n## 3.3.1\n\n### Patch Changes\n\n- ⚠️ Fix bail when the `getInitialProps` call indicates we've finished the response, by [@JoviDeCroock](https://github.com/JoviDeCroock) (See [#2101](https://github.com/FormidableLabs/urql/pull/2101))\n\n## 3.3.0\n\n### Minor Changes\n\n- Support forwarding the getLayout function from pages, by [@JoviDeCroock](https://github.com/JoviDeCroock) (See [#2065](https://github.com/FormidableLabs/urql/pull/2065))\n\n## 3.2.1\n\n### Patch Changes\n\n- ⚠️ Fix issue where the `renderToString` pass would keep looping due to reexecuting operations on the server, by [@JoviDeCroock](https://github.com/JoviDeCroock) (See [#1895](https://github.com/FormidableLabs/urql/pull/1895))\n\n## 3.2.0\n\n### Minor Changes\n\n- Add new `staleWhileRevalidate` option from the `ssrExchange` addition to `withUrqlClient`'s options. This is useful when Next.js is used in static site generation (SSG) mode, by [@kitten](https://github.com/kitten) (See [#1852](https://github.com/FormidableLabs/urql/pull/1852))\n\n### Patch Changes\n\n- Use the built-in `next` types for next-urql HOC return values, by [@JoviDeCroock](https://github.com/JoviDeCroock) (See [#1812](https://github.com/FormidableLabs/urql/pull/1812))\n\n## 3.1.1\n\n### Patch Changes\n\n- ⚠️ Fix `resetUrqlClient` not resetting the SSR cache itself and instead restoring data when all data related to this `Client` and session should've been deleted, by [@Biboswan](https://github.com/Biboswan) (See [#1715](https://github.com/FormidableLabs/urql/pull/1715))\n\n## 3.1.0\n\n### Minor Changes\n\n- Allow subsequent static-pages to hydrate the cache, by [@JoviDeCroock](https://github.com/JoviDeCroock) (See [#1602](https://github.com/FormidableLabs/urql/pull/1602))\n\n### Patch Changes\n\n- Remove closure-compiler from the build step (See [#1570](https://github.com/FormidableLabs/urql/pull/1570))\n\n## 3.0.1\n\n### Patch Changes\n\n- Ensure `urqlState` is hydrated onto the client when a user opts out of `ssr` and uses the `getServerSideProps` or `getStaticProps` on a page-level and `withUrqlClient` is wrapped on an `_app` level.\n  Examples:\n  - [getStaticProps](https://codesandbox.io/s/urql-get-static-props-dmjch?file=/pages/index.js)\n  - [getServerSideProps](https://codesandbox.io/s/urql-get-static-props-forked-xfbrs?file=/pages/index.js), by [@JoviDeCroock](https://github.com/JoviDeCroock) (See [#1501](https://github.com/FormidableLabs/urql/pull/1501))\n\n## 3.0.0\n\n### Patch Changes\n\n- Updated dependencies (See [#1335](https://github.com/FormidableLabs/urql/pull/1335), [#1357](https://github.com/FormidableLabs/urql/pull/1357), and [#1374](https://github.com/FormidableLabs/urql/pull/1374))\n  - urql@2.0.0\n\n## 2.2.0\n\n### Minor Changes\n\n- Fix, update Next integration types so that they work with the newer `NextPage` typings, by [@wgolledge](https://github.com/wgolledge) (See [#1294](https://github.com/FormidableLabs/urql/pull/1294))\n\n### Patch Changes\n\n- ⚠️ Fix `withUrqlClient` fast-refresh detection, by [@JoviDeCroock](https://github.com/JoviDeCroock) (See [#1302](https://github.com/FormidableLabs/urql/pull/1302))\n\n## 2.1.1\n\n### Patch Changes\n\n- ⚠️ Fix the production build overwriting the development build. Specifically in the previous release we mistakenly replaced all development bundles with production bundles. This doesn't have any direct influence on how these packages work, but prevented development warnings from being logged or full errors from being thrown, by [@kitten](https://github.com/kitten) (See [#1097](https://github.com/FormidableLabs/urql/pull/1097))\n- Updated dependencies\n  - urql@1.10.3\n\n## 2.1.0\n\n### Minor Changes\n\n- Update `next-urql` types to be free-standing and not depend on the types from the `next` packages, by [@kitten](https://github.com/kitten) (See [#1095](https://github.com/FormidableLabs/urql/pull/1095))\n\n### Patch Changes\n\n- Updated dependencies (See [#1045](https://github.com/FormidableLabs/urql/pull/1045))\n  - urql@1.10.2\n\n## 2.0.0\n\nThis release moves `urql` from being in `dependencies` to `peerDependencies`. Please install it\nexplicitly, as you may have already in the past, and ensure that both `urql` and `@urql/core` are\nnot duplicated with either `npm dedupe` or `npx yarn-deduplicate`.\n\n```sh\nnpm i --save urql\n# or\nyarn add urql\n```\n\n### Major Changes\n\n- Move the `urql` dependency to a peer dependency.\n- Remove the automatic polyfilling of `fetch` since this is done automatically starting at\n  [`Next v9.4`](https://nextjs.org/blog/next-9-4#improved-built-in-fetch-support)\n  If you are using a version before 9.4 you can upgrade by installing [`isomorphic-unfetch`](https://www.npmjs.com/package/isomorphic-unfetch)\n  and importing it to polyfill the behavior, by [@JoviDeCroock](https://github.com/JoviDeCroock) (See [#1018](https://github.com/FormidableLabs/urql/pull/1018))\n\n## 1.2.0\n\n### Minor Changes\n\n- Add option called `neverSuspend` to disable `React.Suspense` on next.js, by [@JoviDeCroock](https://github.com/JoviDeCroock) (See [#923](https://github.com/FormidableLabs/urql/pull/923))\n- Expose `initUrqlClient` function so that a `Client` can be created manually for use in Next's newer SSR methods manually, such as `getServerSideProps`, by [@sunpietro](https://github.com/sunpietro) (See [#993](https://github.com/FormidableLabs/urql/pull/993))\n\n## 1.1.0\n\n### Minor Changes\n\n- Add the option to reset the client on a next-urql application, by [@JoviDeCroock](https://github.com/JoviDeCroock) (See [#894](https://github.com/FormidableLabs/urql/pull/894))\n\n### Patch Changes\n\n- Updated dependencies (See [#924](https://github.com/FormidableLabs/urql/pull/924) and [#904](https://github.com/FormidableLabs/urql/pull/904))\n  - urql@1.10.0\n\n## 1.0.2\n\n### Patch Changes\n\n- Disable suspense on the `Client` when we aren't using `react-ssr-prepass`, by [@JoviDeCroock](https://github.com/JoviDeCroock) (See [#884](https://github.com/FormidableLabs/urql/pull/884))\n\n## 1.0.1\n\n### Patch Cho\n\n0nges\n\n- Prevent serialization of the `Client` for `withUrqlClient` even if the target component doesn't have a `getInitialProps` method. Before this caused the client to not be initialised correctly on the client-side, by [@JoviDeCroock](https://github.com/JoviDeCroock) (See [#857](https://github.com/FormidableLabs/urql/pull/857))\n\n## 1.0.0\n\nTo migrate to the new version, you will now have to pass a single function argument, instead\nof two arguments to the `withUrqlClient` HOC helper. For instance, you would have to transform this:\n\n```js\nexport default withUrqlClient(\n  ctx => ({\n    url: '',\n  }),\n  ssrExchange => [dedupExchange, cacheExchange, ssrExchange, fetchExchange]\n);\n```\n\nTo look like the following:\n\n```js\nexport default withUrqlClient(\n  (ssrExchange, ctx) => ({\n    url: '',\n    exchanges: [dedupExchange, cacheExchange, ssrExchange, fetchExchange],\n  }),\n  { ssr: true }\n);\n```\n\nThe second argument may now be used to pass `{ ssr: true }` explicitly, when you are\nwrapping a page without another `getInitialProps` method. This gives you better support\nwhen you implement custom methods like `getStaticProps`.\n\n### Major Changes\n\n- Change `getInitialProps` to be applied when the wrapped page `getInitialProps` or when `{ ssr: true }` is passed as a second options object. This is to better support alternative methods like `getStaticProps`. By [@JoviDeCroock](https://github.com/JoviDeCroock) (See [#797](https://github.com/FormidableLabs/urql/pull/797))\n- Update the `withUrqlClient` function to remove the second argument formerly called `mergeExchanges` and merges it with the first argument.\n\n### Patch Changes\n\n- Reuse the ssrExchange when there is one present on the client-side, by [@JoviDeCroock](https://github.com/JoviDeCroock) (See [#855](https://github.com/FormidableLabs/urql/pull/855))\n- Updated dependencies (See [#842](https://github.com/FormidableLabs/urql/pull/842))\n  - urql@1.9.8\n\n## 0.3.8\n\n### Patch Changes\n\n- Bump `react-ssr-prepass` so it can get eliminated in the client-side bundle, this because the 1.2.1 version added \"sideEffects:false\", by [@JoviDeCroock](https://github.com/JoviDeCroock) (See [#809](https://github.com/FormidableLabs/urql/pull/809))\n\n## 0.3.7\n\n### Patch Changes\n\n- Ensure that the Next.js context is available during all stages of SSR. Previously a missing check in `useMemo` on the server-side caused `clientConfig` from being called repeatedly, and another issue may have caused the client from being serialized to initial props, by [@parkerziegler](https://github.com/parkerziegler) (See [#719](https://github.com/FormidableLabs/urql/pull/719))\n\n## 0.3.6\n\n### Patch Changes\n\n- ⚠️ Fix bundling for packages depending on React, as it doesn't have native ESM bundles, by [@kitten](https://github.com/kitten) (See [#646](https://github.com/FormidableLabs/urql/pull/646))\n- Updated dependencies (See [#646](https://github.com/FormidableLabs/urql/pull/646))\n  - urql@1.9.4\n\n## 0.3.5\n\n### Patch Changes\n\n- ⚠️ Fix node resolution when using Webpack, which experiences a bug where it only resolves\n  `package.json:main` instead of `module` when an `.mjs` file imports a package, by [@JoviDeCroock](https://github.com/JoviDeCroock) (See [#642](https://github.com/FormidableLabs/urql/pull/642))\n- Updated dependencies (See [#642](https://github.com/FormidableLabs/urql/pull/642))\n  - urql@1.9.3\n\n## 0.3.4\n\n### Patch Changes\n\n- ⚠️ Fix Node.js Module support for v13 (experimental-modules) and v14. If your bundler doesn't support\n  `.mjs` files and fails to resolve the new version, please double check your configuration for\n  Webpack, or similar tools, by [@JoviDeCroock](https://github.com/JoviDeCroock) (See [#637](https://github.com/FormidableLabs/urql/pull/637))\n- Updated dependencies (See [#637](https://github.com/FormidableLabs/urql/pull/637))\n  - urql@1.9.2\n\n## 0.3.3\n\n### Patch Changes\n\n- ⚠️ Fix Rollup bundle output being written to .es.js instead of .esm.js, by [@kitten](https://github.com/kitten) (See [#609](https://github.com/FormidableLabs/urql/pull/609))\n\n## 0.3.2\n\n### Patch Changes\n\n- Pass the `Client` down in `withUrqlClient.getInitialProps` to prevent it from being created twice, by [@JoviDeCroock](https://github.com/JoviDeCroock) (See [#589](https://github.com/FormidableLabs/urql/pull/589))\n- Add missing GraphQLError serialization for extensions and path field to ssrExchange, by [@kitten](https://github.com/kitten) (See [#607](https://github.com/FormidableLabs/urql/pull/607))\n- Enable users to configure the `suspense` option and clean up suspense warning message, by [@ryan-gilb](https://github.com/ryan-gilb) (See [#603](https://github.com/FormidableLabs/urql/pull/603))\n\n## 0.3.1\n\n### Patch Changes\n\n- Remove type import from internal urql package file that has been removed, by [@parkerziegler](https://github.com/parkerziegler) (See [#557](https://github.com/FormidableLabs/urql/pull/557))\n- Ensure empty object gets returned in withUrqlClient's getInitialProps. Update next-urql examples to run in the urql monorepo, by [@parkerziegler](https://github.com/parkerziegler) (See [#563](https://github.com/FormidableLabs/urql/pull/563))\n\nAll notable changes to this project will be documented in this file.\n\nThe format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),\nand this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).\n\n## 0.3.0\n\nThis release adds support for different `urql` Client configurations between the client-side and the server-side when using `next-urql`.\n\n**Warning:** To support this, access to Next's context object, `ctx`, **can only happen on the server**.\n\n### Added\n\n- An example showing how to use a custom exchange with `next-urql`. PR by @ryan-gilb [here](https://github.com/FormidableLabs/next-urql/pull/32).\n- Instructions for using `next-urql` with ReasonML. PR by @parkerziegler [here](https://github.com/FormidableLabs/next-urql/pull/28).\n\n### Fixed\n\n- `clientOptions` are no longer serialized inside of `withUrql`'s `getInitialProps` method. This ensures that users can use different Client configurations between the client and server. PR by @parkerziegler [here](https://github.com/FormidableLabs/next-urql/pull/33).\n- Proper support for forwarding `pageProps` when using `withUrqlClient` with an `_app.js` component. The `urql` Client instance is also attached to `ctx` for `_app.js` `getInitialProps`. PR by @parkerziegler [here](https://github.com/FormidableLabs/next-urql/pull/38).\n- `react-ssr-prepass` dependency upgraded to `1.1.2` to support `urql` `>= 1.9.0`. PR by @JoviDeCroock [here](https://github.com/FormidableLabs/next-urql/pull/37).\n\n### Diff\n\nhttps://github.com/FormidableLabs/next-urql/compare/v0.2.5...v0.3.0\n\n## 0.2.5\n\nThis release encompasses small changes to our TypeScript definitions for `next-urql`, with an upgrade to using `next@9` as the basis for new type definitions in lieu of `@types/next`. The examples were also converted over to TypeScript from JavaScript.\n\n### Added\n\n- All example projects now use TypeScript 🎉 PRs by @ryan-gilb [here](https://github.com/FormidableLabs/next-urql/pull/19) and [here](https://github.com/FormidableLabs/next-urql/pull/21). This gives us stronger guarantees around library types.\n\n### Fixed\n\n- Upgraded type definitions to use types from `next@9`. PR by @ryan-gilb [here](https://github.com/FormidableLabs/next-urql/pull/22). If accessing the `NextContextWithAppTree` `interface`, the name has changed to `NextUrqlContext`.\n\n### Diff\n\nhttps://github.com/FormidableLabs/next-urql/compare/v0.2.4...v0.2.5\n\n## 0.2.4\n\nThis release adds support for accessing the `urqlClient` instance off of Next's context object.\n\n### Added\n\n- `urqlClient` is now added to Next's context object, `ctx`, such that it can be accessed by other components lower in the tree. PR by @BjoernRave [here](https://github.com/FormidableLabs/next-urql/pull/15).\n\n### Diff\n\nhttps://github.com/FormidableLabs/next-urql/compare/v0.2.3...v0.2.4\n\n## 0.2.3\n\nThis release fixes support for using `withUrqlClient` with `_app.js`.\n\n### Added\n\n- Examples are now separated into an `examples` directory. The first, `1-with-urql-client`, shows recommended usage by wrapping a Page component, while the second, `2-with-_app.js` shows how to set up `next-urql` with `_app.js`.\n\n### Fixed\n\n- Be sure to check for `urqlClient` in both direct props and `pageProps` to handle `_app.js` usage with `withUrqlClient`. PR by @bmathews and @parkerziegler [here](https://github.com/FormidableLabs/next-urql/pull/13).\n\n### Diff\n\nhttps://github.com/FormidableLabs/next-urql/compare/v0.2.2...v0.2.3\n\n## 0.2.2\n\nThis release fixes a small discrepancy in the types used by `withUrqlClient` and the public API defined by our `index.d.ts` file.\n\n### Fixed\n\n- Use `NextUrqlClientConfig` in lieu of `NextUrqlClientOptions` in `index.d.ts` to match implementation of `withUrqlClient`. PR by @kylealwyn [here](https://github.com/FormidableLabs/next-urql/pull/9).\n\n### Diff\n\nhttps://github.com/FormidableLabs/next-urql/compare/v0.2.1...v0.2.2\n\n## 0.2.1\n\nThis release fixes a regression introduced in 0.2.0 involving circular structures created by `withUrqlClient`'s `getInitialProps` method.\n\n### Fixed\n\n- Amend circular structure in `withUrqlClient` caused by returning `ctx` in `getInitialProps`. PR by @parkerziegler [here](https://github.com/FormidableLabs/next-urql/pull/7).\n- Fix dependency resolution issues in the `example` project. Update `example` documentation. PR by @parkerziegler [here](https://github.com/FormidableLabs/next-urql/pull/7).\n\n### Diff\n\nhttps://github.com/FormidableLabs/next-urql/compare/v0.2.0...v0.2.1\n\n## 0.2.0 [Deprecated]\n\nThis release adds support for accessing Next's context object, `ctx`, to instantiate your `urql` Client instance.\n\n### Added\n\n- Support for accessing Next's context object, `ctx`, when initializing `withUrqlClient` and creating client options. This should assist users who need to access some data stored in `ctx` to instantiate their `urql` Client instance. PR by @parkerziegler [here](https://github.com/FormidableLabs/next-urql/pull/4).\n\n### Diff\n\nhttps://github.com/FormidableLabs/next-urql/compare/v0.1.1...v0.2.0\n\n## 0.1.1\n\nThis release adds TypeScript definitions to `next-urql`, alongside important pieces like a License (MIT), and improved documentation for users and contributors.\n\n### Added\n\n- TypeScript definitions for the public API of `next-urql` now ship with the library. PR by @parkerziegler [here](https://github.com/FormidableLabs/next-urql/pull/2).\n- MIT License.\n- Improved README documentation around `withUrqlClient` usage.\n- CONTRIBUTING.md to help new contributors to the project get involved.\n\n### Diff\n\nhttps://github.com/FormidableLabs/next-urql/compare/v0.1.0...v0.1.1\n\n## 0.1.0\n\nThis is the initial release of `next-urql` in its Beta API. The package is not meant to be consumed yet, and this purely serves as a prerelease for local testing.\n"
  },
  {
    "path": "packages/next-urql/README.md",
    "content": "## `next-urql`\n\nA set of convenience utilities for using `urql` with Next.js.\n\nMore documentation is available at https://urql.dev/goto/docs/advanced/server-side-rendering/#nextjs\nExamples can be found at https://github.com/urql-graphql/urql/tree/main/examples/with-next\n"
  },
  {
    "path": "packages/next-urql/jsr.json",
    "content": "{\n  \"name\": \"@urql/next\",\n  \"version\": \"2.0.0\",\n  \"exports\": {\n    \".\": \"./src/index.ts\",\n    \"./rsc\": \"./src/rsc.ts\"\n  },\n  \"exclude\": [\n    \"node_modules\",\n    \"cypress\",\n    \"**/*.test.*\",\n    \"**/*.spec.*\",\n    \"**/*.test.*.snap\",\n    \"**/*.spec.*.snap\"\n  ]\n}"
  },
  {
    "path": "packages/next-urql/package.json",
    "content": "{\n  \"name\": \"@urql/next\",\n  \"version\": \"2.0.0\",\n  \"description\": \"Convenience wrappers for using urql with NextJS.\",\n  \"sideEffects\": false,\n  \"homepage\": \"https://formidable.com/open-source/urql/docs/\",\n  \"bugs\": \"https://github.com/urql-graphql/urql/issues\",\n  \"license\": \"MIT\",\n  \"author\": \"urql GraphQL Contributors\",\n  \"repository\": {\n    \"type\": \"git\",\n    \"url\": \"https://github.com/urql-graphql/urql.git\",\n    \"directory\": \"packages/next-urql\"\n  },\n  \"main\": \"dist/urql-next\",\n  \"module\": \"dist/urql-next.mjs\",\n  \"types\": \"dist/urql-next.d.ts\",\n  \"source\": \"src/index.ts\",\n  \"exports\": {\n    \".\": {\n      \"types\": \"./dist/urql-next.d.ts\",\n      \"import\": \"./dist/urql-next.mjs\",\n      \"require\": \"./dist/urql-next.js\",\n      \"source\": \"./src/index.ts\"\n    },\n    \"./package.json\": \"./package.json\",\n    \"./rsc\": {\n      \"types\": \"./dist/urql-next-rsc.d.ts\",\n      \"import\": \"./dist/urql-next-rsc.mjs\",\n      \"require\": \"./dist/urql-next-rsc.js\",\n      \"source\": \"./src/rsc.ts\"\n    }\n  },\n  \"files\": [\n    \"LICENSE\",\n    \"CHANGELOG.md\",\n    \"README.md\",\n    \"rsc/\",\n    \"dist/\"\n  ],\n  \"scripts\": {\n    \"clean\": \"rimraf dist\",\n    \"check\": \"tsc --noEmit\",\n    \"lint\": \"eslint --ext=js,jsx,ts,tsx .\",\n    \"build\": \"rollup -c ../../scripts/rollup/config.mjs\",\n    \"prepare\": \"node ../../scripts/prepare/index.js\",\n    \"prepublishOnly\": \"run-s clean build\"\n  },\n  \"devDependencies\": {\n    \"@urql/core\": \"workspace:*\",\n    \"urql\": \"workspace:*\",\n    \"@types/react\": \"^18.3.8\",\n    \"@types/react-dom\": \"^18.3.0\",\n    \"graphql\": \"^16.0.0\",\n    \"next\": \"^13.0.0\",\n    \"react\": \"^18.0.0\",\n    \"react-dom\": \"^18.0.0\"\n  },\n  \"peerDependencies\": {\n    \"next\": \">=13.0.0\",\n    \"react\": \">=18.0.0\",\n    \"urql\": \"^5.0.0\"\n  },\n  \"publishConfig\": {\n    \"access\": \"public\",\n    \"provenance\": true\n  }\n}\n"
  },
  {
    "path": "packages/next-urql/src/DataHydrationContext.ts",
    "content": "import * as React from 'react';\nimport { ServerInsertedHTMLContext } from 'next/navigation';\nimport type { UrqlResult } from './useUrqlValue';\nimport { htmlEscapeJsonString } from './htmlescape';\n\ninterface DataHydrationValue {\n  isInjecting: boolean;\n  operationValuesByKey: Record<number, UrqlResult>;\n  RehydrateScript: () =>\n    | React.DetailedReactHTMLElement<\n        { dangerouslySetInnerHTML: { __html: string } },\n        HTMLElement\n      >\n    | React.FunctionComponentElement<any>;\n}\n\nconst DataHydrationContext = React.createContext<\n  DataHydrationValue | undefined\n>(undefined);\n\nfunction transportDataToJS(data: any) {\n  const key = 'urql_transport';\n  return `(window[Symbol.for(\"${key}\")] ??= []).push(${htmlEscapeJsonString(\n    JSON.stringify(data)\n  )})`;\n}\n\nexport const DataHydrationContextProvider = ({\n  nonce,\n  children,\n}: React.PropsWithChildren<{ nonce?: string }>) => {\n  const dataHydrationContext = React.useRef<DataHydrationValue>();\n  if (typeof window == 'undefined') {\n    if (!dataHydrationContext.current)\n      dataHydrationContext.current = buildContext({ nonce });\n  }\n\n  return React.createElement(\n    DataHydrationContext.Provider,\n    { value: dataHydrationContext.current },\n    children\n  );\n};\n\nexport function useDataHydrationContext(): DataHydrationValue | undefined {\n  const dataHydrationContext = React.useContext(DataHydrationContext);\n  const insertHtml = React.useContext(ServerInsertedHTMLContext as any) as (\n    cb: () => any\n  ) => any;\n\n  if (typeof window !== 'undefined') return;\n\n  if (insertHtml && dataHydrationContext && !dataHydrationContext.isInjecting) {\n    dataHydrationContext.isInjecting = true;\n    insertHtml(() =>\n      React.createElement(dataHydrationContext.RehydrateScript, {})\n    );\n  }\n  return dataHydrationContext;\n}\n\nlet key = 0;\nfunction buildContext({ nonce }: { nonce?: string }): DataHydrationValue {\n  const dataHydrationContext: DataHydrationValue = {\n    isInjecting: false,\n    operationValuesByKey: {},\n    RehydrateScript() {\n      dataHydrationContext.isInjecting = false;\n      if (!Object.keys(dataHydrationContext.operationValuesByKey).length)\n        return React.createElement(React.Fragment);\n\n      const __html = transportDataToJS({\n        rehydrate: { ...dataHydrationContext.operationValuesByKey },\n      });\n\n      dataHydrationContext.operationValuesByKey = {};\n\n      return React.createElement('script', {\n        key: key++,\n        nonce: nonce,\n        dangerouslySetInnerHTML: { __html },\n      });\n    },\n  };\n\n  return dataHydrationContext;\n}\n"
  },
  {
    "path": "packages/next-urql/src/Provider.ts",
    "content": "'use client';\n\nimport * as React from 'react';\nimport type { SSRExchange, Client } from 'urql';\nimport { Provider } from 'urql';\nimport { DataHydrationContextProvider } from './DataHydrationContext';\n\nexport const SSRContext = React.createContext<SSRExchange | undefined>(\n  undefined\n);\n\n/** Provider for `@urql/next` during non-rsc interactions.\n *\n * @remarks\n * `Provider` accepts a {@link Client} and provides it to all GraphQL hooks, it\n * also accepts an {@link SSRExchange} to distribute data when re-hydrating\n * on the client.\n *\n * @example\n * ```tsx\n * import { useMemo } from 'react';\n * import {\n *  UrqlProvider,\n *  ssrExchange,\n *  cacheExchange,\n *  fetchExchange,\n *  createClient,\n * } from '@urql/next';\n *\n * export default function Layout({ children }: React.PropsWithChildren) {\n *  const [client, ssr] = useMemo(() => {\n *    const ssr = ssrExchange();\n *      const client = createClient({\n *      url: 'https://trygql.formidable.dev/graphql/web-collections',\n *      exchanges: [cacheExchange, ssr, fetchExchange],\n *      suspense: true,\n *    });\n *\n *    return [client, ssr];\n *  }, []);\n *\n *  return (\n *    <UrqlProvider client={client} ssr={ssr}>\n *      {children}\n *    </UrqlProvider>\n *  );\n * }\n *\n * ```\n */\nexport function UrqlProvider({\n  children,\n  ssr,\n  client,\n  nonce,\n}: React.PropsWithChildren<{\n  ssr: SSRExchange;\n  client: Client;\n  nonce?: string;\n}>) {\n  return React.createElement(\n    Provider,\n    { value: client },\n    React.createElement(\n      SSRContext.Provider,\n      { value: ssr },\n      React.createElement(DataHydrationContextProvider, { nonce }, children)\n    )\n  );\n}\n"
  },
  {
    "path": "packages/next-urql/src/htmlescape.ts",
    "content": "// See: https://github.com/vercel/next.js/blob/6bc07792a4462a4bf921a72ab30dc4ab2c4e1bda/packages/next/src/server/htmlescape.ts\n// License: https://github.com/vercel/next.js/blob/6bc07792a4462a4bf921a72ab30dc4ab2c4e1bda/packages/next/license.md\n\n// This utility is based on https://github.com/zertosh/htmlescape\n// License: https://github.com/zertosh/htmlescape/blob/0527ca7156a524d256101bb310a9f970f63078ad/LICENSE\n\nconst ESCAPE_LOOKUP: { [match: string]: string } = {\n  '&': '\\\\u0026',\n  '>': '\\\\u003e',\n  '<': '\\\\u003c',\n  '\\u2028': '\\\\u2028',\n  '\\u2029': '\\\\u2029',\n};\n\nexport const ESCAPE_REGEX = /[&><\\u2028\\u2029]/g;\n\nexport function htmlEscapeJsonString(str: string): string {\n  return str.replace(ESCAPE_REGEX, match => ESCAPE_LOOKUP[match]);\n}\n"
  },
  {
    "path": "packages/next-urql/src/index.ts",
    "content": "export * from 'urql';\nexport { useQuery } from './useQuery';\nexport { UrqlProvider, SSRContext } from './Provider';\n"
  },
  {
    "path": "packages/next-urql/src/rsc.ts",
    "content": "import * as React from 'react';\nimport type { Client } from '@urql/core';\n\n/** Function to cache an urql-client across React Server Components.\n *\n * @param makeClient - A function that creates an urql-client.\n * @returns an object containing a getClient method.\n *\n * @example\n * ```ts\n * import { cacheExchange, createClient, fetchExchange, gql } from '@urql/core';\n * import { registerUrql } from '@urql/next/rsc';\n * const makeClient = () => {\n *   return createClient({\n *     url: 'https://trygql.formidable.dev/graphql/basic-pokedex',\n *     exchanges: [cacheExchange, fetchExchange],\n *   });\n * };\n *\n * const { getClient } = registerUrql(makeClient);\n * ```\n */\nexport function registerUrql(makeClient: () => Client): {\n  getClient: () => Client;\n} {\n  // @ts-ignore you exist don't worry\n  const getClient = React.cache(makeClient);\n  return {\n    getClient,\n  };\n}\n"
  },
  {
    "path": "packages/next-urql/src/useQuery.ts",
    "content": "'use client';\n\nimport type {\n  AnyVariables,\n  CombinedError,\n  GraphQLRequestParams,\n  Operation,\n  OperationContext,\n  RequestPolicy,\n} from 'urql';\nimport { createRequest, useQuery as orig_useQuery } from 'urql';\nimport { useUrqlValue } from './useUrqlValue';\n\n/** Input arguments for the {@link useQuery} hook.\n *\n * @param query - The GraphQL query that `useQuery` executes.\n * @param variables - The variables for the GraphQL query that `useQuery` executes.\n */\nexport type UseQueryArgs<\n  Variables extends AnyVariables = AnyVariables,\n  Data = any,\n> = {\n  /** Updates the {@link RequestPolicy} for the executed GraphQL query operation.\n   *\n   * @remarks\n   * `requestPolicy` modifies the {@link RequestPolicy} of the GraphQL query operation\n   * that `useQuery` executes, and indicates a caching strategy for cache exchanges.\n   *\n   * For example, when set to `'cache-and-network'`, {@link useQuery} will\n   * receive a cached result with `stale: true` and an API request will be\n   * sent in the background.\n   *\n   * @see {@link OperationContext.requestPolicy} for where this value is set.\n   */\n  requestPolicy?: RequestPolicy;\n  /** Updates the {@link OperationContext} for the executed GraphQL query operation.\n   *\n   * @remarks\n   * `context` may be passed to {@link useQuery}, to update the {@link OperationContext}\n   * of a query operation. This may be used to update the `context` that exchanges\n   * will receive for a single hook.\n   *\n   * Hint: This should be wrapped in a `useMemo` hook, to make sure that your\n   * component doesn’t infinitely update.\n   *\n   * @example\n   * ```ts\n   * const [result, reexecute] = useQuery({\n   *   query,\n   *   context: useMemo(() => ({\n   *     additionalTypenames: ['Item'],\n   *   }), [])\n   * });\n   * ```\n   */\n  context?: Partial<OperationContext>;\n  /** Prevents {@link useQuery} from automatically executing GraphQL query operations.\n   *\n   * @remarks\n   * `pause` may be set to `true` to stop {@link useQuery} from executing\n   * automatically. The hook will stop receiving updates from the {@link Client}\n   * and won’t execute the query operation, until either it’s set to `false`\n   * or the {@link UseQueryExecute} function is called.\n   *\n   * @see {@link https://urql.dev/goto/docs/basics/react-preact/#pausing-usequery} for\n   * documentation on the `pause` option.\n   */\n  pause?: boolean;\n} & GraphQLRequestParams<Data, Variables>;\n\n/** State of the current query, your {@link useQuery} hook is executing.\n *\n * @remarks\n * `UseQueryState` is returned (in a tuple) by {@link useQuery} and\n * gives you the updating {@link OperationResult} of GraphQL queries.\n *\n * Even when the query and variables passed to {@link useQuery} change,\n * this state preserves the prior state and sets the `fetching` flag to\n * `true`.\n * This allows you to display the previous state, while implementing\n * a separate loading indicator separately.\n */\nexport interface UseQueryState<\n  Data = any,\n  Variables extends AnyVariables = AnyVariables,\n> {\n  /** Indicates whether `useQuery` is waiting for a new result.\n   *\n   * @remarks\n   * When `useQuery` is passed a new query and/or variables, it will\n   * start executing the new query operation and `fetching` is set to\n   * `true` until a result arrives.\n   *\n   * Hint: This is subtly different than whether the query is actually\n   * fetching, and doesn’t indicate whether a query is being re-executed\n   * in the background. For this, see {@link UseQueryState.stale}.\n   */\n  fetching: boolean;\n  /** Indicates that the state is not fresh and a new result will follow.\n   *\n   * @remarks\n   * The `stale` flag is set to `true` when a new result for the query\n   * is expected and `useQuery` is waiting for it. This may indicate that\n   * a new request is being requested in the background.\n   *\n   * @see {@link OperationResult.stale} for the source of this value.\n   */\n  stale: boolean;\n  /** The {@link OperationResult.data} for the executed query. */\n  data?: Data;\n  /** The {@link OperationResult.error} for the executed query. */\n  error?: CombinedError;\n  /** The {@link OperationResult.hasNext} for the executed query. */\n  hasNext: boolean;\n  /** The {@link OperationResult.extensions} for the executed query. */\n  extensions?: Record<string, any>;\n  /** The {@link Operation} that the current state is for.\n   *\n   * @remarks\n   * This is the {@link Operation} that is currently being executed.\n   * When {@link UseQueryState.fetching} is `true`, this is the\n   * last `Operation` that the current state was for.\n   */\n  operation?: Operation<Data, Variables>;\n}\n\n/** Triggers {@link useQuery} to execute a new GraphQL query operation.\n *\n * @param opts - optionally, context options that will be merged with the hook's\n * {@link UseQueryArgs.context} options and the `Client`’s options.\n *\n * @remarks\n * When called, {@link useQuery} will re-execute the GraphQL query operation\n * it currently holds, even if {@link UseQueryArgs.pause} is set to `true`.\n *\n * This is useful for executing a paused query or re-executing a query\n * and get a new network result, by passing a new request policy.\n *\n * ```ts\n * const [result, reexecuteQuery] = useQuery({ query });\n *\n * const refresh = () => {\n *   // Re-execute the query with a network-only policy, skipping the cache\n *   reexecuteQuery({ requestPolicy: 'network-only' });\n * };\n * ```\n */\nexport type UseQueryExecute = (opts?: Partial<OperationContext>) => void;\n\n/** Result tuple returned by the {@link useQuery} hook.\n *\n * @remarks\n * Similarly to a `useState` hook’s return value,\n * the first element is the {@link useQuery}’s result and state,\n * a {@link UseQueryState} object,\n * and the second is used to imperatively re-execute the query\n * via a {@link UseQueryExecute} function.\n */\nexport type UseQueryResponse<\n  Data = any,\n  Variables extends AnyVariables = AnyVariables,\n> = [UseQueryState<Data, Variables>, UseQueryExecute];\n\n/** Hook to run a GraphQL query and get updated GraphQL results.\n *\n * @param args - a {@link UseQueryArgs} object, to pass a `query`, `variables`, and options.\n * @returns a {@link UseQueryResponse} tuple of a {@link UseQueryState} result, and re-execute function.\n *\n * @remarks\n * `useQuery` allows GraphQL queries to be defined and executed.\n * Given {@link UseQueryArgs.query}, it executes the GraphQL query with the\n * context’s {@link Client}.\n *\n * The returned result updates when the `Client` has new results\n * for the query, and changes when your input `args` change.\n *\n * Additionally, if the `suspense` option is enabled on the `Client`,\n * the `useQuery` hook will suspend instead of indicating that it’s\n * waiting for a result via {@link UseQueryState.fetching}.\n *\n * @see {@link https://urql.dev/goto/urql/docs/basics/react-preact/#queries} for `useQuery` docs.\n *\n * @example\n * ```ts\n * import { gql, useQuery } from 'urql';\n *\n * const TodosQuery = gql`\n *   query { todos { id, title } }\n * `;\n *\n * const Todos = () => {\n *   const [result, reexecuteQuery] = useQuery({\n *     query: TodosQuery,\n *     variables: {},\n *   });\n *   // ...\n * };\n * ```\n */\nexport function useQuery<\n  Data = any,\n  Variables extends AnyVariables = AnyVariables,\n>(\n  args: UseQueryArgs<Variables, Data>\n): UseQueryResponse<Data, Variables | undefined> {\n  const request = createRequest(\n    args.query,\n    (args.variables || {}) as AnyVariables\n  );\n  useUrqlValue(request.key);\n\n  const [result, execute] = orig_useQuery(args);\n\n  useUrqlValue(request.key);\n\n  return [result, execute];\n}\n"
  },
  {
    "path": "packages/next-urql/src/useUrqlValue.ts",
    "content": "'use client';\n\nimport * as React from 'react';\nimport { useDataHydrationContext } from './DataHydrationContext';\nimport { SSRContext } from './Provider';\n\nexport const symbolString = 'urql_transport';\nexport const urqlTransportSymbol = Symbol.for(symbolString);\n\nexport type UrqlResult = { data?: any; error?: any; extensions?: any };\n\nexport function useUrqlValue(operationKey: number): void {\n  const ssrExchange = React.useContext(SSRContext);\n  const rehydrationContext = useDataHydrationContext();\n\n  if (!ssrExchange) {\n    throw new Error(\n      'Missing \"UrqlProvider\" component as a parent or did not pass in an \"ssrExchange\" to the Provider.'\n    );\n  }\n\n  if (typeof window == 'undefined') {\n    const data = ssrExchange.extractData();\n    if (rehydrationContext && data[operationKey]) {\n      const res = data[operationKey];\n      const parsed = {\n        ...res,\n        extensions: res.extensions\n          ? JSON.parse(res.extensions)\n          : res.extensions,\n        data: res.data ? JSON.parse(res.data) : res.data,\n        error: res.error,\n      };\n      rehydrationContext.operationValuesByKey[operationKey] = parsed;\n    }\n  } else {\n    const stores = (window[urqlTransportSymbol as any] ||\n      []) as unknown as Array<{\n      rehydrate: Record<number, UrqlResult>;\n    }>;\n\n    const store = stores.find(\n      x => x && x.rehydrate && x.rehydrate[operationKey]\n    );\n    if (store) {\n      const result = store.rehydrate && store.rehydrate[operationKey];\n      if (result) {\n        delete store.rehydrate[operationKey];\n        ssrExchange.restoreData({\n          [operationKey]: {\n            extensions: JSON.stringify(result.extensions),\n            data: JSON.stringify(result.data),\n            error: result.error,\n          },\n        });\n        delete store.rehydrate[operationKey];\n      }\n    }\n  }\n}\n"
  },
  {
    "path": "packages/next-urql/tsconfig.json",
    "content": "{\n  \"extends\": \"../../tsconfig.json\",\n  \"include\": [\"src\"]\n}\n"
  },
  {
    "path": "packages/next-urql/vitest.config.ts",
    "content": "import { mergeConfig } from 'vitest/config';\nimport baseConfig from '../../vitest.config';\n\nexport default mergeConfig(baseConfig, {});\n"
  },
  {
    "path": "packages/preact-urql/CHANGELOG.md",
    "content": "# @urql/preact\n\n## 5.0.0\n\n### Patch Changes\n\n- Updated dependencies (See [#3789](https://github.com/urql-graphql/urql/pull/3789) and [#3807](https://github.com/urql-graphql/urql/pull/3807))\n  - @urql/core@6.0.0\n\n## 4.1.2\n\n### Patch Changes\n\n- Omit minified files and sourcemaps' `sourcesContent` in published packages\n  Submitted by [@kitten](https://github.com/kitten) (See [#3755](https://github.com/urql-graphql/urql/pull/3755))\n- Updated dependencies (See [#3755](https://github.com/urql-graphql/urql/pull/3755))\n  - @urql/core@5.1.1\n\n## 4.1.1\n\n### Patch Changes\n\n- Add type for `hasNext` to the query and mutation results\n  Submitted by [@JoviDeCroock](https://github.com/JoviDeCroock) (See [#3703](https://github.com/urql-graphql/urql/pull/3703))\n\n## 4.1.0\n\n### Minor Changes\n\n- Mark `@urql/core` as a peer dependency as well as a regular dependency\n  Submitted by [@kitten](https://github.com/kitten) (See [#3579](https://github.com/urql-graphql/urql/pull/3579))\n\n### Patch Changes\n\n- ⚠️ Fix subscription handlers to not receive `null` values\n  Submitted by [@kitten](https://github.com/kitten) (See [#3581](https://github.com/urql-graphql/urql/pull/3581))\n\n## 4.0.5\n\n### Patch Changes\n\n- Updated dependencies (See [#3520](https://github.com/urql-graphql/urql/pull/3520), [#3553](https://github.com/urql-graphql/urql/pull/3553), and [#3520](https://github.com/urql-graphql/urql/pull/3520))\n  - @urql/core@5.0.0\n\n## 4.0.4\n\n### Patch Changes\n\n- Prioritise `context.suspense` and fallback to checking `client.suspense`\n  Submitted by [@JoviDeCroock](https://github.com/JoviDeCroock) (See [#3427](https://github.com/urql-graphql/urql/pull/3427))\n- Updated dependencies (See [#3430](https://github.com/urql-graphql/urql/pull/3430))\n  - @urql/core@4.2.0\n\n## 4.0.3\n\n### Patch Changes\n\n- Apply shallow difference patch from React bindings to `@urql/preact` (See: #3195)\n  Submitted by [@kitten](https://github.com/kitten) (See [#3266](https://github.com/urql-graphql/urql/pull/3266))\n\n## 4.0.2\n\n### Patch Changes\n\n- Update build process to generate correct source maps\n  Submitted by [@kitten](https://github.com/kitten) (See [#3201](https://github.com/urql-graphql/urql/pull/3201))\n\n## 4.0.1\n\n### Patch Changes\n\n- Publish with npm provenance\n  Submitted by [@kitten](https://github.com/kitten) (See [#3180](https://github.com/urql-graphql/urql/pull/3180))\n\n## 4.0.0\n\n### Major Changes\n\n- Remove the default `Client` from `Context`. Previously, `urql` kept a legacy default client in its context, with default exchanges and calling an API at `/graphql`. This has now been removed and you will have to create your own `Client` if you were relying on this behaviour\n  Submitted by [@JoviDeCroock](https://github.com/JoviDeCroock) (See [#3033](https://github.com/urql-graphql/urql/pull/3033))\n\n### Minor Changes\n\n- Allow mutations to update their results in bindings when `hasNext: true` is set, which indicates deferred or streamed results\n  Submitted by [@kitten](https://github.com/kitten) (See [#3103](https://github.com/urql-graphql/urql/pull/3103))\n\n### Patch Changes\n\n- ⚠️ Fix source maps included with recently published packages, which lost their `sourcesContent`, including additional source files, and had incorrect paths in some of them\n  Submitted by [@kitten](https://github.com/kitten) (See [#3053](https://github.com/urql-graphql/urql/pull/3053))\n- Upgrade to `wonka@^6.3.0`\n  Submitted by [@kitten](https://github.com/kitten) (See [#3104](https://github.com/urql-graphql/urql/pull/3104))\n- Add TSDocs to all `urql` bindings packages\n  Submitted by [@kitten](https://github.com/kitten) (See [#3079](https://github.com/urql-graphql/urql/pull/3079))\n- Updated dependencies (See [#3101](https://github.com/urql-graphql/urql/pull/3101), [#3033](https://github.com/urql-graphql/urql/pull/3033), [#3054](https://github.com/urql-graphql/urql/pull/3054), [#3053](https://github.com/urql-graphql/urql/pull/3053), [#3060](https://github.com/urql-graphql/urql/pull/3060), [#3081](https://github.com/urql-graphql/urql/pull/3081), [#3039](https://github.com/urql-graphql/urql/pull/3039), [#3104](https://github.com/urql-graphql/urql/pull/3104), [#3082](https://github.com/urql-graphql/urql/pull/3082), [#3097](https://github.com/urql-graphql/urql/pull/3097), [#3061](https://github.com/urql-graphql/urql/pull/3061), [#3055](https://github.com/urql-graphql/urql/pull/3055), [#3085](https://github.com/urql-graphql/urql/pull/3085), [#3079](https://github.com/urql-graphql/urql/pull/3079), [#3087](https://github.com/urql-graphql/urql/pull/3087), [#3059](https://github.com/urql-graphql/urql/pull/3059), [#3055](https://github.com/urql-graphql/urql/pull/3055), [#3057](https://github.com/urql-graphql/urql/pull/3057), [#3050](https://github.com/urql-graphql/urql/pull/3050), [#3062](https://github.com/urql-graphql/urql/pull/3062), [#3051](https://github.com/urql-graphql/urql/pull/3051), [#3043](https://github.com/urql-graphql/urql/pull/3043), [#3063](https://github.com/urql-graphql/urql/pull/3063), [#3054](https://github.com/urql-graphql/urql/pull/3054), [#3102](https://github.com/urql-graphql/urql/pull/3102), [#3097](https://github.com/urql-graphql/urql/pull/3097), [#3106](https://github.com/urql-graphql/urql/pull/3106), [#3058](https://github.com/urql-graphql/urql/pull/3058), and [#3062](https://github.com/urql-graphql/urql/pull/3062))\n  - @urql/core@4.0.0\n\n## 3.0.3\n\n### Patch Changes\n\n- ⚠️ Fix type utilities turning the `variables` properties optional when a type from `TypedDocumentNode` has no `Variables` or all optional `Variables`. Previously this would break for wrappers, e.g. in code generators, or when the type didn't quite match what we'd expect\n  Submitted by [@kitten](https://github.com/kitten) (See [#3022](https://github.com/urql-graphql/urql/pull/3022))\n- Updated dependencies (See [#3007](https://github.com/urql-graphql/urql/pull/3007), [#2962](https://github.com/urql-graphql/urql/pull/2962), [#3007](https://github.com/urql-graphql/urql/pull/3007), [#3015](https://github.com/urql-graphql/urql/pull/3015), and [#3022](https://github.com/urql-graphql/urql/pull/3022))\n  - @urql/core@3.2.0\n\n## 3.0.2\n\n### Patch Changes\n\n- Update generics for components, by [@JoviDeCroock](https://github.com/JoviDeCroock) (See [#2663](https://github.com/FormidableLabs/urql/pull/2663))\n- Updated dependencies (See [#2665](https://github.com/FormidableLabs/urql/pull/2665))\n  - @urql/core@3.0.3\n\n## 3.0.1\n\n### Patch Changes\n\n- Tweak the variables type for when generics only contain nullable keys, by [@JoviDeCroock](https://github.com/JoviDeCroock) (See [#2623](https://github.com/FormidableLabs/urql/pull/2623))\n\n## 3.0.0\n\n### Major Changes\n\n- **Goodbye IE11!** 👋 This major release removes support for IE11. All code that is shipped will be transpiled much less and will _not_ be ES5-compatible anymore, by [@kitten](https://github.com/kitten) (See [#2504](https://github.com/FormidableLabs/urql/pull/2504))\n- Implement stricter variables types, which require variables to always be passed and match TypeScript types when the generic is set or inferred. This is a breaking change for TypeScript users potentially, unless all types are adhered to, by [@kitten](https://github.com/kitten) (See [#2607](https://github.com/FormidableLabs/urql/pull/2607))\n- Upgrade to [Wonka v6](https://github.com/0no-co/wonka) (`wonka@^6.0.0`), which has no breaking changes but is built to target ES2015 and comes with other minor improvements.\n  The library has fully been migrated to TypeScript which will hopefully help with making contributions easier!, by [@kitten](https://github.com/kitten) (See [#2504](https://github.com/FormidableLabs/urql/pull/2504))\n\n### Patch Changes\n\n- Updated dependencies (See [#2551](https://github.com/FormidableLabs/urql/pull/2551), [#2504](https://github.com/FormidableLabs/urql/pull/2504), [#2619](https://github.com/FormidableLabs/urql/pull/2619), [#2607](https://github.com/FormidableLabs/urql/pull/2607), and [#2504](https://github.com/FormidableLabs/urql/pull/2504))\n  - @urql/core@3.0.0\n\n## 2.0.4\n\n### Patch Changes\n\n- ⚠️ Fix Node.js ESM re-export detection for `@urql/core` in `urql` package and CommonJS output for all other CommonJS-first packages. This ensures that Node.js' `cjs-module-lexer` can correctly identify re-exports and report them properly. Otherwise, this will lead to a runtime error, by [@kitten](https://github.com/kitten) (See [#2485](https://github.com/FormidableLabs/urql/pull/2485))\n\n## 2.0.3\n\n### Patch Changes\n\n- Extend peer dependency range of `graphql` to include `^16.0.0`.\n  As always when upgrading across many packages of `urql`, especially including `@urql/core` we recommend you to deduplicate dependencies after upgrading, using `npm dedupe` or `npx yarn-deduplicate`, by [@kitten](https://github.com/kitten) (See [#2133](https://github.com/FormidableLabs/urql/pull/2133))\n- Updated dependencies (See [#2133](https://github.com/FormidableLabs/urql/pull/2133))\n  - @urql/core@2.3.6\n\n## 2.0.2\n\n### Patch Changes\n\n- Remove closure-compiler from the build step (See [#1570](https://github.com/FormidableLabs/urql/pull/1570))\n- Updated dependencies (See [#1570](https://github.com/FormidableLabs/urql/pull/1570), [#1509](https://github.com/FormidableLabs/urql/pull/1509), [#1600](https://github.com/FormidableLabs/urql/pull/1600), and [#1515](https://github.com/FormidableLabs/urql/pull/1515))\n  - @urql/core@2.1.0\n\n## 2.0.1\n\n### Patch Changes\n\n- Add a displayName to the Provider, by [@JoviDeCroock](https://github.com/JoviDeCroock) (See [#1431](https://github.com/FormidableLabs/urql/pull/1431))\n\n## 2.0.0\n\n### Major Changes\n\n- **Breaking**: Remove `pollInterval` option from `useQuery`. Instead please consider using `useEffect` calling `executeQuery` on an interval, by [@kitten](https://github.com/kitten) (See [#1374](https://github.com/FormidableLabs/urql/pull/1374))\n\n### Minor Changes\n\n- Remove deprecated `operationName` property from `Operation`s. The new `Operation.kind` property is now preferred. If you're creating new operations you may also use the `makeOperation` utility instead.\n  When upgrading `@urql/core` please ensure that your package manager didn't install any duplicates of it. You may deduplicate it manually using `npx yarn-deduplicate` (for Yarn) or `npm dedupe` (for npm), by [@kitten](https://github.com/kitten) (See [#1357](https://github.com/FormidableLabs/urql/pull/1357))\n\n### Patch Changes\n\n- Updated dependencies (See [#1374](https://github.com/FormidableLabs/urql/pull/1374), [#1357](https://github.com/FormidableLabs/urql/pull/1357), and [#1375](https://github.com/FormidableLabs/urql/pull/1375))\n  - @urql/core@2.0.0\n\n## 1.4.4\n\n### Patch Changes\n\n- ⚠️ Fix Suspense when results share data, this would return partial results for graphCache and not update to the eventual data, by [@JoviDeCroock](https://github.com/JoviDeCroock) (See [#1282](https://github.com/FormidableLabs/urql/pull/1282))\n\n## 1.4.3\n\n### Patch Changes\n\n- Add a built-in `gql` tag function helper to `@urql/core`. This behaves similarly to `graphql-tag` but only warns about _locally_ duplicated fragment names rather than globally. It also primes `@urql/core`'s key cache with the parsed `DocumentNode`, by [@kitten](https://github.com/kitten) (See [#1187](https://github.com/FormidableLabs/urql/pull/1187))\n- Add `suspense: false` to options when `executeQuery` is called explicitly, by [@kitten](https://github.com/kitten) (See [#1181](https://github.com/FormidableLabs/urql/pull/1181))\n- Updated dependencies (See [#1187](https://github.com/FormidableLabs/urql/pull/1187), [#1186](https://github.com/FormidableLabs/urql/pull/1186), and [#1186](https://github.com/FormidableLabs/urql/pull/1186))\n  - @urql/core@1.16.0\n\n## 1.4.2\n\n### Patch Changes\n\n- ⚠️ Fix regression in client-side Suspense behaviour. This has been fixed in `urql@1.11.0` and `@urql/preact@1.4.0` but regressed in the patches afterwards that were aimed at fixing server-side Suspense, by [@kitten](https://github.com/kitten) (See [#1142](https://github.com/FormidableLabs/urql/pull/1142))\n\n## 1.4.1\n\n### Patch Changes\n\n- ⚠️ Fix server-side rendering by disabling the new Suspense cache on the server-side and clear it for prepasses, by [@JoviDeCroock](https://github.com/JoviDeCroock) (See [#1138](https://github.com/FormidableLabs/urql/pull/1138))\n- Updated dependencies (See [#1135](https://github.com/FormidableLabs/urql/pull/1135))\n  - @urql/core@1.15.1\n\n## 1.4.0\n\n### Minor Changes\n\n- Improve the Suspense implementation, which fixes edge-cases when Suspense is used with subscriptions, partially disabled, or _used on the client-side_. It has now been ensured that client-side suspense functions without the deprecated `suspenseExchange` and uncached results are loaded consistently. As part of this work, the `Client` itself does now never throw Suspense promises anymore, which is functionality that either way has no place outside of the React/Preact bindings, by [@kitten](https://github.com/kitten) (See [#1123](https://github.com/FormidableLabs/urql/pull/1123))\n\n### Patch Changes\n\n- Add support for `TypedDocumentNode` to infer the type of the `OperationResult` and `Operation` for all methods, functions, and hooks that either directly or indirectly accept a `DocumentNode`. See [`graphql-typed-document-node` and the corresponding blog post for more information.](https://github.com/dotansimha/graphql-typed-document-node), by [@kitten](https://github.com/kitten) (See [#1113](https://github.com/FormidableLabs/urql/pull/1113))\n- Refactor `useSource` hooks which powers `useQuery` and `useSubscription` to improve various edge case behaviour. This will not change the behaviour of these hooks dramatically but avoid unnecessary state updates when any updates are obviously equivalent and the hook will furthermore improve continuation from mount to effects, which will fix cases where the state between the mounting and effect phase may slightly change, by [@kitten](https://github.com/kitten) (See [#1104](https://github.com/FormidableLabs/urql/pull/1104))\n- Updated dependencies (See [#1119](https://github.com/FormidableLabs/urql/pull/1119), [#1113](https://github.com/FormidableLabs/urql/pull/1113), [#1104](https://github.com/FormidableLabs/urql/pull/1104), and [#1123](https://github.com/FormidableLabs/urql/pull/1123))\n  - @urql/core@1.15.0\n\n## 1.3.2\n\n### Patch Changes\n\n- ⚠️ Fix the production build overwriting the development build. Specifically in the previous release we mistakenly replaced all development bundles with production bundles. This doesn't have any direct influence on how these packages work, but prevented development warnings from being logged or full errors from being thrown, by [@kitten](https://github.com/kitten) (See [#1097](https://github.com/FormidableLabs/urql/pull/1097))\n- Updated dependencies (See [#1097](https://github.com/FormidableLabs/urql/pull/1097))\n  - @urql/core@1.14.1\n\n## 1.3.1\n\n### Patch Changes\n\n- Add missing `.mjs` extension to all imports from `graphql` to fix Webpack 5 builds, which require extension-specific import paths for ESM bundles and packages. **This change allows you to safely upgrade to Webpack 5.**, by [@kitten](https://github.com/kitten) (See [#1094](https://github.com/FormidableLabs/urql/pull/1094))\n- Updated dependencies (See [#1094](https://github.com/FormidableLabs/urql/pull/1094) and [#1045](https://github.com/FormidableLabs/urql/pull/1045))\n  - @urql/core@1.14.0\n\n## 1.3.0\n\n### Minor Changes\n\n- Update `@urql/preact` implementation to match `urql` React implementation. Internally these changes should align behaviour and updates slightly, but outwardly no changes should be apparent apart from how some updates are scheduled, by [@kitten](https://github.com/kitten) (See [#1008](https://github.com/FormidableLabs/urql/pull/1008))\n\n### Patch Changes\n\n- Updated dependencies (See [#1011](https://github.com/FormidableLabs/urql/pull/1011))\n  - @urql/core@1.13.1\n\n## 1.2.1\n\n### Patch Changes\n\n- Handle a bug in Preact where the current request might be `null`, by [@jlengstorf](https://github.com/jlengstorf) (See [#944](https://github.com/FormidableLabs/urql/pull/944))\n- Updated dependencies (See [#947](https://github.com/FormidableLabs/urql/pull/947), [#962](https://github.com/FormidableLabs/urql/pull/962), and [#957](https://github.com/FormidableLabs/urql/pull/957))\n  - @urql/core@1.13.0\n\n## 1.2.0\n\n### Minor Changes\n\n- Add the operation to the query, mutation and subscription result, by [@JoviDeCroock](https://github.com/JoviDeCroock) (See [#924](https://github.com/FormidableLabs/urql/pull/924))\n\n### Patch Changes\n\n- Updated dependencies (See [#911](https://github.com/FormidableLabs/urql/pull/911) and [#908](https://github.com/FormidableLabs/urql/pull/908))\n  - @urql/core@1.12.3\n\n## 1.1.8\n\n### Patch Changes\n\n- Upgrade to a minimum version of wonka@^4.0.14 to work around issues with React Native's minification builds, which use uglify-es and could lead to broken bundles, by [@kitten](https://github.com/kitten) (See [#842](https://github.com/FormidableLabs/urql/pull/842))\n- Updated dependencies (See [#838](https://github.com/FormidableLabs/urql/pull/838) and [#842](https://github.com/FormidableLabs/urql/pull/842))\n  - @urql/core@1.12.0\n\n## 1.1.7\n\n### Patch Changes\n\n- Add a `\"./package.json\"` entry to the `package.json`'s `\"exports\"` field for Node 14. This seems to be required by packages like `rollup-plugin-svelte` to function properly, by [@JoviDeCroock](https://github.com/JoviDeCroock) (See [#771](https://github.com/FormidableLabs/urql/pull/771))\n- Updated dependencies (See [#771](https://github.com/FormidableLabs/urql/pull/771))\n  - @urql/core@1.11.6\n\n## 1.1.6\n\n### Patch Changes\n\n- Bump @urql/core to ensure exchanges have dispatchDebug, this could formerly result in a crash, by [@JoviDeCroock](https://github.com/JoviDeCroock) (See [#726](https://github.com/FormidableLabs/urql/pull/726))\n\n## 1.1.5\n\n### Patch Changes\n\n- Add graphql@^15.0.0 to peer dependency range, by [@kitten](https://github.com/kitten) (See [#688](https://github.com/FormidableLabs/urql/pull/688))\n- Forcefully bump @urql/core package in all bindings and in @urql/exchange-graphcache.\n  We're aware that in some cases users may not have upgraded to @urql/core, even though that's within\n  the typical patch range. Since the latest @urql/core version contains a patch that is required for\n  `cache-and-network` to work, we're pushing another patch that now forcefully bumps everyone to the\n  new version that includes this fix, by [@kitten](https://github.com/kitten) (See [#684](https://github.com/FormidableLabs/urql/pull/684))\n- Updated dependencies (See [#688](https://github.com/FormidableLabs/urql/pull/688) and [#678](https://github.com/FormidableLabs/urql/pull/678))\n  - @urql/core@1.10.8\n\n## 1.1.4\n\n### Patch Changes\n\n- ⚠️ Fix node resolution when using Webpack, which experiences a bug where it only resolves\n  `package.json:main` instead of `module` when an `.mjs` file imports a package, by [@JoviDeCroock](https://github.com/JoviDeCroock) (See [#642](https://github.com/FormidableLabs/urql/pull/642))\n- Updated dependencies (See [#642](https://github.com/FormidableLabs/urql/pull/642))\n  - @urql/core@1.10.4\n\n## 1.1.3\n\n### Patch Changes\n\n- ⚠️ Fix Node.js Module support for v13 (experimental-modules) and v14. If your bundler doesn't support\n  `.mjs` files and fails to resolve the new version, please double check your configuration for\n  Webpack, or similar tools, by [@JoviDeCroock](https://github.com/JoviDeCroock) (See [#637](https://github.com/FormidableLabs/urql/pull/637))\n- Updated dependencies (See [#637](https://github.com/FormidableLabs/urql/pull/637))\n  - @urql/core@1.10.3\n\n## 1.1.2\n\n### Patch Changes\n\n- Bumps the `@urql/core` dependency minor version to ^1.10.1 for React, Preact and Svelte, by [@JoviDeCroock](https://github.com/JoviDeCroock) (See [#623](https://github.com/FormidableLabs/urql/pull/623))\n- Updated dependencies (See [#621](https://github.com/FormidableLabs/urql/pull/621))\n  - @urql/core@1.10.2\n\n## 1.1.1\n\n### Patch Changes\n\n- Switch over to using @urql/core package (See [`75323c0`](https://github.com/FormidableLabs/urql/commit/75323c0))\n- Updated dependencies (See [#533](https://github.com/FormidableLabs/urql/pull/533), [#519](https://github.com/FormidableLabs/urql/pull/519), [#515](https://github.com/FormidableLabs/urql/pull/515), [#512](https://github.com/FormidableLabs/urql/pull/512), and [#518](https://github.com/FormidableLabs/urql/pull/518))\n  - @urql/core@1.9.0\n\n## 1.1.0\n\n- Update urql to 1.8.0\n- Update wonka to 4.0.0 (and incorporate breaking changes)\n"
  },
  {
    "path": "packages/preact-urql/README.md",
    "content": "<div align=\"center\">\n  <br />\n  <br />\n  <a href=\"https://www.npmjs.com/package/@urql/preact\">\n    <img alt=\"Npm version\" src=\"https://badgen.net/npm/v/@urql/preact\" />\n  </a>\n  <a href=\"https://bundlephobia.com/result?p=@urql/preact\">\n    <img alt=\"Minified gzip size\" src=\"https://img.shields.io/bundlephobia/minzip/@urql/preact.svg?label=gzip%20size\" />\n  </a>\n  <a href=\"https://github.com/urql-graphql/urql/discussions\">\n    <img alt=\"GitHub Discussions: Chat With Us\" src=\"https://badgen.net/badge/discussions/chat%20with%20us/purple\" />\n  </a>\n  <br />\n  <br />\n</div>\n\n## Installation\n\n```sh\nyarn add @urql/preact urql graphql\n# or\nnpm install --save @urql/preact urql graphql\n```\n\n## Usage\n\nThe usage is a 1:1 mapping of the React usage found [here](https://formidable.com/open-source/urql/docs)\n\nsmall example:\n\n```jsx\nimport { createClient, cacheExchange, fetchExchange, Provider, useQuery } from '@urql/preact';\n\nconst client = createClient({\n  url: 'https://myHost/graphql',\n  exchanges: [cacheExchange, fetchExchange],\n});\n\nconst App = () => (\n  <Provider value={client}>\n    <Dogs />\n  </Provider>\n);\n\nconst Dogs = () => {\n  const [result] = useQuery({\n    query: `{ dogs { id name } }`,\n  });\n\n  if (result.fetching) return <p>Loading...</p>;\n  if (result.error) return <p>Oh no...</p>;\n\n  return result.data.dogs.map(dog => <p>{dog.name} is a good boy!</p>);\n};\n```\n"
  },
  {
    "path": "packages/preact-urql/jsr.json",
    "content": "{\n  \"name\": \"@urql/preact\",\n  \"version\": \"5.0.0\",\n  \"exports\": {\n    \".\": \"./src/index.ts\"\n  },\n  \"exclude\": [\n    \"node_modules\",\n    \"cypress\",\n    \"**/*.test.*\",\n    \"**/*.spec.*\",\n    \"**/*.test.*.snap\",\n    \"**/*.spec.*.snap\"\n  ]\n}"
  },
  {
    "path": "packages/preact-urql/package.json",
    "content": "{\n  \"name\": \"@urql/preact\",\n  \"version\": \"5.0.0\",\n  \"description\": \"A highly customizable and versatile GraphQL client for Preact\",\n  \"sideEffects\": false,\n  \"homepage\": \"https://formidable.com/open-source/urql/docs/\",\n  \"bugs\": \"https://github.com/urql-graphql/urql/issues\",\n  \"license\": \"MIT\",\n  \"author\": \"urql GraphQL Contributors\",\n  \"repository\": {\n    \"type\": \"git\",\n    \"url\": \"https://github.com/urql-graphql/urql.git\",\n    \"directory\": \"packages/preact-urql\"\n  },\n  \"keywords\": [\n    \"graphql client\",\n    \"state management\",\n    \"cache\",\n    \"graphql\",\n    \"exchanges\",\n    \"preact\"\n  ],\n  \"main\": \"dist/urql-preact\",\n  \"module\": \"dist/urql-preact.mjs\",\n  \"types\": \"dist/urql-preact.d.ts\",\n  \"source\": \"src/index.ts\",\n  \"exports\": {\n    \".\": {\n      \"types\": \"./dist/urql-preact.d.ts\",\n      \"import\": \"./dist/urql-preact.mjs\",\n      \"require\": \"./dist/urql-preact.js\",\n      \"source\": \"./src/index.ts\"\n    },\n    \"./package.json\": \"./package.json\"\n  },\n  \"files\": [\n    \"LICENSE\",\n    \"CHANGELOG.md\",\n    \"README.md\",\n    \"dist/\"\n  ],\n  \"scripts\": {\n    \"test\": \"vitest\",\n    \"clean\": \"rimraf dist\",\n    \"check\": \"tsc --noEmit\",\n    \"lint\": \"eslint --ext=js,jsx,ts,tsx .\",\n    \"build\": \"rollup -c ../../scripts/rollup/config.mjs\",\n    \"prepare\": \"node ../../scripts/prepare/index.js\",\n    \"prepublishOnly\": \"run-s clean build\"\n  },\n  \"devDependencies\": {\n    \"@testing-library/preact\": \"^2.0.0\",\n    \"@urql/core\": \"workspace:*\",\n    \"graphql\": \"^16.0.0\",\n    \"preact\": \"^10.13.0\"\n  },\n  \"peerDependencies\": {\n    \"@urql/core\": \"^6.0.0\",\n    \"preact\": \">= 10.0.0\"\n  },\n  \"dependencies\": {\n    \"@urql/core\": \"workspace:^6.0.1\",\n    \"wonka\": \"^6.3.2\"\n  },\n  \"publishConfig\": {\n    \"access\": \"public\",\n    \"provenance\": true\n  }\n}\n"
  },
  {
    "path": "packages/preact-urql/src/components/Mutation.test.tsx",
    "content": "// @vitest-environment jsdom\n\nimport { h } from 'preact';\nimport { act, cleanup, render } from '@testing-library/preact';\nimport { pipe, fromValue, delay } from 'wonka';\nimport { vi, expect, it, beforeEach, describe, afterEach, Mock } from 'vitest';\n\nimport { Provider } from '../context';\nimport { Mutation } from './Mutation';\n\nconst mock = {\n  executeMutation: vi.fn(() =>\n    pipe(fromValue({ data: 1, error: 2, extensions: { i: 1 } }), delay(200))\n  ),\n};\nconst client = mock as { executeMutation: Mock };\nconst query = 'mutation Example { example }';\n\ndescribe('Mutation', () => {\n  beforeEach(() => {\n    vi.useFakeTimers();\n\n    vi.spyOn(globalThis.console, 'error').mockImplementation(() => {\n      // do nothing\n    });\n  });\n\n  afterEach(() => {\n    cleanup();\n  });\n\n  it('Should execute the mutation', () => {\n    // eslint-disable-next-line\n    let execute = () => {},\n      props = {};\n    const Test = () => h('p', {}, 'hi');\n    const App = () => {\n      // @ts-ignore\n      return h(Provider, {\n        value: client,\n        children: [\n          h(\n            Mutation as any,\n            { query },\n            ({ data, fetching, error, executeMutation }) => {\n              execute = executeMutation;\n              props = { data, fetching, error };\n              // @ts-ignore\n              return h(Test, {});\n            }\n          ),\n        ],\n      });\n    };\n    render(h(App, {}));\n    expect(client.executeMutation).toBeCalledTimes(0);\n    expect(props).toStrictEqual({\n      data: undefined,\n      fetching: false,\n      error: undefined,\n    });\n\n    act(() => {\n      execute();\n    });\n\n    expect(props).toStrictEqual({\n      data: undefined,\n      fetching: true,\n      error: undefined,\n    });\n\n    act(() => {\n      vi.advanceTimersByTime(400);\n    });\n\n    expect(props).toStrictEqual({ data: 1, fetching: false, error: 2 });\n  });\n});\n"
  },
  {
    "path": "packages/preact-urql/src/components/Mutation.ts",
    "content": "import type { VNode } from 'preact';\nimport type { AnyVariables, DocumentInput } from '@urql/core';\n\nimport type { UseMutationState, UseMutationExecute } from '../hooks';\nimport { useMutation } from '../hooks';\n\n/** Props accepted by {@link Mutation}.\n *\n * @remarks\n * `MutationProps` are the props accepted by the {@link Mutation} component.\n *\n * The result, the {@link MutationState} object, will be passed to\n * a {@link MutationProps.children} function, passed as children\n * to the `Mutation` component.\n */\nexport interface MutationProps<\n  Data = any,\n  Variables extends AnyVariables = AnyVariables,\n> {\n  /* The GraphQL mutation document that {@link useMutation} will execute. */\n  query: DocumentInput<Data, Variables>;\n  children(arg: MutationState<Data, Variables>): VNode<any>;\n}\n\n/** Object that {@link MutationProps.children} is called with.\n *\n * @remarks\n * This is an extented {@link UseMutationstate} with an added\n * {@link MutationState.executeMutation} method, which is usually\n * part of a tuple returned by {@link useMutation}.\n */\nexport interface MutationState<\n  Data = any,\n  Variables extends AnyVariables = AnyVariables,\n> extends UseMutationState<Data, Variables> {\n  /** Alias to {@link useMutation}’s `executeMutation` function. */\n  executeMutation: UseMutationExecute<Data, Variables>;\n}\n\n/** Component Wrapper around {@link useMutation} to run a GraphQL query.\n *\n * @remarks\n * `Mutation` is a component wrapper around the {@link useMutation} hook\n * that calls the {@link MutationProps.children} prop, as a function,\n * with the {@link MutationState} object.\n */\nexport function Mutation<\n  Data = any,\n  Variables extends AnyVariables = AnyVariables,\n>(props: MutationProps<Data, Variables>): VNode<any> {\n  const mutation = useMutation<Data, Variables>(props.query);\n  return props.children({ ...mutation[0], executeMutation: mutation[1] });\n}\n"
  },
  {
    "path": "packages/preact-urql/src/components/Query.test.tsx",
    "content": "// @vitest-environment jsdom\n\nimport { h } from 'preact';\nimport { cleanup, render } from '@testing-library/preact';\nimport { map, interval, pipe } from 'wonka';\nimport { vi, expect, it, beforeEach, describe, afterEach } from 'vitest';\n\nimport { Query } from './Query';\nimport { Provider } from '../context';\n\nconst query = '{ example }';\nconst variables = {\n  myVar: 1234,\n};\n\nconst client = {\n  executeQuery: vi.fn(() =>\n    pipe(\n      interval(200),\n      map((i: number) => ({ data: i, error: i + 1 }))\n    )\n  ),\n};\n\ndescribe('Query', () => {\n  beforeEach(() => {\n    vi.spyOn(globalThis.console, 'error').mockImplementation(() => {\n      // do nothing\n    });\n  });\n\n  afterEach(() => {\n    cleanup();\n  });\n\n  it('Should execute the query', async () => {\n    let props = {};\n    const Test = () => h('p', {}, 'hi');\n    const App = () => {\n      // @ts-ignore\n      return h(Provider, {\n        value: client,\n        children: [\n          // @ts-ignore\n          h(Query, { query, variables }, ({ data, fetching, error }) => {\n            props = { data, fetching, error };\n            // @ts-ignore\n            return h(Test, {});\n          }),\n        ],\n      });\n    };\n    render(h(App, {}));\n    expect(props).toStrictEqual({\n      data: undefined,\n      fetching: true,\n      error: undefined,\n    });\n\n    await new Promise(res => {\n      setTimeout(() => {\n        expect(props).toStrictEqual({ data: 0, fetching: false, error: 1 });\n        res(null);\n      }, 250);\n    });\n  });\n});\n"
  },
  {
    "path": "packages/preact-urql/src/components/Query.ts",
    "content": "import type { VNode } from 'preact';\nimport type { AnyVariables } from '@urql/core';\n\nimport type { UseQueryArgs, UseQueryState, UseQueryExecute } from '../hooks';\nimport { useQuery } from '../hooks';\n\n/** Props accepted by {@link Query}.\n *\n * @remarks\n * `QueryProps` are the props accepted by the {@link Query} component,\n * which is identical to {@link UseQueryArgs}.\n *\n * The result, the {@link QueryState} object, will be passed to\n * a {@link QueryProps.children} function, passed as children\n * to the `Query` component.\n */\nexport type QueryProps<\n  Data = any,\n  Variables extends AnyVariables = AnyVariables,\n> = UseQueryArgs<Variables, Data> & {\n  children(arg: QueryState<Data, Variables>): VNode<any>;\n};\n\n/** Object that {@link QueryProps.children} is called with.\n *\n * @remarks\n * This is an extented {@link UseQueryState} with an added\n * {@link QueryState.executeQuery} method, which is usually\n * part of a tuple returned by {@link useQuery}.\n */\nexport interface QueryState<\n  Data = any,\n  Variables extends AnyVariables = AnyVariables,\n> extends UseQueryState<Data, Variables> {\n  /** Alias to {@link useQuery}’s `executeQuery` function. */\n  executeQuery: UseQueryExecute;\n}\n\n/** Component Wrapper around {@link useQuery} to run a GraphQL query.\n *\n * @remarks\n * `Query` is a component wrapper around the {@link useQuery} hook\n * that calls the {@link QueryProps.children} prop, as a function,\n * with the {@link QueryState} object.\n */\nexport function Query<\n  Data = any,\n  Variables extends AnyVariables = AnyVariables,\n>(props: QueryProps<Data, Variables>): VNode<any> {\n  const query = useQuery<Data, Variables>(props);\n  return props.children({ ...query[0], executeQuery: query[1] });\n}\n"
  },
  {
    "path": "packages/preact-urql/src/components/Subscription.test.tsx",
    "content": "// @vitest-environment jsdom\n\nimport { h } from 'preact';\nimport { cleanup, render, act } from '@testing-library/preact';\nimport { map, interval, pipe } from 'wonka';\nimport { vi, expect, it, beforeEach, describe, afterEach } from 'vitest';\n\nimport { Provider } from '../context';\nimport { Subscription } from './Subscription';\n\nconst query = 'subscription Example { example }';\nconst client = {\n  executeSubscription: vi.fn(() => {\n    return pipe(\n      interval(200),\n      map((i: number) => ({ data: i, error: i + 1 }))\n    );\n  }),\n};\n\ndescribe('Subscription', () => {\n  beforeEach(() => {\n    vi.useFakeTimers();\n    vi.spyOn(globalThis.console, 'error').mockImplementation(() => {\n      // do nothing\n    });\n  });\n\n  afterEach(() => {\n    cleanup();\n  });\n\n  it('Should execute the subscription', () => {\n    let props = {};\n    const Test = () => h('p', {}, 'hi');\n    const App = () => {\n      // @ts-ignore\n      return h(Provider, {\n        value: client,\n        children: [\n          // @ts-ignore\n          h(Subscription, { query }, ({ data, fetching, error }) => {\n            props = { data, fetching, error };\n            // @ts-ignore\n            return h(Test, {});\n          }),\n        ],\n      });\n    };\n\n    render(h(App, {}));\n\n    expect(props).toStrictEqual({\n      data: undefined,\n      fetching: true,\n      error: undefined,\n    });\n\n    act(() => {\n      vi.advanceTimersByTime(200);\n    });\n\n    expect(props).toStrictEqual({ data: 0, fetching: true, error: 1 });\n  });\n});\n"
  },
  {
    "path": "packages/preact-urql/src/components/Subscription.ts",
    "content": "import type { VNode } from 'preact';\nimport type { AnyVariables } from '@urql/core';\n\nimport type {\n  UseSubscriptionArgs,\n  UseSubscriptionState,\n  UseSubscriptionExecute,\n  SubscriptionHandler,\n} from '../hooks';\nimport { useSubscription } from '../hooks';\n\n/** Props accepted by {@link Subscription}.\n *\n * @remarks\n * `SubscriptionProps` are the props accepted by the {@link Subscription} component,\n * which is identical to {@link UseSubscriptionArgs} with an added\n * {@link SubscriptionProps.handler} prop, which {@link useSubscription} usually\n * accepts as an additional argument.\n *\n * The result, the {@link SubscriptionState} object, will be passed to\n * a {@link SubscriptionProps.children} function, passed as children\n * to the `Subscription` component.\n */\nexport type SubscriptionProps<\n  Data = any,\n  Result = Data,\n  Variables extends AnyVariables = AnyVariables,\n> = UseSubscriptionArgs<Variables, Data> & {\n  /** Accepts the {@link SubscriptionHandler} as a prop. */\n  handler?: SubscriptionHandler<Data, Result>;\n  children(arg: SubscriptionState<Result, Variables>): VNode<any>;\n};\n\n/** Object that {@link SubscriptionProps.children} is called with.\n *\n * @remarks\n * This is an extented {@link UseSubscriptionState} with an added\n * {@link SubscriptionState.executeSubscription} method, which is usually\n * part of a tuple returned by {@link useSubscription}.\n */\nexport interface SubscriptionState<\n  Data = any,\n  Variables extends AnyVariables = AnyVariables,\n> extends UseSubscriptionState<Data, Variables> {\n  /** Alias to {@link useSubscription}’s `executeMutation` function. */\n  executeSubscription: UseSubscriptionExecute;\n}\n\n/** Component Wrapper around {@link useSubscription} to run a GraphQL subscription.\n *\n * @remarks\n * `Subscription` is a component wrapper around the {@link useSubscription} hook\n * that calls the {@link SubscriptionProps.children} prop, as a function,\n * with the {@link SubscriptionState} object.\n */\nexport function Subscription<\n  Data = any,\n  Result = Data,\n  Variables extends AnyVariables = AnyVariables,\n>(props: SubscriptionProps<Data, Result, Variables>): VNode<any> {\n  const subscription = useSubscription<Data, Result, Variables>(\n    props,\n    props.handler\n  );\n\n  return props.children({\n    ...subscription[0],\n    executeSubscription: subscription[1],\n  });\n}\n"
  },
  {
    "path": "packages/preact-urql/src/components/index.ts",
    "content": "export * from './Mutation';\nexport * from './Query';\nexport * from './Subscription';\n"
  },
  {
    "path": "packages/preact-urql/src/context.ts",
    "content": "import { createContext } from 'preact';\nimport { useContext } from 'preact/hooks';\nimport type { Client } from '@urql/core';\n\nconst OBJ = {};\n\n/** `@urql/preact`'s Preact Context.\n *\n * @remarks\n * The Preact Context that `urql`’s {@link Client} will be provided with.\n * You may use the reexported {@link Provider} to provide a `Client` as well.\n */\nexport const Context: import('preact').Context<Client | object> =\n  createContext(OBJ);\n\n/** Provider for `urql`’s {@link Client} to GraphQL hooks.\n *\n * @remarks\n * `Provider` accepts a {@link Client} and provides it to all GraphQL hooks,\n * and {@link useClient}.\n *\n * You should make sure to create a {@link Client} and provide it with the\n * `Provider` to parts of your component tree that use GraphQL hooks.\n *\n * @example\n * ```tsx\n * import { Provider } from '@urql/preact';\n * // All of `@urql/core` is also re-exported by `@urql/preact`:\n * import { Client, cacheExchange, fetchExchange } from '@urql/core';\n *\n * const client = new Client({\n *   url: 'https://API',\n *   exchanges: [cacheExchange, fetchExchange],\n * });\n *\n * const App = () => (\n *   <Provider value={client}>\n *     <Component />\n *   </Provider>\n * );\n * ```\n */\n\nexport const Provider: import('preact').Provider<Client | object> =\n  Context.Provider;\n\n/** Preact Consumer component, providing the {@link Client} provided on a parent component.\n * @remarks\n * This is an alias for {@link Context.Consumer}.\n */\nexport const Consumer: import('preact').Consumer<Client | object> =\n  Context.Consumer;\n\nContext.displayName = 'UrqlContext';\n\n/** Hook returning a {@link Client} from {@link Context}.\n *\n * @remarks\n * `useClient` is a convenience hook, which accesses `@urql/preact`'s {@link Context}\n * and returns the {@link Client} defined on it.\n *\n * This will be the {@link Client} you passed to a {@link Provider}\n * you wrapped your elements containing this hook with.\n *\n * @throws\n * In development, if the component you call `useClient()` in is\n * not wrapped in a {@link Provider}, an error is thrown.\n */\nexport const useClient = (): Client => {\n  const client = useContext(Context);\n\n  if (client === OBJ && process.env.NODE_ENV !== 'production') {\n    const error =\n      \"No client has been specified using urql's Provider. please create a client and add a Provider.\";\n\n    console.error(error);\n    throw new Error(error);\n  }\n\n  return client as Client;\n};\n"
  },
  {
    "path": "packages/preact-urql/src/hooks/constants.ts",
    "content": "export const initialState = {\n  fetching: false,\n  stale: false,\n  hasNext: false,\n  error: undefined,\n  data: undefined,\n  extensions: undefined,\n  operation: undefined,\n};\n"
  },
  {
    "path": "packages/preact-urql/src/hooks/index.ts",
    "content": "export * from './useQuery';\nexport * from './useMutation';\nexport * from './useSubscription';\n"
  },
  {
    "path": "packages/preact-urql/src/hooks/useMutation.test.tsx",
    "content": "// @vitest-environment jsdom\n\nimport { FunctionalComponent as FC, h } from 'preact';\nimport { render, cleanup, act } from '@testing-library/preact';\nimport { print } from 'graphql';\nimport { gql } from '@urql/core';\nimport { fromValue, delay, pipe } from 'wonka';\nimport {\n  vi,\n  expect,\n  it,\n  beforeEach,\n  describe,\n  beforeAll,\n  afterEach,\n  Mock,\n} from 'vitest';\n\nimport { useMutation } from './useMutation';\nimport { Provider } from '../context';\n\nconst mock = {\n  executeMutation: vi.fn(() =>\n    pipe(fromValue({ data: 1, error: 2, extensions: { i: 1 } }), delay(200))\n  ),\n};\n\nconst client = mock as { executeMutation: Mock };\nconst props = {\n  query: 'mutation Example { example }',\n};\n\nlet state: any;\nlet execute: any;\n\nconst MutationUser: FC<typeof props> = ({ query }) => {\n  [state, execute] = useMutation(query);\n  return h('p', {}, state.data);\n};\n\nbeforeAll(() => {\n  vi.spyOn(globalThis.console, 'error').mockImplementation(() => {\n    // do nothing\n  });\n});\n\ndescribe('useMutation', () => {\n  beforeEach(() => {\n    client.executeMutation.mockClear();\n    state = undefined;\n    execute = undefined;\n  });\n\n  afterEach(() => cleanup());\n\n  it('does not execute subscription', () => {\n    render(\n      h(Provider, {\n        value: client as any,\n        children: [h(MutationUser, { ...props })],\n      })\n    );\n    expect(client.executeMutation).toBeCalledTimes(0);\n  });\n\n  it('executes mutation', () => {\n    render(\n      h(Provider, {\n        value: client as any,\n        children: [h(MutationUser, { ...props })],\n      })\n    );\n    const vars = { test: 1234 };\n    act(() => {\n      execute(vars);\n    });\n    const call = client.executeMutation.mock.calls[0][0];\n    expect(state).toHaveProperty('fetching', true);\n    expect(client.executeMutation).toBeCalledTimes(1);\n    expect(print(call.query)).toBe(print(gql(props.query)));\n    expect(call).toHaveProperty('variables', vars);\n  });\n\n  it('respects context changes', () => {\n    render(\n      h(Provider, {\n        value: client as any,\n        children: [h(MutationUser, { ...props })],\n      })\n    );\n    const vars = { test: 1234 };\n    act(() => {\n      execute(vars, { url: 'test' });\n    });\n    const call = client.executeMutation.mock.calls[0][1];\n    expect(call.url).toBe('test');\n  });\n\n  describe('on sub update', () => {\n    const vars = { test: 1234 };\n\n    it('receives data', async () => {\n      const { rerender } = render(\n        h(Provider, {\n          value: client as any,\n          children: [h(MutationUser, { ...props })],\n        })\n      );\n      await execute(vars);\n      rerender(\n        h(Provider, {\n          value: client as any,\n          children: [h(MutationUser, { ...props })],\n        })\n      );\n\n      expect(state).toHaveProperty('data', 1);\n      expect(state).toHaveProperty('error', 2);\n      expect(state).toHaveProperty('extensions', { i: 1 });\n      expect(state).toHaveProperty('fetching', false);\n    });\n  });\n});\n"
  },
  {
    "path": "packages/preact-urql/src/hooks/useMutation.ts",
    "content": "import { useState, useCallback, useRef, useEffect } from 'preact/hooks';\nimport { pipe, onPush, filter, toPromise, take } from 'wonka';\n\nimport type {\n  AnyVariables,\n  DocumentInput,\n  OperationResult,\n  OperationContext,\n  CombinedError,\n  Operation,\n} from '@urql/core';\nimport { createRequest } from '@urql/core';\n\nimport { useClient } from '../context';\nimport { initialState } from './constants';\n\n/** State of the last mutation executed by your {@link useMutation} hook.\n *\n * @remarks\n * `UseMutationState` is returned (in a tuple) by {@link useMutation} and\n * gives you the {@link OperationResult} of the last mutation executed\n * with {@link UseMutationExecute}.\n *\n * Even if the mutation document passed to {@link useMutation} changes,\n * the state isn’t reset, so you can keep displaying the previous result.\n */\nexport interface UseMutationState<\n  Data = any,\n  Variables extends AnyVariables = AnyVariables,\n> {\n  /** Indicates whether `useMutation` is currently executing a mutation. */\n  fetching: boolean;\n  /** Indicates that the mutation result is not fresh.\n   *\n   * @remarks\n   * The `stale` flag is set to `true` when a new result for the mutation\n   * is expected.\n   * This is mostly unused for mutations and will rarely affect you, and\n   * is more relevant for queries.\n   *\n   * @see {@link OperationResult.stale} for the source of this value.\n   */\n  stale: boolean;\n  /** The {@link OperationResult.data} for the executed mutation. */\n  data?: Data;\n  /** The {@link OperationResult.error} for the executed mutation. */\n  error?: CombinedError;\n  /** The {@link OperationResult.hasNext} for the executed query. */\n  hasNext: boolean;\n  /** The {@link OperationResult.extensions} for the executed mutation. */\n  extensions?: Record<string, any>;\n  /** The {@link Operation} that the current state is for.\n   *\n   * @remarks\n   * This is the mutation {@link Operation} that has last been executed.\n   * When {@link UseQueryState.fetching} is `true`, this is the\n   * last `Operation` that the current state was for.\n   */\n  operation?: Operation<Data, Variables>;\n}\n\n/** Triggers {@link useMutation} to execute its GraphQL mutation operation.\n *\n * @param variables - variables using which the mutation will be executed.\n * @param context - optionally, context options that will be merged with the hook's\n * {@link UseQueryArgs.context} options and the `Client`’s options.\n * @returns the {@link OperationResult} of the mutation.\n *\n * @remarks\n * When called, {@link useMutation} will start the GraphQL mutation\n * it currently holds and use the `variables` passed to it.\n *\n * Once the mutation response comes back from the API, its\n * returned promise will resolve to the mutation’s {@link OperationResult}\n * and the {@link UseMutationState} will be updated with the result.\n *\n * @example\n * ```ts\n * const [result, executeMutation] = useMutation(UpdateTodo);\n * const start = async ({ id, title }) => {\n *   const result = await executeMutation({ id, title });\n * };\n */\nexport type UseMutationExecute<\n  Data = any,\n  Variables extends AnyVariables = AnyVariables,\n> = (\n  variables: Variables,\n  context?: Partial<OperationContext>\n) => Promise<OperationResult<Data, Variables>>;\n\n/** Result tuple returned by the {@link useMutation} hook.\n *\n * @remarks\n * Similarly to a `useState` hook’s return value,\n * the first element is the {@link useMutation}’s state, updated\n * as mutations are executed with the second value, which is\n * used to start mutations and is a {@link UseMutationExecute}\n * function.\n */\nexport type UseMutationResponse<\n  Data = any,\n  Variables extends AnyVariables = AnyVariables,\n> = [UseMutationState<Data, Variables>, UseMutationExecute<Data, Variables>];\n\n/** Hook to create a GraphQL mutation, run by passing variables to the returned execute function.\n *\n * @param query - a GraphQL mutation document which `useMutation` will execute.\n * @returns a {@link UseMutationResponse} tuple of a {@link UseMutationState} result,\n * and an execute function to start the mutation.\n *\n * @remarks\n * `useMutation` allows GraphQL mutations to be defined and keeps its state\n * after the mutation is started with the returned execute function.\n *\n * Given a GraphQL mutation document it returns state to keep track of the\n * mutation state and a {@link UseMutationExecute} function, which accepts\n * variables for the mutation to be executed.\n * Once called, the mutation executes and the state will be updated with\n * the mutation’s result.\n *\n * @see {@link https://urql.dev/goto/docs/basics/react-preact/#mutations} for `useMutation` docs.\n *\n * @example\n * ```ts\n * import { gql, useMutation } from '@urql/preact';\n *\n * const UpdateTodo = gql`\n *   mutation ($id: ID!, $title: String!) {\n *     updateTodo(id: $id, title: $title) {\n *       id, title\n *     }\n *   }\n * `;\n *\n * const UpdateTodo = () => {\n *   const [result, executeMutation] = useMutation(UpdateTodo);\n *   const start = async ({ id, title }) => {\n *     const result = await executeMutation({ id, title });\n *   };\n *   // ...\n * };\n * ```\n */\nexport function useMutation<\n  Data = any,\n  Variables extends AnyVariables = AnyVariables,\n>(query: DocumentInput<Data, Variables>): UseMutationResponse<Data, Variables> {\n  const isMounted = useRef(true);\n  const client = useClient();\n\n  const [state, setState] =\n    useState<UseMutationState<Data, Variables>>(initialState);\n\n  const executeMutation = useCallback(\n    (variables: Variables, context?: Partial<OperationContext>) => {\n      setState({ ...initialState, fetching: true });\n      return pipe(\n        client.executeMutation<Data, Variables>(\n          createRequest<Data, Variables>(query, variables),\n          context || {}\n        ),\n        onPush(result => {\n          if (isMounted.current) {\n            setState({\n              fetching: false,\n              stale: result.stale,\n              data: result.data,\n              hasNext: result.hasNext,\n              error: result.error,\n              extensions: result.extensions,\n              operation: result.operation,\n            });\n          }\n        }),\n        filter(result => !result.hasNext),\n        take(1),\n        toPromise\n      );\n    },\n    // eslint-disable-next-line react-hooks/exhaustive-deps\n    [client, query, setState]\n  );\n\n  useEffect(() => {\n    return () => {\n      isMounted.current = false;\n    };\n  }, []);\n\n  return [state, executeMutation];\n}\n"
  },
  {
    "path": "packages/preact-urql/src/hooks/useQuery.test.tsx",
    "content": "// @vitest-environment jsdom\n\nimport { FunctionalComponent as FC, h } from 'preact';\nimport { render, cleanup, act } from '@testing-library/preact';\nimport { OperationContext } from '@urql/core';\nimport { map, interval, pipe, never, onStart, onEnd, empty } from 'wonka';\n\nimport { vi, expect, it, beforeEach, describe, afterEach, Mock } from 'vitest';\n\nimport { useQuery, UseQueryArgs, UseQueryState } from './useQuery';\nimport { Provider } from '../context';\n\nconst mock = {\n  executeQuery: vi.fn(() =>\n    pipe(\n      interval(400),\n      map((i: number) => ({ data: i, error: i + 1, extensions: { i: 1 } }))\n    )\n  ),\n};\n\nconst client = mock as { executeQuery: Mock };\nconst props: UseQueryArgs<{ myVar: number }> = {\n  query: '{ example }',\n  variables: {\n    myVar: 1234,\n  },\n  pause: false,\n};\n\nlet state: UseQueryState<any> | undefined;\nlet execute: ((_opts?: Partial<OperationContext>) => void) | undefined;\n\nconst QueryUser: FC<UseQueryArgs<{ myVar: number }>> = ({\n  query,\n  variables,\n  pause,\n}) => {\n  [state, execute] = useQuery({ query, variables, pause });\n  return h('p', {}, state.data);\n};\n\nbeforeEach(() => {\n  vi.useFakeTimers();\n  vi.spyOn(globalThis.console, 'error');\n});\n\ndescribe('useQuery', () => {\n  beforeEach(() => {\n    client.executeQuery.mockClear();\n    state = undefined;\n    execute = undefined;\n  });\n\n  afterEach(() => cleanup());\n\n  it('executes subscription', () => {\n    render(\n      h(Provider, {\n        value: client as any,\n        children: [h(QueryUser, { ...props })],\n      })\n    );\n    expect(client.executeQuery).toBeCalledTimes(1);\n  });\n\n  it('passes query and vars to executeQuery', () => {\n    render(\n      h(Provider, {\n        value: client as any,\n        children: [h(QueryUser, { ...props })],\n      })\n    );\n\n    expect(client.executeQuery).toBeCalledWith(\n      {\n        key: expect.any(Number),\n        query: expect.any(Object),\n        variables: props.variables,\n      },\n      expect.objectContaining({\n        requestPolicy: undefined,\n      })\n    );\n  });\n\n  it('sets fetching to true', () => {\n    const { rerender } = render(\n      h(Provider, {\n        value: client as any,\n        children: [h(QueryUser, { ...props })],\n      })\n    );\n\n    rerender(\n      h(Provider, {\n        value: client as any,\n        children: [h(QueryUser, { ...props })],\n      })\n    );\n    expect(state).toHaveProperty('fetching', true);\n  });\n\n  it('forwards data response', () => {\n    const { rerender } = render(\n      h(Provider, {\n        value: client as any,\n        children: [h(QueryUser, { ...props })],\n      })\n    );\n\n    rerender(\n      h(Provider, {\n        value: client as any,\n        children: [h(QueryUser, { ...props })],\n      })\n    );\n\n    act(() => {\n      vi.advanceTimersByTime(400);\n      rerender(\n        h(Provider, {\n          value: client as any,\n          children: [h(QueryUser, { ...props })],\n        })\n      );\n    });\n\n    expect(state).toHaveProperty('data', 0);\n  });\n\n  it('forwards error response', () => {\n    const { rerender } = render(\n      h(Provider, {\n        value: client as any,\n        children: [h(QueryUser, { ...props })],\n      })\n    );\n\n    rerender(\n      h(Provider, {\n        value: client as any,\n        children: [h(QueryUser, { ...props })],\n      })\n    );\n\n    act(() => {\n      vi.advanceTimersByTime(400);\n      rerender(\n        h(Provider, {\n          value: client as any,\n          children: [h(QueryUser, { ...props })],\n        })\n      );\n    });\n\n    expect(state).toHaveProperty('error', 1);\n  });\n\n  it('forwards extensions response', () => {\n    const { rerender } = render(\n      h(Provider, {\n        value: client as any,\n        children: [h(QueryUser, { ...props })],\n      })\n    );\n\n    rerender(\n      h(Provider, {\n        value: client as any,\n        children: [h(QueryUser, { ...props })],\n      })\n    );\n\n    act(() => {\n      vi.advanceTimersByTime(400);\n      rerender(\n        h(Provider, {\n          value: client as any,\n          children: [h(QueryUser, { ...props })],\n        })\n      );\n    });\n\n    expect(state).toHaveProperty('extensions', { i: 1 });\n  });\n\n  it('sets fetching to false', () => {\n    const { rerender } = render(\n      h(Provider, {\n        value: client as any,\n        children: [h(QueryUser, { ...props })],\n      })\n    );\n\n    rerender(\n      h(Provider, {\n        value: client as any,\n        children: [h(QueryUser, { ...props })],\n      })\n    );\n\n    act(() => {\n      vi.advanceTimersByTime(400);\n      rerender(\n        h(Provider, {\n          value: client as any,\n          children: [h(QueryUser, { ...props })],\n        })\n      );\n    });\n\n    expect(state).toHaveProperty('fetching', false);\n  });\n\n  describe('on change', () => {\n    const q = 'query NewQuery { example }';\n\n    it('new query executes subscription', () => {\n      const { rerender } = render(\n        h(Provider, {\n          value: client as any,\n          children: [h(QueryUser, { ...props })],\n        })\n      );\n\n      rerender(\n        h(Provider, {\n          value: client as any,\n          children: [h(QueryUser, { ...props, query: q })],\n        })\n      );\n\n      act(() => {\n        rerender(\n          h(Provider, {\n            value: client as any,\n            children: [h(QueryUser, { ...props, query: q })],\n          })\n        );\n      });\n\n      expect(client.executeQuery).toBeCalledTimes(2);\n    });\n  });\n\n  describe('on unmount', () => {\n    const start = vi.fn();\n    const unsubscribe = vi.fn();\n\n    beforeEach(() => {\n      client.executeQuery.mockReturnValue(\n        pipe(never, onStart(start), onEnd(unsubscribe))\n      );\n    });\n\n    it('unsubscribe is called', () => {\n      const { unmount } = render(\n        h(Provider, {\n          value: client as any,\n          children: [h(QueryUser, { ...props })],\n        })\n      );\n\n      act(() => {\n        unmount();\n      });\n\n      expect(start).toBeCalledTimes(2);\n      expect(unsubscribe).toBeCalledTimes(2);\n    });\n  });\n\n  describe('active teardown', () => {\n    it('sets fetching to false when the source ends', () => {\n      client.executeQuery.mockReturnValueOnce(empty);\n      act(() => {\n        render(\n          h(Provider, {\n            value: client as any,\n            children: [h(QueryUser, { ...props })],\n          })\n        );\n      });\n      expect(client.executeQuery).toHaveBeenCalled();\n      expect(state).toMatchObject({ fetching: false });\n    });\n  });\n\n  describe('execute query', () => {\n    it('triggers query execution', () => {\n      render(\n        h(Provider, {\n          value: client as any,\n          children: [h(QueryUser, { ...props })],\n        })\n      );\n      act(() => execute && execute());\n      expect(client.executeQuery).toBeCalledTimes(2);\n    });\n  });\n\n  describe('pause', () => {\n    it('skips executing the query if pause is true', () => {\n      render(\n        h(Provider, {\n          value: client as any,\n          children: [h(QueryUser, { ...props, pause: true })],\n        })\n      );\n      expect(client.executeQuery).not.toBeCalled();\n    });\n\n    it('skips executing queries if pause updates to true', () => {\n      const { rerender } = render(\n        h(Provider, {\n          value: client as any,\n          children: [h(QueryUser, { ...props })],\n        })\n      );\n\n      rerender(\n        h(Provider, {\n          value: client as any,\n          children: [h(QueryUser, { ...props, pause: true })],\n        })\n      );\n\n      expect(client.executeQuery).toBeCalledTimes(1);\n    });\n  });\n});\n"
  },
  {
    "path": "packages/preact-urql/src/hooks/useQuery.ts",
    "content": "import { useEffect, useCallback, useMemo } from 'preact/hooks';\n\nimport type { Source } from 'wonka';\nimport {\n  pipe,\n  share,\n  takeWhile,\n  concat,\n  fromValue,\n  switchMap,\n  map,\n  scan,\n} from 'wonka';\n\nimport type {\n  Client,\n  GraphQLRequestParams,\n  AnyVariables,\n  CombinedError,\n  OperationContext,\n  RequestPolicy,\n  OperationResult,\n  Operation,\n} from '@urql/core';\n\nimport { useClient } from '../context';\nimport { useSource } from './useSource';\nimport { useRequest } from './useRequest';\nimport { initialState } from './constants';\n\n/** Input arguments for the {@link useQuery} hook.\n *\n * @param query - The GraphQL query that `useQuery` executes.\n * @param variables - The variables for the GraphQL query that `useQuery` executes.\n */\nexport type UseQueryArgs<\n  Variables extends AnyVariables = AnyVariables,\n  Data = any,\n> = {\n  /** Updates the {@link RequestPolicy} for the executed GraphQL query operation.\n   *\n   * @remarks\n   * `requestPolicy` modifies the {@link RequestPolicy} of the GraphQL query operation\n   * that `useQuery` executes, and indicates a caching strategy for cache exchanges.\n   *\n   * For example, when set to `'cache-and-network'`, {@link useQuery} will\n   * receive a cached result with `stale: true` and an API request will be\n   * sent in the background.\n   *\n   * @see {@link OperationContext.requestPolicy} for where this value is set.\n   */\n  requestPolicy?: RequestPolicy;\n  /** Updates the {@link OperationContext} for the executed GraphQL query operation.\n   *\n   * @remarks\n   * `context` may be passed to {@link useQuery}, to update the {@link OperationContext}\n   * of a query operation. This may be used to update the `context` that exchanges\n   * will receive for a single hook.\n   *\n   * Hint: This should be wrapped in a `useMemo` hook, to make sure that your\n   * component doesn’t infinitely update.\n   *\n   * @example\n   * ```ts\n   * const [result, reexecute] = useQuery({\n   *   query,\n   *   context: useMemo(() => ({\n   *     additionalTypenames: ['Item'],\n   *   }), [])\n   * });\n   * ```\n   */\n  context?: Partial<OperationContext>;\n  /** Prevents {@link useQuery} from automatically executing GraphQL query operations.\n   *\n   * @remarks\n   * `pause` may be set to `true` to stop {@link useQuery} from executing\n   * automatically. The hook will stop receiving updates from the {@link Client}\n   * and won’t execute the query operation, until either it’s set to `false`\n   * or the {@link UseQueryExecute} function is called.\n   *\n   * @see {@link https://urql.dev/goto/docs/basics/react-preact/#pausing-usequery} for\n   * documentation on the `pause` option.\n   */\n  pause?: boolean;\n} & GraphQLRequestParams<Data, Variables>;\n\n/** State of the current query, your {@link useQuery} hook is executing.\n *\n * @remarks\n * `UseQueryState` is returned (in a tuple) by {@link useQuery} and\n * gives you the updating {@link OperationResult} of GraphQL queries.\n *\n * Even when the query and variables passed to {@link useQuery} change,\n * this state preserves the prior state and sets the `fetching` flag to\n * `true`.\n * This allows you to display the previous state, while implementing\n * a separate loading indicator separately.\n */\nexport interface UseQueryState<\n  Data = any,\n  Variables extends AnyVariables = AnyVariables,\n> {\n  /** Indicates whether `useQuery` is waiting for a new result.\n   *\n   * @remarks\n   * When `useQuery` is passed a new query and/or variables, it will\n   * start executing the new query operation and `fetching` is set to\n   * `true` until a result arrives.\n   *\n   * Hint: This is subtly different than whether the query is actually\n   * fetching, and doesn’t indicate whether a query is being re-executed\n   * in the background. For this, see {@link UseQueryState.stale}.\n   */\n  fetching: boolean;\n  /** Indicates that the state is not fresh and a new result will follow.\n   *\n   * @remarks\n   * The `stale` flag is set to `true` when a new result for the query\n   * is expected and `useQuery` is waiting for it. This may indicate that\n   * a new request is being requested in the background.\n   *\n   * @see {@link OperationResult.stale} for the source of this value.\n   */\n  stale: boolean;\n  /** The {@link OperationResult.data} for the executed query. */\n  data?: Data;\n  /** The {@link OperationResult.error} for the executed query. */\n  error?: CombinedError;\n  /** The {@link OperationResult.extensions} for the executed query. */\n  extensions?: Record<string, any>;\n  /** The {@link Operation} that the current state is for.\n   *\n   * @remarks\n   * This is the {@link Operation} that is currently being executed.\n   * When {@link UseQueryState.fetching} is `true`, this is the\n   * last `Operation` that the current state was for.\n   */\n  operation?: Operation<Data, Variables>;\n  /** The {@link OperationResult.hasNext} for the executed query. */\n  hasNext: boolean;\n}\n\n/** Triggers {@link useQuery} to execute a new GraphQL query operation.\n *\n * @remarks\n * When called, {@link useQuery} will re-execute the GraphQL query operation\n * it currently holds, even if {@link UseQueryArgs.pause} is set to `true`.\n *\n * This is useful for executing a paused query or re-executing a query\n * and get a new network result, by passing a new request policy.\n *\n * ```ts\n * const [result, reexecuteQuery] = useQuery({ query });\n *\n * const refresh = () => {\n *   // Re-execute the query with a network-only policy, skipping the cache\n *   reexecuteQuery({ requestPolicy: 'network-only' });\n * };\n * ```\n */\nexport type UseQueryExecute = (opts?: Partial<OperationContext>) => void;\n\n/** Result tuple returned by the {@link useQuery} hook.\n *\n * @remarks\n * Similarly to a `useState` hook’s return value,\n * the first element is the {@link useQuery}’s result and state,\n * a {@link UseQueryState} object,\n * and the second is used to imperatively re-execute the query\n * via a {@link UseQueryExecute} function.\n */\nexport type UseQueryResponse<\n  Data = any,\n  Variables extends AnyVariables = AnyVariables,\n> = [UseQueryState<Data, Variables>, UseQueryExecute];\n\n/** Convert the Source to a React Suspense source on demand\n * @internal\n */\nfunction toSuspenseSource<T>(source: Source<T>): Source<T> {\n  const shared = share(source);\n  let cache: T | void;\n  let resolve: (value: T) => void;\n\n  return sink => {\n    let hasSuspended = false;\n\n    pipe(\n      shared,\n      takeWhile(result => {\n        // The first result that is received will resolve the suspense\n        // promise after waiting for a microtick\n        if (cache === undefined) Promise.resolve(result).then(resolve);\n        cache = result;\n        return !hasSuspended;\n      })\n    )(sink);\n\n    // If we haven't got a previous result then start suspending\n    // otherwise issue the last known result immediately\n    if (cache !== undefined) {\n      const signal = [cache] as [T] & { tag: 1 };\n      signal.tag = 1;\n      sink(signal);\n    } else {\n      hasSuspended = true;\n      sink(0 /* End */);\n      throw new Promise<T>(_resolve => {\n        resolve = _resolve;\n      });\n    }\n  };\n}\n\nconst isSuspense = (client: Client, context?: Partial<OperationContext>) =>\n  context && context.suspense !== undefined\n    ? !!context.suspense\n    : client.suspense;\n\nconst sources = new Map<number, Source<OperationResult>>();\n\n/** Hook to run a GraphQL query and get updated GraphQL results.\n *\n * @param args - a {@link UseQueryArgs} object, to pass a `query`, `variables`, and options.\n * @returns a {@link UseQueryResponse} tuple of a {@link UseQueryState} result, and re-execute function.\n *\n * @remarks\n * `useQuery` allows GraphQL queries to be defined and executed.\n * Given {@link UseQueryArgs.query}, it executes the GraphQL query with the\n * context’s {@link Client}.\n *\n * The returned result updates when the `Client` has new results\n * for the query, and changes when your input `args` change.\n *\n * Additionally, if the `suspense` option is enabled on the `Client`,\n * the `useQuery` hook will suspend instead of indicating that it’s\n * waiting for a result via {@link UseQueryState.fetching}.\n *\n * @see {@link https://urql.dev/goto/docs/basics/react-preact/#queries} for `useQuery` docs.\n *\n * @example\n * ```ts\n * import { gql, useQuery } from '@urql/preact';\n *\n * const TodosQuery = gql`\n *   query { todos { id, title } }\n * `;\n *\n * const Todos = () => {\n *   const [result, reexecuteQuery] = useQuery({\n *     query: TodosQuery,\n *     variables: {},\n *   });\n *   // ...\n * };\n * ```\n */\nexport function useQuery<\n  Data = any,\n  Variables extends AnyVariables = AnyVariables,\n>(args: UseQueryArgs<Variables, Data>): UseQueryResponse<Data, Variables> {\n  const client = useClient();\n  // This creates a request which will keep a stable reference\n  // if request.key doesn't change\n  const request = useRequest(args.query, args.variables as Variables);\n\n  // Create a new query-source from client.executeQuery\n  const makeQuery$ = useCallback(\n    (opts?: Partial<OperationContext>) => {\n      // Determine whether suspense is enabled for the given operation\n      const suspense = isSuspense(client, args.context);\n      let source: Source<OperationResult> | void = suspense\n        ? sources.get(request.key)\n        : undefined;\n\n      if (!source) {\n        source = client.executeQuery(request, {\n          requestPolicy: args.requestPolicy,\n          ...args.context,\n          ...opts,\n        });\n\n        // Create a suspense source and cache it for the given request\n        if (suspense) {\n          source = toSuspenseSource(source);\n          if (typeof window !== 'undefined') {\n            sources.set(request.key, source);\n          }\n        }\n      }\n\n      return source;\n    },\n    [client, request, args.requestPolicy, args.context]\n  );\n\n  const query$ = useMemo(() => {\n    return args.pause ? null : makeQuery$();\n  }, [args.pause, makeQuery$]);\n\n  const [state, update] = useSource(\n    query$,\n    useCallback((query$$, prevState?: UseQueryState<Data, Variables>) => {\n      return pipe(\n        query$$,\n        switchMap(query$ => {\n          if (!query$)\n            return fromValue({ fetching: false, stale: false, hasNext: false });\n\n          return concat([\n            // Initially set fetching to true\n            fromValue({ fetching: true, stale: false }),\n            pipe(\n              query$,\n              map(({ stale, data, error, extensions, operation, hasNext }) => ({\n                fetching: false,\n                stale: !!stale,\n                hasNext,\n                data,\n                error,\n                operation,\n                extensions,\n              }))\n            ),\n            // When the source proactively closes, fetching is set to false\n            fromValue({ fetching: false, stale: false, hasNext: false }),\n          ]);\n        }),\n        // The individual partial results are merged into each previous result\n        scan(\n          (result: UseQueryState<Data, Variables>, partial) => ({\n            ...result,\n            ...partial,\n          }),\n          prevState || initialState\n        )\n      );\n    }, [])\n  );\n\n  // This is the imperative execute function passed to the user\n  const executeQuery = useCallback(\n    (opts?: Partial<OperationContext>) => {\n      update(makeQuery$({ suspense: false, ...opts }));\n    },\n    [update, makeQuery$]\n  );\n\n  useEffect(() => {\n    sources.delete(request.key); // Delete any cached suspense source\n    if (!isSuspense(client, args.context)) update(query$);\n  }, [update, client, query$, request, args.context]);\n\n  if (isSuspense(client, args.context)) {\n    update(query$);\n  }\n\n  return [state, executeQuery];\n}\n"
  },
  {
    "path": "packages/preact-urql/src/hooks/useRequest.ts",
    "content": "import type { DocumentNode } from 'graphql';\nimport { useRef, useMemo } from 'preact/hooks';\nimport type {\n  AnyVariables,\n  TypedDocumentNode,\n  GraphQLRequest,\n} from '@urql/core';\nimport { createRequest } from '@urql/core';\n\n/** Creates a request from a query and variables but preserves reference equality if the key isn't changing\n * @internal\n */\nexport function useRequest<\n  Data = any,\n  Variables extends AnyVariables = AnyVariables,\n>(\n  query: string | DocumentNode | TypedDocumentNode<Data, Variables>,\n  variables: Variables\n): GraphQLRequest<Data, Variables> {\n  const prev = useRef<undefined | GraphQLRequest<Data, Variables>>(undefined);\n  return useMemo(() => {\n    const request = createRequest<Data, Variables>(query, variables);\n    // We manually ensure reference equality if the key hasn't changed\n    if (prev.current !== undefined && prev.current.key === request.key) {\n      return prev.current;\n    } else {\n      prev.current = request;\n      return request;\n    }\n  }, [query, variables]);\n}\n"
  },
  {
    "path": "packages/preact-urql/src/hooks/useSource.ts",
    "content": "/* eslint-disable react-hooks/exhaustive-deps */\n\nimport { useMemo, useEffect, useState } from 'preact/hooks';\n\nimport type { Source } from 'wonka';\nimport { fromValue, makeSubject, pipe, concat, subscribe } from 'wonka';\n\ntype Updater<T> = (input: T) => void;\n\nlet currentInit = false;\n\n// Two operations are considered equal if they have the same key\nconst areOperationsEqual = (\n  a: { key: number } | undefined,\n  b: { key: number } | undefined\n) => {\n  return a === b || !!(a && b && a.key === b.key);\n};\n\nconst isShallowDifferent = (a: any, b: any) => {\n  if (typeof a != 'object' || typeof b != 'object') return a !== b;\n  for (const x in a) if (!(x in b)) return true;\n  for (const key in b) {\n    if (\n      key === 'operation'\n        ? !areOperationsEqual(a[key], b[key])\n        : a[key] !== b[key]\n    ) {\n      return true;\n    }\n  }\n  return false;\n};\n\nexport function useSource<T, R>(\n  input: T,\n  transform: (input$: Source<T>, initial?: R) => Source<R>\n): [R, Updater<T>] {\n  const [input$, updateInput] = useMemo((): [Source<T>, (value: T) => void] => {\n    const subject = makeSubject<T>();\n    const source = concat([fromValue(input), subject.source]);\n\n    const updateInput = (nextInput: T) => {\n      if (nextInput !== input) subject.next((input = nextInput));\n    };\n\n    return [source, updateInput];\n  }, []);\n\n  const [state, setState] = useState<R>(() => {\n    currentInit = true;\n    let state: R;\n    try {\n      pipe(\n        transform(fromValue(input)),\n        subscribe(value => {\n          state = value;\n        })\n      ).unsubscribe();\n    } finally {\n      currentInit = false;\n    }\n\n    return state!;\n  });\n\n  useEffect(() => {\n    return pipe(\n      transform(input$, state),\n      subscribe(value => {\n        if (!currentInit) {\n          setState(prevValue => {\n            return isShallowDifferent(prevValue, value) ? value : prevValue;\n          });\n        }\n      })\n    ).unsubscribe;\n  }, [input$ /* `state` is only an initialiser */]);\n\n  return [state, updateInput];\n}\n"
  },
  {
    "path": "packages/preact-urql/src/hooks/useSubscription.test.tsx",
    "content": "// @vitest-environment jsdom\n\nimport { FunctionalComponent as FC, h } from 'preact';\nimport { render, cleanup, act } from '@testing-library/preact';\nimport { OperationContext } from '@urql/core';\nimport {\n  vi,\n  expect,\n  it,\n  beforeEach,\n  describe,\n  beforeAll,\n  Mock,\n  afterEach,\n} from 'vitest';\nimport { merge, fromValue, never, empty } from 'wonka';\n\nimport { useSubscription, UseSubscriptionState } from './useSubscription';\nimport { Provider } from '../context';\n\nconst data = { data: 1234, error: 5678 };\nconst mock = {\n  // @ts-ignore\n  executeSubscription: vi.fn(() => merge([fromValue(data), never])),\n};\n\nconst client = mock as { executeSubscription: Mock };\nconst query = 'subscription Example { example }';\n\nlet state: UseSubscriptionState<any> | undefined;\nlet execute: ((_opts?: Partial<OperationContext>) => void) | undefined;\n\nconst SubscriptionUser: FC<{\n  q: string;\n  handler?: (_prev: any, _data: any) => any;\n  context?: Partial<OperationContext>;\n  pause?: boolean;\n}> = ({ q, handler, context, pause = false }) => {\n  [state, execute] = useSubscription({ query: q, context, pause }, handler);\n  return h('p', {}, state.data);\n};\n\nbeforeAll(() => {\n  vi.spyOn(globalThis.console, 'error').mockImplementation(() => {\n    // do nothing\n  });\n});\n\ndescribe('useSubscription', () => {\n  beforeEach(() => {\n    client.executeSubscription.mockClear();\n    state = undefined;\n    execute = undefined;\n  });\n\n  const props = { q: query };\n\n  afterEach(() => cleanup());\n\n  it('executes subscription', () => {\n    render(\n      h(Provider, {\n        value: client as any,\n        children: [h(SubscriptionUser, { ...props })],\n      })\n    );\n    expect(client.executeSubscription).toBeCalledTimes(1);\n  });\n\n  it('should support setting context in useSubscription params', () => {\n    render(\n      h(Provider, {\n        value: client as any,\n        children: [h(SubscriptionUser, { ...props, context: { url: 'test' } })],\n      })\n    );\n    expect(client.executeSubscription).toBeCalledWith(\n      {\n        key: expect.any(Number),\n        query: expect.any(Object),\n        variables: {},\n      },\n      {\n        url: 'test',\n      }\n    );\n  });\n\n  describe('on subscription', () => {\n    it('forwards client response', () => {\n      const { rerender } = render(\n        h(Provider, {\n          value: client as any,\n          children: [h(SubscriptionUser, { ...props })],\n        })\n      );\n      /**\n       * Have to call update (without changes) in order to see the\n       * result of the state change.\n       */\n      rerender(\n        h(Provider, {\n          value: client as any,\n          children: [h(SubscriptionUser, { ...props })],\n        })\n      );\n      expect(state).toEqual({\n        ...data,\n        hasNext: false,\n        extensions: undefined,\n        fetching: true,\n        stale: false,\n      });\n    });\n  });\n\n  it('calls handler', () => {\n    const handler = vi.fn();\n    const { rerender } = render(\n      h(Provider, {\n        value: client as any,\n        children: [h(SubscriptionUser, { ...props, handler })],\n      })\n    );\n    rerender(\n      h(Provider, {\n        value: client as any,\n        children: [h(SubscriptionUser, { ...props })],\n      })\n    );\n    expect(handler).toBeCalledTimes(2);\n    expect(handler).toBeCalledWith(undefined, 1234);\n  });\n\n  describe('active teardown', () => {\n    it('sets fetching to false when the source ends', () => {\n      client.executeSubscription.mockReturnValueOnce(empty);\n      render(\n        h(Provider, {\n          value: client as any,\n          children: [h(SubscriptionUser, { ...props })],\n        })\n      );\n      expect(client.executeSubscription).toHaveBeenCalled();\n      expect(state).toMatchObject({ fetching: false });\n    });\n  });\n\n  describe('execute subscription', () => {\n    it('triggers subscription execution', () => {\n      render(\n        h(Provider, {\n          value: client as any,\n          children: [h(SubscriptionUser, { ...props })],\n        })\n      );\n      act(() => execute && execute());\n      expect(client.executeSubscription).toBeCalledTimes(2);\n    });\n  });\n\n  describe('pause', () => {\n    const props = { q: query };\n\n    it('skips executing the query if pause is true', () => {\n      render(\n        h(Provider, {\n          value: client as any,\n          children: [h(SubscriptionUser, { ...props, pause: true })],\n        })\n      );\n      expect(client.executeSubscription).not.toBeCalled();\n    });\n\n    it('skips executing queries if pause updates to true', () => {\n      const { rerender } = render(\n        h(Provider, {\n          value: client as any,\n          children: [h(SubscriptionUser, { ...props })],\n        })\n      );\n\n      rerender(\n        h(Provider, {\n          value: client as any,\n          children: [h(SubscriptionUser, { ...props, pause: true })],\n        })\n      );\n      rerender(\n        h(Provider, {\n          value: client as any,\n          children: [h(SubscriptionUser, { ...props, pause: true })],\n        })\n      );\n      expect(client.executeSubscription).toBeCalledTimes(1);\n      expect(state).toMatchObject({ fetching: false });\n    });\n  });\n});\n"
  },
  {
    "path": "packages/preact-urql/src/hooks/useSubscription.ts",
    "content": "import { useEffect, useCallback, useRef, useMemo } from 'preact/hooks';\nimport { pipe, concat, fromValue, switchMap, map, scan } from 'wonka';\n\nimport type {\n  AnyVariables,\n  GraphQLRequestParams,\n  CombinedError,\n  OperationContext,\n  Operation,\n} from '@urql/core';\n\nimport { useClient } from '../context';\nimport { useSource } from './useSource';\nimport { useRequest } from './useRequest';\nimport { initialState } from './constants';\n\n/** Input arguments for the {@link useSubscription} hook.\n *\n * @param query - The GraphQL subscription document that `useSubscription` executes.\n * @param variables - The variables for the GraphQL subscription that `useSubscription` executes.\n */\nexport type UseSubscriptionArgs<\n  Variables extends AnyVariables = AnyVariables,\n  Data = any,\n> = {\n  /** Prevents {@link useSubscription} from automatically starting GraphQL subscriptions.\n   *\n   * @remarks\n   * `pause` may be set to `true` to stop {@link useSubscription} from starting its subscription\n   * automatically. The hook will stop receiving updates from the {@link Client}\n   * and won’t start the subscription operation, until either it’s set to `false`\n   * or the {@link UseSubscriptionExecute} function is called.\n   */\n  pause?: boolean;\n  /** Updates the {@link OperationContext} for the executed GraphQL subscription operation.\n   *\n   * @remarks\n   * `context` may be passed to {@link useSubscription}, to update the {@link OperationContext}\n   * of a subscription operation. This may be used to update the `context` that exchanges\n   * will receive for a single hook.\n   *\n   * Hint: This should be wrapped in a `useMemo` hook, to make sure that your\n   * component doesn’t infinitely update.\n   *\n   * @example\n   * ```ts\n   * const [result, reexecute] = useSubscription({\n   *   query,\n   *   context: useMemo(() => ({\n   *     additionalTypenames: ['Item'],\n   *   }), [])\n   * });\n   * ```\n   */\n  context?: Partial<OperationContext>;\n} & GraphQLRequestParams<Data, Variables>;\n\n/** Combines previous data with an incoming subscription result’s data.\n *\n * @remarks\n * A `SubscriptionHandler` may be passed to {@link useSubscription} to\n * aggregate subscription results into a combined {@link UseSubscriptionState.data}\n * value.\n *\n * This is useful when a subscription event delivers a single item, while\n * you’d like to display a list of events.\n *\n * @example\n * ```ts\n * const NotificationsSubscription = gql`\n *   subscription { newNotification { id, text } }\n * `;\n *\n * const combineNotifications = (notifications = [], data) => {\n *   return [...notifications, data.newNotification];\n * };\n *\n * const [result, executeSubscription] = useSubscription(\n *   { query: NotificationsSubscription },\n *   combineNotifications,\n * );\n * ```\n */\nexport type SubscriptionHandler<T, R> = (prev: R | undefined, data: T) => R;\n\n/** State of the current subscription, your {@link useSubscription} hook is executing.\n *\n * @remarks\n * `UseSubscriptionState` is returned (in a tuple) by {@link useSubscription} and\n * gives you the updating {@link OperationResult} of GraphQL subscriptions.\n *\n * If a {@link SubscriptionHandler} has been passed to `useSubscription` then\n * {@link UseSubscriptionState.data} is instead the updated data as returned\n * by the handler, otherwise it’s the latest result’s data.\n *\n * Hint: Even when the query and variables passed to {@link useSubscription} change,\n * this state preserves the prior state.\n */\nexport interface UseSubscriptionState<\n  Data = any,\n  Variables extends AnyVariables = AnyVariables,\n> {\n  /** Indicates whether `useSubscription`’s subscription is active.\n   *\n   * @remarks\n   * When `useSubscription` starts a subscription, the `fetching` flag\n   * is set to `true` and will remain `true` until the subscription\n   * completes on the API, or the {@link UseSubscriptionArgs.pause}\n   * flag is set to `true`.\n   */\n  fetching: boolean;\n  /** Indicates that the subscription result is not fresh.\n   *\n   * @remarks\n   * This is mostly unused for subscriptions and will rarely affect you, and\n   * is more relevant for queries.\n   *\n   * @see {@link OperationResult.stale} for the source of this value.\n   */\n  stale: boolean;\n  /** The {@link OperationResult.data} for the executed subscription, or data returned by a handler.\n   *\n   * @remarks\n   * `data` will be set to the last {@link OperationResult.data} value\n   * received for the subscription.\n   *\n   * It will instead be set to the values that {@link SubscriptionHandler}\n   * returned, if a handler has been passed to {@link useSubscription}.\n   */\n  data?: Data;\n  /** The {@link OperationResult.error} for the executed subscription. */\n  error?: CombinedError;\n  /** The {@link OperationResult.extensions} for the executed mutation. */\n  extensions?: Record<string, any>;\n  /** The {@link Operation} that the current state is for.\n   *\n   * @remarks\n   * This is the subscription {@link Operation} that is currently active.\n   * When {@link UseSubscriptionState.fetching} is `true`, this is the\n   * last `Operation` that the current state was for.\n   */\n  operation?: Operation<Data, Variables>;\n}\n\n/** Triggers {@link useSubscription} to reexecute a GraphQL subscription operation.\n *\n * @param opts - optionally, context options that will be merged with the hook's\n * {@link UseSubscriptionArgs.context} options and the `Client`’s options.\n *\n * @remarks\n * When called, {@link useSubscription} will restart the GraphQL subscription\n * operation it currently holds. If {@link UseSubscriptionArgs.pause} is set\n * to `true`, it will start executing the subscription.\n *\n * ```ts\n * const [result, executeSubscription] = useSubscription({\n *   query,\n *   pause: true,\n * });\n *\n * const start = () => {\n *   executeSubscription();\n * };\n * ```\n */\nexport type UseSubscriptionExecute = (opts?: Partial<OperationContext>) => void;\n\n/** Result tuple returned by the {@link useSubscription} hook.\n *\n * @remarks\n * Similarly to a `useState` hook’s return value,\n * the first element is the {@link useSubscription}’s state,\n * a {@link UseSubscriptionState} object,\n * and the second is used to imperatively re-execute or start the subscription\n * via a {@link UseMutationExecute} function.\n */\nexport type UseSubscriptionResponse<\n  Data = any,\n  Variables extends AnyVariables = AnyVariables,\n> = [UseSubscriptionState<Data, Variables>, UseSubscriptionExecute];\n\n/** Hook to run a GraphQL subscription and get updated GraphQL results.\n *\n * @param args - a {@link UseSubscriptionArgs} object, to pass a `query`, `variables`, and options.\n * @param handler - optionally, a {@link SubscriptionHandler} function to combine multiple subscription results.\n * @returns a {@link UseSubscriptionResponse} tuple of a {@link UseSubscriptionState} result, and an execute function.\n *\n * @remarks\n * `useSubscription` allows GraphQL subscriptions to be defined and executed.\n * Given {@link UseSubscriptionArgs.query}, it executes the GraphQL subscription with the\n * context’s {@link Client}.\n *\n * The returned result updates when the `Client` has new results\n * for the subscription, and `data` is updated with the result’s data\n * or with the `data` that a `handler` returns.\n *\n * @example\n * ```ts\n * import { gql, useSubscription } from '@urql/preact';\n *\n * const NotificationsSubscription = gql`\n *   subscription { newNotification { id, text } }\n * `;\n *\n * const combineNotifications = (notifications = [], data) => {\n *   return [...notifications, data.newNotification];\n * };\n *\n * const Notifications = () => {\n *   const [result, executeSubscription] = useSubscription(\n *     { query: NotificationsSubscription },\n *     combineNotifications,\n *   );\n *   // ...\n * };\n * ```\n */\nexport function useSubscription<\n  Data = any,\n  Result = Data,\n  Variables extends AnyVariables = AnyVariables,\n>(\n  args: UseSubscriptionArgs<Variables, Data>,\n  handler?: SubscriptionHandler<Data, Result>\n): UseSubscriptionResponse<Result, Variables> {\n  const client = useClient();\n\n  // Update handler on constant ref, since handler changes shouldn't\n  // trigger a new subscription run\n  const handlerRef = useRef(handler);\n  handlerRef.current = handler!;\n\n  // This creates a request which will keep a stable reference\n  // if request.key doesn't change\n  const request = useRequest(args.query, args.variables as Variables);\n\n  // Create a new subscription-source from client.executeSubscription\n  const makeSubscription$ = useCallback(\n    (opts?: Partial<OperationContext>) => {\n      return client.executeSubscription<Data, Variables>(request, {\n        ...args.context,\n        ...opts,\n      });\n    },\n    [client, request, args.context]\n  );\n\n  const subscription$ = useMemo(() => {\n    return args.pause ? null : makeSubscription$();\n  }, [args.pause, makeSubscription$]);\n\n  const [state, update] = useSource(\n    subscription$,\n    useCallback(\n      (subscription$$, prevState?: UseSubscriptionState<Result, Variables>) => {\n        return pipe(\n          subscription$$,\n          switchMap(subscription$ => {\n            if (!subscription$) return fromValue({ fetching: false });\n\n            return concat([\n              // Initially set fetching to true\n              fromValue({ fetching: true, stale: false }),\n              pipe(\n                subscription$,\n                map(({ stale, data, error, extensions, operation }) => ({\n                  fetching: true,\n                  stale: !!stale,\n                  data,\n                  error,\n                  extensions,\n                  operation,\n                }))\n              ),\n              // When the source proactively closes, fetching is set to false\n              fromValue({ fetching: false, stale: false }),\n            ]);\n          }),\n          // The individual partial results are merged into each previous result\n          scan(\n            (result: UseSubscriptionState<Result, Variables>, partial: any) => {\n              const { current: handler } = handlerRef;\n              // If a handler has been passed, it's used to merge new data in\n              const data =\n                partial.data != null\n                  ? typeof handler === 'function'\n                    ? handler(result.data, partial.data)\n                    : partial.data\n                  : result.data;\n              return { ...result, ...partial, data };\n            },\n            prevState || initialState\n          )\n        );\n      },\n      []\n    )\n  );\n\n  // This is the imperative execute function passed to the user\n  const executeSubscription = useCallback(\n    (opts?: Partial<OperationContext>) => update(makeSubscription$(opts)),\n    [update, makeSubscription$]\n  );\n\n  useEffect(() => {\n    update(subscription$);\n  }, [update, subscription$]);\n\n  return [state, executeSubscription];\n}\n"
  },
  {
    "path": "packages/preact-urql/src/index.ts",
    "content": "export * from '@urql/core';\nexport * from './hooks';\nexport * from './components';\nexport * from './context';\n"
  },
  {
    "path": "packages/preact-urql/tsconfig.json",
    "content": "{\n  \"extends\": \"../../tsconfig.json\",\n  \"include\": [\"src\"]\n}\n"
  },
  {
    "path": "packages/preact-urql/vitest.config.ts",
    "content": "import { mergeConfig } from 'vitest/config';\nimport baseConfig from '../../vitest.config';\n\nexport default mergeConfig(baseConfig, {});\n"
  },
  {
    "path": "packages/react-urql/CHANGELOG.md",
    "content": "# urql\n\n## 5.0.1\n\n### Patch Changes\n\n- Upgrade false-positive circumvention for internal React warning to support React 19\n  Submitted by [@kitten](https://github.com/kitten) (See [#3769](https://github.com/urql-graphql/urql/pull/3769))\n\n## 5.0.0\n\n### Patch Changes\n\n- Updated dependencies (See [#3789](https://github.com/urql-graphql/urql/pull/3789) and [#3807](https://github.com/urql-graphql/urql/pull/3807))\n  - @urql/core@6.0.0\n\n## 4.2.2\n\n### Patch Changes\n\n- Omit minified files and sourcemaps' `sourcesContent` in published packages\n  Submitted by [@kitten](https://github.com/kitten) (See [#3755](https://github.com/urql-graphql/urql/pull/3755))\n- Updated dependencies (See [#3755](https://github.com/urql-graphql/urql/pull/3755))\n  - @urql/core@5.1.1\n\n## 4.2.1\n\n### Patch Changes\n\n- Add type for `hasNext` to the query and mutation results\n  Submitted by [@JoviDeCroock](https://github.com/JoviDeCroock) (See [#3703](https://github.com/urql-graphql/urql/pull/3703))\n\n## 4.2.0\n\n### Minor Changes\n\n- Support use of defer with suspense\n  Submitted by [@AndrewIngram](https://github.com/AndrewIngram) (See [#3687](https://github.com/urql-graphql/urql/pull/3687))\n\n## 4.1.0\n\n### Minor Changes\n\n- Mark `@urql/core` as a peer dependency as well as a regular dependency\n  Submitted by [@kitten](https://github.com/kitten) (See [#3579](https://github.com/urql-graphql/urql/pull/3579))\n\n### Patch Changes\n\n- ⚠️ Fix subscription handlers to not receive `null` values\n  Submitted by [@kitten](https://github.com/kitten) (See [#3581](https://github.com/urql-graphql/urql/pull/3581))\n\n## 4.0.7\n\n### Patch Changes\n\n- Updated dependencies (See [#3520](https://github.com/urql-graphql/urql/pull/3520), [#3553](https://github.com/urql-graphql/urql/pull/3553), and [#3520](https://github.com/urql-graphql/urql/pull/3520))\n  - @urql/core@5.0.0\n\n## 4.0.6\n\n### Patch Changes\n\n- Prioritise `context.suspense` and fallback to checking `client.suspense`\n  Submitted by [@JoviDeCroock](https://github.com/JoviDeCroock) (See [#3427](https://github.com/urql-graphql/urql/pull/3427))\n- Updated dependencies (See [#3430](https://github.com/urql-graphql/urql/pull/3430))\n  - @urql/core@4.2.0\n\n## 4.0.5\n\n### Patch Changes\n\n- ⚠️ Fix edge case that causes execute functions from `useQuery` and `useSubscription` to fail when they’re called in their state after a render that changes `pause`. This would previously cause internal dependencies to be outdated and the source to be discarded immediately in some cases\n  Submitted by [@kitten](https://github.com/kitten) (See [#3323](https://github.com/urql-graphql/urql/pull/3323))\n- Updated dependencies (See [#3317](https://github.com/urql-graphql/urql/pull/3317) and [#3308](https://github.com/urql-graphql/urql/pull/3308))\n  - @urql/core@4.1.0\n\n## 4.0.4\n\n### Patch Changes\n\n- Switch `react` imports to namespace imports, and update build process for CommonJS outputs to interoperate with `__esModule` marked modules again\n  Submitted by [@kitten](https://github.com/kitten) (See [#3251](https://github.com/urql-graphql/urql/pull/3251))\n\n## 4.0.3\n\n### Patch Changes\n\n- Update build process to generate correct source maps\n  Submitted by [@kitten](https://github.com/kitten) (See [#3201](https://github.com/urql-graphql/urql/pull/3201))\n\n## 4.0.2\n\n### Patch Changes\n\n- Avoid unnecessary re-render when two components use the same query but receive unchanging results, due to differing operations\n  Submitted by [@nathan-knight](https://github.com/nathan-knight) (See [#3195](https://github.com/urql-graphql/urql/pull/3195))\n\n## 4.0.1\n\n### Patch Changes\n\n- Publish with npm provenance\n  Submitted by [@kitten](https://github.com/kitten) (See [#3180](https://github.com/urql-graphql/urql/pull/3180))\n\n## 4.0.0\n\n### Major Changes\n\n- Remove the default `Client` from `Context`. Previously, `urql` kept a legacy default client in its context, with default exchanges and calling an API at `/graphql`. This has now been removed and you will have to create your own `Client` if you were relying on this behaviour\n  Submitted by [@JoviDeCroock](https://github.com/JoviDeCroock) (See [#3033](https://github.com/urql-graphql/urql/pull/3033))\n\n### Minor Changes\n\n- Allow mutations to update their results in bindings when `hasNext: true` is set, which indicates deferred or streamed results\n  Submitted by [@kitten](https://github.com/kitten) (See [#3103](https://github.com/urql-graphql/urql/pull/3103))\n\n### Patch Changes\n\n- ⚠️ Fix source maps included with recently published packages, which lost their `sourcesContent`, including additional source files, and had incorrect paths in some of them\n  Submitted by [@kitten](https://github.com/kitten) (See [#3053](https://github.com/urql-graphql/urql/pull/3053))\n- Upgrade to `wonka@^6.3.0`\n  Submitted by [@kitten](https://github.com/kitten) (See [#3104](https://github.com/urql-graphql/urql/pull/3104))\n- Silence \"Cannot update a component (%s) while rendering a different component (%s).\" warning forcefully\n  Submitted by [@kitten](https://github.com/kitten) (See [#3095](https://github.com/urql-graphql/urql/pull/3095))\n- Add TSDocs to all `urql` bindings packages\n  Submitted by [@kitten](https://github.com/kitten) (See [#3079](https://github.com/urql-graphql/urql/pull/3079))\n- Updated dependencies (See [#3101](https://github.com/urql-graphql/urql/pull/3101), [#3033](https://github.com/urql-graphql/urql/pull/3033), [#3054](https://github.com/urql-graphql/urql/pull/3054), [#3053](https://github.com/urql-graphql/urql/pull/3053), [#3060](https://github.com/urql-graphql/urql/pull/3060), [#3081](https://github.com/urql-graphql/urql/pull/3081), [#3039](https://github.com/urql-graphql/urql/pull/3039), [#3104](https://github.com/urql-graphql/urql/pull/3104), [#3082](https://github.com/urql-graphql/urql/pull/3082), [#3097](https://github.com/urql-graphql/urql/pull/3097), [#3061](https://github.com/urql-graphql/urql/pull/3061), [#3055](https://github.com/urql-graphql/urql/pull/3055), [#3085](https://github.com/urql-graphql/urql/pull/3085), [#3079](https://github.com/urql-graphql/urql/pull/3079), [#3087](https://github.com/urql-graphql/urql/pull/3087), [#3059](https://github.com/urql-graphql/urql/pull/3059), [#3055](https://github.com/urql-graphql/urql/pull/3055), [#3057](https://github.com/urql-graphql/urql/pull/3057), [#3050](https://github.com/urql-graphql/urql/pull/3050), [#3062](https://github.com/urql-graphql/urql/pull/3062), [#3051](https://github.com/urql-graphql/urql/pull/3051), [#3043](https://github.com/urql-graphql/urql/pull/3043), [#3063](https://github.com/urql-graphql/urql/pull/3063), [#3054](https://github.com/urql-graphql/urql/pull/3054), [#3102](https://github.com/urql-graphql/urql/pull/3102), [#3097](https://github.com/urql-graphql/urql/pull/3097), [#3106](https://github.com/urql-graphql/urql/pull/3106), [#3058](https://github.com/urql-graphql/urql/pull/3058), and [#3062](https://github.com/urql-graphql/urql/pull/3062))\n  - @urql/core@4.0.0\n\n## 3.0.4\n\n### Patch Changes\n\n- ⚠️ Fix type utilities turning the `variables` properties optional when a type from `TypedDocumentNode` has no `Variables` or all optional `Variables`. Previously this would break for wrappers, e.g. in code generators, or when the type didn't quite match what we'd expect\n  Submitted by [@kitten](https://github.com/kitten) (See [#3022](https://github.com/urql-graphql/urql/pull/3022))\n- Updated dependencies (See [#3007](https://github.com/urql-graphql/urql/pull/3007), [#2962](https://github.com/urql-graphql/urql/pull/2962), [#3007](https://github.com/urql-graphql/urql/pull/3007), [#3015](https://github.com/urql-graphql/urql/pull/3015), and [#3022](https://github.com/urql-graphql/urql/pull/3022))\n  - @urql/core@3.2.0\n\n## 3.0.3\n\n### Patch Changes\n\n- ⚠️ Fix `fetching` going to `false` after changing variables in a subscription, by [@JoviDeCroock](https://github.com/JoviDeCroock) (See [#2667](https://github.com/FormidableLabs/urql/pull/2667))\n\n## 3.0.2\n\n### Patch Changes\n\n- Update generics for components, by [@JoviDeCroock](https://github.com/JoviDeCroock) (See [#2663](https://github.com/FormidableLabs/urql/pull/2663))\n- Updated dependencies (See [#2665](https://github.com/FormidableLabs/urql/pull/2665))\n  - @urql/core@3.0.3\n\n## 3.0.1\n\n### Patch Changes\n\n- Tweak the variables type for when generics only contain nullable keys, by [@JoviDeCroock](https://github.com/JoviDeCroock) (See [#2623](https://github.com/FormidableLabs/urql/pull/2623))\n\n## 3.0.0\n\n### Major Changes\n\n- **Goodbye IE11!** 👋 This major release removes support for IE11. All code that is shipped will be transpiled much less and will _not_ be ES5-compatible anymore, by [@kitten](https://github.com/kitten) (See [#2504](https://github.com/FormidableLabs/urql/pull/2504))\n- Implement stricter variables types, which require variables to always be passed and match TypeScript types when the generic is set or inferred. This is a breaking change for TypeScript users potentially, unless all types are adhered to, by [@kitten](https://github.com/kitten) (See [#2607](https://github.com/FormidableLabs/urql/pull/2607))\n- Upgrade to [Wonka v6](https://github.com/0no-co/wonka) (`wonka@^6.0.0`), which has no breaking changes but is built to target ES2015 and comes with other minor improvements.\n  The library has fully been migrated to TypeScript which will hopefully help with making contributions easier!, by [@kitten](https://github.com/kitten) (See [#2504](https://github.com/FormidableLabs/urql/pull/2504))\n\n### Patch Changes\n\n- Updated dependencies (See [#2551](https://github.com/FormidableLabs/urql/pull/2551), [#2504](https://github.com/FormidableLabs/urql/pull/2504), [#2619](https://github.com/FormidableLabs/urql/pull/2619), [#2607](https://github.com/FormidableLabs/urql/pull/2607), and [#2504](https://github.com/FormidableLabs/urql/pull/2504))\n  - @urql/core@3.0.0\n\n## 2.2.3\n\n### Patch Changes\n\n- ⚠️ Fix missing React updates after an incoming response that schedules a mount. We now prevent dispatched operations from continuing to flush synchronously when the original source that runs the queue has terminated. This is important for the React bindings, because an update (e.g. `setState`) may recursively schedule a mount, which then disabled other `setState` updates from being processed. Previously we assumed that React used a trampoline scheduler for updates, however it appears that `setState` can recursively start more React work, by [@kitten](https://github.com/kitten) (See [#2556](https://github.com/FormidableLabs/urql/pull/2556))\n- Updated dependencies (See [#2556](https://github.com/FormidableLabs/urql/pull/2556))\n  - @urql/core@2.6.1\n\n## 2.2.2\n\n### Patch Changes\n\n- ⚠️ Fix Node.js ESM re-export detection for `@urql/core` in `urql` package and CommonJS output for all other CommonJS-first packages. This ensures that Node.js' `cjs-module-lexer` can correctly identify re-exports and report them properly. Otherwise, this will lead to a runtime error, by [@kitten](https://github.com/kitten) (See [#2485](https://github.com/FormidableLabs/urql/pull/2485))\n\n## 2.2.1\n\n### Patch Changes\n\n- ⚠️ Fix issue where a paused subscription would execute with stale variables, by [@JoviDeCroock](https://github.com/JoviDeCroock) (See [#2463](https://github.com/FormidableLabs/urql/pull/2463))\n\n## 2.2.0\n\n### Minor Changes\n\n- Revert to the previous `useQuery` implementation, `use-sync-external-store` seems to be causing some unexpected timing issues, by [@JoviDeCroock](https://github.com/JoviDeCroock) (See [#2308](https://github.com/FormidableLabs/urql/pull/2308))\n\n### Patch Changes\n\n- Updated dependencies (See [#2295](https://github.com/FormidableLabs/urql/pull/2295))\n  - @urql/core@2.4.3\n\n## 2.1.3\n\n### Patch Changes\n\n- ⚠️ fix diff data correctly for the next state computing, this avoids having UI-flashes due to undefined data, by [@JoviDeCroock](https://github.com/JoviDeCroock) (See [#2238](https://github.com/FormidableLabs/urql/pull/2238))\n- ⚠️ fix issue where the cache infinitely loops, by [@JoviDeCroock](https://github.com/JoviDeCroock) (See [#2237](https://github.com/FormidableLabs/urql/pull/2237))\n\n## 2.1.2\n\n### Patch Changes\n\n- Update `useQuery` implementation to avoid an aborted render on initial mount. We abort a render-on-update once when the state needs to be updated according to the `OperationResult` source we need to listen to and execute. However, we can avoid this on the initial mount as we've done in a prior version. This fix **does not** change any of the current behaviour, but simply avoids the confusing state transition on mount, by [@kitten](https://github.com/kitten) (See [#2227](https://github.com/FormidableLabs/urql/pull/2227))\n- Updated dependencies (See [#2228](https://github.com/FormidableLabs/urql/pull/2228))\n  - @urql/core@2.4.1\n\n## 2.1.1\n\n### Patch Changes\n\n- pin version for `use-sync-external-store`, by [@JoviDeCroock](https://github.com/JoviDeCroock) (See [#2223](https://github.com/FormidableLabs/urql/pull/2223))\n\n## 2.1.0\n\n### Minor Changes\n\n- Leverage the new `use-sync-external-store` package and `useSyncExternalStore` hook in `useQuery` implementation to bring the state synchronisation in React in line with React v18. While the current implementation works already with React Suspense and React Concurrent this will reduce the maintenance burden of our implementation and ensure certain guarantees so that React doesn't break us, by [@JoviDeCroock](https://github.com/JoviDeCroock) (See [#2164](https://github.com/FormidableLabs/urql/pull/2164))\n\n### Patch Changes\n\n- ⚠️ Fix `useMutation` not working correctly with React 18, by [@Dremora](https://github.com/Dremora) (See [#2158](https://github.com/FormidableLabs/urql/pull/2158))\n- Updated dependencies (See [#2189](https://github.com/FormidableLabs/urql/pull/2189), [#2153](https://github.com/FormidableLabs/urql/pull/2153), [#2210](https://github.com/FormidableLabs/urql/pull/2210), and [#2198](https://github.com/FormidableLabs/urql/pull/2198))\n  - @urql/core@2.4.0\n\n## 2.0.6\n\n### Patch Changes\n\n- Extend peer dependency range of `graphql` to include `^16.0.0`.\n  As always when upgrading across many packages of `urql`, especially including `@urql/core` we recommend you to deduplicate dependencies after upgrading, using `npm dedupe` or `npx yarn-deduplicate`, by [@kitten](https://github.com/kitten) (See [#2133](https://github.com/FormidableLabs/urql/pull/2133))\n- Updated dependencies (See [#2133](https://github.com/FormidableLabs/urql/pull/2133))\n  - @urql/core@2.3.6\n\n## 2.0.5\n\n### Patch Changes\n\n- ⚠️ Fix issue where a paused query would not behave correctly when calling `executeQuery`, this scenario occured when the query has variables, there would be cases where on the first call it would think that the dependencies had changed (previous request vs current request) which made the source reset to null, by [@JoviDeCroock](https://github.com/JoviDeCroock) (See [#1982](https://github.com/FormidableLabs/urql/pull/1982))\n- Updated dependencies (See [#1944](https://github.com/FormidableLabs/urql/pull/1944))\n  - @urql/core@2.3.2\n\n## 2.0.4\n\n### Patch Changes\n\n- ⚠️ Fix issue with `useQuery`'s `executeQuery` state updates, where some calls wouldn't trigger a source change and start a request when the hook was paused, by [@kitten](https://github.com/kitten) (See [#1722](https://github.com/FormidableLabs/urql/pull/1722))\n- Updated dependencies (See [#1709](https://github.com/FormidableLabs/urql/pull/1709))\n  - @urql/core@2.1.4\n\n## 2.0.3\n\n### Patch Changes\n\n- Remove closure-compiler from the build step (See [#1570](https://github.com/FormidableLabs/urql/pull/1570))\n- Updated dependencies (See [#1570](https://github.com/FormidableLabs/urql/pull/1570), [#1509](https://github.com/FormidableLabs/urql/pull/1509), [#1600](https://github.com/FormidableLabs/urql/pull/1600), and [#1515](https://github.com/FormidableLabs/urql/pull/1515))\n  - @urql/core@2.1.0\n\n## 2.0.2\n\n### Patch Changes\n\n- Add a displayName to the Provider, by [@JoviDeCroock](https://github.com/JoviDeCroock) (See [#1431](https://github.com/FormidableLabs/urql/pull/1431))\n\n## 2.0.1\n\n### Patch Changes\n\n- ⚠️ Fix issue where `useSubscription` would endlessly loop when the callback wasn't memoized, by [@JoviDeCroock](https://github.com/JoviDeCroock) (See [#1384](https://github.com/FormidableLabs/urql/pull/1384))\n- ⚠️ Fix case where identical `useQuery` calls would result in cross-component updates, by [@JoviDeCroock](https://github.com/JoviDeCroock) (See [#1383](https://github.com/FormidableLabs/urql/pull/1383))\n\n## 2.0.0\n\n### Major Changes\n\n- **Breaking**: Remove `pollInterval` option from `useQuery`. Instead please consider using `useEffect` calling `executeQuery` on an interval, by [@kitten](https://github.com/kitten) (See [#1374](https://github.com/FormidableLabs/urql/pull/1374))\n\n### Minor Changes\n\n- Reimplement `useQuery` to apply a consistent Suspense cache (torn down queries will still eliminate stale values) and support all Concurrent Mode edge cases. This work is based on `useMutableSource`'s mechanisms and allows React to properly fork lanes since no implicit state exists outside of `useState` in the implementation. The `useSubscription` hook has been updated similarly without a cache or retrieving values on mount, by [@kitten](https://github.com/kitten) (See [#1335](https://github.com/FormidableLabs/urql/pull/1335))\n- Remove deprecated `operationName` property from `Operation`s. The new `Operation.kind` property is now preferred. If you're creating new operations you may also use the `makeOperation` utility instead.\n  When upgrading `@urql/core` please ensure that your package manager didn't install any duplicates of it. You may deduplicate it manually using `npx yarn-deduplicate` (for Yarn) or `npm dedupe` (for npm), by [@kitten](https://github.com/kitten) (See [#1357](https://github.com/FormidableLabs/urql/pull/1357))\n\n### Patch Changes\n\n- Updated dependencies (See [#1374](https://github.com/FormidableLabs/urql/pull/1374), [#1357](https://github.com/FormidableLabs/urql/pull/1357), and [#1375](https://github.com/FormidableLabs/urql/pull/1375))\n  - @urql/core@2.0.0\n\n## 1.11.6\n\n### Patch Changes\n\n- ⚠️ Fix edge cases related to Suspense triggering on an update in Concurrent Mode. Previously it was possible for stale state to be preserved across the Suspense update instead of the new state showing up. This has been fixed by preventing the suspending query source from closing prematurely, by [@kitten](https://github.com/kitten) (See [#1308](https://github.com/FormidableLabs/urql/pull/1308))\n\n## 1.11.5\n\n### Patch Changes\n\n- ⚠️ Fix Suspense when results share data, this would return partial results for graphCache and not update to the eventual data, by [@JoviDeCroock](https://github.com/JoviDeCroock) (See [#1282](https://github.com/FormidableLabs/urql/pull/1282))\n\n## 1.11.4\n\n### Patch Changes\n\n- Add a built-in `gql` tag function helper to `@urql/core`. This behaves similarly to `graphql-tag` but only warns about _locally_ duplicated fragment names rather than globally. It also primes `@urql/core`'s key cache with the parsed `DocumentNode`, by [@kitten](https://github.com/kitten) (See [#1187](https://github.com/FormidableLabs/urql/pull/1187))\n- Add `suspense: false` to options when `executeQuery` is called explicitly, by [@kitten](https://github.com/kitten) (See [#1181](https://github.com/FormidableLabs/urql/pull/1181))\n- Updated dependencies (See [#1187](https://github.com/FormidableLabs/urql/pull/1187), [#1186](https://github.com/FormidableLabs/urql/pull/1186), and [#1186](https://github.com/FormidableLabs/urql/pull/1186))\n  - @urql/core@1.16.0\n\n## 1.11.3\n\n### Patch Changes\n\n- ⚠️ Fix in edge-case in client-side React Suspense, where after suspending due to an update a new state value is given to `useSource` in a render update. This was previously then causing us to subscribe to an outdated source in `useEffect` since the updated source would be ignored by the time we reach `useEffect` in `useSource`, by [@kitten](https://github.com/kitten) (See [#1157](https://github.com/FormidableLabs/urql/pull/1157))\n\n## 1.11.2\n\n### Patch Changes\n\n- ⚠️ Fix regression in client-side Suspense behaviour. This has been fixed in `urql@1.11.0` and `@urql/preact@1.4.0` but regressed in the patches afterwards that were aimed at fixing server-side Suspense, by [@kitten](https://github.com/kitten) (See [#1142](https://github.com/FormidableLabs/urql/pull/1142))\n\n## 1.11.1\n\n### Patch Changes\n\n- ⚠️ Fix server-side rendering by disabling the new Suspense cache on the server-side and clear it for prepasses, by [@JoviDeCroock](https://github.com/JoviDeCroock) (See [#1138](https://github.com/FormidableLabs/urql/pull/1138))\n- Updated dependencies (See [#1135](https://github.com/FormidableLabs/urql/pull/1135))\n  - @urql/core@1.15.1\n\n## 1.11.0\n\n### Minor Changes\n\n- Improve the Suspense implementation, which fixes edge-cases when Suspense is used with subscriptions, partially disabled, or _used on the client-side_. It has now been ensured that client-side suspense functions without the deprecated `suspenseExchange` and uncached results are loaded consistently. As part of this work, the `Client` itself does now never throw Suspense promises anymore, which is functionality that either way has no place outside of the React/Preact bindings, by [@kitten](https://github.com/kitten) (See [#1123](https://github.com/FormidableLabs/urql/pull/1123))\n\n### Patch Changes\n\n- Add support for `TypedDocumentNode` to infer the type of the `OperationResult` and `Operation` for all methods, functions, and hooks that either directly or indirectly accept a `DocumentNode`. See [`graphql-typed-document-node` and the corresponding blog post for more information.](https://github.com/dotansimha/graphql-typed-document-node), by [@kitten](https://github.com/kitten) (See [#1113](https://github.com/FormidableLabs/urql/pull/1113))\n- Refactor `useSource` hooks which powers `useQuery` and `useSubscription` to improve various edge case behaviour. This will not change the behaviour of these hooks dramatically but avoid unnecessary state updates when any updates are obviously equivalent and the hook will furthermore improve continuation from mount to effects, which will fix cases where the state between the mounting and effect phase may slightly change, by [@kitten](https://github.com/kitten) (See [#1104](https://github.com/FormidableLabs/urql/pull/1104))\n- Updated dependencies (See [#1119](https://github.com/FormidableLabs/urql/pull/1119), [#1113](https://github.com/FormidableLabs/urql/pull/1113), [#1104](https://github.com/FormidableLabs/urql/pull/1104), and [#1123](https://github.com/FormidableLabs/urql/pull/1123))\n  - @urql/core@1.15.0\n\n## 1.10.3\n\n### Patch Changes\n\n- ⚠️ Fix the production build overwriting the development build. Specifically in the previous release we mistakenly replaced all development bundles with production bundles. This doesn't have any direct influence on how these packages work, but prevented development warnings from being logged or full errors from being thrown, by [@kitten](https://github.com/kitten) (See [#1097](https://github.com/FormidableLabs/urql/pull/1097))\n- Updated dependencies (See [#1097](https://github.com/FormidableLabs/urql/pull/1097))\n  - @urql/core@1.14.1\n\n## 1.10.2\n\n### Patch Changes\n\n- Deprecate the `Operation.operationName` property in favor of `Operation.kind`. This name was\n  previously confusing as `operationName` was effectively referring to two different things. You can\n  safely upgrade to this new version, however to mute all deprecation warnings you will have to\n  **upgrade** all `urql` packages you use. If you have custom exchanges that spread operations, please\n  use [the new `makeOperation` helper\n  function](https://formidable.com/open-source/urql/docs/api/core/#makeoperation) instead, by [@bkonkle](https://github.com/bkonkle) (See [#1045](https://github.com/FormidableLabs/urql/pull/1045))\n- Updated dependencies (See [#1094](https://github.com/FormidableLabs/urql/pull/1094) and [#1045](https://github.com/FormidableLabs/urql/pull/1045))\n  - @urql/core@1.14.0\n\n## 1.10.1\n\n### Patch Changes\n\n- ⚠️ Fix React Fast Refresh beng broken due to an invalid effect, by [@JoviDeCroock](https://github.com/JoviDeCroock) (See [#969](https://github.com/FormidableLabs/urql/pull/969))\n\n## 1.10.0\n\n### Minor Changes\n\n- Add the operation to the query, mutation and subscription result, by [@JoviDeCroock](https://github.com/JoviDeCroock) (See [#924](https://github.com/FormidableLabs/urql/pull/924))\n\n### Patch Changes\n\n- Update hooks to be exported functions rather than exported block-scoped variables to provide TypeScript consumers with better access to their signature, by [@dotansimha](https://github.com/dotansimha) (See [#904](https://github.com/FormidableLabs/urql/pull/904))\n- Updated dependencies (See [#911](https://github.com/FormidableLabs/urql/pull/911) and [#908](https://github.com/FormidableLabs/urql/pull/908))\n  - @urql/core@1.12.3\n\n## 1.9.8\n\n### Patch Changes\n\n- Upgrade to a minimum version of wonka@^4.0.14 to work around issues with React Native's minification builds, which use uglify-es and could lead to broken bundles, by [@kitten](https://github.com/kitten) (See [#842](https://github.com/FormidableLabs/urql/pull/842))\n- Updated dependencies (See [#838](https://github.com/FormidableLabs/urql/pull/838) and [#842](https://github.com/FormidableLabs/urql/pull/842))\n  - @urql/core@1.12.0\n\n## 1.9.7\n\n### Patch Changes\n\n- Bump @urql/core to ensure exchanges have dispatchDebug, this could formerly result in a crash, by [@JoviDeCroock](https://github.com/JoviDeCroock) (See [#726](https://github.com/FormidableLabs/urql/pull/726))\n\n## 1.9.6\n\n### Patch Changes\n\n- Add graphql@^15.0.0 to peer dependency range, by [@kitten](https://github.com/kitten) (See [#688](https://github.com/FormidableLabs/urql/pull/688))\n- Forcefully bump @urql/core package in all bindings and in @urql/exchange-graphcache.\n  We're aware that in some cases users may not have upgraded to @urql/core, even though that's within\n  the typical patch range. Since the latest @urql/core version contains a patch that is required for\n  `cache-and-network` to work, we're pushing another patch that now forcefully bumps everyone to the\n  new version that includes this fix, by [@kitten](https://github.com/kitten) (See [#684](https://github.com/FormidableLabs/urql/pull/684))\n- Updated dependencies (See [#688](https://github.com/FormidableLabs/urql/pull/688) and [#678](https://github.com/FormidableLabs/urql/pull/678))\n  - @urql/core@1.10.8\n\n## 1.9.5\n\n### Patch Changes\n\n- Avoid setting state on an unmounted component when useMutation is used, by [@JoviDeCroock](https://github.com/JoviDeCroock) (See [#656](https://github.com/FormidableLabs/urql/pull/656))\n- Updated dependencies (See [#658](https://github.com/FormidableLabs/urql/pull/658) and [#650](https://github.com/FormidableLabs/urql/pull/650))\n  - @urql/core@1.10.5\n\n## 1.9.4\n\n### Patch Changes\n\n- ⚠️ Fix bundling for packages depending on React, as it doesn't have native ESM bundles, by [@kitten](https://github.com/kitten) (See [#646](https://github.com/FormidableLabs/urql/pull/646))\n\n## 1.9.3\n\n### Patch Changes\n\n- ⚠️ Fix node resolution when using Webpack, which experiences a bug where it only resolves\n  `package.json:main` instead of `module` when an `.mjs` file imports a package, by [@JoviDeCroock](https://github.com/JoviDeCroock) (See [#642](https://github.com/FormidableLabs/urql/pull/642))\n- Updated dependencies (See [#642](https://github.com/FormidableLabs/urql/pull/642))\n  - @urql/core@1.10.4\n\n## 1.9.2\n\n### Patch Changes\n\n- ⚠️ Fix Node.js Module support for v13 (experimental-modules) and v14. If your bundler doesn't support\n  `.mjs` files and fails to resolve the new version, please double check your configuration for\n  Webpack, or similar tools, by [@JoviDeCroock](https://github.com/JoviDeCroock) (See [#637](https://github.com/FormidableLabs/urql/pull/637))\n- Updated dependencies (See [#637](https://github.com/FormidableLabs/urql/pull/637))\n  - @urql/core@1.10.3\n\n## 1.9.1\n\n### Patch Changes\n\n- Bumps the `@urql/core` dependency minor version to ^1.10.1 for React, Preact and Svelte, by [@JoviDeCroock](https://github.com/JoviDeCroock) (See [#623](https://github.com/FormidableLabs/urql/pull/623))\n- Avoid React v16.13.0's \"Warning: Cannot update a component\" by preventing cross-hook updates during render or initial mount, by [@kitten](https://github.com/kitten) (See [#630](https://github.com/FormidableLabs/urql/pull/630))\n- Updated dependencies (See [#621](https://github.com/FormidableLabs/urql/pull/621))\n  - @urql/core@1.10.2\n\n## 1.9.0\n\n### Patch Changes\n\n- ⚠️ Fix more concurrent-mode and strict-mode edge cases and bugs by switching to useSubscription. (See [#514](https://github.com/FormidableLabs/urql/pull/514))\n- ⚠️ Fix client-side suspense support (as minimally as possible) by altering\n  the useBehaviourSubject behaviour. (See [#512](https://github.com/FormidableLabs/urql/pull/521))\n- Updated dependencies (See [#533](https://github.com/FormidableLabs/urql/pull/533), [#519](https://github.com/FormidableLabs/urql/pull/519), [#515](https://github.com/FormidableLabs/urql/pull/515), [#512](https://github.com/FormidableLabs/urql/pull/512), and [#518](https://github.com/FormidableLabs/urql/pull/518))\n  - @urql/core@1.9.0\n\n## 1.8.2\n\nThis patch fixes client-side suspense. While we wouldn't recommend its use\nanymore, since suspense lends itself to prerendering instead of a loading\nprimitive, we'd like to ensure that suspense-mode works as expected in `urql`.\n\nAlso, as mentioned in `v1.8.0`'s notes, please ensure that `urql` upgrades to\nuse `wonka@^4.0.7` to avoid any issues. If your bundler or packager uses a\nlower version with `urql`, you will see runtime errors.\n\n- Clean up unnecessary `useMemo` for `useCallback` in hooks (see [#504](https://github.com/FormidableLabs/urql/pull/504))\n- Fix synchronous, client-side suspense and simplify `toSuspenseSource` helper (see [#506](https://github.com/FormidableLabs/urql/pull/506))\n\n## 1.8.1\n\nThis patch fixes `urql` relying on a quirk in older versions of `wonka` where\nshared sources wouldn't cascade cancellations, which they now do. This meant\nthat when an app goes from some queries/subscriptions to having none at all,\nthe exchange pipeline would be stopped completely.\n\n- Fix exchange pipeline stalling when all queries end (see [#503](https://github.com/FormidableLabs/urql/pull/503))\n\n## 1.8.0\n\nThis release doesn't change any major feature aspects, but comes with bugfixes\nto our suspense and concurrent-mode handling. Due to an upgrade to `wonka@^4.0.0`\nthis is a minor version though.\n\nIn [v1.6.0](https://github.com/FormidableLabs/urql/blob/main/CHANGELOG.md#160) we believed to\nhave solved all issues related to suspense and concurrent mode. However there were\nstill some remaining cases where concurrent mode behaved incorrectly. With the new\n`useOperator` hook in [`react-wonka@2.0.0`](https://github.com/kitten/react-wonka) we believe\nto have now fixed all issues.\n\nThe initial mount of `useQuery` and `useSubscription` will now synchronously reflect\nwhatever `urql` returns, most of the times those will be cached results. Afterwards\nall subsequent updates and fetches will be scheduled cooperatively with React on\nan effect.\n\nIf you're using `wonka` for an exchange with `urql` you may want to upgrade to `wonka@^4.0.5` soon.\nYou can still use the older `v3.2.2` which will work with the new version (even in the same bundle),\nunless you're making use of its `subscribe`, `make`, or `makeSubject` exports.\n[A migration guide can be found in the `wonka` docs.](https://wonka.kitten.sh/migration)\n\n- Support concurrent mode with all edge cases fully (see [#496](https://github.com/FormidableLabs/urql/pull/496))\n- Move to `react-wonka@2.0.0` with the prior fix in #496 (see [#499](https://github.com/FormidableLabs/urql/pull/499))\n\n## 1.7.0\n\nThis release splits our main package into two entrypoints. Importing from `urql` remains\nunchanged, but internally this entrypoint uses `urql/core`, which doesn't contain any\nReact-related code. If you're building framework-agnostic libraries or apps without\nReact, you can now use `urql/core` directly.\n\n- Fix `originalError` on `GraphQLError` instances (see [#470](https://github.com/FormidableLabs/urql/pull/470))\n- Fix `stringifyVariables` not using `.toJSON()` which prevented Dates from being stringified, by [@BjoernRave](https://github.com/BjoernRave) (see [#485](https://github.com/FormidableLabs/urql/pull/485))\n- Expose `urql/core` without any React code included (see [#424](https://github.com/FormidableLabs/urql/pull/424))\n\n## 1.6.3\n\n- Fix suspense-mode being erroneously activated when using `client.query()` (see [#466](https://github.com/FormidableLabs/react-ssr-prepass/pull/21))\n\n## 1.6.2\n\nThis fixes a potentially critical bug, where a component would enter an infinite rerender loop,\nwhen another hook triggers an update. This may happen when multiple `useQuery` hooks are used in\na single component or when another state hook triggers a synchronous update.\n\n- Add generic type-parameter to `client.query` and `client.mutation`, by [@ctrlplusb](https://github.com/ctrlplusb) (see [#456](https://github.com/FormidableLabs/urql/pull/456))\n- ⚠️ Fix `useQuery` entering an infinite loop during SSR when an update is triggered (see [#459](https://github.com/FormidableLabs/urql/pull/459))\n\n## 1.6.1\n\n- Fix hook updates not being propagated to potential context providers (see [#451](https://github.com/FormidableLabs/urql/pull/451))\n\n## 1.6.0\n\nThis release comes with stability improvements for the `useQuery` and `useSubscription` hooks\nwhen using suspense and concurrent mode. They should behave the same as before under normal\ncircumstances and continue to deliver the correct state on initial mount and updates.\nThe `useQuery` hook may however now trigger suspense updates when its inputs are changing,\nas it should, instead of erroneously throwing a promise in `useEffect`.\n\nThe added `stale: boolean` flag on the hooks indicates whether a result is \"stale\".\n`useQuery` will expose `stale: true` on results that are cached but will be updated\ndue to the use of `cache-and-network`.\n\nWe've also made some changes so that `client.query()` won't throw a promise, when suspense\nmode is activated.\n\n- ✨ Add `stale` flag to `OperationResult` and hook results (see [#449](https://github.com/FormidableLabs/urql/pull/449))\n- Replace `useImmeditateEffect` and `useImmediateState` with `react-wonka` derived state and effect (see [#447](https://github.com/FormidableLabs/urql/pull/447))\n- Add (internal) `suspense` flag to `OperationContext`\n\n## 1.5.1\n\n- Replace `fast-json-stable-stringify` with embedded code (see [#426](https://github.com/FormidableLabs/urql/pull/426))\n- ⚠ Prevent caching `null` data (see [#437](https://github.com/FormidableLabs/urql/pull/437))\n\n## 1.5.0\n\nThis release finally adds shortcuts to imperatively make queries and mutations.\nThey make it easier to quickly use the client programmatically, either with\na Wonka source-based or Promise-based call.\n\n```js\n// Call .query or .mutation which return Source<OperationResult>\nconst source = client.query(doc, vars);\nconst source = client.mutation(doc, vars);\n// Call .toPromise() on the source to get Promise<OperationResult>\nconst promise = client.query(doc, vars).toPromise();\nconst promise = client.mutation(doc, vars).toPromise();\n```\n\nThis version also adds a `useClient` hook as a shortcut for `useContext(Context)`.\nWe provide a default client that makes requests to `/graphql`. Since that has\nconfused users before, we now log a warning, when it's used.\n\n- ✨ Implement `client.query()` and `client.mutation()` (see [#405](https://github.com/FormidableLabs/urql/pull/405))\n- Fix `useImmediateEffect` for concurrent mode (see [#418](https://github.com/FormidableLabs/urql/pull/418))\n- Deconstruct `Wonka.pipe` using a Babel transform (see [#419](https://github.com/FormidableLabs/urql/pull/419))\n- ⚠ Add `useClient` hook and warning when default client is used (see [#420](https://github.com/FormidableLabs/urql/pull/420))\n\n## 1.4.1\n\nThis release adds \"active teardowns\" for operations, which means that an exchange can now send a teardown to cancel ongoing operations. The `subscriptionsExchange` for instance now ends ongoing subscriptions proactively if the server says that they've completed! This is also reflected as `fetching: false` in the `useQuery` and `useSubscription` hook.\n\nWe've also fixed a small issue with suspense and added all features from `useQuery` to `useSubscription`! This includes the `pause` argument and an `executeSubscription` function.\n\n- ✨ Implement active teardowns and add missing features to `useSubscription` (see [#410](https://github.com/FormidableLabs/urql/pull/410))\n- Fix `UseMutationResponse` TypeScript type, by [@jbugman](https://github.com/jbugman) (see [#412](https://github.com/FormidableLabs/urql/pull/412))\n- Exclude subscriptions from suspense source (see [#415](https://github.com/FormidableLabs/urql/pull/415))\n\n## 1.4.0\n\nThis release removes all metadata for the `@urql/devtools` extension from the core\n`urql` package. This data will now be generated internally in the devtools exchange\nitself. [Please also upgrade to the latest `@urql/devtools` version if you're using\nthe extension.](https://github.com/FormidableLabs/urql-devtools/releases/tag/v0.0.3)\n\nThis release has mainly been focused on minor refactors to keep the bundlesize low.\nBut it also introduces new features, like specifying a default `requestPolicy` and\na new polling option on `useQuery`!\n\nThis release also exports `makeResult` and `makeErrorResult`, which will reduce the\nboilerplate code that you need for custom fetch exchanges.\n\n- Minor bundlesize optimizations and remove `debugExchange` in production (see [#375](https://github.com/FormidableLabs/urql/pull/375))\n- ✨ Add `requestPolicy` option to `Client` to change the default request policy (see [#376](https://github.com/FormidableLabs/urql/pull/376))\n- ⚠ Remove dependency on `graphql-tag` and improve `Operation.key` hashing (see [#383](https://github.com/FormidableLabs/urql/pull/383))\n- Remove `networkLatency` and `source` metadata from context, and delete `useDevtoolsContext` (see [#387](https://github.com/FormidableLabs/urql/pull/387) and [#388](https://github.com/FormidableLabs/urql/pull/388))\n- ✨ Add support for polling with `pollInterval` argument to `useQuery`, by [@mxstbr](https://github.com/mxstbr) (see [#397](https://github.com/FormidableLabs/urql/pull/397))\n- ⚠ Prevent `__typename` from being added to the toplevel GraphQL documents (see [#399](https://github.com/FormidableLabs/urql/pull/399))\n- Add `operationName` field to `fetch` request body (see [#401](https://github.com/FormidableLabs/urql/pull/401))\n\n## 1.3.0\n\nThis release comes with some important fixes and enhancements, which all address\ncertain edge-cases when using `urql`.\n\nIt fixes the `cache-and-network` request policy, which wouldn't always work correctly and issue another network request after resolving a response from the default cache. We also had a major bug in React Native environments where responses wouldn't ever be reflected in the `useQuery` hook's state. Lastly, you can now use `extensions` from your GraphQL servers and modify the `OperationContext` from the hooks options.\n\n- ✨ Add support for `extensions` key in GraphQL responses, by [@adamscybot](https://github.com/adamscybot) (see [#355](https://github.com/FormidableLabs/urql/pull/355))\n- ⚠ Fix `cache-and-network` request policy by adding operation flushing to the client (see [#356](https://github.com/FormidableLabs/urql/pull/356))\n- Add `fetch` option to the Client so it doesn't have to be polyfilled globally (see [#357](https://github.com/FormidableLabs/urql/pull/357) and [#359](https://github.com/FormidableLabs/urql/pull/359))\n- ⚠ Fix `useImmediateState` for React Native environments (see [#358](https://github.com/FormidableLabs/urql/pull/358))\n- ✨ Add `context` option to all hooks to allow `OperationContext` to be changed dynamically (see [#351](https://github.com/FormidableLabs/urql/pull/351))\n- Add `isClient` option to `ssrExchange` in case `suspense` is activated on the client-side (see [#369](https://github.com/FormidableLabs/urql/pull/369))\n\n## 1.2.0\n\nA release focused on improving developer experience (in preparation for the\nupcoming devtools) as well as minor documentation improvements and bug fixes.\n\n- Add metadata to operation context in development (see [#305](https://github.com/FormidableLabs/urql/pull/305), [#324](https://github.com/FormidableLabs/urql/pull/324), [#325](https://github.com/FormidableLabs/urql/pull/325) and [#329](https://github.com/FormidableLabs/urql/pull/329))\n- Fix minor typename memory leak (see [#321](https://github.com/FormidableLabs/urql/pull/321))\n- Fix types for react subscription components (see [#328](https://github.com/FormidableLabs/urql/pull/328))\n- Fix displayName attributes not populated in examples (see [#330](https://github.com/FormidableLabs/urql/pull/330))\n- Fix error in `collectTypes` method (see [#343](https://github.com/FormidableLabs/urql/pull/343))\n- Fix HTTP status bounds check error (see [#348](https://github.com/FormidableLabs/urql/pull/348/files))\n\n## 1.1.3\n\nThis is a hotfix that patches a small regression from `1.1.2` where\n`useQuery` would crash due to an incorrect teardown function from pause.\n\n- Fix `executeQuery` dispose function when `pause` is set, by[@JoviDeCroock](https://github.com/JoviDeCroock) (see [#315](https://github.com/FormidableLabs/urql/pull/315))\n\n## 1.1.2\n\nThis patch fixes a small bug that usually manifests in development,\nwhere the initial state would be incorrect after a fast response from\nthe GraphQL API. This used to lock the state into `fetching: true`\nindefinitely in some cases.\n\n- Export all TS types for components (see [#312](https://github.com/FormidableLabs/urql/pull/312))\n- ⚠️ Fix state getting stuck on initial mount for fast responses (see [#310](https://github.com/FormidableLabs/urql/pull/310))\n- Refactor build tooling to be driven only by Rollup (see [#306](https://github.com/FormidableLabs/urql/pull/306))\n- Remove dev-only dependencies from `dependencies` (see [#304](https://github.com/FormidableLabs/urql/pull/304))\n\n## 1.1.1\n\nThis release comes with two small patches. One being a critical fix,\nwhere cancelled requests would be erroneously deduped, which meant\na previously cancelled query would never be fetched.\n\nIt also refactors our bundling process to transpile `Object.assign` to\nrestore IE11 support and reduce the amount of duplicate helper in our bundles.\n\n- ⚠️ Fix torn-down requests being deduped forever (see [#281](https://github.com/FormidableLabs/urql/pull/281))\n- Fix `useQuery`'s `pause` argument blocking explicit `executeQuery` calls (see [#278](https://github.com/FormidableLabs/urql/pull/278))\n- Add `Object.assign` transpilation for IE11 and refactor bundling (see [#274](https://github.com/FormidableLabs/urql/pull/274))\n\n## 1.1.0\n\nThis release introduces support for **server-side rendering**.\nYou can find out more about it by reading\n[the new Basics section on how to set it up.](https://github.com/FormidableLabs/urql/blob/master/docs/basics.md#server-side-rendering)\n\nThis version now also requires a version of React supporting hooks! (>= 16.8.0)\nWe unfortunately forgot to correct the `peerDependencies` entries in our v1.0.0 release.\n\n- ✨ Add **server-side rendering** support (see [#268](https://github.com/FormidableLabs/urql/pull/268))\n- ✨ Ensure that state changes are applied immediately on mount (see [#256](https://github.com/FormidableLabs/urql/pull/256))\n- Ensure that effects are run immediately on mount (see [#250](https://github.com/FormidableLabs/urql/pull/250))\n- ⚠️ Remove `create-react-context` and bump React peer dependency (see [#252](https://github.com/FormidableLabs/urql/pull/252))\n- Add generics to the `Query`, `Mutation`, and `Subscription` components\n- ⚠️ Fix issues where `useQuery` wouldn't update or teardown correctly (see [#243](https://github.com/FormidableLabs/urql/pull/243))\n- ✨ Add support for `pause` prop/option to `useQuery` and `Query` (see [#237](https://github.com/FormidableLabs/urql/pull/237))\n\n## 1.0.5\n\n- Export `MutationProps` types for TS typings, by [@mxstbr](https://github.com/mxstbr) (see [#236](https://github.com/FormidableLabs/urql/pull/236))\n- Export `Use*Args` types for TS typings, by [@mxstbr](https://github.com/mxstbr) (see [#235](https://github.com/FormidableLabs/urql/pull/235))\n- Export all hook response types for TS typings, by [@good-idea](https://github.com/good-idea) (see [#233](https://github.com/FormidableLabs/urql/pull/233))\n- ⚠ Fix runtime error in `cachExchange` where already deleted keys where being accessed (see [#223](https://github.com/FormidableLabs/urql/pull/223))\n- ⚠️ Fix `cacheExchange` not forwarding teardowns correctly, which lead to unnecessary/outdated queries being executed, by [@federicobadini](https://github.com/federicobadini) (see [#222](https://github.com/FormidableLabs/urql/pull/222))\n- Change `GraphQLRequest` to always pass on a parsed GraphQL `DocumentNode` instead of just a string, which reduces work (see [#221](https://github.com/FormidableLabs/urql/pull/221))\n- Fix incorrect TS types by using `Omit<T, K>` (see [#220](https://github.com/FormidableLabs/urql/pull/220))\n\n## 1.0.4\n\n- Fix `__typename` not being extracted from responses correctly, which broke caching\n- Fix `fetchOptions` being called in the client instead of the `fetchExchange`\n- Improve `CombinedError` to actually extend `Error` and rehydrate `GraphQLError` instances\n- Fix `executeMutation` prop not accepting any generics types\n\n## 1.0.3\n\n- Fix bug where `variables` were only compared using reference equality, leading to\n  infinite rerenders\n\n## 1.0.2\n\n- Allow `graphql-tag` / `DocumentNode` usage; Operations' queries can now be `DocumentNode`s\n- Generating keys for queries has been optimized\n\nhttps://github.com/FormidableLabs/urql/compare/v1.0.4...v1.0.5\n\n## 1.0.0\n\n> Since the entire library has been rewritten for v1.0.0, no changes\n> are listed here!\n\n`urql` v1 is more customisable than ever with \"Exchanges\", which\nallow you to change every aspect of how `urql` works.\n"
  },
  {
    "path": "packages/react-urql/README.md",
    "content": "# urql\n\n> A highly customizable and versatile GraphQL client **for React**\n\nMore documentation is available at [formidable.com/open-source/urql](https://formidable.com/open-source/urql/).\n"
  },
  {
    "path": "packages/react-urql/core/index.d.ts",
    "content": "export * from '@urql/core';\n"
  },
  {
    "path": "packages/react-urql/core/index.esm.js",
    "content": "export * from '@urql/core';\n"
  },
  {
    "path": "packages/react-urql/core/index.js",
    "content": "module.exports = require('@urql/core');\n"
  },
  {
    "path": "packages/react-urql/core/package.json",
    "content": "{\n  \"name\": \"urql-core\",\n  \"private\": true,\n  \"main\": \"index.js\",\n  \"module\": \"index.esm.js\",\n  \"types\": \"index.d.ts\",\n  \"dependencies\": {\n    \"@urql/core\": \"^1.7.0\"\n  }\n}\n"
  },
  {
    "path": "packages/react-urql/cypress/fixtures/example.json",
    "content": "{\n  \"name\": \"Using fixtures to represent data\",\n  \"email\": \"hello@cypress.io\",\n  \"body\": \"Fixtures are a great way to mock data for responses to routes\"\n}\n"
  },
  {
    "path": "packages/react-urql/cypress/support/component-index.html",
    "content": "<!doctype html>\n<html>\n  <head>\n    <meta charset=\"utf-8\" />\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\" />\n    <meta name=\"viewport\" content=\"width=device-width,initial-scale=1.0\" />\n    <title>Components App</title>\n  </head>\n  <body>\n    <div data-cy-root></div>\n  </body>\n</html>\n"
  },
  {
    "path": "packages/react-urql/cypress/support/component.js",
    "content": "// ***********************************************************\n// This example support/component.js is processed and\n// loaded automatically before your test files.\n//\n// This is a great place to put global configuration and\n// behavior that modifies Cypress.\n//\n// You can change the location of this file or turn off\n// automatically serving support files with the\n// 'supportFile' configuration option.\n//\n// You can read more here:\n// https://on.cypress.io/configuration\n// ***********************************************************\n\nimport { mount } from 'cypress/react';\n\nCypress.Commands.add('mount', mount);\n"
  },
  {
    "path": "packages/react-urql/cypress.config.js",
    "content": "// eslint-disable-next-line\nconst { defineConfig } = require('cypress');\n// eslint-disable-next-line\nconst tsconfigPaths = require('vite-tsconfig-paths').default;\n\nmodule.exports = defineConfig({\n  video: false,\n\n  e2e: {\n    setupNodeEvents(_on, _config) {\n      /*noop*/\n    },\n    supportFile: false,\n  },\n  component: {\n    specPattern: './**/e2e-tests/*spec.tsx',\n    devServer: {\n      framework: 'react',\n      bundler: 'vite',\n      viteConfig: {\n        plugins: [tsconfigPaths()],\n        server: {\n          fs: {\n            allow: ['..'],\n          },\n        },\n      },\n    },\n  },\n});\n"
  },
  {
    "path": "packages/react-urql/e2e-tests/useQuery.spec.tsx",
    "content": "/// <reference types=\"cypress\" />\n\nimport * as React from 'react';\nimport { mount } from '@cypress/react';\nimport { delay, pipe } from 'wonka';\n\nimport {\n  Provider,\n  createClient,\n  gql,\n  useQuery,\n  cacheExchange,\n  fetchExchange,\n  Exchange,\n} from '../src';\n\nconst delayExchange: Exchange = ({ forward }) => {\n  return ops$ => {\n    return pipe(ops$, forward, delay(250));\n  };\n};\n\nconst Boundary = props => {\n  return (\n    <React.Suspense fallback={<p id=\"suspense\">Loading...</p>}>\n      {props.children}\n    </React.Suspense>\n  );\n};\n\ndescribe('Suspense', () => {\n  let UrqlProvider;\n\n  const PokemonsQuery = gql`\n    query ($skip: Int!) {\n      pokemons(limit: 10, skip: $skip) {\n        id\n        name\n      }\n    }\n  `;\n\n  const Pokemons = () => {\n    const [skip, setSkip] = React.useState(0);\n    const [result] = useQuery({ query: PokemonsQuery, variables: { skip } });\n\n    return (\n      <main>\n        <ul id=\"pokemon-list\">\n          {result.data.pokemons.map(pokemon => (\n            <li key={pokemon.id}>\n              {pokemon.id}. {pokemon.name}\n            </li>\n          ))}\n        </ul>\n        {skip > 0 && (\n          <button id=\"previous-page\" onClick={() => setSkip(skip - 10)}>\n            Previous Page\n          </button>\n        )}\n        <button id=\"next-page\" onClick={() => setSkip(skip + 10)}>\n          Next Page\n        </button>\n      </main>\n    );\n  };\n\n  beforeEach(() => {\n    const client = createClient({\n      url: 'https://trygql.formidable.dev/graphql/basic-pokedex',\n      suspense: true,\n      exchanges: [cacheExchange, delayExchange, fetchExchange],\n    });\n\n    // eslint-disable-next-line\n    UrqlProvider = props => {\n      return <Provider value={client}>{props.children}</Provider>;\n    };\n  });\n\n  it('Suspends for a basic query', () => {\n    mount(\n      <UrqlProvider>\n        <Boundary>\n          <Pokemons />\n        </Boundary>\n      </UrqlProvider>\n    );\n\n    cy.get('#suspense').contains('Loading...');\n    cy.get('#pokemon-list > li').then(items => {\n      expect(items.length).to.equal(10);\n    });\n  });\n\n  it('Suspends when changing variables', () => {\n    mount(\n      <UrqlProvider>\n        <Boundary>\n          <Pokemons />\n        </Boundary>\n      </UrqlProvider>\n    );\n\n    cy.get('#suspense').contains('Loading...');\n    cy.get('#pokemon-list > li').then(items => {\n      expect(items.length).to.equal(10);\n    });\n\n    cy.get('#next-page').click();\n    cy.get('#suspense').contains('Loading...');\n    cy.get('#pokemon-list > li').then(items => {\n      expect(items.length).to.equal(10);\n    });\n  });\n\n  it('Does not suspend for pages that already have been cached', () => {\n    mount(\n      <UrqlProvider>\n        <Boundary>\n          <Pokemons />\n        </Boundary>\n      </UrqlProvider>\n    );\n\n    cy.get('#suspense').contains('Loading...');\n    cy.get('#pokemon-list > li').then(items => {\n      expect(items.length).to.equal(10);\n    });\n\n    cy.get('#next-page').click();\n    cy.get('#suspense').contains('Loading...');\n    cy.get('#pokemon-list > li').then(items => {\n      expect(items.length).to.equal(10);\n    });\n\n    cy.get('#previous-page').click();\n    cy.get('#suspense').should('not.exist');\n    cy.get('#pokemon-list > li').then(items => {\n      expect(items.length).to.equal(10);\n    });\n  });\n\n  it('does not cause an infinite loop with multiple components querying the same thing', () => {\n    mount(\n      <UrqlProvider>\n        <Boundary>\n          <Pokemons />\n          <Pokemons />\n          <Pokemons />\n        </Boundary>\n      </UrqlProvider>\n    );\n\n    cy.get('#suspense').contains('Loading...');\n    cy.get('ul').then(items => {\n      expect(items.length).to.equal(3);\n    });\n  });\n});\n\ndescribe('executeQuery', () => {\n  let UrqlProvider;\n\n  const PokemonsQuery = gql`\n    query {\n      pokemons(limit: 10) {\n        id\n        name\n      }\n    }\n  `;\n\n  const Pokemons = () => {\n    const [result, excuteQuery] = useQuery({ query: PokemonsQuery });\n\n    if (result.fetching) return <p id=\"loading\">Loading...</p>;\n\n    return (\n      <main>\n        <ul id=\"pokemon-list\">\n          {result.data.pokemons.map(pokemon => (\n            <li key={pokemon.id}>\n              {pokemon.id}. {pokemon.name}\n            </li>\n          ))}\n        </ul>\n        <button\n          id=\"refetch\"\n          onClick={() => excuteQuery({ requestPolicy: 'network-only' })}\n        >\n          Refetch\n        </button>\n      </main>\n    );\n  };\n\n  beforeEach(() => {\n    const client = createClient({\n      url: 'https://trygql.formidable.dev/graphql/basic-pokedex',\n      suspense: false,\n      exchanges: [cacheExchange, delayExchange, fetchExchange],\n    });\n\n    // eslint-disable-next-line\n    UrqlProvider = props => {\n      return <Provider value={client}>{props.children}</Provider>;\n    };\n  });\n\n  it('should set \"fetching\" to true when reexecuting', () => {\n    mount(\n      <UrqlProvider>\n        <Pokemons />\n      </UrqlProvider>\n    );\n\n    cy.get('#loading').contains('Loading...');\n    cy.get('#pokemon-list > li').then(items => {\n      expect(items.length).to.equal(10);\n    });\n\n    cy.get('#refetch').click();\n    cy.get('#loading').contains('Loading...');\n    cy.get('#pokemon-list > li').then(items => {\n      expect(items.length).to.equal(10);\n    });\n  });\n});\n"
  },
  {
    "path": "packages/react-urql/jsr.json",
    "content": "{\n  \"name\": \"urql\",\n  \"version\": \"5.0.1\",\n  \"exports\": \"src/index.ts\",\n  \"exclude\": [\n    \"node_modules\",\n    \"cypress\",\n    \"**/*.test.*\",\n    \"**/*.spec.*\",\n    \"**/*.test.*.snap\",\n    \"**/*.spec.*.snap\"\n  ]\n}"
  },
  {
    "path": "packages/react-urql/package.json",
    "content": "{\n  \"name\": \"urql\",\n  \"version\": \"5.0.1\",\n  \"description\": \"A highly customizable and versatile GraphQL client for React\",\n  \"sideEffects\": false,\n  \"homepage\": \"https://formidable.com/open-source/urql/docs/\",\n  \"bugs\": \"https://github.com/urql-graphql/urql/issues\",\n  \"license\": \"MIT\",\n  \"author\": \"urql GraphQL Contributors\",\n  \"repository\": {\n    \"type\": \"git\",\n    \"url\": \"https://github.com/urql-graphql/urql.git\",\n    \"directory\": \"packages/react-urql\"\n  },\n  \"keywords\": [\n    \"graphql client\",\n    \"state management\",\n    \"cache\",\n    \"graphql\",\n    \"exchanges\",\n    \"react\"\n  ],\n  \"main\": \"dist/urql.js\",\n  \"module\": \"dist/urql.es.js\",\n  \"types\": \"dist/urql.d.ts\",\n  \"source\": \"src/index.ts\",\n  \"files\": [\n    \"LICENSE\",\n    \"CHANGELOG.md\",\n    \"README.md\",\n    \"core/\",\n    \"dist/\"\n  ],\n  \"scripts\": {\n    \"test\": \"vitest\",\n    \"clean\": \"rimraf dist\",\n    \"check\": \"tsc --noEmit\",\n    \"lint\": \"eslint --ext=js,jsx,ts,tsx .\",\n    \"build\": \"rollup -c ../../scripts/rollup/config.mjs\",\n    \"prepare\": \"node ../../scripts/prepare/index.js\",\n    \"prepublishOnly\": \"run-s clean build\"\n  },\n  \"devDependencies\": {\n    \"@cypress/react\": \"^8.0.2\",\n    \"@cypress/vite-dev-server\": \"^5.2.0\",\n    \"@testing-library/react\": \"^16.0.1\",\n    \"@types/react\": \"^18.3.8\",\n    \"@types/react-test-renderer\": \"^17.0.1\",\n    \"@urql/core\": \"workspace:*\",\n    \"cypress\": \"^13.14.0\",\n    \"graphql\": \"^16.6.0\",\n    \"react\": \"^18.3.1\",\n    \"react-dom\": \"^18.3.1\",\n    \"react-is\": \"^18.3.1\",\n    \"react-ssr-prepass\": \"^1.5.0\",\n    \"react-test-renderer\": \"^18.3.1\"\n  },\n  \"peerDependencies\": {\n    \"@urql/core\": \"^6.0.0\",\n    \"react\": \">= 16.8.0\"\n  },\n  \"dependencies\": {\n    \"@urql/core\": \"workspace:^6.0.1\",\n    \"wonka\": \"^6.3.2\"\n  },\n  \"publishConfig\": {\n    \"provenance\": true\n  }\n}\n"
  },
  {
    "path": "packages/react-urql/src/components/Mutation.test.tsx",
    "content": "// @vitest-environment jsdom\n\nimport { vi, expect, it, beforeEach, describe, Mock, afterEach } from 'vitest';\n\nvi.mock('../context', async () => {\n  const { delay, fromValue, pipe } =\n    await vi.importActual<typeof import('wonka')>('wonka');\n\n  const mock = {\n    executeMutation: vi.fn(() =>\n      pipe(fromValue({ data: 1, error: 2 }), delay(200))\n    ),\n  };\n\n  return {\n    useClient: () => mock,\n  };\n});\n\nimport * as React from 'react';\nimport { act, cleanup, render } from '@testing-library/react';\nimport { Mutation } from './Mutation';\nimport { useClient } from '../context';\n\n// @ts-ignore\nconst client = useClient() as { executeMutation: Mock };\nconst query = 'mutation Example { example }';\n\ndescribe('Mutation', () => {\n  beforeEach(() => {\n    vi.useFakeTimers();\n    // TODO: Fix use of act()\n    vi.spyOn(globalThis.console, 'error').mockImplementation(() => {\n      // do nothing\n    });\n  });\n\n  afterEach(() => {\n    cleanup();\n  });\n\n  it('Should execute the mutation', () => {\n    let execute = () => {\n        /* noop */\n      },\n      props = {};\n    const Test = () => <p>Hi</p>;\n    const App = () => {\n      return (\n        // @ts-ignore\n        <Mutation query={query}>\n          {({ data, fetching, error, executeMutation }) => {\n            execute = executeMutation;\n            props = { data, fetching, error };\n            return <Test />;\n          }}\n        </Mutation>\n      );\n    };\n    render(<App />);\n    expect(client.executeMutation).toBeCalledTimes(0);\n    expect(props).toStrictEqual({\n      data: undefined,\n      fetching: false,\n      error: undefined,\n    });\n    act(() => {\n      execute();\n    });\n    expect(props).toStrictEqual({\n      data: undefined,\n      fetching: true,\n      error: undefined,\n    });\n    act(() => {\n      vi.advanceTimersByTime(400);\n    });\n    expect(props).toStrictEqual({ data: 1, fetching: false, error: 2 });\n  });\n});\n"
  },
  {
    "path": "packages/react-urql/src/components/Mutation.ts",
    "content": "import type { ReactElement } from 'react';\nimport type { AnyVariables, DocumentInput } from '@urql/core';\n\nimport type { UseMutationState, UseMutationExecute } from '../hooks';\nimport { useMutation } from '../hooks';\n\n/** Props accepted by {@link Mutation}.\n *\n * @remarks\n * `MutationProps` are the props accepted by the {@link Mutation} component.\n *\n * The result, the {@link MutationState} object, will be passed to\n * a {@link MutationProps.children} function, passed as children\n * to the `Mutation` component.\n */\nexport interface MutationProps<\n  Data = any,\n  Variables extends AnyVariables = AnyVariables,\n> {\n  /* The GraphQL mutation document that {@link useMutation} will execute. */\n  query: DocumentInput<Data, Variables>;\n  children(arg: MutationState<Data, Variables>): ReactElement<any>;\n}\n\n/** Object that {@link MutationProps.children} is called with.\n *\n * @remarks\n * This is an extented {@link UseMutationstate} with an added\n * {@link MutationState.executeMutation} method, which is usually\n * part of a tuple returned by {@link useMutation}.\n */\nexport interface MutationState<\n  Data = any,\n  Variables extends AnyVariables = AnyVariables,\n> extends UseMutationState<Data, Variables> {\n  /** Alias to {@link useMutation}’s `executeMutation` function. */\n  executeMutation: UseMutationExecute<Data, Variables>;\n}\n\n/** Component Wrapper around {@link useMutation} to run a GraphQL query.\n *\n * @remarks\n * `Mutation` is a component wrapper around the {@link useMutation} hook\n * that calls the {@link MutationProps.children} prop, as a function,\n * with the {@link MutationState} object.\n */\nexport function Mutation<\n  Data = any,\n  Variables extends AnyVariables = AnyVariables,\n>(props: MutationProps<Data, Variables>): ReactElement<any> {\n  const mutation = useMutation<Data, Variables>(props.query);\n  return props.children({ ...mutation[0], executeMutation: mutation[1] });\n}\n"
  },
  {
    "path": "packages/react-urql/src/components/Query.test.tsx",
    "content": "// @vitest-environment jsdom\n\nimport { vi, expect, it, beforeEach, describe, afterEach } from 'vitest';\n\nvi.mock('../context', async () => {\n  const { map, interval, pipe } =\n    await vi.importActual<typeof import('wonka')>('wonka');\n\n  const mock = {\n    executeQuery: vi.fn(() =>\n      pipe(\n        interval(150),\n        map((i: number) => ({ data: i, error: i + 1 }))\n      )\n    ),\n  };\n\n  return {\n    useClient: () => mock,\n  };\n});\n\nimport * as React from 'react';\nimport { cleanup, render } from '@testing-library/react';\nimport { Query } from './Query';\n\n// @ts-ignore\nconst query = '{ example }';\nconst variables = {\n  myVar: 1234,\n};\n\ndescribe('Query', () => {\n  beforeEach(() => {\n    // TODO: Fix use of act()\n    vi.spyOn(globalThis.console, 'error').mockImplementation(() => {\n      // do nothing\n    });\n  });\n\n  afterEach(() => {\n    cleanup();\n  });\n\n  it('Should execute the query', async () => {\n    let props = {};\n    const Test = () => <p>Hi</p>;\n    const App = () => {\n      return (\n        // @ts-ignore\n        <Query query={query} variables={variables}>\n          {({ data, fetching, error }) => {\n            props = { data, fetching, error };\n            return <Test />;\n          }}\n        </Query>\n      );\n    };\n    render(<App />);\n    expect(props).toStrictEqual({\n      data: undefined,\n      fetching: true,\n      error: undefined,\n    });\n    await new Promise(res => {\n      setTimeout(() => {\n        expect(props).toStrictEqual({ data: 0, fetching: false, error: 1 });\n        res(null);\n      }, 200);\n    });\n  });\n});\n"
  },
  {
    "path": "packages/react-urql/src/components/Query.ts",
    "content": "import type { ReactElement } from 'react';\nimport type { AnyVariables } from '@urql/core';\n\nimport type { UseQueryArgs, UseQueryState, UseQueryExecute } from '../hooks';\nimport { useQuery } from '../hooks';\n\n/** Props accepted by {@link Query}.\n *\n * @remarks\n * `QueryProps` are the props accepted by the {@link Query} component,\n * which is identical to {@link UseQueryArgs}.\n *\n * The result, the {@link QueryState} object, will be passed to\n * a {@link QueryProps.children} function, passed as children\n * to the `Query` component.\n */\nexport type QueryProps<\n  Data = any,\n  Variables extends AnyVariables = AnyVariables,\n> = UseQueryArgs<Variables, Data> & {\n  children(arg: QueryState<Data, Variables>): ReactElement<any>;\n};\n\n/** Object that {@link QueryProps.children} is called with.\n *\n * @remarks\n * This is an extented {@link UseQueryState} with an added\n * {@link QueryState.executeQuery} method, which is usually\n * part of a tuple returned by {@link useQuery}.\n */\nexport interface QueryState<\n  Data = any,\n  Variables extends AnyVariables = AnyVariables,\n> extends UseQueryState<Data, Variables> {\n  /** Alias to {@link useQuery}’s `executeQuery` function. */\n  executeQuery: UseQueryExecute;\n}\n\n/** Component Wrapper around {@link useQuery} to run a GraphQL query.\n *\n * @remarks\n * `Query` is a component wrapper around the {@link useQuery} hook\n * that calls the {@link QueryProps.children} prop, as a function,\n * with the {@link QueryState} object.\n */\nexport function Query<\n  Data = any,\n  Variables extends AnyVariables = AnyVariables,\n>(props: QueryProps<Data, Variables>): ReactElement<any> {\n  const query = useQuery<Data, Variables>(props);\n  return props.children({ ...query[0], executeQuery: query[1] });\n}\n"
  },
  {
    "path": "packages/react-urql/src/components/Subscription.ts",
    "content": "import type { ReactElement } from 'react';\nimport type { AnyVariables } from '@urql/core';\n\nimport type {\n  UseSubscriptionArgs,\n  UseSubscriptionState,\n  UseSubscriptionExecute,\n  SubscriptionHandler,\n} from '../hooks';\nimport { useSubscription } from '../hooks';\n\n/** Props accepted by {@link Subscription}.\n *\n * @remarks\n * `SubscriptionProps` are the props accepted by the {@link Subscription} component,\n * which is identical to {@link UseSubscriptionArgs} with an added\n * {@link SubscriptionProps.handler} prop, which {@link useSubscription} usually\n * accepts as an additional argument.\n *\n * The result, the {@link SubscriptionState} object, will be passed to\n * a {@link SubscriptionProps.children} function, passed as children\n * to the `Subscription` component.\n */\nexport type SubscriptionProps<\n  Data = any,\n  Result = Data,\n  Variables extends AnyVariables = AnyVariables,\n> = UseSubscriptionArgs<Variables, Data> & {\n  handler?: SubscriptionHandler<Data, Result>;\n  children(arg: SubscriptionState<Result, Variables>): ReactElement<any>;\n};\n\n/** Object that {@link SubscriptionProps.children} is called with.\n *\n * @remarks\n * This is an extented {@link UseSubscriptionState} with an added\n * {@link SubscriptionState.executeSubscription} method, which is usually\n * part of a tuple returned by {@link useSubscription}.\n */\nexport interface SubscriptionState<\n  Data = any,\n  Variables extends AnyVariables = AnyVariables,\n> extends UseSubscriptionState<Data, Variables> {\n  /** Alias to {@link useSubscription}’s `executeMutation` function. */\n  executeSubscription: UseSubscriptionExecute;\n}\n\n/** Component Wrapper around {@link useSubscription} to run a GraphQL subscription.\n *\n * @remarks\n * `Subscription` is a component wrapper around the {@link useSubscription} hook\n * that calls the {@link SubscriptionProps.children} prop, as a function,\n * with the {@link SubscriptionState} object.\n */\nexport function Subscription<\n  Data = any,\n  Result = Data,\n  Variables extends AnyVariables = AnyVariables,\n>(props: SubscriptionProps<Data, Result, Variables>): ReactElement<any> {\n  const subscription = useSubscription<Data, Result, Variables>(\n    props,\n    props.handler\n  );\n\n  return props.children({\n    ...subscription[0],\n    executeSubscription: subscription[1],\n  });\n}\n"
  },
  {
    "path": "packages/react-urql/src/components/index.ts",
    "content": "export * from './Mutation';\nexport * from './Query';\nexport * from './Subscription';\n"
  },
  {
    "path": "packages/react-urql/src/context.ts",
    "content": "import * as React from 'react';\nimport type { Client } from '@urql/core';\n\nconst OBJ = {};\n\n/** `urql`'s React Context.\n *\n * @remarks\n * The React Context that `urql`’s {@link Client} will be provided with.\n * You may use the reexported {@link Provider} to provide a `Client` as well.\n */\nexport const Context: import('react').Context<Client | object> =\n  React.createContext(OBJ);\n\n/** Provider for `urql`'s {@link Client} to GraphQL hooks.\n *\n * @remarks\n * `Provider` accepts a {@link Client} and provides it to all GraphQL hooks,\n * and {@link useClient}.\n *\n * You should make sure to create a {@link Client} and provide it with the\n * `Provider` to parts of your component tree that use GraphQL hooks.\n *\n * @example\n * ```tsx\n * import { Provider } from 'urql';\n * // All of `@urql/core` is also re-exported by `urql`:\n * import { Client, cacheExchange, fetchExchange } from '@urql/core';\n *\n * const client = new Client({\n *   url: 'https://API',\n *   exchanges: [cacheExchange, fetchExchange],\n * });\n *\n * const App = () => (\n *   <Provider value={client}>\n *     <Component />\n *   </Provider>\n * );\n * ```\n */\nexport const Provider: React.Provider<Client | object> = Context.Provider;\n\n/** React Consumer component, providing the {@link Client} provided on a parent component.\n * @remarks\n * This is an alias for {@link Context.Consumer}.\n */\nexport const Consumer: React.Consumer<Client | object> = Context.Consumer;\n\nContext.displayName = 'UrqlContext';\n\n/** Hook returning a {@link Client} from {@link Context}.\n *\n * @remarks\n * `useClient` is a convenience hook, which accesses `urql`'s {@link Context}\n * and returns the {@link Client} defined on it.\n *\n * This will be the {@link Client} you passed to a {@link Provider}\n * you wrapped your elements containing this hook with.\n *\n * @throws\n * In development, if the component you call `useClient()` in is\n * not wrapped in a {@link Provider}, an error is thrown.\n */\nexport const useClient = (): Client => {\n  const client = React.useContext(Context);\n\n  if (client === OBJ && process.env.NODE_ENV !== 'production') {\n    const error =\n      \"No client has been specified using urql's Provider. please create a client and add a Provider.\";\n\n    console.error(error);\n    throw new Error(error);\n  }\n\n  return client as Client;\n};\n"
  },
  {
    "path": "packages/react-urql/src/hooks/__snapshots__/useMutation.test.tsx.snap",
    "content": "// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html\n\nexports[`on initial useEffect > initialises default state 1`] = `\n{\n  \"data\": undefined,\n  \"error\": undefined,\n  \"extensions\": undefined,\n  \"fetching\": false,\n  \"hasNext\": false,\n  \"operation\": undefined,\n  \"stale\": false,\n}\n`;\n"
  },
  {
    "path": "packages/react-urql/src/hooks/__snapshots__/useQuery.test.tsx.snap",
    "content": "// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html\n\nexports[`on initial useEffect > initialises default state 1`] = `\n{\n  \"data\": undefined,\n  \"error\": undefined,\n  \"extensions\": undefined,\n  \"fetching\": true,\n  \"hasNext\": false,\n  \"operation\": undefined,\n  \"stale\": false,\n}\n`;\n"
  },
  {
    "path": "packages/react-urql/src/hooks/__snapshots__/useSubscription.test.tsx.snap",
    "content": "// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html\n\nexports[`on initial useEffect > initialises default state 1`] = `\n{\n  \"data\": undefined,\n  \"error\": undefined,\n  \"extensions\": undefined,\n  \"fetching\": true,\n  \"hasNext\": false,\n  \"operation\": undefined,\n  \"stale\": false,\n}\n`;\n"
  },
  {
    "path": "packages/react-urql/src/hooks/cache.ts",
    "content": "import { pipe, subscribe } from 'wonka';\nimport type { Client, OperationResult } from '@urql/core';\n\ntype CacheEntry = OperationResult | Promise<unknown> | undefined;\n\ninterface Cache {\n  get(key: number): CacheEntry;\n  set(key: number, value: CacheEntry): void;\n  dispose(key: number): void;\n}\n\ninterface ClientWithCache extends Client {\n  _react?: Cache;\n}\n\nexport const getCacheForClient = (client: Client): Cache => {\n  if (!(client as ClientWithCache)._react) {\n    const reclaim = new Set();\n    const map = new Map<number, CacheEntry>();\n\n    if (client.operations$ /* not available in mocks */) {\n      pipe(\n        client.operations$,\n        subscribe(operation => {\n          if (operation.kind === 'teardown' && reclaim.has(operation.key)) {\n            reclaim.delete(operation.key);\n            map.delete(operation.key);\n          }\n        })\n      );\n    }\n\n    (client as ClientWithCache)._react = {\n      get(key) {\n        return map.get(key);\n      },\n      set(key, value) {\n        reclaim.delete(key);\n        map.set(key, value);\n      },\n      dispose(key) {\n        reclaim.add(key);\n      },\n    };\n  }\n\n  return (client as ClientWithCache)._react!;\n};\n"
  },
  {
    "path": "packages/react-urql/src/hooks/index.ts",
    "content": "export * from './useMutation';\nexport * from './useQuery';\nexport * from './useSubscription';\n"
  },
  {
    "path": "packages/react-urql/src/hooks/state.ts",
    "content": "import type { Dispatch } from 'react';\n\nexport const initialState = {\n  fetching: false,\n  stale: false,\n  hasNext: false,\n  error: undefined,\n  data: undefined,\n  extensions: undefined,\n  operation: undefined,\n};\n\n// Two operations are considered equal if they have the same key\nconst areOperationsEqual = (\n  a: { key: number } | undefined,\n  b: { key: number } | undefined\n) => {\n  return a === b || !!(a && b && a.key === b.key);\n};\n\n/**\n * Checks if two objects are shallowly different with a special case for\n * 'operation' where it compares the key if they are not the otherwise equal\n */\nconst isShallowDifferent = <T extends Record<string, any>>(a: T, b: T) => {\n  for (const key in a) if (!(key in b)) return true;\n  for (const key in b) {\n    if (\n      key === 'operation'\n        ? !areOperationsEqual(a[key], b[key])\n        : a[key] !== b[key]\n    ) {\n      return true;\n    }\n  }\n  return false;\n};\n\ninterface Stateish {\n  data?: any;\n  error?: any;\n  hasNext: boolean;\n  fetching: boolean;\n  stale: boolean;\n}\n\nexport const computeNextState = <T extends Stateish>(\n  prevState: T,\n  result: Partial<T>\n): T => {\n  const newState: T = {\n    ...prevState,\n    ...result,\n    data:\n      result.data !== undefined || result.error ? result.data : prevState.data,\n    fetching: !!result.fetching,\n    stale: !!result.stale,\n  };\n\n  return isShallowDifferent(prevState, newState) ? newState : prevState;\n};\n\nexport const hasDepsChanged = <T extends { length: number }>(a: T, b: T) => {\n  for (let i = 0, l = b.length; i < l; i++) if (a[i] !== b[i]) return true;\n  return false;\n};\n\nlet isDispatching = false;\n\nfunction deferDispatch<F extends Dispatch<any>>(\n  setState: F,\n  value: F extends Dispatch<infer State> ? State : void\n): void;\n\nfunction deferDispatch<F extends Dispatch<any>>(setState: F): ReturnType<F>;\n\nfunction deferDispatch<F extends Dispatch<any>>(\n  setState: F,\n  value?: F extends Dispatch<infer State> ? State : void\n): any {\n  if (!isDispatching || value === undefined) {\n    try {\n      isDispatching = true;\n      return setState(value);\n    } finally {\n      isDispatching = false;\n    }\n  } else {\n    Promise.resolve(value).then(setState);\n  }\n}\n\nexport { deferDispatch };\n"
  },
  {
    "path": "packages/react-urql/src/hooks/useMutation.test.tsx",
    "content": "// @vitest-environment jsdom\n\nimport { vi, expect, it, beforeEach, describe, Mock } from 'vitest';\n\n// Note: Testing for hooks is not yet supported in Enzyme - https://github.com/airbnb/enzyme/issues/2011\nvi.mock('../context', async () => {\n  const { delay, fromValue, pipe } =\n    await vi.importActual<typeof import('wonka')>('wonka');\n\n  const mock = {\n    executeMutation: vi.fn(() =>\n      pipe(fromValue({ data: 1, error: 2, extensions: { i: 1 } }), delay(200))\n    ),\n  };\n\n  return {\n    useClient: () => mock,\n  };\n});\n\nimport { print } from 'graphql';\nimport { gql } from '@urql/core';\nimport React from 'react';\nimport renderer, { act } from 'react-test-renderer';\n\nimport { useClient } from '../context';\nimport { useMutation } from './useMutation';\n\n// @ts-ignore\nconst client = useClient() as { executeMutation: Mock };\n\nconst props = {\n  query: 'mutation Example { example }',\n};\n\nlet state: any;\nlet execute: any;\n\nconst MutationUser = ({ query }: { query: any }) => {\n  const [s, e] = useMutation(query);\n  state = s;\n  execute = e;\n  return <p>{s.data}</p>;\n};\n\nbeforeEach(() => {\n  vi.useFakeTimers();\n\n  vi.spyOn(globalThis.console, 'error').mockImplementation(() => {\n    // do nothing\n  });\n\n  client.executeMutation.mockClear();\n  state = undefined;\n  execute = undefined;\n});\n\ndescribe('on initial useEffect', () => {\n  it('initialises default state', () => {\n    renderer.create(<MutationUser {...props} />);\n    expect(state).toMatchSnapshot();\n  });\n\n  it('does not execute subscription', () => {\n    renderer.create(<MutationUser {...props} />);\n    expect(client.executeMutation).toBeCalledTimes(0);\n  });\n});\n\ndescribe('on execute', () => {\n  const vars = { test: 1234 };\n\n  it('sets fetching to true', () => {\n    renderer.create(<MutationUser {...props} />);\n    act(() => {\n      execute(vars);\n    });\n    expect(state).toHaveProperty('fetching', true);\n  });\n\n  it('calls executeMutation', () => {\n    renderer.create(<MutationUser {...props} />);\n    act(() => {\n      execute(vars);\n    });\n    expect(client.executeMutation).toBeCalledTimes(1);\n  });\n\n  it('calls executeMutation with query', () => {\n    renderer.create(<MutationUser {...props} />);\n    act(() => {\n      execute(vars);\n    });\n\n    const call = client.executeMutation.mock.calls[0][0];\n    expect(print(call.query)).toBe(print(gql(props.query)));\n  });\n\n  it('calls executeMutation with variables', () => {\n    renderer.create(<MutationUser {...props} />);\n    act(() => {\n      execute(vars);\n    });\n    expect(client.executeMutation.mock.calls[0][0]).toHaveProperty(\n      'variables',\n      vars\n    );\n  });\n\n  it('can adjust context in executeMutation', () => {\n    renderer.create(<MutationUser {...props} />);\n    act(() => {\n      execute(vars, { url: 'test' });\n    });\n    expect(client.executeMutation.mock.calls[0][1].url).toBe('test');\n  });\n});\n\ndescribe('on subscription update', () => {\n  it('forwards data response', () => {\n    const wrapper = renderer.create(<MutationUser {...props} />);\n    execute();\n    act(() => {\n      vi.advanceTimersByTime(200);\n      wrapper.update(<MutationUser {...props} />);\n    });\n    expect(state).toHaveProperty('data', 1);\n  });\n\n  it('forwards error response', () => {\n    const wrapper = renderer.create(<MutationUser {...props} />);\n    execute();\n    act(() => {\n      vi.advanceTimersByTime(200);\n      wrapper.update(<MutationUser {...props} />);\n    });\n    expect(state).toHaveProperty('error', 2);\n  });\n\n  it('forwards extensions response', () => {\n    const wrapper = renderer.create(<MutationUser {...props} />);\n    execute();\n    act(() => {\n      vi.advanceTimersByTime(200);\n      wrapper.update(<MutationUser {...props} />);\n    });\n    expect(state).toHaveProperty('extensions', { i: 1 });\n  });\n\n  it('sets fetching to false', () => {\n    const wrapper = renderer.create(<MutationUser {...props} />);\n    wrapper.update(<MutationUser {...props} />);\n\n    execute();\n    act(() => {\n      vi.advanceTimersByTime(200);\n      wrapper.update(<MutationUser {...props} />);\n    });\n    expect(state).toHaveProperty('fetching', false);\n  });\n});\n"
  },
  {
    "path": "packages/react-urql/src/hooks/useMutation.ts",
    "content": "import * as React from 'react';\nimport { pipe, onPush, filter, toPromise, take } from 'wonka';\n\nimport type {\n  AnyVariables,\n  DocumentInput,\n  OperationResult,\n  OperationContext,\n  CombinedError,\n  Operation,\n} from '@urql/core';\nimport { createRequest } from '@urql/core';\n\nimport { useClient } from '../context';\nimport { deferDispatch, initialState } from './state';\n\n/** State of the last mutation executed by your {@link useMutation} hook.\n *\n * @remarks\n * `UseMutationState` is returned (in a tuple) by {@link useMutation} and\n * gives you the {@link OperationResult} of the last mutation executed\n * with {@link UseMutationExecute}.\n *\n * Even if the mutation document passed to {@link useMutation} changes,\n * the state isn’t reset, so you can keep displaying the previous result.\n */\nexport interface UseMutationState<\n  Data = any,\n  Variables extends AnyVariables = AnyVariables,\n> {\n  /** Indicates whether `useMutation` is currently executing a mutation. */\n  fetching: boolean;\n  /** Indicates that the mutation result is not fresh.\n   *\n   * @remarks\n   * The `stale` flag is set to `true` when a new result for the mutation\n   * is expected.\n   * This is mostly unused for mutations and will rarely affect you, and\n   * is more relevant for queries.\n   *\n   * @see {@link OperationResult.stale} for the source of this value.\n   */\n  stale: boolean;\n  /** The {@link OperationResult.data} for the executed mutation. */\n  data?: Data;\n  /** The {@link OperationResult.error} for the executed mutation. */\n  error?: CombinedError;\n  /** The {@link OperationResult.extensions} for the executed mutation. */\n  extensions?: Record<string, any>;\n  /** The {@link OperationResult.hasNext} for the executed query. */\n  hasNext: boolean;\n  /** The {@link Operation} that the current state is for.\n   *\n   * @remarks\n   * This is the mutation {@link Operation} that has last been executed.\n   * When {@link UseQueryState.fetching} is `true`, this is the\n   * last `Operation` that the current state was for.\n   */\n  operation?: Operation<Data, Variables>;\n}\n\n/** Triggers {@link useMutation} to execute its GraphQL mutation operation.\n *\n * @param variables - variables using which the mutation will be executed.\n * @param context - optionally, context options that will be merged with the hook's\n * {@link UseQueryArgs.context} options and the `Client`’s options.\n * @returns the {@link OperationResult} of the mutation.\n *\n * @remarks\n * When called, {@link useMutation} will start the GraphQL mutation\n * it currently holds and use the `variables` passed to it.\n *\n * Once the mutation response comes back from the API, its\n * returned promise will resolve to the mutation’s {@link OperationResult}\n * and the {@link UseMutationState} will be updated with the result.\n *\n * @example\n * ```ts\n * const [result, executeMutation] = useMutation(UpdateTodo);\n * const start = async ({ id, title }) => {\n *   const result = await executeMutation({ id, title });\n * };\n */\nexport type UseMutationExecute<\n  Data = any,\n  Variables extends AnyVariables = AnyVariables,\n> = (\n  variables: Variables,\n  context?: Partial<OperationContext>\n) => Promise<OperationResult<Data, Variables>>;\n\n/** Result tuple returned by the {@link useMutation} hook.\n *\n * @remarks\n * Similarly to a `useState` hook’s return value,\n * the first element is the {@link useMutation}’s state, updated\n * as mutations are executed with the second value, which is\n * used to start mutations and is a {@link UseMutationExecute}\n * function.\n */\nexport type UseMutationResponse<\n  Data = any,\n  Variables extends AnyVariables = AnyVariables,\n> = [UseMutationState<Data, Variables>, UseMutationExecute<Data, Variables>];\n\n/** Hook to create a GraphQL mutation, run by passing variables to the returned execute function.\n *\n * @param query - a GraphQL mutation document which `useMutation` will execute.\n * @returns a {@link UseMutationResponse} tuple of a {@link UseMutationState} result,\n * and an execute function to start the mutation.\n *\n * @remarks\n * `useMutation` allows GraphQL mutations to be defined and keeps its state\n * after the mutation is started with the returned execute function.\n *\n * Given a GraphQL mutation document it returns state to keep track of the\n * mutation state and a {@link UseMutationExecute} function, which accepts\n * variables for the mutation to be executed.\n * Once called, the mutation executes and the state will be updated with\n * the mutation’s result.\n *\n * @see {@link https://urql.dev/goto/urql/docs/basics/react-preact/#mutations} for `useMutation` docs.\n *\n * @example\n * ```ts\n * import { gql, useMutation } from 'urql';\n *\n * const UpdateTodo = gql`\n *   mutation ($id: ID!, $title: String!) {\n *     updateTodo(id: $id, title: $title) {\n *       id, title\n *     }\n *   }\n * `;\n *\n * const UpdateTodo = () => {\n *   const [result, executeMutation] = useMutation(UpdateTodo);\n *   const start = async ({ id, title }) => {\n *     const result = await executeMutation({ id, title });\n *   };\n *   // ...\n * };\n * ```\n */\nexport function useMutation<\n  Data = any,\n  Variables extends AnyVariables = AnyVariables,\n>(query: DocumentInput<Data, Variables>): UseMutationResponse<Data, Variables> {\n  const isMounted = React.useRef(true);\n  const client = useClient();\n\n  const [state, setState] =\n    React.useState<UseMutationState<Data, Variables>>(initialState);\n\n  const executeMutation = React.useCallback(\n    (variables: Variables, context?: Partial<OperationContext>) => {\n      deferDispatch(setState, { ...initialState, fetching: true });\n      return pipe(\n        client.executeMutation<Data, Variables>(\n          createRequest<Data, Variables>(query, variables),\n          context || {}\n        ),\n        onPush(result => {\n          if (isMounted.current) {\n            deferDispatch(setState, {\n              fetching: false,\n              stale: result.stale,\n              data: result.data,\n              error: result.error,\n              extensions: result.extensions,\n              operation: result.operation,\n              hasNext: result.hasNext,\n            });\n          }\n        }),\n        filter(result => !result.hasNext),\n        take(1),\n        toPromise\n      );\n    },\n    // eslint-disable-next-line react-hooks/exhaustive-deps\n    [client, query, setState]\n  );\n\n  React.useEffect(() => {\n    isMounted.current = true;\n    return () => {\n      isMounted.current = false;\n    };\n  }, []);\n\n  return [state, executeMutation];\n}\n"
  },
  {
    "path": "packages/react-urql/src/hooks/useQuery.spec.ts",
    "content": "// @vitest-environment jsdom\n\nimport { renderHook, act } from '@testing-library/react';\nimport { interval, map, pipe } from 'wonka';\nimport { RequestPolicy } from '@urql/core';\nimport { vi, expect, it, beforeEach, describe, beforeAll, Mock } from 'vitest';\n\nimport { useClient } from '../context';\nimport { useQuery } from './useQuery';\n\nvi.mock('../context', () => {\n  const mock = {\n    executeQuery: vi.fn(() =>\n      pipe(\n        interval(1000 / 60),\n        map(i => ({ data: i, error: i + 1 }))\n      )\n    ),\n  };\n\n  return {\n    useClient: () => mock,\n  };\n});\n\n// @ts-ignore\nconst client = useClient() as { executeQuery: Mock };\n\nconst mockQuery = `\n  query todo($id: ID!) {\n    todo(id: $id) {\n      id\n      text\n      completed\n    }\n  }\n`;\n\nconst mockVariables = {\n  id: 1,\n};\n\ndescribe('useQuery', () => {\n  beforeAll(() => {\n    // TODO: Fix use of act()\n    vi.spyOn(globalThis.console, 'error').mockImplementation(() => {\n      // do nothing\n    });\n  });\n\n  beforeEach(() => {\n    client.executeQuery.mockClear();\n  });\n\n  it('should set fetching to true and run effect on first mount', () => {\n    const { result } = renderHook(\n      ({ query, variables }) => useQuery({ query, variables }),\n      { initialProps: { query: mockQuery, variables: mockVariables } }\n    );\n\n    const [state] = result.current;\n    expect(state).toEqual({\n      fetching: true,\n      stale: false,\n      hasNext: false,\n      extensions: undefined,\n      error: undefined,\n      data: undefined,\n    });\n  });\n\n  it('should support setting context in useQuery params', () => {\n    const context = { url: 'test' };\n    renderHook(\n      ({ query, variables }) => useQuery({ query, variables, context }),\n      { initialProps: { query: mockQuery, variables: mockVariables } }\n    );\n\n    expect(client.executeQuery).toBeCalledWith(\n      {\n        key: expect.any(Number),\n        query: expect.any(Object),\n        variables: mockVariables,\n      },\n      {\n        requestPolicy: undefined,\n        url: 'test',\n      }\n    );\n  });\n\n  it('should execute the subscription', async () => {\n    renderHook(({ query, variables }) => useQuery({ query, variables }), {\n      initialProps: { query: mockQuery, variables: mockVariables },\n    });\n\n    expect(client.executeQuery).toBeCalledTimes(1);\n  });\n\n  it('should pass query and variables to executeQuery', async () => {\n    renderHook(({ query, variables }) => useQuery({ query, variables }), {\n      initialProps: { query: mockQuery, variables: mockVariables },\n    });\n\n    expect(client.executeQuery).toBeCalledTimes(1);\n    expect(client.executeQuery).toBeCalledWith(\n      {\n        key: expect.any(Number),\n        query: expect.any(Object),\n        variables: mockVariables,\n      },\n      expect.objectContaining({\n        requestPolicy: undefined,\n      })\n    );\n  });\n\n  it('should return data from executeQuery', async () => {\n    const { result } = renderHook(\n      ({ query, variables }) => useQuery({ query, variables }),\n      { initialProps: { query: mockQuery, variables: mockVariables } }\n    );\n\n    await new Promise(res => setTimeout(res, 30));\n    const [state] = result.current;\n    expect(state).toEqual({\n      fetching: false,\n      stale: false,\n      extensions: undefined,\n      hasNext: false,\n      error: 1,\n      data: 0,\n    });\n  });\n\n  it('should update if a new query is received', async () => {\n    const { rerender } = renderHook<\n      any,\n      { query: string; variables: { id?: number } }\n    >(({ query, variables }) => useQuery({ query, variables }), {\n      initialProps: { query: mockQuery, variables: mockVariables },\n    });\n\n    expect(client.executeQuery).toBeCalledTimes(1);\n\n    const newQuery = `\n      query places {\n        id\n        address\n      }\n    `;\n\n    rerender({ query: newQuery, variables: {} });\n    expect(client.executeQuery).toBeCalledTimes(2);\n    expect(client.executeQuery).toHaveBeenNthCalledWith(\n      2,\n      {\n        key: expect.any(Number),\n        query: expect.any(Object),\n        variables: {},\n      },\n      expect.objectContaining({\n        requestPolicy: undefined,\n      })\n    );\n  });\n\n  it('should update if new variables are received', async () => {\n    const { rerender } = renderHook(\n      ({ query, variables }) => useQuery({ query, variables }),\n      {\n        initialProps: { query: mockQuery, variables: mockVariables },\n      }\n    );\n\n    expect(client.executeQuery).toBeCalledTimes(1);\n\n    const newVariables = {\n      id: 2,\n    };\n\n    rerender({ query: mockQuery, variables: newVariables });\n    expect(client.executeQuery).toBeCalledTimes(2);\n    expect(client.executeQuery).toHaveBeenNthCalledWith(\n      2,\n      {\n        key: expect.any(Number),\n        query: expect.any(Object),\n        variables: newVariables,\n      },\n      expect.objectContaining({\n        requestPolicy: undefined,\n      })\n    );\n  });\n\n  it('should not update if query and variables are unchanged', async () => {\n    const { rerender } = renderHook(\n      ({ query, variables }) => useQuery({ query, variables }),\n      {\n        initialProps: { query: mockQuery, variables: mockVariables },\n      }\n    );\n\n    expect(client.executeQuery).toBeCalledTimes(1);\n\n    rerender({ query: mockQuery, variables: mockVariables });\n    expect(client.executeQuery).toBeCalledTimes(1);\n  });\n\n  it('should update if a new requestPolicy is provided', async () => {\n    const { rerender } = renderHook(\n      ({ query, variables, requestPolicy }) =>\n        useQuery({ query, variables, requestPolicy }),\n      {\n        initialProps: {\n          query: mockQuery,\n          variables: mockVariables,\n          requestPolicy: 'cache-first' as RequestPolicy,\n        },\n      }\n    );\n\n    expect(client.executeQuery).toBeCalledTimes(1);\n    expect(client.executeQuery).toHaveBeenNthCalledWith(\n      1,\n      {\n        key: expect.any(Number),\n        query: expect.any(Object),\n        variables: mockVariables,\n      },\n      expect.objectContaining({\n        requestPolicy: 'cache-first',\n      })\n    );\n\n    rerender({\n      query: mockQuery,\n      variables: mockVariables,\n      requestPolicy: 'network-only',\n    });\n    expect(client.executeQuery).toBeCalledTimes(2);\n    expect(client.executeQuery).toHaveBeenNthCalledWith(\n      2,\n      {\n        key: expect.any(Number),\n        query: expect.any(Object),\n        variables: mockVariables,\n      },\n      expect.objectContaining({\n        requestPolicy: 'network-only',\n      })\n    );\n  });\n\n  it('should provide an executeQuery function to be imperatively executed', async () => {\n    const { result } = renderHook(\n      ({ query, variables }) => useQuery({ query, variables }),\n      { initialProps: { query: mockQuery, variables: mockVariables } }\n    );\n\n    expect(client.executeQuery).toBeCalledTimes(1);\n\n    const [, executeQuery] = result.current;\n    act(() => executeQuery());\n    expect(client.executeQuery).toBeCalledTimes(2);\n  });\n\n  it('should pause executing the query if pause is true', () => {\n    renderHook(\n      ({ query, variables, pause }) => useQuery({ query, variables, pause }),\n      {\n        initialProps: {\n          query: mockQuery,\n          variables: mockVariables,\n          pause: true,\n        },\n      }\n    );\n\n    expect(client.executeQuery).not.toBeCalled();\n  });\n\n  it('should pause executing the query if pause updates to true', async () => {\n    const { rerender } = renderHook(\n      props => {\n        const { query, variables, pause } = props;\n        return useQuery({ query, variables, pause });\n      },\n      {\n        initialProps: {\n          query: mockQuery,\n          variables: mockVariables,\n          pause: false,\n        },\n      }\n    );\n\n    expect(client.executeQuery).toBeCalledTimes(1);\n\n    rerender({ query: mockQuery, variables: mockVariables, pause: true });\n    expect(client.executeQuery).toBeCalledTimes(1);\n  });\n});\n"
  },
  {
    "path": "packages/react-urql/src/hooks/useQuery.test.tsx",
    "content": "// @vitest-environment jsdom\nimport { vi, expect, it, beforeEach, describe, Mock } from 'vitest';\n\n// Note: Testing for hooks is not yet supported in Enzyme - https://github.com/airbnb/enzyme/issues/2011\nvi.mock('../context', async () => {\n  const { map, interval, pipe } =\n    await vi.importActual<typeof import('wonka')>('wonka');\n  const mock = {\n    executeQuery: vi.fn(() =>\n      pipe(\n        interval(400),\n        map((i: number) => ({ data: i, error: i + 1, extensions: { i: 1 } }))\n      )\n    ),\n  };\n\n  return {\n    useClient: () => mock,\n  };\n});\n\nimport React from 'react';\nimport renderer, { act } from 'react-test-renderer';\nimport { pipe, onStart, onEnd, never } from 'wonka';\nimport { OperationContext } from '@urql/core';\n\nimport { useQuery, UseQueryArgs, UseQueryState } from './useQuery';\nimport { useClient } from '../context';\n\n// @ts-ignore\nconst client = useClient() as { executeQuery: Mock };\n\nconst props: UseQueryArgs<{ myVar: number }> = {\n  query: '{ example }',\n  variables: {\n    myVar: 1234,\n  },\n  pause: false,\n};\n\nlet state: UseQueryState<any> | undefined;\nlet execute: ((_opts?: Partial<OperationContext>) => void) | undefined;\n\nconst QueryUser = ({\n  query,\n  variables,\n  pause,\n}: UseQueryArgs<{ myVar: number }>) => {\n  const [s, e] = useQuery({ query, variables, pause });\n  state = s;\n  execute = e;\n  return <p>{s.data}</p>;\n};\n\nbeforeEach(() => {\n  vi.useFakeTimers();\n  // TODO: Fix use of act()\n  vi.spyOn(globalThis.console, 'error').mockImplementation(() => {\n    // do nothings\n  });\n\n  client.executeQuery.mockClear();\n  state = undefined;\n  execute = undefined;\n});\n\ndescribe('on initial useEffect', () => {\n  it('initialises default state', () => {\n    renderer.create(<QueryUser {...props} />);\n    expect(state).toMatchSnapshot();\n  });\n\n  it('executes subscription', () => {\n    renderer.create(<QueryUser {...props} />);\n    expect(client.executeQuery).toBeCalledTimes(1);\n  });\n\n  it('passes query and vars to executeQuery', () => {\n    renderer.create(<QueryUser {...props} />);\n\n    expect(client.executeQuery).toBeCalledWith(\n      {\n        key: expect.any(Number),\n        query: expect.any(Object),\n        variables: props.variables,\n      },\n      expect.objectContaining({\n        requestPolicy: undefined,\n      })\n    );\n  });\n});\n\ndescribe('on subscription', () => {\n  it('sets fetching to true', () => {\n    const wrapper = renderer.create(<QueryUser {...props} />);\n    wrapper.update(<QueryUser {...props} />);\n    expect(state).toHaveProperty('fetching', true);\n  });\n});\n\ndescribe('on subscription update', () => {\n  it('forwards data response', () => {\n    const wrapper = renderer.create(<QueryUser {...props} />);\n    /**\n     * Have to call update (without changes) in order to see the\n     * result of the state change.\n     */\n    wrapper.update(<QueryUser {...props} />);\n\n    act(() => {\n      vi.advanceTimersByTime(400);\n      wrapper.update(<QueryUser {...props} />);\n    });\n\n    expect(state).toHaveProperty('data', 0);\n  });\n\n  it('forwards error response', () => {\n    const wrapper = renderer.create(<QueryUser {...props} />);\n    wrapper.update(<QueryUser {...props} />);\n\n    act(() => {\n      vi.advanceTimersByTime(400);\n      wrapper.update(<QueryUser {...props} />);\n    });\n\n    expect(state).toHaveProperty('error', 1);\n  });\n\n  it('forwards extensions response', () => {\n    const wrapper = renderer.create(<QueryUser {...props} />);\n    wrapper.update(<QueryUser {...props} />);\n\n    act(() => {\n      vi.advanceTimersByTime(400);\n      wrapper.update(<QueryUser {...props} />);\n    });\n\n    expect(state).toHaveProperty('extensions', { i: 1 });\n  });\n\n  it('sets fetching to false', () => {\n    const wrapper = renderer.create(<QueryUser {...props} />);\n    wrapper.update(<QueryUser {...props} />);\n\n    act(() => {\n      vi.advanceTimersByTime(400);\n      wrapper.update(<QueryUser {...props} />);\n    });\n\n    expect(state).toHaveProperty('fetching', false);\n  });\n});\n\ndescribe('on change', () => {\n  const q = 'query NewQuery { example }';\n\n  it('new query executes subscription', () => {\n    const wrapper = renderer.create(<QueryUser {...props} />);\n    wrapper.update(<QueryUser {...props} query={q} />);\n\n    act(() => {\n      wrapper.update(<QueryUser {...props} query={q} />);\n    });\n\n    expect(client.executeQuery).toBeCalledTimes(2);\n  });\n});\n\ndescribe('on unmount', () => {\n  const start = vi.fn();\n  const unsubscribe = vi.fn();\n\n  beforeEach(() => {\n    client.executeQuery.mockReturnValue(\n      pipe(never, onStart(start), onEnd(unsubscribe))\n    );\n  });\n\n  it('unsubscribe is called', () => {\n    const wrapper = renderer.create(<QueryUser {...props} />);\n    act(() => wrapper.unmount());\n    expect(start).toHaveBeenCalled();\n    expect(unsubscribe).toHaveBeenCalled();\n  });\n});\n\ndescribe('execute query', () => {\n  it('triggers query execution', () => {\n    renderer.create(<QueryUser {...props} />);\n    act(() => execute && execute());\n    expect(client.executeQuery).toBeCalledTimes(2);\n  });\n});\n\ndescribe('pause', () => {\n  it('skips executing the query if pause is true', () => {\n    renderer.create(<QueryUser {...props} pause={true} />);\n    expect(client.executeQuery).not.toBeCalled();\n  });\n\n  it('skips executing queries if pause updates to true', () => {\n    const wrapper = renderer.create(<QueryUser {...props} />);\n    wrapper.update(<QueryUser {...props} pause={true} />);\n\n    act(() => {\n      wrapper.update(<QueryUser {...props} pause={true} />);\n    });\n\n    expect(client.executeQuery).toBeCalledTimes(1);\n  });\n});\n"
  },
  {
    "path": "packages/react-urql/src/hooks/useQuery.ts",
    "content": "/* eslint-disable react-hooks/exhaustive-deps */\n\nimport type { Source } from 'wonka';\nimport { pipe, subscribe, onEnd, onPush, takeWhile } from 'wonka';\nimport * as React from 'react';\n\nimport type {\n  GraphQLRequestParams,\n  AnyVariables,\n  Client,\n  CombinedError,\n  OperationContext,\n  RequestPolicy,\n  OperationResult,\n  Operation,\n} from '@urql/core';\n\nimport { useClient } from '../context';\nimport { useRequest } from './useRequest';\nimport { getCacheForClient } from './cache';\n\nimport {\n  deferDispatch,\n  initialState,\n  computeNextState,\n  hasDepsChanged,\n} from './state';\n\n/** Input arguments for the {@link useQuery} hook.\n *\n * @param query - The GraphQL query that `useQuery` executes.\n * @param variables - The variables for the GraphQL query that `useQuery` executes.\n */\nexport type UseQueryArgs<\n  Variables extends AnyVariables = AnyVariables,\n  Data = any,\n> = {\n  /** Updates the {@link RequestPolicy} for the executed GraphQL query operation.\n   *\n   * @remarks\n   * `requestPolicy` modifies the {@link RequestPolicy} of the GraphQL query operation\n   * that `useQuery` executes, and indicates a caching strategy for cache exchanges.\n   *\n   * For example, when set to `'cache-and-network'`, {@link useQuery} will\n   * receive a cached result with `stale: true` and an API request will be\n   * sent in the background.\n   *\n   * @see {@link OperationContext.requestPolicy} for where this value is set.\n   */\n  requestPolicy?: RequestPolicy;\n  /** Updates the {@link OperationContext} for the executed GraphQL query operation.\n   *\n   * @remarks\n   * `context` may be passed to {@link useQuery}, to update the {@link OperationContext}\n   * of a query operation. This may be used to update the `context` that exchanges\n   * will receive for a single hook.\n   *\n   * Hint: This should be wrapped in a `useMemo` hook, to make sure that your\n   * component doesn’t infinitely update.\n   *\n   * @example\n   * ```ts\n   * const [result, reexecute] = useQuery({\n   *   query,\n   *   context: useMemo(() => ({\n   *     additionalTypenames: ['Item'],\n   *   }), [])\n   * });\n   * ```\n   */\n  context?: Partial<OperationContext>;\n  /** Prevents {@link useQuery} from automatically executing GraphQL query operations.\n   *\n   * @remarks\n   * `pause` may be set to `true` to stop {@link useQuery} from executing\n   * automatically. The hook will stop receiving updates from the {@link Client}\n   * and won’t execute the query operation, until either it’s set to `false`\n   * or the {@link UseQueryExecute} function is called.\n   *\n   * @see {@link https://urql.dev/goto/docs/basics/react-preact/#pausing-usequery} for\n   * documentation on the `pause` option.\n   */\n  pause?: boolean;\n} & GraphQLRequestParams<Data, Variables>;\n\n/** State of the current query, your {@link useQuery} hook is executing.\n *\n * @remarks\n * `UseQueryState` is returned (in a tuple) by {@link useQuery} and\n * gives you the updating {@link OperationResult} of GraphQL queries.\n *\n * Even when the query and variables passed to {@link useQuery} change,\n * this state preserves the prior state and sets the `fetching` flag to\n * `true`.\n * This allows you to display the previous state, while implementing\n * a separate loading indicator separately.\n */\nexport interface UseQueryState<\n  Data = any,\n  Variables extends AnyVariables = AnyVariables,\n> {\n  /** Indicates whether `useQuery` is waiting for a new result.\n   *\n   * @remarks\n   * When `useQuery` is passed a new query and/or variables, it will\n   * start executing the new query operation and `fetching` is set to\n   * `true` until a result arrives.\n   *\n   * Hint: This is subtly different than whether the query is actually\n   * fetching, and doesn’t indicate whether a query is being re-executed\n   * in the background. For this, see {@link UseQueryState.stale}.\n   */\n  fetching: boolean;\n  /** Indicates that the state is not fresh and a new result will follow.\n   *\n   * @remarks\n   * The `stale` flag is set to `true` when a new result for the query\n   * is expected and `useQuery` is waiting for it. This may indicate that\n   * a new request is being requested in the background.\n   *\n   * @see {@link OperationResult.stale} for the source of this value.\n   */\n  stale: boolean;\n  /** The {@link OperationResult.data} for the executed query. */\n  data?: Data;\n  /** The {@link OperationResult.error} for the executed query. */\n  error?: CombinedError;\n  /** The {@link OperationResult.hasNext} for the executed query. */\n  hasNext: boolean;\n  /** The {@link OperationResult.extensions} for the executed query. */\n  extensions?: Record<string, any>;\n  /** The {@link Operation} that the current state is for.\n   *\n   * @remarks\n   * This is the {@link Operation} that is currently being executed.\n   * When {@link UseQueryState.fetching} is `true`, this is the\n   * last `Operation` that the current state was for.\n   */\n  operation?: Operation<Data, Variables>;\n}\n\n/** Triggers {@link useQuery} to execute a new GraphQL query operation.\n *\n * @param opts - optionally, context options that will be merged with the hook's\n * {@link UseQueryArgs.context} options and the `Client`’s options.\n *\n * @remarks\n * When called, {@link useQuery} will re-execute the GraphQL query operation\n * it currently holds, even if {@link UseQueryArgs.pause} is set to `true`.\n *\n * This is useful for executing a paused query or re-executing a query\n * and get a new network result, by passing a new request policy.\n *\n * ```ts\n * const [result, reexecuteQuery] = useQuery({ query });\n *\n * const refresh = () => {\n *   // Re-execute the query with a network-only policy, skipping the cache\n *   reexecuteQuery({ requestPolicy: 'network-only' });\n * };\n * ```\n */\nexport type UseQueryExecute = (opts?: Partial<OperationContext>) => void;\n\n/** Result tuple returned by the {@link useQuery} hook.\n *\n * @remarks\n * Similarly to a `useState` hook’s return value,\n * the first element is the {@link useQuery}’s result and state,\n * a {@link UseQueryState} object,\n * and the second is used to imperatively re-execute the query\n * via a {@link UseQueryExecute} function.\n */\nexport type UseQueryResponse<\n  Data = any,\n  Variables extends AnyVariables = AnyVariables,\n> = [UseQueryState<Data, Variables>, UseQueryExecute];\n\nconst isSuspense = (client: Client, context?: Partial<OperationContext>) =>\n  context && context.suspense !== undefined\n    ? !!context.suspense\n    : client.suspense;\n\n/** Hook to run a GraphQL query and get updated GraphQL results.\n *\n * @param args - a {@link UseQueryArgs} object, to pass a `query`, `variables`, and options.\n * @returns a {@link UseQueryResponse} tuple of a {@link UseQueryState} result, and re-execute function.\n *\n * @remarks\n * `useQuery` allows GraphQL queries to be defined and executed.\n * Given {@link UseQueryArgs.query}, it executes the GraphQL query with the\n * context’s {@link Client}.\n *\n * The returned result updates when the `Client` has new results\n * for the query, and changes when your input `args` change.\n *\n * Additionally, if the `suspense` option is enabled on the `Client`,\n * the `useQuery` hook will suspend instead of indicating that it’s\n * waiting for a result via {@link UseQueryState.fetching}.\n *\n * @see {@link https://urql.dev/goto/urql/docs/basics/react-preact/#queries} for `useQuery` docs.\n *\n * @example\n * ```ts\n * import { gql, useQuery } from 'urql';\n *\n * const TodosQuery = gql`\n *   query { todos { id, title } }\n * `;\n *\n * const Todos = () => {\n *   const [result, reexecuteQuery] = useQuery({\n *     query: TodosQuery,\n *     variables: {},\n *   });\n *   // ...\n * };\n * ```\n */\nexport function useQuery<\n  Data = any,\n  Variables extends AnyVariables = AnyVariables,\n>(args: UseQueryArgs<Variables, Data>): UseQueryResponse<Data, Variables> {\n  const client = useClient();\n  const cache = getCacheForClient(client);\n  const suspense = isSuspense(client, args.context);\n  const request = useRequest(args.query, args.variables as Variables);\n\n  const source = React.useMemo(() => {\n    if (args.pause) return null;\n\n    const source = client.executeQuery(request, {\n      requestPolicy: args.requestPolicy,\n      ...args.context,\n    });\n\n    return suspense\n      ? pipe(\n          source,\n          onPush(result => {\n            cache.set(request.key, result);\n          })\n        )\n      : source;\n  }, [\n    cache,\n    client,\n    request,\n    suspense,\n    args.pause,\n    args.requestPolicy,\n    args.context,\n  ]);\n\n  const getSnapshot = React.useCallback(\n    (\n      source: Source<OperationResult<Data, Variables>> | null,\n      suspense: boolean\n    ): Partial<UseQueryState<Data, Variables>> => {\n      if (!source) return { fetching: false };\n\n      let result = cache.get(request.key);\n      if (!result) {\n        let resolve: (value: unknown) => void;\n\n        const subscription = pipe(\n          source,\n          takeWhile(\n            () =>\n              (suspense && !resolve) ||\n              !result ||\n              ('hasNext' in result && result.hasNext)\n          ),\n          subscribe(_result => {\n            result = _result;\n            if (resolve) resolve(result);\n          })\n        );\n\n        if (result == null && suspense) {\n          const promise = new Promise(_resolve => {\n            resolve = _resolve;\n          });\n\n          cache.set(request.key, promise);\n          throw promise;\n        } else {\n          subscription.unsubscribe();\n        }\n      } else if (suspense && result != null && 'then' in result) {\n        throw result;\n      }\n\n      return (result as OperationResult<Data, Variables>) || { fetching: true };\n    },\n    [cache, request]\n  );\n\n  const deps = [\n    client,\n    request,\n    args.requestPolicy,\n    args.context,\n    args.pause,\n  ] as const;\n\n  const [state, setState] = React.useState(\n    () =>\n      [\n        source,\n        computeNextState(\n          initialState,\n          deferDispatch(() => getSnapshot(source, suspense))\n        ),\n        deps,\n      ] as const\n  );\n\n  let currentResult = state[1];\n  if (source !== state[0] && hasDepsChanged(state[2], deps)) {\n    setState([\n      source,\n      (currentResult = computeNextState(\n        state[1],\n        deferDispatch(() => getSnapshot(source, suspense))\n      )),\n      deps,\n    ]);\n  }\n\n  React.useEffect(() => {\n    const source = state[0];\n    const request = state[2][1];\n\n    let hasResult = false;\n\n    const updateResult = (result: Partial<UseQueryState<Data, Variables>>) => {\n      hasResult = true;\n      deferDispatch(setState, state => {\n        const nextResult = computeNextState(state[1], result);\n        return state[1] !== nextResult\n          ? [state[0], nextResult, state[2]]\n          : state;\n      });\n    };\n\n    if (source) {\n      const subscription = pipe(\n        source,\n        onEnd(() => {\n          updateResult({ fetching: false });\n        }),\n        subscribe(updateResult)\n      );\n\n      if (!hasResult) updateResult({ fetching: true });\n\n      return () => {\n        cache.dispose(request.key);\n        subscription.unsubscribe();\n      };\n    } else {\n      updateResult({ fetching: false });\n    }\n  }, [cache, state[0], state[2][1]]);\n\n  const executeQuery = React.useCallback(\n    (opts?: Partial<OperationContext>) => {\n      const context = {\n        requestPolicy: args.requestPolicy,\n        ...args.context,\n        ...opts,\n      };\n\n      deferDispatch(setState, state => {\n        const source = suspense\n          ? pipe(\n              client.executeQuery(request, context),\n              onPush(result => {\n                cache.set(request.key, result);\n              })\n            )\n          : client.executeQuery(request, context);\n        return [source, state[1], deps];\n      });\n    },\n    [\n      client,\n      cache,\n      request,\n      suspense,\n      args.requestPolicy,\n      args.context,\n      args.pause,\n    ]\n  );\n\n  return [currentResult, executeQuery];\n}\n"
  },
  {
    "path": "packages/react-urql/src/hooks/useRequest.test.ts",
    "content": "// @vitest-environment jsdom\nimport { gql } from '@urql/core';\nimport { renderHook } from '@testing-library/react';\nimport { it, expect } from 'vitest';\nimport { useRequest } from './useRequest';\n\nit('preserves instance of request when key has not changed', () => {\n  const query = gql`\n    query getUser($name: String) {\n      user(name: $name) {\n        id\n        firstName\n        lastName\n      }\n    }\n  `;\n\n  let variables = {\n    name: 'Clara',\n  };\n\n  const { result, rerender } = renderHook(\n    ({ query, variables }) => useRequest(query, variables),\n    { initialProps: { query, variables } }\n  );\n\n  const resultA = result.current;\n  expect(resultA).toEqual({\n    key: expect.any(Number),\n    query: expect.anything(),\n    variables: variables,\n  });\n\n  variables = { ...variables }; // Change reference\n  rerender({ query, variables });\n\n  const resultB = result.current;\n  expect(resultA).toBe(resultB);\n\n  variables = { ...variables, test: true } as any; // Change values\n  rerender({ query, variables });\n\n  const resultC = result.current;\n  expect(resultA).not.toBe(resultC);\n});\n"
  },
  {
    "path": "packages/react-urql/src/hooks/useRequest.ts",
    "content": "import * as React from 'react';\nimport type { AnyVariables, DocumentInput, GraphQLRequest } from '@urql/core';\nimport { createRequest } from '@urql/core';\n\n/** Creates a request from a query and variables but preserves reference equality if the key isn't changing\n * @internal\n */\nexport function useRequest<\n  Data = any,\n  Variables extends AnyVariables = AnyVariables,\n>(\n  query: DocumentInput<Data, Variables>,\n  variables: Variables\n): GraphQLRequest<Data, Variables> {\n  const prev = React.useRef<undefined | GraphQLRequest<Data, Variables>>(\n    undefined\n  );\n\n  return React.useMemo(() => {\n    const request = createRequest<Data, Variables>(query, variables);\n    // We manually ensure reference equality if the key hasn't changed\n    if (prev.current !== undefined && prev.current.key === request.key) {\n      return prev.current;\n    } else {\n      prev.current = request;\n      return request;\n    }\n  }, [query, variables]);\n}\n"
  },
  {
    "path": "packages/react-urql/src/hooks/useSubscription.test.tsx",
    "content": "// @vitest-environment jsdom\nimport { vi, expect, it, beforeEach, describe, Mock } from 'vitest';\n\n// Note: Testing for hooks is not yet supported in Enzyme - https://github.com/airbnb/enzyme/issues/2011\nvi.mock('../context', async () => {\n  const d = { data: 1234, error: 5678 };\n  const { merge, fromValue, never } =\n    await vi.importActual<typeof import('wonka')>('wonka');\n  const mock = {\n    executeSubscription: vi.fn(() => merge([fromValue(d), never])),\n  };\n\n  return {\n    useClient: () => mock,\n  };\n});\n\nimport React from 'react';\nimport renderer, { act } from 'react-test-renderer';\nimport { OperationContext } from '@urql/core';\n\nimport { useSubscription, UseSubscriptionState } from './useSubscription';\nimport { useClient } from '../context';\n\n// @ts-ignore\nconst client = useClient() as { executeSubscription: Mock };\nconst query = 'subscription Example { example }';\n\nlet state: UseSubscriptionState<any> | undefined;\nlet execute: ((_opts?: Partial<OperationContext>) => void) | undefined;\n\nconst SubscriptionUser = ({\n  q,\n  handler,\n  context,\n  pause = false,\n}: {\n  q: string;\n  handler?: (_prev: any, _data: any) => any;\n  context?: Partial<OperationContext>;\n  pause?: boolean;\n}) => {\n  [state, execute] = useSubscription({ query: q, context, pause }, handler);\n  return <p>{state.data}</p>;\n};\n\nbeforeEach(() => {\n  client.executeSubscription.mockClear();\n  state = undefined;\n});\n\ndescribe('on initial useEffect', () => {\n  it('initialises default state', () => {\n    renderer.create(<SubscriptionUser q={query} />);\n    expect(state).toMatchSnapshot();\n  });\n\n  it('executes subscription', () => {\n    renderer.create(<SubscriptionUser q={query} />);\n    expect(client.executeSubscription).toBeCalledTimes(1);\n  });\n});\n\nit('should support setting context in useSubscription params', () => {\n  const context = { url: 'test' };\n  act(() => {\n    renderer.create(<SubscriptionUser q={query} context={context} />);\n  });\n  expect(client.executeSubscription).toBeCalledWith(\n    {\n      key: expect.any(Number),\n      query: expect.any(Object),\n      variables: {},\n    },\n    {\n      url: 'test',\n    }\n  );\n});\n\nit('calls handler', () => {\n  const handler = vi.fn();\n  const wrapper = renderer.create(\n    <SubscriptionUser q={query} handler={handler} />\n  );\n  wrapper.update(<SubscriptionUser q={query} handler={handler} />);\n  expect(handler).toBeCalledWith(undefined, 1234);\n});\n\ndescribe('execute subscription', () => {\n  it('triggers subscription execution', () => {\n    renderer.create(<SubscriptionUser q={query} />);\n    act(() => execute && execute());\n    expect(client.executeSubscription).toBeCalledTimes(2);\n  });\n});\n\ndescribe('pause', () => {\n  const props = { q: query };\n\n  it('skips executing the query if pause is true', () => {\n    renderer.create(<SubscriptionUser {...props} pause={true} />);\n    expect(client.executeSubscription).not.toBeCalled();\n  });\n\n  it('skips executing queries if pause updates to true', () => {\n    const wrapper = renderer.create(<SubscriptionUser {...props} />);\n\n    wrapper.update(<SubscriptionUser {...props} pause={true} />);\n    wrapper.update(<SubscriptionUser {...props} pause={true} />);\n    expect(client.executeSubscription).toBeCalledTimes(1);\n    expect(state).toMatchObject({ fetching: false });\n  });\n});\n"
  },
  {
    "path": "packages/react-urql/src/hooks/useSubscription.ts",
    "content": "/* eslint-disable react-hooks/exhaustive-deps */\n\nimport { pipe, subscribe, onEnd } from 'wonka';\nimport * as React from 'react';\n\nimport type {\n  GraphQLRequestParams,\n  AnyVariables,\n  CombinedError,\n  OperationContext,\n  Operation,\n} from '@urql/core';\n\nimport { useClient } from '../context';\nimport { useRequest } from './useRequest';\n\nimport {\n  deferDispatch,\n  initialState,\n  computeNextState,\n  hasDepsChanged,\n} from './state';\n\n/** Input arguments for the {@link useSubscription} hook.\n *\n * @param query - The GraphQL subscription document that `useSubscription` executes.\n * @param variables - The variables for the GraphQL subscription that `useSubscription` executes.\n */\nexport type UseSubscriptionArgs<\n  Variables extends AnyVariables = AnyVariables,\n  Data = any,\n> = {\n  /** Prevents {@link useSubscription} from automatically starting GraphQL subscriptions.\n   *\n   * @remarks\n   * `pause` may be set to `true` to stop {@link useSubscription} from starting its subscription\n   * automatically. The hook will stop receiving updates from the {@link Client}\n   * and won’t start the subscription operation, until either it’s set to `false`\n   * or the {@link UseSubscriptionExecute} function is called.\n   */\n  pause?: boolean;\n  /** Updates the {@link OperationContext} for the executed GraphQL subscription operation.\n   *\n   * @remarks\n   * `context` may be passed to {@link useSubscription}, to update the {@link OperationContext}\n   * of a subscription operation. This may be used to update the `context` that exchanges\n   * will receive for a single hook.\n   *\n   * Hint: This should be wrapped in a `useMemo` hook, to make sure that your\n   * component doesn’t infinitely update.\n   *\n   * @example\n   * ```ts\n   * const [result, reexecute] = useSubscription({\n   *   query,\n   *   context: useMemo(() => ({\n   *     additionalTypenames: ['Item'],\n   *   }), [])\n   * });\n   * ```\n   */\n  context?: Partial<OperationContext>;\n} & GraphQLRequestParams<Data, Variables>;\n\n/** Combines previous data with an incoming subscription result’s data.\n *\n * @remarks\n * A `SubscriptionHandler` may be passed to {@link useSubscription} to\n * aggregate subscription results into a combined {@link UseSubscriptionState.data}\n * value.\n *\n * This is useful when a subscription event delivers a single item, while\n * you’d like to display a list of events.\n *\n * @example\n * ```ts\n * const NotificationsSubscription = gql`\n *   subscription { newNotification { id, text } }\n * `;\n *\n * const combineNotifications = (notifications = [], data) => {\n *   return [...notifications, data.newNotification];\n * };\n *\n * const [result, executeSubscription] = useSubscription(\n *   { query: NotificationsSubscription },\n *   combineNotifications,\n * );\n * ```\n */\nexport type SubscriptionHandler<T, R> = (prev: R | undefined, data: T) => R;\n\n/** State of the current subscription, your {@link useSubscription} hook is executing.\n *\n * @remarks\n * `UseSubscriptionState` is returned (in a tuple) by {@link useSubscription} and\n * gives you the updating {@link OperationResult} of GraphQL subscriptions.\n *\n * If a {@link SubscriptionHandler} has been passed to `useSubscription` then\n * {@link UseSubscriptionState.data} is instead the updated data as returned\n * by the handler, otherwise it’s the latest result’s data.\n *\n * Hint: Even when the query and variables passed to {@link useSubscription} change,\n * this state preserves the prior state.\n */\nexport interface UseSubscriptionState<\n  Data = any,\n  Variables extends AnyVariables = AnyVariables,\n> {\n  /** Indicates whether `useSubscription`’s subscription is active.\n   *\n   * @remarks\n   * When `useSubscription` starts a subscription, the `fetching` flag\n   * is set to `true` and will remain `true` until the subscription\n   * completes on the API, or the {@link UseSubscriptionArgs.pause}\n   * flag is set to `true`.\n   */\n  fetching: boolean;\n  /** Indicates that the subscription result is not fresh.\n   *\n   * @remarks\n   * This is mostly unused for subscriptions and will rarely affect you, and\n   * is more relevant for queries.\n   *\n   * @see {@link OperationResult.stale} for the source of this value.\n   */\n  stale: boolean;\n  /** The {@link OperationResult.data} for the executed subscription, or data returned by a handler.\n   *\n   * @remarks\n   * `data` will be set to the last {@link OperationResult.data} value\n   * received for the subscription.\n   *\n   * It will instead be set to the values that {@link SubscriptionHandler}\n   * returned, if a handler has been passed to {@link useSubscription}.\n   */\n  data?: Data;\n  /** The {@link OperationResult.error} for the executed subscription. */\n  error?: CombinedError;\n  /** The {@link OperationResult.extensions} for the executed mutation. */\n  extensions?: Record<string, any>;\n  /** The {@link Operation} that the current state is for.\n   *\n   * @remarks\n   * This is the subscription {@link Operation} that is currently active.\n   * When {@link UseSubscriptionState.fetching} is `true`, this is the\n   * last `Operation` that the current state was for.\n   */\n  operation?: Operation<Data, Variables>;\n}\n\n/** Triggers {@link useSubscription} to reexecute a GraphQL subscription operation.\n *\n * @param opts - optionally, context options that will be merged with the hook's\n * {@link UseSubscriptionArgs.context} options and the `Client`’s options.\n *\n * @remarks\n * When called, {@link useSubscription} will restart the GraphQL subscription\n * operation it currently holds. If {@link UseSubscriptionArgs.pause} is set\n * to `true`, it will start executing the subscription.\n *\n * ```ts\n * const [result, executeSubscription] = useSubscription({\n *   query,\n *   pause: true,\n * });\n *\n * const start = () => {\n *   executeSubscription();\n * };\n * ```\n */\nexport type UseSubscriptionExecute = (opts?: Partial<OperationContext>) => void;\n\n/** Result tuple returned by the {@link useSubscription} hook.\n *\n * @remarks\n * Similarly to a `useState` hook’s return value,\n * the first element is the {@link useSubscription}’s state,\n * a {@link UseSubscriptionState} object,\n * and the second is used to imperatively re-execute or start the subscription\n * via a {@link UseMutationExecute} function.\n */\nexport type UseSubscriptionResponse<\n  Data = any,\n  Variables extends AnyVariables = AnyVariables,\n> = [UseSubscriptionState<Data, Variables>, UseSubscriptionExecute];\n\n/** Hook to run a GraphQL subscription and get updated GraphQL results.\n *\n * @param args - a {@link UseSubscriptionArgs} object, to pass a `query`, `variables`, and options.\n * @param handler - optionally, a {@link SubscriptionHandler} function to combine multiple subscription results.\n * @returns a {@link UseSubscriptionResponse} tuple of a {@link UseSubscriptionState} result, and an execute function.\n *\n * @remarks\n * `useSubscription` allows GraphQL subscriptions to be defined and executed.\n * Given {@link UseSubscriptionArgs.query}, it executes the GraphQL subscription with the\n * context’s {@link Client}.\n *\n * The returned result updates when the `Client` has new results\n * for the subscription, and `data` is updated with the result’s data\n * or with the `data` that a `handler` returns.\n *\n * @example\n * ```ts\n * import { gql, useSubscription } from 'urql';\n *\n * const NotificationsSubscription = gql`\n *   subscription { newNotification { id, text } }\n * `;\n *\n * const combineNotifications = (notifications = [], data) => {\n *   return [...notifications, data.newNotification];\n * };\n *\n * const Notifications = () => {\n *   const [result, executeSubscription] = useSubscription(\n *     { query: NotificationsSubscription },\n *     combineNotifications,\n *   );\n *   // ...\n * };\n * ```\n */\nexport function useSubscription<\n  Data = any,\n  Result = Data,\n  Variables extends AnyVariables = AnyVariables,\n>(\n  args: UseSubscriptionArgs<Variables, Data>,\n  handler?: SubscriptionHandler<Data, Result>\n): UseSubscriptionResponse<Result, Variables> {\n  const client = useClient();\n  const request = useRequest(args.query, args.variables as Variables);\n\n  const handlerRef = React.useRef<\n    SubscriptionHandler<Data, Result> | undefined\n  >(handler);\n  handlerRef.current = handler;\n\n  const source = React.useMemo(\n    () =>\n      !args.pause ? client.executeSubscription(request, args.context) : null,\n    [client, request, args.pause, args.context]\n  );\n\n  const deps = [client, request, args.context, args.pause] as const;\n\n  const [state, setState] = React.useState(\n    () => [source, { ...initialState, fetching: !!source }, deps] as const\n  );\n\n  let currentResult = state[1];\n  if (source !== state[0] && hasDepsChanged(state[2], deps)) {\n    setState([\n      source,\n      (currentResult = computeNextState(state[1], { fetching: !!source })),\n      deps,\n    ]);\n  }\n\n  React.useEffect(() => {\n    const updateResult = (\n      result: Partial<UseSubscriptionState<Data, Variables>>\n    ) => {\n      deferDispatch(setState, state => {\n        const nextResult = computeNextState(state[1], result);\n        if (state[1] === nextResult) return state;\n        if (\n          handlerRef.current &&\n          nextResult.data != null &&\n          state[1].data !== nextResult.data\n        ) {\n          nextResult.data = handlerRef.current(\n            state[1].data,\n            nextResult.data\n          ) as any;\n        }\n\n        return [state[0], nextResult as any, state[2]];\n      });\n    };\n\n    if (state[0]) {\n      return pipe(\n        state[0],\n        onEnd(() => {\n          updateResult({ fetching: !!source });\n        }),\n        subscribe(updateResult)\n      ).unsubscribe;\n    } else {\n      updateResult({ fetching: false });\n    }\n  }, [state[0]]);\n\n  // This is the imperative execute function passed to the user\n  const executeSubscription = React.useCallback(\n    (opts?: Partial<OperationContext>) => {\n      const source = client.executeSubscription(request, {\n        ...args.context,\n        ...opts,\n      });\n\n      deferDispatch(setState, state => [source, state[1], deps]);\n    },\n    [client, request, args.context, args.pause]\n  );\n\n  return [currentResult, executeSubscription];\n}\n"
  },
  {
    "path": "packages/react-urql/src/index.ts",
    "content": "export * from '@urql/core';\nexport * from './context';\nexport * from './components';\nexport * from './hooks';\n"
  },
  {
    "path": "packages/react-urql/src/test-utils/ssr.test.tsx",
    "content": "import React from 'react';\nimport prepass from 'react-ssr-prepass';\nimport { never, publish, filter, delay, pipe, map } from 'wonka';\nimport { describe, it, beforeEach, expect } from 'vitest';\n\nimport {\n  gql,\n  Client,\n  Exchange,\n  cacheExchange,\n  ssrExchange,\n  OperationContext,\n  GraphQLRequest,\n  Operation,\n  OperationResult,\n  makeOperation,\n} from '@urql/core';\n\nimport { Provider } from '../context';\nimport { useQuery } from '../hooks';\n\nconst context: OperationContext = {\n  fetchOptions: {\n    method: 'POST',\n  },\n  requestPolicy: 'cache-first',\n  url: 'http://localhost:3000/graphql',\n  suspense: true,\n};\n\nexport const queryGql: GraphQLRequest = {\n  key: 2,\n  query: gql`\n    query getUser($name: String) {\n      user(name: $name) {\n        id\n        firstName\n        lastName\n      }\n    }\n  `,\n  variables: {\n    name: 'Clara',\n  },\n};\n\nconst teardownOperation: Operation = makeOperation(\n  'teardown',\n  {\n    query: queryGql.query,\n    variables: queryGql.variables,\n    key: queryGql.key,\n  },\n  context\n);\n\nconst queryOperation: Operation = makeOperation(\n  'query',\n  {\n    query: teardownOperation.query,\n    variables: teardownOperation.variables,\n    key: teardownOperation.key,\n  },\n  context\n);\n\nconst queryResponse: OperationResult = {\n  operation: queryOperation,\n  data: {\n    user: {\n      name: 'Clive',\n    },\n  },\n  stale: false,\n  hasNext: false,\n};\n\nconst url = 'https://hostname.com';\n\ndescribe('server-side rendering', () => {\n  let ssr;\n  let client: Client;\n\n  beforeEach(() => {\n    const fetchExchange: Exchange = () => ops$ => {\n      return pipe(\n        ops$,\n        filter(x => x.kind === 'query'),\n        delay(100),\n        map(operation => ({ ...queryResponse, operation }))\n      );\n    };\n\n    ssr = ssrExchange();\n    client = new Client({\n      url,\n      // We include the SSR exchange after the cache\n      exchanges: [cacheExchange, ssr, fetchExchange],\n      suspense: true,\n    });\n  });\n\n  it('works for an actual component tree', async () => {\n    const Query = () => {\n      useQuery({\n        query: queryOperation.query,\n        variables: queryOperation.variables,\n      });\n\n      return null;\n    };\n\n    const Element = Provider as any;\n    const App = () => (\n      <Element value={client}>\n        <Query />\n      </Element>\n    );\n\n    await prepass(<App />);\n\n    const data = ssr.extractData();\n    expect(Object.keys(data).length).toBe(1);\n  });\n});\n\ndescribe('client-side rehydration', () => {\n  let ssr;\n  let client;\n\n  beforeEach(() => {\n    const fetchExchange: Exchange = () => () => never as any;\n\n    ssr = ssrExchange();\n    client = new Client({\n      url,\n      // We include the SSR exchange after the cache\n      exchanges: [cacheExchange, ssr, fetchExchange],\n      suspense: false,\n    });\n  });\n\n  it('can rehydrate results on the client', async () => {\n    ssr.restoreData({\n      [queryOperation.key]: {\n        ...queryResponse,\n        data: JSON.stringify(queryResponse.data),\n      },\n    });\n\n    expect(() => {\n      pipe(client.executeRequestOperation(queryOperation), publish);\n    }).not.toThrow();\n\n    await Promise.resolve();\n\n    const data = ssr.extractData();\n    expect(Object.keys(data).length).toBe(0);\n  });\n});\n"
  },
  {
    "path": "packages/react-urql/tsconfig.json",
    "content": "{\n  \"extends\": \"../../tsconfig.json\",\n  \"include\": [\"src\"]\n}\n"
  },
  {
    "path": "packages/react-urql/vitest.config.ts",
    "content": "import { mergeConfig } from 'vitest/config';\nimport baseConfig from '../../vitest.config';\n\nexport default mergeConfig(baseConfig, {\n  test: {\n    environment: 'jsdom',\n  },\n});\n"
  },
  {
    "path": "packages/site/CHANGELOG.md",
    "content": "# urql-docs\n\n## 1.0.0\n\n### Major Changes\n\n- **Goodbye IE11!** 👋 This major release removes support for IE11. All code that is shipped will be transpiled much less and will _not_ be ES5-compatible anymore, by [@kitten](https://github.com/kitten) (See [#2504](https://github.com/urql-graphql/urql/pull/2504))\n"
  },
  {
    "path": "packages/site/package.json",
    "content": "{\n  \"name\": \"urql-docs\",\n  \"version\": \"1.0.0\",\n  \"description\": \"Documentation site for urql\",\n  \"private\": true,\n  \"scripts\": {\n    \"start\": \"react-static start\",\n    \"build\": \"NODE_OPTIONS=--openssl-legacy-provider react-static build\",\n    \"lint\": \"eslint --ext=js,jsx .\",\n    \"clean\": \"rimraf dist\",\n    \"prepublishOnly\": \"run-s clean build\",\n    \"stage:build\": \"pnpm build --staging\",\n    \"prod:build\": \"pnpm build\"\n  },\n  \"babel\": {\n    \"presets\": [\n      \"react-static/babel-preset\"\n    ],\n    \"plugins\": [\n      \"babel-plugin-styled-components\"\n    ]\n  },\n  \"dependencies\": {\n    \"@babel/runtime\": \"^7.20.1\",\n    \"@mdx-js/react\": \"^1.6.22\",\n    \"formidable-oss-badges\": \"0.3.5\",\n    \"fuse.js\": \"^6.4.6\",\n    \"history\": \"^4.7.2\",\n    \"path\": \"^0.12.7\",\n    \"preact\": \"^10.5.13\",\n    \"prism-react-renderer\": \"^1.1.0\",\n    \"prop-types\": \"^15.6.2\",\n    \"react\": \"^17.0.2\",\n    \"react-dom\": \"^17.0.2\",\n    \"react-ga\": \"^3.3.0\",\n    \"react-gtm-module\": \"^2.0.11\",\n    \"react-inlinesvg\": \"^1.2.0\",\n    \"react-is\": \"^17.0.2\",\n    \"react-router\": \"^5.2.0\",\n    \"react-router-dom\": \"^5.2.0\",\n    \"react-router-ga\": \"^1.2.3\",\n    \"react-scroll\": \"^1.8.1\",\n    \"react-static\": \"7.3.0\",\n    \"react-static-plugin-md-pages\": \"^0.3.3\",\n    \"styled-components\": \"^5.2.3\"\n  },\n  \"devDependencies\": {\n    \"@babel/core\": \"^7.2.0\",\n    \"@mdx-js/mdx\": \"^1.5.7\",\n    \"@octokit/plugin-request-log\": \"1.0.0\",\n    \"babel-plugin-universal-import\": \"^3.1.3\",\n    \"lodash\": \"^4.17.19\",\n    \"react-hot-loader\": \"^4.12.20\",\n    \"react-static-plugin-sitemap\": \"7.2.2\",\n    \"react-static-plugin-styled-components\": \"7.2.2\",\n    \"resolve-from\": \"^3.0.0\",\n    \"surge\": \"^0.21.3\",\n    \"webpack\": \">=4.4.6\"\n  },\n  \"engines\": {\n    \"node\": \">=18.0.0\"\n  }\n}\n"
  },
  {
    "path": "packages/site/plugins/assets-fix/node.api.js",
    "content": "export default () => ({\n  webpack(config) {\n    const rules = config.module.rules[0].oneOf;\n    for (let i = 0; i < rules.length; i++) {\n      const rule = rules[i];\n      if (rule.loader === 'url-loader') {\n        delete rule.options;\n        rule.query = {\n          limit: 10000,\n          name: 'static/[name].[hash:8].[ext]',\n        };\n      }\n    }\n\n    return config;\n  },\n});\n"
  },
  {
    "path": "packages/site/plugins/monorepo-fix/node.api.js",
    "content": "import { silent as resolveFrom } from 'resolve-from';\n\nconst NODE_MODULES_JS_RE = /node_modules[/\\\\].*\\.js$/;\nconst REACT_STATIC_RE = /node_modules[/\\\\]react-static/;\n\nexport default () => ({\n  webpack: (config, { stage }) => {\n    if (stage === 'node') {\n      config.externals = [\n        ...config.externals,\n        (context, request, callback) => {\n          if (/^[./]/.test(request)) {\n            return callback();\n          }\n\n          const res = resolveFrom(`${context}/`, request);\n          if (\n            res &&\n            NODE_MODULES_JS_RE.test(res) &&\n            !REACT_STATIC_RE.test(res)\n          ) {\n            return callback(null, `commonjs ${request}`);\n          } else {\n            return callback();\n          }\n        },\n      ];\n    }\n\n    return config;\n  },\n});\n"
  },
  {
    "path": "packages/site/plugins/preact/node.api.js",
    "content": "export default () => ({\n  webpack: config => {\n    config.resolve.alias = {\n      ...(config.resolve.alias || {}),\n      react: 'preact/compat',\n      'react-dom': 'preact/compat',\n    };\n\n    return config;\n  },\n});\n"
  },
  {
    "path": "packages/site/plugins/react-router/browser.api.js",
    "content": "/* eslint-disable react/display-name */\n/* eslint-disable react-hooks/rules-of-hooks */\n\nimport React from 'react';\nimport { useBasepath, useStaticInfo } from 'react-static';\nimport { BrowserRouter, StaticRouter, withRouter } from 'react-router-dom';\n\nconst Location = withRouter(({ children, location }) => children(location));\n\nconst ReactRouterPlugin = ({ RouterProps: userRouterProps = {} }) => ({\n  Root:\n    PreviousRoot =>\n    ({ children }) => {\n      const routerProps = { basename: useBasepath() || '' };\n      if (routerProps.basename)\n        routerProps.basename = `/${routerProps.basename}`;\n      const staticInfo = useStaticInfo();\n\n      // Test for document to detect the node stage\n      let Router;\n      if (typeof document !== 'undefined') {\n        // NOTE: React Router is inconsistent in how it handles base paths\n        // This will need a trailing slash while the StaticRouter does not\n        if (routerProps.basename) routerProps.basename += '/';\n        // If in the browser, just use the browser router\n        Router = BrowserRouter;\n      } else {\n        Router = StaticRouter;\n        routerProps.location = staticInfo.path; // Required\n        routerProps.context = {}; // Required\n      }\n\n      return (\n        <PreviousRoot>\n          <Router {...routerProps} {...userRouterProps}>\n            {children}\n          </Router>\n        </PreviousRoot>\n      );\n    },\n  Routes: PreviousRoutes => props => (\n    <Location>\n      {location => <PreviousRoutes {...props} location={location} />}\n    </Location>\n  ),\n});\n\nexport default ReactRouterPlugin;\n"
  },
  {
    "path": "packages/site/public/browserconfig.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<browserconfig>\n    <msapplication>\n        <tile>\n            <square70x70logo src=\"./favicon/favicon-32.png\"/>\n            <TileColor>#fff</TileColor>\n        </tile>\n    </msapplication>\n</browserconfig>\n"
  },
  {
    "path": "packages/site/public/site.webmanifest",
    "content": "{\n  \"name\": \"urql Documentation\",\n  \"short_name\": \"urql\",\n  \"icons\": [\n    {\n      \"src\": \"./favicon/favicon-32.png\",\n      \"sizes\": \"16x16\",\n      \"type\": \"image/png\"\n    },\n    {\n      \"src\": \"./favicon/favicon-32.png\",\n      \"sizes\": \"32x32\",\n      \"type\": \"image/png\"\n    },\n    {\n      \"src\": \"./favicon/favicon-192.png\",\n      \"sizes\": \"192x192\",\n      \"type\": \"image/png\"\n    },\n    {\n      \"src\": \"./favicon/favicon-32.png\",\n      \"sizes\": \"512x512\",\n      \"type\": \"image/png\"\n    }\n  ],\n  \"theme_color\": \"#ffffff\",\n  \"background_color\": \"#ffffff\",\n  \"display\": \"standalone\"\n}\n"
  },
  {
    "path": "packages/site/src/analytics.js",
    "content": "import React, { Fragment } from 'react';\nimport PropTypes from 'prop-types';\n\nlet GoogleAnalytics = null;\nif (typeof window !== 'undefined') {\n  GoogleAnalytics = require('react-router-ga');\n  if (GoogleAnalytics.default) GoogleAnalytics = GoogleAnalytics.default;\n}\n\nexport const Analytics = props =>\n  !GoogleAnalytics ? (\n    <GoogleAnalytics {...props} />\n  ) : (\n    <Fragment>{props.children}</Fragment>\n  );\n\nAnalytics.propTypes = {\n  children: PropTypes.element,\n};\n"
  },
  {
    "path": "packages/site/src/app.js",
    "content": "// eslint-disable-next-line react/no-multi-comp\n\nimport React, { useEffect } from 'react';\nimport { Root, Routes } from 'react-static';\nimport { ThemeProvider } from 'styled-components';\n\nimport constants from './constants';\nimport { GlobalStyle } from './styles/global';\nimport * as theme from './styles/theme';\nimport Analytics from './google-analytics';\nimport { initGoogleTagManager } from './google-tag-manager';\nimport { Loading } from './components/loading';\n\nconst App = () => {\n  useEffect(() => {\n    initGoogleTagManager();\n  }, []);\n\n  return (\n    <Root>\n      <ThemeProvider theme={theme}>\n        <GlobalStyle />\n        <React.Suspense fallback={<Loading />}>\n          <Analytics id={constants.googleAnalyticsId}>\n            <Routes />\n          </Analytics>\n        </React.Suspense>\n      </ThemeProvider>\n    </Root>\n  );\n};\n\nexport default App;\n"
  },
  {
    "path": "packages/site/src/assets/anchor.js",
    "content": "import React from 'react';\n\nconst SvgAnchor = props => (\n  <svg viewBox=\"0 0 16 16\" {...props}>\n    <path\n      fill=\"currentColor\"\n      fillRule=\"evenodd\"\n      d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"\n    />\n  </svg>\n);\n\nexport default SvgAnchor;\n"
  },
  {
    "path": "packages/site/src/assets/chevron.js",
    "content": "import React from 'react';\n\nconst SvgChevron = props => (\n  <svg viewBox=\"0 0 12 10\" {...props}>\n    <path\n      d=\"M1.41 1L6 5.33 10.59 1 12 2.34 6 8 0 2.34z\"\n      fill=\"currentColor\"\n      fillRule=\"nonzero\"\n    />\n  </svg>\n);\n\nexport default SvgChevron;\n"
  },
  {
    "path": "packages/site/src/components/body-copy.js",
    "content": "import styled from 'styled-components';\n\nexport const BodyCopy = styled.p`\n  font-size: 1.4rem;\n  line-height: 2.2rem;\n  width: 100%;\n  text-align: center;\n  ${p => p.noMargin && 'margin: 0'};\n  @media (min-width: 768px) {\n    font-size: 1.5rem;\n    line-height: 2.4rem;\n    text-align: left;\n  }\n`;\n"
  },
  {
    "path": "packages/site/src/components/button.js",
    "content": "import React from 'react';\nimport styled, { css } from 'styled-components';\n\nexport const buttonLinkStyling = css`\n  background: white;\n  color: #383838;\n  font-weight: normal;\n  font-size: 1.4rem;\n  font-style: normal;\n  font-stretch: normal;\n  height: 4rem;\n  line-height: 4rem;\n  padding: 0 2rem;\n  letter-spacing: 0.01rem;\n  text-align: center;\n  text-transform: uppercase;\n  transition: opacity 0.4s ease-out;\n\n  &:hover {\n    opacity: 0.8;\n  }\n  &:active {\n    opacity: 0.6;\n  }\n`;\n\nconst ButtonNoBorder = styled.button`\n  border: none;\n`;\n\nexport const Button = styled(props => (\n  <ButtonNoBorder {...props}>{props.children}</ButtonNoBorder>\n))`\n  ${buttonLinkStyling}\n`;\n"
  },
  {
    "path": "packages/site/src/components/footer.js",
    "content": "import React from 'react';\nimport { Wrapper } from './wrapper';\nimport styled from 'styled-components';\n\nimport logoFormidableWhite from '../assets/logo_formidable_white.svg';\n\nconst Container = styled.footer`\n  background: #1f1f1f;\n  color: white;\n  display: flex;\n  flex-direction: column;\n  height: auto;\n  padding: 9rem 0;\n  align-items: center;\n`;\n\nconst FooterDescription = styled.p`\n  flex: 2;\n  font-size: 1.4rem;\n  line-height: 1.6;\n  margin: 2rem 0 0;\n  max-width: 56rem;\n  text-align: left;\n  @media (min-width: 768px) {\n    font-size: 1.5rem;\n    margin: 0;\n    min-width: auto;\n  }\n  & a {\n    color: white;\n    transition: opacity 0.4s;\n  }\n  & a:hover {\n    opacity: 0.7;\n  }\n  & a:visited {\n    color: white;\n  }\n`;\n\nconst FooterLeft = styled.div`\n  display: flex;\n  flex: 1;\n  padding: 0 4rem 0 0;\n  text-align: left;\n`;\n\nconst FooterLogo = styled.img`\n  width: 100px;\n`;\n\nconst FooterLinks = styled.ul`\n  font-size: 1.4rem;\n  list-style: none;\n  padding: 0px 8px;\n  text-transform: uppercase;\n\n  & li {\n    margin: 0.2rem 0;\n  }\n\n  & a {\n    color: white;\n    letter-spacing: 0.05em;\n    transition: opacity 0.4s;\n  }\n\n  & a:hover {\n    opacity: 0.7;\n  }\n\n  & a:visited {\n    color: white;\n  }\n`;\n\nexport const Footer = () => (\n  <Container>\n    <Wrapper noPadding>\n      <FooterLeft>\n        <a href=\"https://formidable.com\" title=\"Formidable\">\n          <FooterLogo src={logoFormidableWhite} alt=\"Formidable Logo\" />\n        </a>\n        <FooterLinks>\n          <li>\n            <a href=\"https://formidable.com/contact/\" title=\"Contact\">\n              Contact\n            </a>\n          </li>\n          <li>\n            <a href=\"https://formidable.com/careers/\" title=\"Careers\">\n              Careers\n            </a>\n          </li>\n        </FooterLinks>\n      </FooterLeft>\n      <FooterDescription>\n        Formidable is a global design and engineering consultancy and open\n        source software organization, specializing in React.js, React Native,\n        GraphQL, Node.js, and the extended JavaScript ecosystem. We have\n        locations in Seattle, London, Toronto, Denver, and Phoenix with remote\n        consultants worldwide. For more information please visit{' '}\n        <a\n          href=\"https://formidable.com/\"\n          target=\"_blank\"\n          rel=\"noopener noreferrer\"\n        >\n          formidable.com.\n        </a>\n      </FooterDescription>\n    </Wrapper>\n  </Container>\n);\n"
  },
  {
    "path": "packages/site/src/components/header.js",
    "content": "import React from 'react';\nimport styled from 'styled-components';\nimport PropTypes from 'prop-types';\n\nimport Hero from '../screens/home/hero';\nimport logoFormidableWhite from '../assets/logo_formidable_white.svg';\nimport LeftTriangles from '../assets/left-triangles.svg';\nimport RightTriangles from '../assets/right-triangles.svg';\n\nconst Container = styled.header`\n  background: rgb(109, 117, 153);\n  background: linear-gradient(\n    225deg,\n    rgba(109, 117, 153, 1) 0%,\n    rgba(41, 45, 55, 1) 100%\n  );\n  background-size: 100% 100%;\n  color: white;\n  height: 100%;\n  padding: 0 0 4rem;\n  width: 100%;\n  display: flex;\n  justify-content: center;\n  position: relative;\n  overflow: hidden;\n`;\n\nconst HeaderContainer = styled.a`\n  display: flex;\n  position: absolute;\n  left: 0.25rem;\n  top: 0.25rem;\n  width: 12rem;\n  flex-direction: column;\n  color: #ffffff;\n  text-decoration: none;\n  z-index: 2;\n`;\n\nconst HeaderText = styled.p`\n  text-transform: uppercase;\n  font-size: 1.5rem;\n  margin-left: 14px;\n  line-height: 1.9rem;\n  margin-bottom: 0;\n`;\n\nconst HeaderLogo = styled.img`\n  width: 70px;\n  z-index: 1;\n`;\n\nconst LeftTrianglesImg = styled.img`\n  position: absolute;\n  display: block;\n  left: 0;\n  top: 0;\n  height: 80%;\n  max-width: none;\n`;\n\nconst RightTrianglesImg = styled.img`\n  position: absolute;\n  right: 0;\n  bottom: 0;\n  display: none;\n  height: 45%;\n  @media (min-width: 768px) {\n    display: block;\n  }\n`;\n\nexport const Header = ({ content }) => (\n  <Container>\n    <LeftTrianglesImg src={LeftTriangles} />\n    <RightTrianglesImg src={RightTriangles} />\n\n    <HeaderContainer href=\"https://formidable.com\" title=\"Formidable\">\n      <HeaderText>Another oss project by </HeaderText>\n      <HeaderLogo src={logoFormidableWhite} alt=\"Formidable Logo\" />\n    </HeaderContainer>\n    <Hero content={content.hero} />\n  </Container>\n);\n\nHeader.propTypes = {\n  content: PropTypes.shape({\n    hero: PropTypes.shape({ copyText: PropTypes.string }),\n  }).isRequired,\n};\n"
  },
  {
    "path": "packages/site/src/components/link.js",
    "content": "import React from 'react';\nimport styled from 'styled-components';\nimport { Link as ReactRouterLink } from 'react-router-dom';\n\nimport { buttonLinkStyling } from './button';\n\nexport const Link = styled(({ isExternal, ...rest }) =>\n  isExternal ? (\n    <a href={rest.to} {...rest}>\n      {rest.children}\n    </a>\n  ) : (\n    <ReactRouterLink {...rest} />\n  )\n)`\n  ${buttonLinkStyling}\n`;\n"
  },
  {
    "path": "packages/site/src/components/loading.js",
    "content": "import React from 'react';\nimport styled, { keyframes } from 'styled-components';\nimport Docs from '../screens/docs';\n\nconst Container = styled.div`\n  height: 100vh;\n  width: 100%;\n`;\n\nconst Loader = styled.div`\n  position: relative;\n  margin: 0 auto;\n  width: ${p => p.theme.spacing.xl};\n  top: calc(50% - ${p => p.theme.spacing.xl});\n\n  &:before {\n    content: '';\n    display: block;\n    padding-top: 100%;\n  }\n`;\n\nconst rotate = keyframes`\n  100% {\n    transform: rotate(360deg);\n  }\n`;\n\nconst dash = keyframes`\n  0% {\n    stroke-dasharray: 1, 200;\n    stroke-dashoffset: 0;\n  }\n  50% {\n    stroke-dasharray: 89, 200;\n    stroke-dashoffset: -35px;\n  }\n  100% {\n    stroke-dasharray: 89, 200;\n    stroke-dashoffset: -124px;\n  }\n`;\n\nconst Svg = styled.svg`\n  animation: ${rotate} 2s linear infinite;\n  height: 100%;\n  transform-origin: center center;\n  width: 100%;\n  position: absolute;\n  top: 0;\n  bottom: 0;\n  left: 0;\n  right: 0;\n  margin: auto;\n`;\n\nconst Circle = styled.circle`\n  stroke: ${p => p.theme.colors.accent};\n  stroke-dasharray: 1, 200;\n  stroke-dashoffset: 0;\n  animation: ${dash} 1.5s ease-in-out infinite;\n  stroke-linecap: round;\n`;\n\nexport const Loading = () => (\n  <Docs isLoading>\n    <Container>\n      <Loader>\n        <Svg className=\"circular\" viewBox=\"25 25 50 50\">\n          <Circle\n            className=\"path\"\n            cx=\"50\"\n            cy=\"50\"\n            r=\"20\"\n            fill=\"none\"\n            strokeWidth=\"2\"\n            strokeMiterlimit=\"10\"\n          />\n        </Svg>\n      </Loader>\n    </Container>\n  </Docs>\n);\n"
  },
  {
    "path": "packages/site/src/components/markdown.js",
    "content": "import styled from 'styled-components';\n\nexport const Markdown = styled.article`\n  width: 60vw;\n\n  @media (max-width: 768px) {\n    width: 75vw;\n  }\n\n  h1 {\n    font-size: 3.4rem;\n    margin: 0 0 2rem;\n\n    @media (min-width: 1024px) {\n      font-size: 4.8rem;\n    }\n\n    @media (max-width: 768px) {\n      margin: 6rem 0 2rem;\n    }\n  }\n\n  h2 {\n    font-size: 2.8rem;\n    margin: 6rem 0 2rem;\n    @media (min-width: 1024px) {\n      font-size: 2.5rem;\n    }\n  }\n\n  h3 {\n    font-size: 1.8rem;\n    margin: 2rem 0;\n    @media (min-width: 1024px) {\n      font-size: 2rem;\n    }\n  }\n\n  table {\n    border-collapse: collapse;\n  }\n\n  td {\n    height: 50px;\n    text-align: left;\n  }\n\n  td,\n  th {\n    padding: 15px;\n  }\n\n  th {\n    text-align: center;\n  }\n\n  table,\n  th,\n  td {\n    font-size: 1.7rem;\n    border: 1px solid lightgrey;\n\n    tr:nth-child(even) {\n      background-color: #f2f2f2;\n    }\n  }\n\n  pre {\n    background-color: #efefef;\n    padding: 2rem;\n    color: #333;\n  }\n\n  pre > code {\n    color: #333;\n  }\n\n  p {\n    font-size: 1.7rem;\n    line-height: 1.3;\n  }\n\n  p code {\n    border: 1px solid lightgrey;\n    opacity: 0.8;\n    padding: 0.5rem;\n    font-size: 1.5rem;\n    margin: 0 0.5rem 0 0.5rem;\n  }\n\n  blockquote {\n    margin: 0 0.2rem;\n    padding: 0 1.8rem;\n    border-left: 3px solid #255db0;\n  }\n\n  li {\n    font-size: 1.7rem;\n    line-height: 1.3;\n    padding: 0.5rem;\n\n    @media (max-width: 768px) {\n      margin-left: -2rem;\n    }\n  }\n\n  li code {\n    border: 1px solid lightgrey;\n    opacity: 0.8;\n    padding: 0.5rem;\n    font-size: 1.5rem;\n    margin: 0 0.5rem 0 0.5rem;\n  }\n\n  a {\n    color: #895160;\n\n    &:target {\n      display: block;\n      position: relative;\n      top: -60px;\n      visibility: hidden;\n    }\n    &:hover {\n      color: black;\n    }\n  }\n`;\n"
  },
  {
    "path": "packages/site/src/components/mdx.js",
    "content": "import React from 'react';\nimport styled, { css } from 'styled-components';\nimport { MDXProvider } from '@mdx-js/react';\nimport { Link } from 'react-router-dom';\nimport Highlight, { Prism } from 'prism-react-renderer';\nimport nightOwlLight from 'prism-react-renderer/themes/nightOwlLight';\n\nimport AnchorSvg from '../assets/anchor';\n\nconst getLanguage = className => {\n  const res = className.match(/language-(\\w+)/);\n  return res ? res[1] : null;\n};\n\nconst Pre = styled.pre`\n  background: ${p => p.theme.colors.codeBg};\n  border: 1px solid ${p => p.theme.colors.border};\n  border-radius: ${p => p.theme.spacing.xs};\n\n  font-size: ${p => p.theme.fontSizes.code};\n  line-height: ${p => p.theme.lineHeights.code};\n\n  max-width: 100%;\n  overflow-x: auto;\n  -webkit-overflow-scrolling: touch;\n  padding: ${p => p.theme.spacing.sm};\n  position: relative;\n  white-space: pre;\n`;\n\nconst Code = styled.code`\n  display: block;\n  font-family: ${p => p.theme.fonts.code};\n  color: ${p => p.theme.colors.code};\n  font-variant-ligatures: none;\n  font-feature-settings: normal;\n  white-space: pre;\n  hyphens: initial;\n`;\n\nconst InlineCode = styled(props => {\n  const children = props.children.replace(/\\\\\\|/g, '|');\n  return <code {...props}>{children}</code>;\n})`\n  background: ${p => p.theme.colors.codeBg};\n  color: ${p => p.theme.colors.code};\n  font-family: ${p => p.theme.fonts.code};\n  font-size: ${p => p.theme.fontSizes.small};\n  border-radius: ${p => p.theme.spacing.xs};\n\n  display: inline-block;\n  vertical-align: baseline;\n  font-variant-ligatures: none;\n  font-feature-settings: normal;\n  padding: 0 0.2em;\n  margin: 0;\n\n  a > & {\n    text-decoration: underline;\n  }\n`;\n\nconst InlineImage = styled.img`\n  display: inline-block;\n  margin: 0 ${p => p.theme.spacing.sm} ${p => p.theme.spacing.md} 0;\n  padding: ${p => p.theme.spacing.xs} ${p => p.theme.spacing.sm};\n  border: 1px solid ${p => p.theme.colors.border};\n  border-radius: ${p => p.theme.spacing.xs};\n`;\n\nconst ImageWrapper = styled.div`\n  margin: ${p => p.theme.spacing.md} 0;\n  border: 1px solid ${p => p.theme.colors.border};\n  border-radius: ${p => p.theme.spacing.xs};\n  background: ${p => p.theme.colors.bg};\n\n  display: flex;\n  flex-direction: column;\n\n  & > img {\n    padding: ${p => p.theme.spacing.md};\n    align-self: center;\n    max-height: 40vh;\n  }\n`;\n\nconst ImageAlt = styled.span.attrs(() => ({\n  'aria-hidden': true, // This is just duplicating alt\n}))`\n  display: block;\n  padding: ${p => p.theme.spacing.xs} ${p => p.theme.spacing.sm};\n  border-top: 1px solid ${p => p.theme.colors.border};\n  background: ${p => p.theme.colors.codeBg};\n  font-size: ${p => p.theme.fontSizes.small};\n`;\n\nconst Image = props => {\n  const { height, width, alt, src } = props;\n  if (height || width) return <InlineImage {...props} />;\n\n  return (\n    <ImageWrapper>\n      <img alt={alt} src={src} />\n      <ImageAlt>{alt}</ImageAlt>\n    </ImageWrapper>\n  );\n};\n\nconst HighlightCode = ({ className = '', children }) => {\n  const language = getLanguage(className);\n\n  return (\n    <Highlight\n      Prism={Prism}\n      theme={nightOwlLight}\n      code={children.trim()}\n      language={language}\n    >\n      {({ className, style, tokens, getLineProps, getTokenProps }) => (\n        <Code\n          style={{ ...style, backgroundColor: 'none' }}\n          className={className}\n        >\n          {tokens.map((line, i) => (\n            <div {...getLineProps({ line, key: i })}>\n              {line.map((token, key) => (\n                <span {...getTokenProps({ token, key })} />\n              ))}\n            </div>\n          ))}\n        </Code>\n      )}\n    </Highlight>\n  );\n};\n\nconst Blockquote = styled.blockquote`\n  margin: ${p => p.theme.spacing.md} 0;\n  padding: 0 0 0 ${p => p.theme.spacing.md};\n  border-left: 0.5rem solid ${p => p.theme.colors.border};\n  font-size: ${p => p.theme.fontSizes.small};\n\n  & > * {\n    margin: ${p => p.theme.spacing.sm} 0;\n  }\n`;\n\nconst sharedTableCellStyling = css`\n  padding: ${p => p.theme.spacing.xs} ${p => p.theme.spacing.sm};\n  border-left: 1px solid ${p => p.theme.colors.passiveBg};\n  border-bottom: 1px solid ${p => p.theme.colors.passiveBg};\n\n  & > ${InlineCode} {\n    white-space: pre-wrap;\n    display: inline;\n  }\n`;\n\nconst TableHeader = styled.th`\n  text-align: left;\n  white-space: nowrap;\n  ${sharedTableCellStyling}\n`;\n\nconst TableCell = styled.td`\n  ${sharedTableCellStyling}\n\n  ${p => {\n    const isCodeOnly = React.Children.toArray(p.children).every(\n      x => x.props && x.props.mdxType === 'inlineCode'\n    );\n    return (\n      isCodeOnly &&\n      css`\n        background-color: ${p.theme.colors.codeBg};\n\n        && > ${InlineCode} {\n          background: none;\n          padding: 0;\n          margin: 0;\n          white-space: pre;\n          display: block;\n        }\n      `\n    );\n  }}\n\n  &:first-child {\n    width: min-content;\n    min-width: 25rem;\n  }\n\n  @media ${p => p.theme.media.md} {\n    &:not(:first-child) {\n      overflow-wrap: break-word;\n    }\n  }\n`;\n\nconst TableScrollContainer = styled.div`\n  overflow-x: auto;\n\n  @media ${p => p.theme.media.maxmd} {\n    overflow-x: scroll;\n    -webkit-overflow-scrolling: touch;\n  }\n`;\n\nconst Table = styled.table`\n  border: 1px solid ${p => p.theme.colors.passiveBg};\n  border-collapse: collapse;\n  overflow-x: auto;\n\n  @media ${p => p.theme.media.maxmd} {\n    overflow-x: scroll;\n    overflow-wrap: initial;\n    word-wrap: initial;\n    word-break: initial;\n    hyphens: initial;\n  }\n`;\n\nconst TableScroll = props => (\n  <TableScrollContainer>\n    <Table {...props} />\n  </TableScrollContainer>\n);\n\nconst MdLink = ({ href, children }) => {\n  if (!/^\\w+:/.test(href) && !href.startsWith('#')) {\n    return <Link to={href}>{children}</Link>;\n  }\n\n  return (\n    <a rel=\"external\" href={href}>\n      {children}\n    </a>\n  );\n};\n\nconst HeadingText = styled.h1`\n  &:target:before {\n    content: '';\n    display: block;\n    height: 1.5em;\n    margin: -1.5em 0 0;\n  }\n`;\n\nconst AnchorLink = styled.a`\n  display: inline-block;\n  color: ${p => p.theme.colors.accent};\n  padding-right: 0.5rem;\n  width: 2rem;\n\n  @media ${({ theme }) => theme.media.sm} {\n    margin-left: -2rem;\n    display: none;\n\n    ${HeadingText}:hover > & {\n      display: inline-block;\n    }\n  }\n`;\n\nconst AnchorIcon = styled(AnchorSvg)`\n  height: 100%;\n`;\n\nconst Header = tag => {\n  const HeaderComponent = ({ id, children }) => (\n    <HeadingText as={tag} id={id}>\n      <AnchorLink href={`#${id}`}>\n        <AnchorIcon />\n      </AnchorLink>\n      {children}\n    </HeadingText>\n  );\n\n  HeaderComponent.displayName = `Header(${tag})`;\n  return HeaderComponent;\n};\n\nconst components = {\n  pre: Pre,\n  img: Image,\n  blockquote: Blockquote,\n  inlineCode: InlineCode,\n  code: HighlightCode,\n  table: TableScroll,\n  th: TableHeader,\n  td: TableCell,\n  a: MdLink,\n  h1: HeadingText,\n  h2: Header('h2'),\n  h3: Header('h3'),\n};\n\nexport const MDXComponents = ({ children }) => (\n  <MDXProvider components={components}>{children}</MDXProvider>\n);\n"
  },
  {
    "path": "packages/site/src/components/navigation.js",
    "content": "import styled from 'styled-components';\nimport { NavLink } from 'react-router-dom';\n\nimport ChevronIcon from '../assets/chevron';\n\nexport const SidebarContainer = styled.div`\n  display: ${p => (p.hidden ? 'none' : 'block')};\n  position: absolute;\n  left: 0;\n  right: 0;\n  bottom: 0;\n  min-height: 100%;\n  width: ${p => p.theme.layout.sidebar};\n\n  @media ${({ theme }) => theme.media.sm} {\n    display: block;\n    position: relative;\n    margin-left: calc(2 * ${p => p.theme.layout.stripes});\n  }\n`;\n\nexport const SideBarStripes = styled.div`\n  border-left: ${p => p.theme.layout.stripes} solid #8196ff;\n  border-right: ${p => p.theme.layout.stripes} solid #bcc6fa;\n  position: absolute;\n  height: 100%;\n  width: 0;\n  left: 0;\n  top: 0;\n  bottom: 0;\n`;\n\nexport const SidebarWrapper = styled.aside`\n  position: fixed;\n  bottom: 0;\n  top: ${p => p.theme.layout.header};\n  -webkit-overflow-scrolling: touch;\n  overflow-y: scroll;\n\n  display: flex;\n  flex-direction: column;\n  z-index: 1;\n  overflow-y: scroll;\n  min-height: 100%;\n  line-height: ${p => p.theme.lineHeights.body};\n  font-size: ${p => p.theme.fontSizes.small};\n\n  padding: ${p => p.theme.spacing.sm} ${p => p.theme.spacing.md};\n  background-color: ${p => p.theme.colors.bg};\n  border-right: 1px solid ${p => p.theme.colors.border};\n  border-top: 1px solid ${p => p.theme.colors.border};\n  width: ${p => p.theme.layout.sidebar};\n\n  @media ${({ theme }) => theme.media.sm} {\n    border: none;\n    background: none;\n    padding-top: ${p => p.theme.spacing.md};\n  }\n`;\n\nexport const SidebarNavItem = styled(NavLink).attrs(() => ({\n  activeClassName: 'active',\n}))`\n  display: block;\n  margin: ${p => p.theme.spacing.xs} 0;\n  color: ${p => p.theme.colors.text};\n  font-weight: ${p => p.theme.fontWeights.heading};\n  text-decoration: none;\n  width: 100%;\n\n  &:hover {\n    color: ${p => p.theme.colors.accent};\n  }\n\n  &.active {\n    color: ${p => p.theme.colors.accent};\n  }\n`;\n\nexport const ChevronItem = styled(ChevronIcon).attrs(() => ({\n  'aria-hidden': 'true',\n}))`\n  display: inline-block;\n  color: inherit;\n  vertical-align: baseline;\n  margin-top: 0.08em;\n  margin-left: 0.3em;\n  padding: 0.08em;\n  width: 1em;\n  height: 1em;\n\n  position: relative;\n  top: 0.16em;\n\n  ${SidebarNavItem}.active & {\n    transform: rotate(180deg);\n  }\n`;\n\nexport const SidebarNavSubItemWrapper = styled.div`\n  padding-left: ${p => p.theme.spacing.sm};\n  margin-bottom: ${p => p.theme.spacing.xs};\n`;\n\nexport const SidebarNavSubItem = styled(NavLink).attrs(() => ({}))`\n  display: block;\n  color: ${p => p.theme.colors.passive};\n  font-weight: ${p => p.theme.fontWeights.body};\n  text-decoration: none;\n  margin: ${p =>\n    `${p.theme.spacing.xs} 0 0 ${p.nested ? p.theme.spacing.sm : 0}`};\n\n  &:first-child {\n    margin-top: 0;\n  }\n\n  &:hover {\n    color: ${p => p.theme.colors.accent};\n  }\n\n  &.active {\n    color: ${p => p.theme.colors.accent};\n    font-weight: ${p => p.theme.fontWeights.heading};\n  }\n`;\n"
  },
  {
    "path": "packages/site/src/components/panel.js",
    "content": "import React from 'react';\nimport styled, { css } from 'styled-components';\nimport constants from '../constants';\n\nconst dark = css`\n  background-color: #0d1129;\n`;\n\nconst light = css`\n  background: ${constants.color};\n  border-bottom: 1rem solid rgba(0, 0, 0, 0.4);\n  box-shadow: inset 0 -1rem 0 rgba(0, 0, 0, 0.2);\n`;\nexport const FullWidthContainer = styled.div`\n  color: #e3eef8;\n  display: flex;\n  justify-content: center;\n  ${p => (p.isLight ? light : dark)};\n  ${p => p.background && `background: ${p.background}`}\n`;\n\nexport const SectionWrapper = styled.div`\n  flex-direction: column;\n  align-items: center;\n  display: flex;\n  padding: 8rem 4rem;\n  width: 100%;\n  @media (min-width: 768px) {\n    flex-direction: column;\n    margin: 0 8rem;\n    padding: 8rem 8rem;\n  }\n`;\n\nexport const PanelSectionWrapper = ({\n  children,\n  isLight,\n  background,\n  ...rest\n}) => (\n  <FullWidthContainer isLight={!!isLight} background={background} {...rest}>\n    <SectionWrapper>{children}</SectionWrapper>\n  </FullWidthContainer>\n);\n"
  },
  {
    "path": "packages/site/src/components/scroll-to-top.js",
    "content": "import React, { useEffect, useRef } from 'react';\nimport { useLocation } from 'react-router-dom';\nimport { useMarkdownPage } from 'react-static-plugin-md-pages';\n\nconst parsePathname = pathname => {\n  const match = pathname && pathname.match(/#[a-z|-]+/);\n  return match && match[0];\n};\n\nexport const ScrollToTop = () => {\n  const inputRef = useRef(null);\n  const location = useLocation();\n  const md = useMarkdownPage();\n\n  const hash = location.hash || parsePathname(location.pathname);\n\n  useEffect(() => {\n    if (hash && md) {\n      inputRef.current.click();\n    } else {\n      window.scrollTo(0, 0);\n    }\n  }, [hash, md]);\n\n  return <a href={hash} ref={inputRef} />;\n};\n"
  },
  {
    "path": "packages/site/src/components/secondary-title.js",
    "content": "import styled from 'styled-components';\n\nexport const SecondaryTitle = styled.h3`\n  color: white;\n  font-size: 2rem;\n  line-height: 2.4rem;\n  margin: 2rem auto 1rem;\n  text-align: center;\n  @media (min-width: 768px) {\n    font-size: 2.2rem;\n    line-height: 2.6rem;\n  }\n`;\n"
  },
  {
    "path": "packages/site/src/components/section-title.js",
    "content": "import styled from 'styled-components';\n\nexport const SectionTitle = styled.h2`\n  color: #fff;\n  font-size: 3.5rem;\n  flex: auto;\n  line-height: 1.3;\n  margin: 0 0 3rem;\n  width: 100%;\n  text-align: center;\n  @media (min-width: 768px) {\n    font-size: 4.5rem;\n    margin: 0 0 6rem;\n  }\n`;\n"
  },
  {
    "path": "packages/site/src/components/sidebar-search-input.js",
    "content": "import React from 'react';\nimport PropTypes from 'prop-types';\nimport styled from 'styled-components';\n\nconst StyledInput = styled.input`\n  background-color: rgba(255, 255, 255, 0.8);\n  border: none;\n  border-radius: 0.5rem;\n  color: ${p => p.theme.colors.text};\n  font-family: ${p => p.theme.fonts.body};\n  font-size: 1.6rem;\n  line-height: 2.3rem;\n  letter-spacing: -0.6px;\n  margin: ${p =>\n    `${p.theme.spacing.sm} 0 ${p.theme.spacing.sm} calc(${p.theme.spacing.xs} * -1.5)`};\n  padding: ${p =>\n    `${p.theme.spacing.xs} calc(${p.theme.spacing.xs} * 1.5) ${p.theme.spacing.xs}`};\n  width: calc(100% + 1.8rem);\n  background-color: ${p => p.theme.colors.passiveBg};\n\n  @media ${p => p.theme.media.sm} {\n    background-color: ${p => p.theme.colors.bg};\n  }\n`;\n\nconst SidebarSearchInput = ({ value, onHandleInputChange }) => (\n  <StyledInput\n    onChange={onHandleInputChange}\n    placeholder=\"Filter...\"\n    type=\"search\"\n    value={value}\n  />\n);\n\nSidebarSearchInput.propTypes = {\n  value: PropTypes.string,\n  onHandleInputChange: PropTypes.func,\n};\n\nexport default SidebarSearchInput;\n"
  },
  {
    "path": "packages/site/src/components/sidebar.js",
    "content": "/* eslint-disable react-hooks/rules-of-hooks */\n\nimport React, { Fragment, useMemo, useState } from 'react';\nimport styled from 'styled-components';\nimport Fuse from 'fuse.js';\nimport { Link, useLocation } from 'react-router-dom';\n\nimport { useMarkdownTree } from 'react-static-plugin-md-pages';\n\nimport {\n  SidebarNavItem,\n  SidebarNavSubItem,\n  SidebarNavSubItemWrapper,\n  SidebarContainer,\n  SidebarWrapper,\n  SideBarStripes,\n  ChevronItem,\n} from './navigation';\nimport SidebarSearchInput from './sidebar-search-input';\n\nimport logoSidebar from '../assets/sidebar-badge.svg';\n\nconst HeroLogoLink = styled(Link)`\n  display: none;\n  flex-direction: row;\n  justify-content: center;\n  margin-bottom: ${p => p.theme.spacing.sm};\n  align-self: center;\n\n  @media ${p => p.theme.media.sm} {\n    display: flex;\n  }\n`;\n\nconst HeroLogo = styled.img.attrs(() => ({\n  src: logoSidebar,\n  alt: 'urql',\n}))`\n  width: ${p => p.theme.layout.logo};\n  height: ${p => p.theme.layout.logo};\n`;\n\nconst ContentWrapper = styled.div`\n  display: flex;\n  flex-direction: column;\n  padding-bottom: ${p => p.theme.spacing.lg};\n`;\n\nexport const SidebarStyling = ({ children, sidebarOpen }) => (\n  <>\n    <SideBarStripes />\n    <SidebarContainer hidden={!sidebarOpen}>\n      <SidebarWrapper>\n        <HeroLogoLink to=\"/\">\n          <HeroLogo />\n        </HeroLogoLink>\n        <ContentWrapper>{children}</ContentWrapper>\n      </SidebarWrapper>\n    </SidebarContainer>\n  </>\n);\n\nconst getMatchTree = (() => {\n  const sortByRefIndex = (a, b) => a.refIndex - b.refIndex;\n\n  const options = {\n    distance: 100,\n    findAllMatches: true,\n    includeMatches: true,\n    keys: [\n      'frontmatter.title',\n      `children.frontmatter.title`,\n      'children.headings.value',\n    ],\n    threshold: 0.2,\n  };\n\n  return (children, pattern) => {\n    // Filter any nested heading with a depth greater than 2\n    const childrenMaxH3 = children.map(child => ({\n      ...child,\n      children:\n        child.children &&\n        child.children.map(child => ({\n          ...child,\n          headings: child.headings.filter(heading => heading.depth == 2),\n        })),\n    }));\n\n    const fuse = new Fuse(childrenMaxH3, options);\n    let matches = fuse.search(pattern);\n\n    // For every matching section, include only matching headers\n    return matches\n      .reduce((matches, match) => {\n        const matchesMap = new Map();\n        match.matches.forEach(individualMatch => {\n          matchesMap.set(individualMatch.value, {\n            indices: individualMatch.indices,\n          });\n        });\n\n        // Add the top level heading but don't add subheadings unless they match\n        const currentItem = {\n          ...match.item,\n          matchedIndices: match.indices,\n          refIndex: match.refIndex,\n        };\n\n        // For every child of the currently matched section, add all appplicable\n        // H2 and H3 headers plus their indices\n        if (currentItem.children) {\n          currentItem.children = currentItem.children.reduce(\n            (children, child) => {\n              const newChild = { ...child };\n              newChild.headings = newChild.headings.reduce(\n                (headings, header) => {\n                  const match = matchesMap.get(header.value);\n                  if (match) {\n                    headings.push({\n                      ...header,\n                      matchedIndices: match.indices,\n                    });\n                  }\n                  return headings;\n                },\n                []\n              );\n\n              const match = matchesMap.get(newChild.frontmatter.title);\n              if (match) {\n                newChild.matchedIndices = match.indices;\n              }\n\n              if (match || newChild.headings.length > 0) {\n                children.push(newChild);\n              }\n              return children;\n            },\n            []\n          );\n        }\n\n        return [...matches, currentItem];\n      }, [])\n      .sort(sortByRefIndex);\n  };\n})();\n\n// Wrap matching substrings in <strong>\nconst highlightText = (text, indices) => (\n  <>\n    {indices.map(([startIndex, endIndex], i) => {\n      const isLastIndex = !indices[i + 1];\n      const prevEndIndex = indices[i - 1] ? indices[i - 1][1] : -1;\n\n      return (\n        <>\n          {startIndex != 0 ? text.slice(prevEndIndex + 1, startIndex) : ''}\n          <strong>{text.slice(startIndex, endIndex + 1)}</strong>\n          {isLastIndex && endIndex < text.length\n            ? text.slice(endIndex + 1, text.length)\n            : ''}\n        </>\n      );\n    })}\n  </>\n);\n\nconst Sidebar = ({ closeSidebar, ...props }) => {\n  const [filterTerm, setFilterTerm] = useState('');\n  const location = useLocation();\n  const tree = useMarkdownTree();\n\n  const sidebarItems = useMemo(() => {\n    let pathname = location.pathname.match(/docs\\/?(.+)?/);\n    if (!pathname || !tree || !tree.children || !location) {\n      return null;\n    }\n\n    pathname = pathname[0];\n    const trimmedPathname = pathname.replace(/(\\/$)|(\\/#.+)/, '');\n\n    let children = tree.children;\n    if (tree.frontmatter && tree.originalPath) {\n      children = [{ ...tree, children: undefined }, ...children];\n    }\n\n    if (filterTerm) {\n      children = getMatchTree(children, filterTerm);\n    }\n\n    return children.map(page => {\n      const pageChildren = page.children || [];\n\n      const isActive = pageChildren.length\n        ? trimmedPathname.startsWith(page.path)\n        : !!page.path.match(new RegExp(`${trimmedPathname}$`, 'g'));\n\n      const showSubItems = !!filterTerm || (pageChildren.length && isActive);\n\n      return (\n        <Fragment key={page.key}>\n          <SidebarNavItem\n            to={`/${page.path}/`}\n            // If there is an active filter term in place, expand all headings\n            isActive={() => isActive}\n            onClick={closeSidebar}\n          >\n            {page.matchedIndices\n              ? highlightText(page.frontmatter.title, page.matchedIndices)\n              : page.frontmatter.title}\n            {pageChildren.length ? <ChevronItem /> : null}\n          </SidebarNavItem>\n\n          {showSubItems ? (\n            <SidebarNavSubItemWrapper>\n              {pageChildren.map(childPage => (\n                <Fragment key={childPage.key}>\n                  <SidebarNavSubItem\n                    isActive={() =>\n                      !!childPage.path.match(\n                        new RegExp(`${trimmedPathname}$`, 'g')\n                      )\n                    }\n                    to={`/${childPage.path}/`}\n                  >\n                    {childPage.matchedIndices\n                      ? highlightText(\n                          childPage.frontmatter.title,\n                          childPage.matchedIndices\n                        )\n                      : childPage.frontmatter.title}\n                  </SidebarNavSubItem>\n                  {/* Only Show H3 items if there is a search applied */}\n                  {filterTerm\n                    ? childPage.headings.map(heading => (\n                        <SidebarNavSubItem\n                          to={`/${childPage.path}/#${heading.slug}`}\n                          key={heading.value}\n                          nested={true}\n                        >\n                          {highlightText(heading.value, heading.matchedIndices)}\n                        </SidebarNavSubItem>\n                      ))\n                    : null}\n                </Fragment>\n              ))}\n            </SidebarNavSubItemWrapper>\n          ) : null}\n        </Fragment>\n      );\n    });\n  }, [location, tree, filterTerm, closeSidebar]);\n\n  return (\n    <SidebarStyling {...props}>\n      <SidebarSearchInput\n        onHandleInputChange={e => setFilterTerm(e.target.value)}\n        value={filterTerm}\n      />\n      {sidebarItems}\n    </SidebarStyling>\n  );\n};\n\nexport default Sidebar;\n"
  },
  {
    "path": "packages/site/src/components/wrapper.js",
    "content": "import styled from 'styled-components';\n\nexport const Wrapper = styled.div`\n  display: flex;\n  flex-direction: column;\n  flex-wrap: wrap;\n  justify-content: space-between;\n  margin: 0;\n  padding: ${props => (props.noPadding ? '0 4rem' : '4rem')};\n  text-align: center;\n  width: 100%;\n\n  @media (min-width: 768px) {\n    flex-direction: row;\n    max-width: 116rem;\n    padding: ${props => (props.noPadding ? '0 4rem' : '4rem 8rem')};\n  }\n\n  @media (max-width: 768px) {\n    padding: ${props => (props.noPadding ? '0 4rem' : '0 8rem')};\n    text-align: center;\n    img {\n      max-width: 240px;\n    }\n  }\n`;\n"
  },
  {
    "path": "packages/site/src/constants.js",
    "content": "const constants = {\n  docsTitle: 'URQL',\n  githubIssues: 'https://www.github.com/urql-graphql/urql/issues',\n  github: 'https://www.github.com/urql-graphql/urql',\n  readme: 'https://github.com/urql-graphql/urql/blob/main/README.md',\n  color: '#6B78B8',\n  googleAnalyticsId: 'UA-43290258-1',\n};\n\nexport default constants;\n"
  },
  {
    "path": "packages/site/src/google-analytics.js",
    "content": "import React from 'react';\nimport { useBasepath } from 'react-static';\nimport PropTypes from 'prop-types';\n\nlet Analytics = {};\n\nif (typeof document !== 'undefined') {\n  Analytics = require('react-router-ga').default;\n} else {\n  Analytics = React.Fragment;\n}\n\nconst GoogleAnalytics = ({ children, ...rest }) => {\n  const basename = `/${useBasepath() || ''}`;\n  if (typeof document !== 'undefined') {\n    // fragment doesn't like it when you try to give it attributes\n    return (\n      <Analytics {...rest} basename={basename}>\n        {children}\n      </Analytics>\n    );\n  }\n  return <Analytics>{children}</Analytics>;\n};\n\nGoogleAnalytics.propTypes = {\n  children: PropTypes.element,\n};\n\nexport default GoogleAnalytics;\n"
  },
  {
    "path": "packages/site/src/google-tag-manager.js",
    "content": "/**\n * Google Tag Manager\n */\nconst TagManager = require('react-gtm-module');\n\nexport const initGoogleTagManager = () => {\n  if (typeof document === 'undefined') {\n    return {};\n  } else {\n    return TagManager.initialize({ gtmId: 'GTM-MD32945' });\n  }\n};\n"
  },
  {
    "path": "packages/site/src/html.js",
    "content": "import React from 'react';\n\nconst Document = ({ Html, Head, Body, children }) => (\n  <Html lang=\"en\">\n    <Head>\n      <meta charSet=\"utf-8\" />\n      <meta httpEquiv=\"X-UA-Compatible\" content=\"IE=edge\" />\n      <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\" />\n      <meta\n        name=\"description\"\n        content=\"A highly customisable and versatile GraphQL client.\"\n      />\n      <meta property=\"og:title\" content=\"urql Documentation\" />\n      <meta property=\"og:site_name\" content=\"urql Documentation\" />\n      <meta property=\"og:type\" content=\"website\" />\n      <meta\n        property=\"og:url\"\n        content=\"http://www.formidable.com/open-source/urql/\"\n      />\n      <meta\n        property=\"og:description\"\n        content=\"A highly customisable and versatile GraphQL client.\"\n      />\n      <link\n        rel=\"icon\"\n        type=\"image/png\"\n        sizes=\"32x32\"\n        href=\"/favicon/favicon-32.png\"\n      />\n      <link rel=\"manifest\" href=\"./site.webmanifest\" />\n      <meta name=\"msapplication-TileColor\" content=\"#ff4081\" />\n      <meta name=\"msapplica tion-config\" content=\"./browserconfig.xml\" />\n      <meta name=\"theme-color\" content=\"#ffffff\" />\n      <link\n        href=\"https://fonts.googleapis.com/css?family=Space+Mono&display=swap\"\n        rel=\"stylesheet\"\n      />\n      <title>urql Documentation</title>\n    </Head>\n    <Body>{children}</Body>\n  </Html>\n);\n\nexport default Document;\n"
  },
  {
    "path": "packages/site/src/index.js",
    "content": "import React from 'react';\nimport { render, hydrate } from 'react-dom';\nimport { AppContainer } from 'react-hot-loader';\n\nimport App from './app';\n\nexport default App;\n\n// Render your app\nif (typeof document !== 'undefined') {\n  const renderMethod = module.hot ? render : hydrate;\n  const mount = Comp => {\n    renderMethod(\n      <AppContainer>\n        <Comp />\n      </AppContainer>,\n      document.getElementById('root')\n    );\n  };\n\n  mount(App);\n  if (module.hot) {\n    module.hot.accept('./app', () => mount(require('./app').default));\n  }\n}\n"
  },
  {
    "path": "packages/site/src/screens/404/404.js",
    "content": "import React from 'react';\n\nconst NotFound = () => {\n  return <h1>404! That page does not exist :(</h1>;\n};\n\nexport default NotFound;\n"
  },
  {
    "path": "packages/site/src/screens/404/index.js",
    "content": "import React from 'react';\nimport Docs from '../docs';\nimport NotFoundPage from './404';\n\nconst NotFound = () => {\n  return (\n    <Docs isLoading>\n      <NotFoundPage />\n    </Docs>\n  );\n};\n\nexport default NotFound;\n"
  },
  {
    "path": "packages/site/src/screens/docs/article.js",
    "content": "/* eslint-disable react-hooks/rules-of-hooks */\n\nimport React from 'react';\nimport { Head } from 'react-static';\nimport styled from 'styled-components';\nimport { useMarkdownPage } from 'react-static-plugin-md-pages';\nimport { ScrollToTop } from '../../components/scroll-to-top';\n\nimport { MDXComponents } from '../../components/mdx';\n\nconst Container = styled.main.attrs(() => ({\n  className: 'page-content',\n}))`\n  flex: 1;\n  width: 100%;\n  display: flex;\n  flex-direction: row-reverse;\n  align-items: flex-start;\n`;\n\nconst Content = styled.article.attrs(() => ({\n  id: 'page-content',\n}))`\n  flex: 1;\n  min-height: calc(100vh - ${p => p.theme.layout.header});\n  background: ${p => p.theme.colors.bg};\n  padding: ${p => p.theme.spacing.md};\n\n  @media ${p => p.theme.media.lg} {\n    padding: ${p => p.theme.spacing.lg};\n  }\n\n  overflow-wrap: break-word;\n  word-wrap: break-word;\n  word-break: break-word;\n  hyphens: auto;\n`;\n\nconst Legend = styled.aside`\n  display: none;\n\n  @media ${({ theme }) => theme.media.lg} {\n    display: block;\n    position: sticky;\n    top: ${p => p.theme.layout.header};\n    width: 100%;\n    max-width: ${p => p.theme.layout.legend};\n    padding: ${p => p.theme.spacing.lg} ${p => p.theme.spacing.md};\n    margin: 0;\n    overflow: auto;\n    height: calc(100vh - ${p => p.theme.layout.header});\n  }\n`;\n\nconst LegendTitle = styled.h3`\n  font-size: ${p => p.theme.fontSizes.body};\n  font-weight: ${p => p.theme.fontWeights.heading};\n  margin-bottom: ${p => p.theme.spacing.sm};\n`;\n\nconst HeadingList = styled.ul`\n  list-style-type: none;\n  margin: 0;\n  padding: 0;\n`;\n\nconst HeadingItem = styled.li`\n  line-height: ${p => p.theme.lineHeights.heading};\n  margin-bottom: ${p => p.theme.spacing.xs};\n  margin-left: ${p => (p.depth >= 3 ? p.theme.spacing.sm : 0)};\n\n  > a {\n    font-size: ${p => p.theme.fontSizes.small};\n    font-weight: ${p =>\n      p.depth < 3 ? p.theme.fontWeights.links : p.theme.fontWeights.body};\n    color: ${p => p.theme.colors.passive};\n    text-decoration: none;\n  }\n`;\n\nconst SectionList = () => {\n  const page = useMarkdownPage();\n  if (!page || !page.headings) return null;\n\n  const title = (page.frontmatter && page.frontmatter.title) || null;\n  const headings = page.headings.filter(x => x.depth > 1);\n  if (headings.length === 0) return null;\n\n  return (\n    <>\n      {title && (\n        <Head>\n          <title>{title} | urql Documentation</title>\n        </Head>\n      )}\n      <LegendTitle>In this section</LegendTitle>\n      <HeadingList>\n        {headings.map(heading => (\n          <HeadingItem key={heading.slug} depth={heading.depth}>\n            <a href={`#${heading.slug}`}>{heading.value}</a>\n          </HeadingItem>\n        ))}\n      </HeadingList>\n    </>\n  );\n};\n\nexport const ArticleStyling = ({ children, SectionList }) => (\n  <Container>\n    <Legend>{SectionList && <SectionList />}</Legend>\n    <Content>{children}</Content>\n  </Container>\n);\n\nconst Article = ({ children }) => (\n  <>\n    <ScrollToTop />\n    <ArticleStyling SectionList={SectionList}>\n      <MDXComponents>{children}</MDXComponents>\n    </ArticleStyling>\n  </>\n);\n\nexport default Article;\n"
  },
  {
    "path": "packages/site/src/screens/docs/header.js",
    "content": "import React from 'react';\nimport styled from 'styled-components';\nimport { Link } from 'react-router-dom';\n\nimport formidableLogo from '../../assets/logos/logo-formidable.svg';\n\nconst Fixed = styled.header`\n  position: fixed;\n  top: 0;\n  left: 0;\n  right: 0;\n  width: 100%;\n  z-index: 1;\n\n  box-sizing: border-box;\n  height: ${p => p.theme.layout.header};\n\n  background: ${p => p.theme.colors.bg};\n  border-bottom: 1px solid ${p => p.theme.colors.border};\n  padding: 0 ${p => p.theme.spacing.md};\n  box-shadow: ${p => p.theme.shadows.header};\n`;\n\nconst Wrapper = styled.div`\n  width: 100%;\n  height: 100%;\n  max-width: ${p => p.theme.layout.page};\n  margin: 0 auto;\n  padding-top: 2px;\n  display: flex;\n  flex-direction: row;\n  align-items: center;\n`;\n\nconst BlockLink = styled.a`\n  display: flex;\n  color: inherit;\n  text-decoration: none;\n`;\n\nconst ProjectWording = styled(Link)`\n  display: flex;\n  text-decoration: none;\n  font-family: ${p => p.theme.fonts.code};\n  color: ${p => p.theme.colors.accent};\n  margin-left: 0.6ch;\n  font-size: 1.9rem;\n`;\n\nconst FormidableLogo = styled.img.attrs(() => ({\n  src: formidableLogo,\n}))`\n  height: 2.8rem;\n  position: relative;\n  top: -0.1rem;\n`;\n\nconst Header = () => (\n  <Fixed>\n    <Wrapper>\n      <BlockLink href=\"https://formidable.com/\">\n        <FormidableLogo />\n      </BlockLink>\n      <ProjectWording to=\"/\">urql</ProjectWording>\n    </Wrapper>\n  </Fixed>\n);\n\nexport default Header;\n"
  },
  {
    "path": "packages/site/src/screens/docs/index.js",
    "content": "import React, { useState, useCallback } from 'react';\nimport styled from 'styled-components';\n\nimport Article, { ArticleStyling } from './article';\nimport Header from './header';\nimport Sidebar from '../../components/sidebar';\n\nimport burger from '../../assets/burger.svg';\nimport closeButton from '../../assets/close.svg';\n\nconst Container = styled.div`\n  position: relative;\n  display: flex;\n  flex-direction: row;\n\n  width: 100%;\n  max-width: ${p => p.theme.layout.page};\n  margin: 0 auto;\n  margin-top: ${p => p.theme.layout.header};\n`;\n\nconst OpenCloseSidebar = styled.img.attrs(props => ({\n  src: props.sidebarOpen ? closeButton : burger,\n}))`\n  cursor: pointer;\n  display: block;\n  margin: ${p => p.theme.spacing.sm} ${p => p.theme.spacing.md};\n  position: fixed;\n  right: 0;\n  top: 0;\n  z-index: 1;\n\n  @media ${p => p.theme.media.sm} {\n    display: none;\n  }\n`;\n\nconst Docs = ({ isLoading, children }) => {\n  const [sidebarOpen, setSidebarOpen] = useState(false);\n\n  const closeSidebar = useCallback(() => {\n    setSidebarOpen(false);\n  }, [setSidebarOpen]);\n\n  return (\n    <>\n      <Header />\n      <Container>\n        <OpenCloseSidebar\n          sidebarOpen={sidebarOpen}\n          onClick={() => setSidebarOpen(prev => !prev)}\n        />\n        {/* load just the styles if Suspense fallback in use */}\n        <Sidebar sidebarOpen={sidebarOpen} closeSidebar={closeSidebar} />\n        {isLoading ? (\n          <ArticleStyling>{children}</ArticleStyling>\n        ) : (\n          <Article>{children}</Article>\n        )}\n      </Container>\n    </>\n  );\n};\n\nexport default Docs;\n"
  },
  {
    "path": "packages/site/src/screens/home/_content.js",
    "content": "const content = {\n  header: {\n    hero: {\n      copyText: 'npm install urql graphql',\n    },\n  },\n  features: [\n    {\n      title: 'Performant and functional',\n      description:\n        'Lightweight, powerful, and easy to use; urql is a great alternative to bulky GraphQL clients.',\n      icon: require('../../assets/gql-tile.svg'),\n    },\n    {\n      title: 'Extensible library that grows with you',\n      description:\n        'Want to change how you fetch, cache, or subscribe to data? The urql exchanges allow you to customize your data layer to suit your needs.',\n      icon: require('../../assets/eagle-tile.svg'),\n    },\n    {\n      title: 'Logical default behavior and caching',\n      description:\n        'Adding urql enables you to rapidly use GraphQL in your apps without complex configuration or large API overhead.',\n      icon: require('../../assets/clock-tile.svg'),\n    },\n  ],\n  preview: {\n    description: '',\n    media: '',\n  },\n  getStarted: {\n    description: `With its intuitive set of lightweight API's, getting started with urql is a breeze. Dive into the documentation to get up and running in minutes.`,\n    link: '/docs',\n  },\n  oss: [\n    {\n      title: 'Victory',\n      description:\n        'An ecosystem of modular data visualization components for React. Friendly and flexible.',\n      logo: require('../../assets/badge_victory.svg'),\n      link: 'https://formidable.com/open-source/victory',\n    },\n    {\n      title: 'urql',\n      description:\n        'Universal React Query Library is a blazing-fast GraphQL client, exposed as a set of ReactJS components.',\n      logo: require('../../assets/sidebar-badge.svg'),\n      link: 'https://formidable.com/open-source/urql/',\n    },\n    {\n      title: 'Spectacle',\n      description:\n        'A React.js based library for creating sleek presentations using JSX syntax that gives you the ability to live demo your code.',\n      logo: require('../../assets/badge_spectacle.svg'),\n      link: 'https://formidable.com/open-source/spectacle/',\n    },\n    {\n      title: 'Runpkg',\n      description:\n        'The online package explorer. Runpkg turns any npm package into an interactive and informative browsing experience',\n      logo: require('../../assets/badge_runpkg.svg'),\n      link: 'https://www.runpkg.com/',\n    },\n  ],\n};\n\nexport default content;\n"
  },
  {
    "path": "packages/site/src/screens/home/features.js",
    "content": "import React from 'react';\nimport PropTypes from 'prop-types';\nimport styled from 'styled-components';\nimport { BodyCopy } from '../../components/body-copy';\nimport { SecondaryTitle } from '../../components/secondary-title';\nimport { SectionTitle } from '../../components/section-title';\nimport { PanelSectionWrapper } from '../../components/panel';\n\nconst FeatureWrapper = styled.div`\n  display: flex;\n  justify-content: space-between;\n  flex-direction: column;\n  @media (min-width: 768px) {\n    flex-direction: row;\n  }\n`;\nconst FeatureCard = styled.div`\n  display: flex;\n  flex-direction: column;\n  align-items: center;\n  width: 100%;\n  max-width: 28rem;\n  text-align: center;\n  > img {\n    width: 100%;\n    max-width: 28rem;\n    box-shadow: -20px 20px 0 0 rgba(0, 0, 0, 0.5);\n  }\n  &:not(:last-child) {\n    margin: 0 0 4rem;\n  }\n  @media (min-width: 768px) {\n    margin: 0;\n    width: calc(1 / 3 * 100% - (1 - 1 / 3) * 40px);\n    align-items: flex-start;\n    text-align: left;\n  }\n  @media (min-width: 1024px) {\n    width: calc(1 / 3 * 100% - (1 - 1 / 3) * 80px);\n  }\n`;\n\nconst SectionTitleStyled = styled(SectionTitle)`\n  margin-top: 0;\n  margin-bottom: 4rem;\n  @media (min-width: 768px) {\n    margin-top: 0;\n    margin-bottom: 6rem;\n  }\n`;\n\nconst SecondaryTitleStyled = styled(SecondaryTitle)`\n  @media (min-width: 768px) {\n    margin-left: 0;\n    margin-right: 0;\n  }\n`;\n\nclass Features extends React.Component {\n  render() {\n    return (\n      <PanelSectionWrapper>\n        <SectionTitleStyled>Features</SectionTitleStyled>\n        <FeatureWrapper>\n          {this.props.featureArray.map(feature => (\n            <FeatureCard key={feature.title}>\n              <img src={feature.icon} />\n              <SecondaryTitleStyled>{feature.title}</SecondaryTitleStyled>\n              <BodyCopy>{feature.description}</BodyCopy>\n            </FeatureCard>\n          ))}\n        </FeatureWrapper>\n      </PanelSectionWrapper>\n    );\n  }\n}\n\nFeatures.propTypes = {\n  featureArray: PropTypes.array,\n};\n\nexport default Features;\n"
  },
  {
    "path": "packages/site/src/screens/home/get-started.js",
    "content": "import React from 'react';\nimport PropTypes from 'prop-types';\nimport styled from 'styled-components';\nimport { BodyCopy } from '../../components/body-copy';\nimport { Link } from '../../components/link';\nimport { SectionTitle } from '../../components/section-title';\nimport { PanelSectionWrapper } from '../../components/panel';\n\nconst GetStartedWrapper = styled.div`\n  align-items: center;\n  display: flex;\n  flex-direction: column;\n  max-width: 55rem;\n  p {\n    text-align: center;\n  }\n  h2 {\n    margin-top: 0;\n  }\n`;\n\nconst GetStartedTitle = styled(SectionTitle)`\n  margin: 2rem 0 4rem;\n`;\n\nconst ButtonsWrapper = styled.div`\n  display: flex;\n  align-items: center;\n  margin-top: 6rem;\n  flex-direction: column;\n  @media (min-width: 768px) {\n    flex-direction: row;\n  }\n`;\n\nclass GetStarted extends React.Component {\n  render() {\n    const { content } = this.props;\n\n    return (\n      <PanelSectionWrapper>\n        <GetStartedWrapper>\n          <GetStartedTitle>Get Started</GetStartedTitle>\n          <BodyCopy noMargin>{content.description}</BodyCopy>\n          <ButtonsWrapper>\n            <Link to=\"docs/\">Quick Start Guide</Link>\n          </ButtonsWrapper>\n        </GetStartedWrapper>\n      </PanelSectionWrapper>\n    );\n  }\n}\n\nGetStarted.propTypes = {\n  content: PropTypes.object,\n};\n\nexport default GetStarted;\n"
  },
  {
    "path": "packages/site/src/screens/home/hero.js",
    "content": "import React, { useCallback } from 'react';\nimport { Link as ReactRouterLink } from 'react-router-dom';\n\nimport { Wrapper } from '../../components/wrapper';\nimport { Button } from '../../components/button';\nimport { Link } from '../../components/link';\nimport styled from 'styled-components';\n\nimport badge from '../../assets/sidebar-badge.svg';\n\nconst WrapperStyled = styled(Wrapper)`\n  z-index: 1;\n`;\n\nconst HeroContent = styled.div`\n  align-items: center;\n  display: flex;\n  flex-direction: column;\n  flex-wrap: wrap;\n  margin-top: 5rem;\n  padding: 0;\n  position: relative;\n  text-align: left;\n  width: 100%;\n  @media (min-width: 768px) {\n    flex-direction: row;\n    margin-top: 20rem;\n    padding-left: 32rem;\n  }\n`;\n\nconst HeroTitle = styled.h1`\n  font-size: 5rem;\n  margin: 0 0 2rem;\n  text-align: center;\n  text-transform: uppercase;\n  width: 100%;\n  color: #fff;\n\n  @media (min-width: 768px) {\n    font-size: 5.8rem;\n    margin: 4rem 0 2rem;\n    text-align: left;\n  }\n`;\n\nconst HeroBody = styled.p`\n  font-size: 2rem;\n  line-height: 3rem;\n  text-align: left;\n  width: 100%;\n  margin-top: 0;\n  margin-bottom: 0;\n  @media (min-width: 768px) {\n    margin: 0 0 6rem;\n    max-width: 50rem;\n  }\n`;\n\nconst HeroLogoContainer = styled.div`\n  display: flex;\n  width: 100%;\n  margin: 6rem 0;\n  height: 160px;\n  @media (min-width: 768px) {\n    height: auto;\n    display: block;\n    width: inherit;\n    margin: 0;\n  }\n`;\n\nconst HeroLogo = styled.img`\n  width: 20rem;\n  margin: auto;\n  @media (min-width: 768px) {\n    left: -3rem;\n    max-width: 32rem;\n    position: absolute;\n    top: 0;\n    width: 100%;\n  }\n`;\n\nconst HeroButtonsWrapper = styled.div`\n  max-width: 100%;\n  flex-direction: column;\n  justify-content: center;\n  display: flex;\n  @media (min-width: 1024px) {\n    flex-direction: row;\n  }\n  @media (max-width: 768px) {\n    align-items: center;\n  }\n`;\nconst HeroNPMWrapper = styled.div`\n  flex-direction: row;\n  justify-content: center;\n  display: none;\n  width: 30rem;\n  @media (min-width: 768px) {\n    display: flex;\n  }\n  @media (min-width: 1024px) {\n    width: 28rem;\n  }\n`;\n\nconst HeroNPMCopy = styled.p`\n  width: 22rem;\n  height: 4rem;\n  color: #383838;\n  background-color: #d5d5d5;\n  color: black;\n  text-align: left;\n  padding: 0.33rem 1.5rem;\n  line-height: 3.44rem;\n  font-size: 14px;\n  margin: 0;\n`;\nconst HeroNPMButton = styled(Button)`\n  width: 8rem;\n  cursor: copy;\n  text-decoration: none;\n`;\n\nexport const HeroDocsButton = styled(Link)`\n  width: 30rem;\n  margin-top: 4rem;\n  @media (min-width: 768px) {\n    margin-top: 2rem;\n    width: 30rem;\n  }\n  @media (min-width: 1024px) {\n    margin-top: 0;\n    margin-left: 2rem;\n    width: 18rem;\n  }\n`;\n\nconst HeroNavList = styled.ul`\n  border-top: 2px solid #707070;\n  margin-top: 2rem;\n  display: flex;\n  flex-direction: row;\n  list-style: none;\n  padding: 2rem 0 0;\n  text-align: center;\n  width: 100%;\n  justify-content: space-around;\n\n  & li {\n    display: inline-block;\n    margin-right: 33px;\n  }\n  & li:last-child {\n    margin-right: 0;\n  }\n  & li a {\n    color: white;\n    display: inline-block;\n    font-size: 1.7rem;\n    transition: opacity 0.4s;\n    text-transform: uppercase;\n    text-decoration: none;\n  }\n  & li a:hover {\n    color: #8196ff;\n  }\n  @media (min-width: 768px) {\n    display: inline-block;\n    border-top: 2px solid #ffffff;\n    padding-top: 4rem;\n    margin: 4rem 0 0 0;\n    & li {\n      margin-right: 66px;\n    }\n  }\n  @media (min-width: 1024px) {\n    width: 48rem;\n    margin: 4rem 0 0 32rem;\n  }\n`;\n\nconst copyFallBack = copyText => {\n  const copyTextArea = document.createElement('textArea');\n  copyTextArea.value = copyText;\n\n  document.body.appendChild(copyTextArea);\n\n  copyTextArea.focus();\n  copyTextArea.select();\n  document.execCommand('copy');\n  copyTextArea.remove();\n};\n\nconst Hero = props => {\n  const handleCopy = useCallback(\n    e => {\n      if (!navigator.clipboard) {\n        copyFallBack(props.content.copyText);\n        e.preventDefault();\n        return;\n      }\n      navigator.clipboard.writeText(props.content.copyText);\n    },\n    [props.content.copyText]\n  );\n\n  return (\n    <WrapperStyled noPadding>\n      <HeroContent>\n        <HeroLogoContainer>\n          <HeroLogo src={badge} />\n        </HeroLogoContainer>\n        <HeroTitle>urql</HeroTitle>\n        <HeroBody>\n          The highly customizable and versatile GraphQL client for React,\n          Svelte, Vue, Solid or plain JavaScript, with which you add on features\n          like normalized caching as you grow.\n        </HeroBody>\n        <HeroButtonsWrapper>\n          <HeroNPMWrapper>\n            <HeroNPMCopy>{props.content.copyText}</HeroNPMCopy>\n            <HeroNPMButton onClick={handleCopy}>copy</HeroNPMButton>\n          </HeroNPMWrapper>\n          <HeroDocsButton to=\"docs/\">Documentation</HeroDocsButton>\n        </HeroButtonsWrapper>\n      </HeroContent>\n      <HeroNavList>\n        <li>\n          <ReactRouterLink to=\"docs/\">Docs</ReactRouterLink>\n        </li>\n        <li>\n          <a\n            title=\"Issues\"\n            href=\"https://www.github.com/urql-graphql/urql/issues\"\n          >\n            Issues\n          </a>\n        </li>\n        <li>\n          <a title=\"GitHub\" href=\"https://github.com/urql-graphql/urql\">\n            GitHub\n          </a>\n        </li>\n      </HeroNavList>\n    </WrapperStyled>\n  );\n};\n\nexport default Hero;\n"
  },
  {
    "path": "packages/site/src/screens/home/index.js",
    "content": "import React from 'react';\nimport styled from 'styled-components';\nimport { usePrefetch } from 'react-static';\nimport { useMarkdownTree } from 'react-static-plugin-md-pages';\n\nimport Features from './features';\nimport GetStarted from './get-started';\nimport MoreOSS from './more-oss';\nimport content from './_content';\nimport { Header } from '../../components/header';\nimport { Footer } from '../../components/footer';\n\nconst Container = styled.div`\n  width: 100%;\n`;\n\nconst Home = () => {\n  const ref = usePrefetch('docs');\n  useMarkdownTree();\n\n  return (\n    <Container ref={ref}>\n      <Header content={content.header} />\n      <Features featureArray={content.features} />\n      <GetStarted content={content.getStarted} />\n      <MoreOSS oss={content.oss} />\n      <Footer />\n    </Container>\n  );\n};\n\nexport default Home;\n"
  },
  {
    "path": "packages/site/src/screens/home/more-oss.js",
    "content": "import React from 'react';\nimport PropTypes from 'prop-types';\nimport styled from 'styled-components';\n\nimport { BodyCopy } from '../../components/body-copy';\nimport { Link } from '../../components/link';\nimport { PanelSectionWrapper } from '../../components/panel';\nimport { SectionTitle } from '../../components/section-title';\nimport { SecondaryTitle } from '../../components/secondary-title';\n\nconst OSSCardContainer = styled.div`\n  display: grid;\n  grid-template-columns: 1fr;\n  grid-template-rows: repeat(4, 1fr);\n  grid-gap: 4rem;\n  width: calc(100% - 4rem);\n  max-width: 75%;\n  margin: auto auto 4rem auto;\n\n  @media (min-width: 768px) {\n    grid-template-columns: repeat(2, 1fr);\n    grid-template-rows: repeat(2, 1fr);\n    max-width: 116rem;\n  }\n`;\n\nconst OSSCard = styled.div`\n  text-align: left;\n  display: flex;\n  flex-direction: column;\n  align-items: center;\n\n  > * {\n    margin-top: 0;\n    margin-bottom: 0;\n  }\n\n  > * + * {\n    margin-top: 1rem;\n  }\n\n  @media (min-width: 768px) {\n    flex-direction: row;\n    justify-content: space-between;\n\n    > * {\n      margin-left: 0;\n      margin-right: 0;\n    }\n\n    > * + * {\n      margin-top: 0;\n      margin-left: 3rem;\n    }\n  }\n`;\n\nconst OSSImage = styled.img`\n  flex: 0 0 15rem;\n  height: 15rem;\n`;\n\nconst OSSCopyContainer = styled.div`\n  display: flex;\n  flex-direction: column;\n\n  > * {\n    margin-top: 0;\n    margin-bottom: 0;\n  }\n\n  > * + * {\n    margin-top: 2rem;\n  }\n`;\n\nconst OSSTitle = styled(SecondaryTitle)`\n  transition: opacity 0.3s ease-out;\n  margin: 0;\n\n  &:hover {\n    opacity: 0.7;\n  }\n\n  @media (min-width: 768px) {\n    text-align: left;\n  }\n`;\n\nconst OSSDescription = styled(BodyCopy)`\n  @media (min-width: 768px) {\n    text-align: left;\n  }\n`;\n\nconst MoreOSS = ({ oss }) => (\n  <PanelSectionWrapper background=\"#000000\">\n    <SectionTitle>More Open Source from Formidable</SectionTitle>\n    <OSSCardContainer>\n      {oss.map(card => {\n        return (\n          <OSSCard key={card.title}>\n            <OSSImage src={card.logo} />\n            <OSSCopyContainer>\n              <a href={card.link} target=\"_blank\" rel=\"noopener noreferrer\">\n                <OSSTitle>{card.title}</OSSTitle>\n              </a>\n              <OSSDescription>{card.description}</OSSDescription>\n            </OSSCopyContainer>\n          </OSSCard>\n        );\n      })}\n    </OSSCardContainer>\n    <Link isExternal to=\"https://formidable.com/open-source/\">\n      View All\n    </Link>\n  </PanelSectionWrapper>\n);\n\nMoreOSS.propTypes = {\n  oss: PropTypes.arrayOf(\n    PropTypes.shape({\n      title: PropTypes.string.isRequired,\n      link: PropTypes.string.isRequired,\n      description: PropTypes.string.isRequired,\n      logo: PropTypes.string.isRequired,\n    }).isRequired\n  ).isRequired,\n};\n\nexport default MoreOSS;\n"
  },
  {
    "path": "packages/site/src/styles/global.js",
    "content": "import { createGlobalStyle } from 'styled-components';\n\nexport const GlobalStyle = createGlobalStyle`\n  * {\n    box-sizing: inherit;\n    min-width: 0;\n  }\n\n  html {\n    box-sizing: border-box;\n    font-size: 62.5%;\n    overflow-x: hidden;\n  }\n\n  body {\n    background: ${p => p.theme.colors.passiveBg};\n    color: ${p => p.theme.colors.text};\n    font-family: ${p => p.theme.fonts.body};\n    line-height: ${p => p.theme.lineHeights.body};\n    font-weight: ${p => p.theme.fontWeights.body};\n    text-rendering: optimizeLegibility;\n    margin: 0;\n    padding: 0;\n\n    font-size: ${p => p.theme.fontSizes.bodySmall};\n    @media ${p => p.theme.media.lg} {\n      font-size: ${p => p.theme.fontSizes.body};\n    }\n  }\n\n  a {\n    color: ${p => p.theme.colors.accent};\n    font-weight: ${p => p.theme.fontWeights.links};\n  }\n\n  table, pre, p, h1, h2, h3 {\n    margin: 0 0 ${p => p.theme.spacing.md} 0;\n  }\n\n  h1, h2, h3 {\n    font-family: ${p => p.theme.fonts.heading};\n    font-weight: ${p => p.theme.fontWeights.heading};\n    line-height: ${p => p.theme.lineHeights.heading};\n    color: ${p => p.theme.colors.heading};\n  }\n\n  h1 {\n    font-size: ${p => p.theme.fontSizes.h1};\n  }\n\n  h2 {\n    font-size: ${p => p.theme.fontSizes.h2};\n  }\n\n  h3 {\n    font-size: ${p => p.theme.fontSizes.h3};\n  }\n\n  img {\n    max-width: 100%;\n  }\n`;\n"
  },
  {
    "path": "packages/site/src/styles/theme.js",
    "content": "const systemFonts = [\n  '-apple-system',\n  'BlinkMacSystemFont',\n  'Segoe UI',\n  'Roboto',\n  'Helvetica Neue',\n  'Arial',\n  'Noto Sans',\n  'sans-serif',\n  'Apple Color Emoji',\n  'Segoe UI Emoji',\n  'Segoe UI Symbol',\n  'Noto Color Emoji',\n];\n\nexport const colors = {\n  passiveBg: '#f2f2f2',\n  codeBg: '#f0f7fb',\n  bg: '#ffffff',\n  border: '#ececec',\n  activeBorder: '#a2b1ff',\n  text: '#000000',\n  heading: '#444444',\n  accent: '#566ac8',\n  code: '#403f53',\n  passive: '#444444',\n};\n\nexport const layout = {\n  page: '144rem',\n  header: '4.8rem',\n  stripes: '0.7rem',\n  sidebar: '28rem',\n  legend: '22rem',\n  logo: '12rem',\n};\n\nexport const fonts = {\n  heading: systemFonts.join(', '),\n  body: systemFonts.join(', '),\n  code: 'Space Mono, monospace',\n};\n\nexport const fontSizes = {\n  small: '0.9em',\n  body: '1.8rem',\n  bodySmall: '1.5rem',\n  code: '0.8em',\n  h1: '3.45em',\n  h2: '2.11em',\n  h3: '1.64em',\n};\n\nexport const fontWeights = {\n  body: '400',\n  links: '500',\n  heading: '600',\n};\n\nexport const lineHeights = {\n  body: '1.5',\n  heading: '1.1',\n  code: '1.2',\n};\n\nexport const shadows = {\n  header: 'rgba(0, 0, 0, 0.09) 0px 2px 10px -3px',\n  input: 'rgba(0, 0, 0, 0.09) 0px 2px 10px -3px',\n};\n\nexport const mediaSizes = {\n  sm: 700,\n  md: 960,\n  lg: 1200,\n};\n\nexport const media = {\n  maxmd: `(max-width: ${mediaSizes.md - 1}px)`,\n  sm: `(min-width: ${mediaSizes.sm}px)`,\n  md: `(min-width: ${mediaSizes.md}px)`,\n  lg: `(min-width: ${mediaSizes.lg}px)`,\n};\n\nexport const spacing = {\n  xs: '0.6rem',\n  sm: '1.5rem',\n  md: '2.75rem',\n  lg: '4.75rem',\n  xl: '8.2rem',\n};\n"
  },
  {
    "path": "packages/site/static.config.js",
    "content": "import * as os from 'os';\nimport { resolve } from 'path';\nimport constants from './src/constants';\nimport Document from './src/html';\n\nconst basePath =\n  process.env.VERCEL_ENV === 'preview' ? '.' : 'open-source/urql';\nconst isStaging = process.env.REACT_STATIC_ENV === 'staging';\nconst isProduction = process.env.REACT_STATIC_ENV === 'production';\n\nexport default {\n  plugins: [\n    resolve(__dirname, 'plugins/assets-fix/'),\n    resolve(__dirname, 'plugins/monorepo-fix/'),\n    resolve(__dirname, 'plugins/react-router/'),\n    (isStaging || isProduction) && resolve(__dirname, 'plugins/preact/'),\n    [\n      'react-static-plugin-md-pages',\n      {\n        location: '../../docs',\n        template: './src/screens/docs',\n        pathPrefix: 'docs',\n      },\n    ],\n\n    'react-static-plugin-styled-components',\n    'react-static-plugin-sitemap',\n  ].filter(Boolean),\n\n  paths: {\n    src: 'src',\n    dist: `dist/${basePath}`,\n    buildArtifacts: 'node_modules/.cache/react-static/artifacts/',\n    devDist: 'node_modules/.cache/react-static/dist/',\n    temp: 'node_modules/.cache/react-static/temp/',\n    assetsPath: 'static',\n    public: 'public', // The public directory (files copied to dist during build)\n  },\n\n  basePath,\n  stagingBasePath: basePath,\n  devBasePath: basePath,\n\n  Document,\n\n  getSiteData: () => ({\n    title: constants.docsTitle,\n  }),\n\n  maxThreads: Math.min(8, os.cpus().length / 2),\n\n  getRoutes: async () => [\n    {\n      path: '/',\n      template: require.resolve('./src/screens/home'),\n    },\n    {\n      path: '/docs/concepts/core-package',\n      redirect: '/docs/basics/core',\n    },\n    {\n      path: '/docs/basics/getting-started',\n      redirect: '/docs/basics',\n    },\n    {\n      path: '/docs/basics/mutations',\n      redirect: '/docs/basics',\n    },\n    {\n      path: '/docs/basics/queries',\n      redirect: '/docs/basics',\n    },\n    {\n      path: '404',\n      template: require.resolve('./src/screens/404'),\n    },\n    {\n      path: '/docs/graphcache/custom-updates',\n      redirect: '/docs/graphcache/cache-updates',\n    },\n    {\n      path: '/docs/graphcache/computed-queries',\n      redirect: '/docs/graphcache/local-resolvers',\n    },\n    {\n      path: '/docs/graphcache/under-the-hood',\n      redirect: '/docs/graphcache/normalized-caching',\n    },\n    {\n      path: '/docs/concepts/document-caching',\n      redirect: '/docs/basics/document-caching',\n    },\n    {\n      path: '/docs/concepts/errors',\n      redirect: '/docs/basics/errors',\n    },\n    {\n      path: '/docs/concepts',\n      redirect: '/docs/architecture',\n    },\n    {\n      path: '/docs/concepts/stream-patterns',\n      redirect: '/docs/architecture',\n    },\n    {\n      path: '/docs/concepts/philosophy',\n      redirect: '/docs/architecture',\n    },\n    {\n      path: '/docs/concepts/exchanges',\n      redirect: '/docs/advanced/authoring-exchanges',\n    },\n  ],\n};\n"
  },
  {
    "path": "packages/site/vercel.json",
    "content": "{\n  \"github\": {\n    \"silent\": true\n  }\n}\n"
  },
  {
    "path": "packages/solid-start-urql/CHANGELOG.md",
    "content": "# @urql/solid-start\n\n## 0.1.0\n\n### Minor Changes\n\n- Initial release of `@urql/solid-start` - URQL integration built with SolidStart's native primitives.\n  Get started with:\n  - **`createQuery`** - GraphQL queries using SolidStart's `query()` and `createAsync()`\n  - **`createMutation`** - GraphQL mutations using SolidStart's `action()` and `useAction()`\n  - **`createSubscription`** - Real-time GraphQL subscriptions\n  - **`Provider`** and **`useClient`** - Context-based client access\n  - **Reactive variables** - All parameters accept signals/accessors for automatic re-execution\n  - **Full SSR support** - Works seamlessly with SolidStart's server-side rendering\n  - **TypeScript support** - Complete type safety with GraphQL types\n  - **Uses `@solid-primitives/utils`** - Leverages standard Solid ecosystem utilities\n    Submitted by [@davedbase](https://github.com/davedbase) (See [#3837](https://github.com/urql-graphql/urql/pull/3837))\n\n### Patch Changes\n\n- Updated dependencies (See [#3837](https://github.com/urql-graphql/urql/pull/3837))\n  - @urql/solid@1.0.1\n"
  },
  {
    "path": "packages/solid-start-urql/README.md",
    "content": "# @urql/solid-start\n\n`@urql/solid-start` provides URQL integration for [SolidStart](https://start.solidjs.com/), built with SolidStart's native primitives like `query`, `action`, and `createAsync`.\n\n> **Note:** This package is specifically designed for SolidStart applications with SSR. If you're building a client-side only SolidJS app, use [`@urql/solid`](https://github.com/urql-graphql/urql/tree/main/packages/solid-urql) instead. See [SolidJS vs SolidStart](#solidjs-vs-solidstart) for key differences.\n\n## Features\n\n- 🎯 **SolidStart Native** - Built with `query`, `action`, `createAsync`, and `useAction`\n- 🚀 **Automatic SSR** - Works seamlessly with SolidStart's server-side rendering\n- 🔄 **Reactive Variables** - Query variables can be signals that automatically trigger re-execution\n- 📡 **Real-time Subscriptions** - Full GraphQL subscription support\n- 🎨 **Type Safe** - Complete TypeScript support with GraphQL types\n- 🪶 **Lightweight** - Minimal wrapper over URQL core\n\n## Installation\n\n```bash\nnpm install @urql/solid-start @urql/solid @urql/core graphql\n# or\npnpm add @urql/solid-start @urql/solid @urql/core graphql\n# or\nyarn add @urql/solid-start @urql/solid @urql/core graphql\n```\n\n> **Note:** `@urql/solid` is a peer dependency required for subscriptions.\n\n## Quick Start\n\n### 1. Set up the Provider\n\nWrap your app with the `Provider` to make the URQL client and router primitives available:\n\n```tsx\n// src/app.tsx\nimport { Router, action, query } from '@solidjs/router';\nimport { FileRoutes } from '@solidjs/start/router';\nimport { Provider } from '@urql/solid-start';\nimport { createClient, cacheExchange, fetchExchange } from '@urql/core';\n\nconst client = createClient({\n  url: 'https://api.example.com/graphql',\n  exchanges: [cacheExchange, fetchExchange],\n});\n\nexport default function App() {\n  return (\n    <Router root={props => <Provider value={{ client, query, action }}>{props.children}</Provider>}>\n      <FileRoutes />\n    </Router>\n  );\n}\n```\n\n> **Note:** The Provider accepts `client`, `query`, and `action` so `createQuery` and `createMutation` can use SolidStart APIs via context.\n\n### 2. Use Queries\n\n```tsx\n// src/routes/todos.tsx\nimport { createQuery } from '@urql/solid-start';\nimport { createAsync } from '@solidjs/router';\nimport { gql } from '@urql/core';\nimport { For, Show, Suspense } from 'solid-js';\n\nconst TodosQuery = gql`\n  query {\n    todos {\n      id\n      title\n      completed\n    }\n  }\n`;\n\nexport default function TodosPage() {\n  const queryTodos = createQuery(TodosQuery, 'todos-list');\n  const todos = createAsync(() => queryTodos());\n\n  return (\n    <div>\n      <h1>Todos</h1>\n      <Suspense fallback={<div>Loading...</div>}>\n        <Show when={todos()?.data}>\n          <ul>\n            <For each={todos()!.data.todos}>\n              {todo => (\n                <li>\n                  <input type=\"checkbox\" checked={todo.completed} />\n                  {todo.title}\n                </li>\n              )}\n            </For>\n          </ul>\n        </Show>\n        <Show when={todos()?.error}>\n          <p>Error: {todos()!.error.message}</p>\n        </Show>\n      </Suspense>\n    </div>\n  );\n}\n```\n\n### 3. Use Mutations\n\n```tsx\n// src/components/AddTodoForm.tsx\nimport { createMutation } from '@urql/solid-start';\nimport { useAction, useSubmission } from '@solidjs/router';\nimport { gql } from '@urql/core';\nimport { Show } from 'solid-js';\n\nconst AddTodoMutation = gql`\n  mutation AddTodo($title: String!) {\n    addTodo(title: $title) {\n      id\n      title\n    }\n  }\n`;\n\nexport function AddTodoForm() {\n  const addTodoAction = createMutation(AddTodoMutation, 'add-todo');\n  const addTodo = useAction(addTodoAction);\n  const submission = useSubmission(addTodoAction);\n\n  let inputRef: HTMLInputElement | undefined;\n\n  const handleSubmit = async (e: Event) => {\n    e.preventDefault();\n    if (!inputRef?.value) return;\n\n    const result = await addTodo({ title: inputRef.value });\n    if (result.data) {\n      inputRef.value = '';\n    }\n  };\n\n  return (\n    <form onSubmit={handleSubmit}>\n      <input ref={inputRef} type=\"text\" placeholder=\"New todo\" />\n      <button type=\"submit\" disabled={submission.pending}>\n        Add Todo\n      </button>\n      <Show when={submission.result?.error}>\n        <p>Error: {submission.result!.error.message}</p>\n      </Show>\n    </form>\n  );\n}\n```\n\n### 4. Use Subscriptions\n\n```tsx\n// src/components/LiveMessages.tsx\nimport { createSubscription } from '@urql/solid-start';\nimport { gql } from '@urql/core';\nimport { For } from 'solid-js';\n\nconst MessagesSubscription = gql`\n  subscription {\n    messageAdded {\n      id\n      text\n      createdAt\n    }\n  }\n`;\n\nexport function LiveMessages() {\n  const [messages] = createSubscription(\n    { query: MessagesSubscription },\n    // Optional handler to accumulate messages\n    (prev = [], data) => [...prev, data.messageAdded]\n  );\n\n  return (\n    <div>\n      <h2>Live Messages</h2>\n      <For each={messages.data}>{msg => <div>{msg.text}</div>}</For>\n    </div>\n  );\n}\n```\n\n## API Reference\n\n### `createQuery(queryDocument, key, options?)`\n\nCreates a GraphQL query using SolidStart's `query` and `createAsync` primitives. The `query` function is automatically retrieved from context.\n\n**Parameters:**\n\n- `queryDocument: DocumentInput` - GraphQL query document\n- `key: string` - Cache key for SolidStart's router\n- `options?: object` - Optional configuration\n  - `variables?: Variables` - Query variables\n  - `requestPolicy?: RequestPolicy` - Cache policy\n  - `context?: Partial<OperationContext>` - Additional context\n\n**Returns:** A query function that can be used with `createAsync`\n\n**Basic Example:**\n\n```tsx\nimport { createAsync } from '@solidjs/router';\nimport { createQuery } from '@urql/solid-start';\n\nexport default function TodosPage() {\n  const queryTodos = createQuery(TodosQuery, 'todos-list');\n  const todos = createAsync(() => queryTodos());\n\n  return <div>{/* ... */}</div>;\n}\n```\n\n**Example with variables:**\n\n```tsx\nimport { createAsync } from '@solidjs/router';\nimport { createQuery } from '@urql/solid-start';\n\nexport default function UserPage() {\n  const queryUser = createQuery(UserQuery, 'user-details', {\n    variables: { id: 1 },\n  });\n  const user = createAsync(() => queryUser());\n\n  return <div>{/* ... */}</div>;\n}\n```\n\n**Example with custom client:**\n\n```tsx\nimport { createAsync } from '@solidjs/router';\nimport { createQuery } from '@urql/solid-start';\nimport { createClient } from '@urql/core';\n\nconst customClient = createClient({ url: 'https://api.example.com/graphql' });\n\nexport default function CustomPage() {\n  const queryTodos = createQuery(TodosQuery, 'todos-list');\n  const todos = createAsync(() => queryTodos(customClient));\n\n  return <div>{/* ... */}</div>;\n}\n```\n\n> **Note:** `createQuery` must be called inside a component where it has access to the URQL context. The query function from `@solidjs/router` is automatically retrieved from the Provider.\n\n### `createMutation(mutation, key)`\n\nCreates a GraphQL mutation action using SolidStart's `action` primitive.\n\n**Args:**\n\n- `mutation: DocumentInput` - GraphQL mutation document\n- `key: string` - Cache key for SolidStart's router\n\n**Returns:** `Action` - A SolidStart action that can be used with `useAction()` and `useSubmission()`\n\n**Example:**\n\n```tsx\nimport { createMutation } from '@urql/solid-start';\nimport { useAction, useSubmission } from '@solidjs/router';\n\nconst updateUserAction = createMutation(UpdateUserMutation, 'update-user');\nconst updateUser = useAction(updateUserAction);\nconst submission = useSubmission(updateUserAction);\n\n// Call the mutation\nconst result = await updateUser({ id: 1, name: 'Alice' });\n\n// Access submission state\nconsole.log(submission.pending); // boolean\nconsole.log(submission.result); // OperationResult\n```\n\n### `createSubscription(args, handler?)`\n\nCreates a GraphQL subscription for real-time updates.\n\n**Args:**\n\n```ts\n{\n  query: DocumentInput;\n  variables?: MaybeAccessor<Variables>;\n  context?: MaybeAccessor<Partial<OperationContext>>;\n  pause?: MaybeAccessor<boolean>;\n}\n```\n\n**Handler:** Optional function to accumulate/transform subscription data\n\n```ts\n(previousData: Data | undefined, newData: Data) => Data;\n```\n\n**Returns:** `[State, ExecuteFunction]`\n\n**Example with handler:**\n\n```tsx\nconst [messages] = createSubscription({ query: MessagesSubscription }, (prev = [], data) => [\n  ...prev,\n  data.messageAdded,\n]);\n```\n\n### `Provider`\n\nContext provider for the URQL client and SolidStart router primitives.\n\n**Props:**\n\n- `value: { client: Client; query: typeof query; action: typeof action }` - Object containing the URQL client and SolidStart router primitives\n\n**Example:**\n\n```tsx\nimport { action, query } from '@solidjs/router';\nimport { Provider } from '@urql/solid-start';\n\n<Provider value={{ client, query, action }}>\n  <App />\n</Provider>;\n```\n\n### `useClient()`\n\nHook to access the URQL client from context.\n\n**Returns:** `Client`\n\n## Request Policies\n\nControl caching behavior with `requestPolicy`:\n\n- `cache-first` (default) - Use cache if available, otherwise fetch\n- `cache-only` - Only use cached data, never fetch\n- `network-only` - Always fetch, ignore cache\n- `cache-and-network` - Return cache immediately, then fetch in background\n\n```tsx\nconst todos = createQuery({\n  query: TodosQuery,\n  requestPolicy: 'cache-and-network',\n});\n```\n\n## Dynamic Queries\n\nFor dynamic queries that change based on reactive values, you can pass variables to the query function:\n\n```tsx\nimport { createSignal } from 'solid-js';\nimport { createAsync } from '@solidjs/router';\nimport { createQuery } from '@urql/solid-start';\n\nexport default function UserPage() {\n  const [userId, setUserId] = createSignal(1);\n\n  // Create the query function\n  const queryUser = createQuery(UserQuery, 'user-details', {\n    variables: { id: userId() },\n  });\n\n  // Wrap with createAsync to get reactive data\n  const user = createAsync(() => queryUser());\n\n  return (\n    <div>\n      <button onClick={() => setUserId(userId() + 1)}>Next User</button>\n      <Show when={user()?.data}>\n        <h1>{user()!.data.user.name}</h1>\n      </Show>\n    </div>\n  );\n}\n```\n\nNote: For fully reactive variables that trigger re-fetches, you may need to create the query function inside a `createEffect` or recreate it when dependencies change.\n\n## Cache Keys\n\nCache keys are required for both queries and mutations to enable SolidStart's caching and revalidation features:\n\n```tsx\n// Query with cache key\nconst queryTodos = createQuery(TodosQuery, 'todos-list', query);\n\n// Mutation with cache key\nconst [state, addTodo] = createMutation(AddTodoMutation, 'add-todo');\n```\n\nChoose descriptive cache keys that:\n\n- Are unique within your application\n- Describe the data being cached (e.g., 'user-profile', 'todos-list')\n- Make debugging easier by being human-readable\n\n## Advanced: Custom Exchanges\n\nAdd custom exchanges for authentication, error handling, etc:\n\n```tsx\nimport { createClient, cacheExchange, fetchExchange } from '@urql/core';\nimport { authExchange } from '@urql/exchange-auth';\n\nconst client = createClient({\n  url: 'https://api.example.com/graphql',\n  exchanges: [\n    cacheExchange,\n    authExchange(async utils => {\n      return {\n        addAuthToOperation(operation) {\n          const token = localStorage.getItem('token');\n          if (!token) return operation;\n          return utils.appendHeaders(operation, {\n            Authorization: `Bearer ${token}`,\n          });\n        },\n        didAuthError(error) {\n          return error.graphQLErrors.some(e => e.extensions?.code === 'UNAUTHENTICATED');\n        },\n        async refreshAuth() {\n          // Refresh token logic\n        },\n      };\n    }),\n    fetchExchange,\n  ],\n});\n```\n\n## TypeScript\n\nFull type safety with GraphQL types:\n\n```tsx\nimport { createQuery } from '@urql/solid-start';\nimport { gql, type TypedDocumentNode } from '@urql/core';\n\ninterface Todo {\n  id: string;\n  title: string;\n  completed: boolean;\n}\n\ninterface TodosData {\n  todos: Todo[];\n}\n\nconst TodosQuery: TypedDocumentNode<TodosData> = gql`\n  query {\n    todos {\n      id\n      title\n      completed\n    }\n  }\n`;\n\n// Fully typed!\nconst todos = createQuery({ query: TodosQuery });\n//    ^? Accessor<OperationResult<TodosData> | undefined>\n```\n\n## How It Works\n\n`@urql/solid-start` integrates URQL with SolidStart's primitives:\n\n- **`createQuery`** wraps SolidStart's `query()` function to execute URQL queries with automatic SSR and caching. The `query` function is automatically retrieved from the URQL context, eliminating the need for manual injection.\n- **`createMutation`** creates SolidStart `action()` primitives that integrate with `useAction()` and `useSubmission()` for form handling and progressive enhancement\n- **`createSubscription`** uses `@urql/solid-start` context so it works with the same Provider as queries and mutations\n\nThis means you get:\n\n- ✅ Automatic server-side rendering\n- ✅ Request deduplication via SolidStart's query caching\n- ✅ Streaming responses\n- ✅ Progressive enhancement with actions\n- ✅ Full fine-grained reactivity\n\n## SolidJS vs SolidStart\n\n### When to Use Each Package\n\n| Use Case           | Package             | Why                                                              |\n| ------------------ | ------------------- | ---------------------------------------------------------------- |\n| Client-side SPA    | `@urql/solid`       | Optimized for client-only apps, uses SolidJS reactivity patterns |\n| SolidStart SSR App | `@urql/solid-start` | Integrates with SolidStart's routing, SSR, and action system     |\n\n### Key Differences\n\n#### Queries\n\n**@urql/solid** (Client-side):\n\n```tsx\nimport { createQuery } from '@urql/solid';\n\nconst [result] = createQuery({ query: TodosQuery });\n// Returns: [Accessor<OperationResult>, Accessor<ReExecute>]\n```\n\n**@urql/solid-start** (SSR):\n\n```tsx\nimport { createQuery } from '@urql/solid-start';\nimport { createAsync } from '@solidjs/router';\n\nconst queryTodos = createQuery(TodosQuery, 'todos');\nconst todos = createAsync(() => queryTodos());\n// Returns: Accessor<OperationResult | undefined>\n// Works with SSR and SolidStart's caching\n```\n\n#### Mutations\n\n**@urql/solid** (Client-side):\n\n```tsx\nimport { createMutation } from '@urql/solid';\n\nconst [result, executeMutation] = createMutation(AddTodoMutation);\nawait executeMutation({ title: 'New Todo' });\n// Returns: [Accessor<OperationResult>, ExecuteMutation]\n```\n\n**@urql/solid-start** (SSR with Actions):\n\n```tsx\nimport { createMutation } from '@urql/solid-start';\nimport { useAction, useSubmission } from '@solidjs/router';\n\nconst addTodoAction = createMutation(AddTodoMutation, 'add-todo');\nconst addTodo = useAction(addTodoAction);\nconst submission = useSubmission(addTodoAction);\nawait addTodo({ title: 'New Todo' });\n// Integrates with SolidStart's action system for progressive enhancement\n```\n\n### Why Different APIs?\n\n- **SSR Support**: SolidStart queries run on the server and stream to the client\n- **Router Integration**: Automatic caching and invalidation with SolidStart's router\n- **Progressive Enhancement**: Actions work without JavaScript enabled\n- **Suspense**: Native support for SolidJS Suspense boundaries\n\n### Migration\n\nIf you're moving from a SolidJS SPA to SolidStart:\n\n1. Change imports from `@urql/solid` to `@urql/solid-start`\n2. Wrap queries with `createAsync()`\n3. Update mutations to use the action pattern with `useAction()` and `useSubmission()`\n\n## Resources\n\n- [SolidStart Documentation](https://start.solidjs.com/)\n- [URQL Documentation](https://formidable.com/open-source/urql/docs/)\n- [Solid Primitives](https://primitives.solidjs.community/)\n\n## License\n\nMIT\n"
  },
  {
    "path": "packages/solid-start-urql/jsr.json",
    "content": "{\n  \"name\": \"@urql/solid-start\",\n  \"version\": \"0.1.0\",\n  \"exports\": {\n    \".\": \"./src/index.ts\"\n  },\n  \"exclude\": [\n    \"node_modules\",\n    \"cypress\",\n    \"**/*.test.*\",\n    \"**/*.spec.*\",\n    \"**/*.test.*.snap\",\n    \"**/*.spec.*.snap\"\n  ]\n}"
  },
  {
    "path": "packages/solid-start-urql/package.json",
    "content": "{\n  \"name\": \"@urql/solid-start\",\n  \"version\": \"0.1.0\",\n  \"description\": \"A highly customizable and versatile GraphQL client for SolidStart\",\n  \"sideEffects\": false,\n  \"homepage\": \"https://formidable.com/open-source/urql/docs/\",\n  \"bugs\": \"https://github.com/urql-graphql/urql/issues\",\n  \"license\": \"MIT\",\n  \"author\": \"urql GraphQL Contributors\",\n  \"repository\": {\n    \"type\": \"git\",\n    \"url\": \"https://github.com/urql-graphql/urql.git\",\n    \"directory\": \"packages/solid-start-urql\"\n  },\n  \"keywords\": [\n    \"graphql client\",\n    \"state management\",\n    \"cache\",\n    \"graphql\",\n    \"exchanges\",\n    \"solid\",\n    \"solidstart\",\n    \"ssr\"\n  ],\n  \"main\": \"dist/urql-solid-start\",\n  \"module\": \"dist/urql-solid-start.mjs\",\n  \"types\": \"dist/urql-solid-start.d.ts\",\n  \"source\": \"src/index.ts\",\n  \"exports\": {\n    \".\": {\n      \"types\": \"./dist/urql-solid-start.d.ts\",\n      \"import\": \"./dist/urql-solid-start.mjs\",\n      \"require\": \"./dist/urql-solid-start.js\",\n      \"source\": \"./src/index.ts\"\n    },\n    \"./package.json\": \"./package.json\"\n  },\n  \"files\": [\n    \"LICENSE\",\n    \"CHANGELOG.md\",\n    \"README.md\",\n    \"dist/\"\n  ],\n  \"scripts\": {\n    \"test\": \"vitest\",\n    \"clean\": \"rimraf dist\",\n    \"check\": \"tsc --noEmit\",\n    \"lint\": \"eslint --ext=js,jsx,ts,tsx .\",\n    \"build\": \"rollup -c ../../scripts/rollup/config.mjs\",\n    \"prepare\": \"node ../../scripts/prepare/index.js\",\n    \"prepublishOnly\": \"run-s clean build\"\n  },\n  \"devDependencies\": {\n    \"@solidjs/testing-library\": \"^0.8.10\",\n    \"@solidjs/start\": \"^1.2.1\",\n    \"@urql/core\": \"workspace:*\",\n    \"graphql\": \"^16.0.0\",\n    \"jsdom\": \"^22.1.0\",\n    \"vite-plugin-solid\": \"^2.11.10\"\n  },\n  \"peerDependencies\": {\n    \"@solidjs/router\": \">=0.15.4\",\n    \"@solidjs/start\": \">=1.2.1\",\n    \"@urql/core\": \"^6.0.0\",\n    \"@urql/solid\": \"^1.0.0\",\n    \"solid-js\": \"^1.9.10\"\n  },\n  \"dependencies\": {\n    \"@solid-primitives/utils\": \"^6.2.1\",\n    \"@urql/core\": \"workspace:^6.0.1\",\n    \"@urql/solid\": \"workspace:^1.0.1\",\n    \"wonka\": \"^6.3.2\"\n  },\n  \"publishConfig\": {\n    \"access\": \"public\",\n    \"provenance\": true\n  }\n}\n"
  },
  {
    "path": "packages/solid-start-urql/src/context.test.tsx",
    "content": "// @vitest-environment jsdom\n/* @jsxImportSource solid-js */\n\nimport { expect, it, describe } from 'vitest';\nimport { Provider, useAction, useClient } from './context';\nimport { renderHook } from '@solidjs/testing-library';\nimport { createClient } from '@urql/core';\n\ndescribe('context', () => {\n  it('should provide client through context', () => {\n    const client = createClient({\n      url: '/graphql',\n      exchanges: [],\n    });\n\n    // Mock query function that matches the expected type\n    const mockQuery = (fn: any) => fn;\n\n    const mockAction = (fn: any) => fn;\n\n    const wrapper = (props: { children: any }) => {\n      return (\n        <Provider\n          value={{ client, query: mockQuery as any, action: mockAction as any }}\n        >\n          {props.children}\n        </Provider>\n      );\n    };\n\n    const { result } = renderHook(() => useClient(), { wrapper });\n\n    expect(result).toBe(client);\n  });\n\n  it('should throw error when client is not provided', () => {\n    const originalEnv = process.env.NODE_ENV;\n    process.env.NODE_ENV = 'development';\n\n    expect(() => {\n      renderHook(() => useClient());\n    }).toThrow();\n\n    process.env.NODE_ENV = originalEnv;\n  });\n\n  it('should provide action through context', () => {\n    const client = createClient({\n      url: '/graphql',\n      exchanges: [],\n    });\n\n    const mockQuery = (fn: any) => fn;\n    const mockAction = (fn: any) => fn;\n\n    const wrapper = (props: { children: any }) => {\n      return (\n        <Provider\n          value={{ client, query: mockQuery as any, action: mockAction as any }}\n        >\n          {props.children}\n        </Provider>\n      );\n    };\n\n    const { result } = renderHook(() => useAction(), { wrapper });\n\n    expect(result).toBe(mockAction);\n  });\n});\n"
  },
  {
    "path": "packages/solid-start-urql/src/context.ts",
    "content": "import type { Client } from '@urql/core';\nimport { createContext, useContext } from 'solid-js';\nimport type {\n  query as defaultQuery,\n  action as defaultAction,\n} from '@solidjs/router';\n\nexport interface UrqlContext {\n  client: Client;\n  query: typeof defaultQuery;\n  action: typeof defaultAction;\n}\n\nexport const Context = createContext<UrqlContext>();\nexport const Provider = Context.Provider;\n\nconst hasContext = (\n  context: UrqlContext | undefined,\n  type: 'client' | 'context' | 'action'\n) => {\n  if (process.env.NODE_ENV !== 'production' && context === undefined) {\n    const error = `No ${type} has been specified using urql's Provider. Please create a context and add a Provider.`;\n\n    console.error(error);\n    throw new Error(error);\n  }\n};\n\nexport type UseClient = () => Client;\nexport const useClient: UseClient = () => {\n  const context = useContext(Context);\n  hasContext(context, 'client');\n  return context!.client;\n};\n\nexport type UseQuery = () => typeof defaultQuery;\nexport const useQuery: UseQuery = () => {\n  const context = useContext(Context);\n  hasContext(context, 'context');\n  return context!.query;\n};\n\nexport type UseAction = () => typeof defaultAction;\nexport const useAction: UseAction = () => {\n  const context = useContext(Context);\n  hasContext(context, 'action');\n  return context!.action;\n};\n"
  },
  {
    "path": "packages/solid-start-urql/src/createMutation.test.ts",
    "content": "// @vitest-environment jsdom\n\nimport { expect, it, describe, vi } from 'vitest';\nimport { createMutation } from './createMutation';\nimport { createClient } from '@urql/core';\nimport { makeSubject } from 'wonka';\nimport { OperationResult } from '@urql/core';\n\nconst client = createClient({\n  url: '/graphql',\n  exchanges: [],\n});\n\nvi.mock('./context', () => {\n  const action = (fn: any, _key?: string) => fn;\n\n  return {\n    useClient: () => client,\n    useAction: () => action,\n  };\n});\n\ndescribe('createMutation', () => {\n  it('should create a mutation action', () => {\n    const mutationAction = createMutation(\n      'mutation AddTodo($title: String!) { addTodo(title: $title) { id } }',\n      'add-todo'\n    );\n\n    expect(mutationAction).toBeDefined();\n    expect(typeof mutationAction).toBe('function');\n  });\n\n  it('should execute a mutation through the action', async () => {\n    const subject =\n      makeSubject<OperationResult<{ addTodo: { id: number } }, any>>();\n\n    const mutationSpy = vi\n      .spyOn(client, 'executeMutation')\n      .mockImplementation(() => subject.source as any);\n\n    const mutationAction = createMutation<\n      { addTodo: { id: number } },\n      { title: string }\n    >(\n      'mutation AddTodo($title: String!) { addTodo(title: $title) { id } }',\n      'add-todo'\n    );\n\n    const promise = mutationAction({ title: 'Test Todo' });\n\n    // Emit result\n    subject.next({\n      data: { addTodo: { id: 1 } },\n      stale: false,\n      hasNext: false,\n    } as any);\n\n    const result = await promise;\n\n    expect(mutationSpy).toHaveBeenCalled();\n    expect(result.data).toEqual({ addTodo: { id: 1 } });\n\n    mutationSpy.mockRestore();\n  });\n\n  it('should handle mutation errors', async () => {\n    const subject = makeSubject<OperationResult<any, any>>();\n\n    const mutationSpy = vi\n      .spyOn(client, 'executeMutation')\n      .mockImplementation(() => subject.source as any);\n\n    const mutationAction = createMutation('mutation { test }', 'test');\n\n    const promise = mutationAction({});\n\n    // Emit error\n    subject.next({\n      data: undefined,\n      error: {\n        message: 'Error',\n        graphQLErrors: [],\n        networkError: undefined,\n      } as any,\n      stale: false,\n      hasNext: false,\n    } as any);\n\n    const result = await promise;\n\n    expect(result.error).toBeDefined();\n    expect(result.error?.message).toEqual('Error');\n\n    mutationSpy.mockRestore();\n  });\n\n  it('should pass context to mutation', async () => {\n    const subject = makeSubject<OperationResult<any, any>>();\n\n    const mutationSpy = vi\n      .spyOn(client, 'executeMutation')\n      .mockImplementation(() => subject.source as any);\n\n    const mutationAction = createMutation('mutation { test }', 'test');\n\n    const customContext = { requestPolicy: 'network-only' as const };\n    const promise = mutationAction({}, customContext);\n\n    // Emit result\n    subject.next({\n      data: { test: 'success' },\n      stale: false,\n      hasNext: false,\n    } as any);\n\n    await promise;\n\n    expect(mutationSpy).toHaveBeenCalledWith(expect.anything(), customContext);\n\n    mutationSpy.mockRestore();\n  });\n});\n"
  },
  {
    "path": "packages/solid-start-urql/src/createMutation.ts",
    "content": "import {\n  type AnyVariables,\n  type DocumentInput,\n  type OperationContext,\n  type OperationResult,\n  createRequest,\n} from '@urql/core';\nimport type { Action } from '@solidjs/router';\nimport { pipe, filter, take, toPromise } from 'wonka';\nimport { useAction, useClient } from './context';\n\nexport type CreateMutationAction<\n  Data = any,\n  Variables extends AnyVariables = AnyVariables,\n> = Action<\n  [variables: Variables, context?: Partial<OperationContext>],\n  OperationResult<Data, Variables>\n>;\n\n/**\n * Creates a GraphQL mutation action for SolidStart.\n *\n * @remarks\n * This uses SolidStart's `action()` primitive to create an action that can be\n * used with `useAction()` and `useSubmission()` in components for form handling and\n * progressive enhancement.\n *\n * IMPORTANT: Must be called inside a component where it has access to the URQL context.\n *\n * @param mutation - The GraphQL mutation document\n * @param key - Cache key for SolidStart's router\n *\n * @example\n * ```tsx\n * import { createMutation } from '@urql/solid-start';\n * import { useAction, useSubmission } from '@solidjs/router';\n * import { gql } from '@urql/core';\n *\n * function AddTodoForm() {\n *   const addTodoAction = createMutation(\n *     gql`mutation AddTodo($title: String!) {\n *       addTodo(title: $title) { id title }\n *     }`,\n *     'add-todo'\n *   );\n *\n *   const addTodo = useAction(addTodoAction);\n *   const submission = useSubmission(addTodoAction);\n *\n *   const handleSubmit = async (e: Event) => {\n *     e.preventDefault();\n *     const result = await addTodo({ title: 'New Todo' });\n *     if (result.data) {\n *       console.log('Todo added:', result.data.addTodo);\n *     }\n *   };\n *\n *   return (\n *     <form onSubmit={handleSubmit}>\n *       <button type=\"submit\" disabled={submission.pending}>\n *         Add Todo\n *       </button>\n *       {submission.result?.error && <p>Error: {submission.result.error.message}</p>}\n *     </form>\n *   );\n * }\n * ```\n */\nexport function createMutation<\n  Data = any,\n  Variables extends AnyVariables = AnyVariables,\n>(\n  mutation: DocumentInput<Data, Variables>,\n  key: string\n): CreateMutationAction<Data, Variables> {\n  const client = useClient();\n  const action = useAction();\n\n  return action(\n    async (variables: Variables, context?: Partial<OperationContext>) => {\n      const request = createRequest(mutation, variables);\n      return pipe(\n        client.executeMutation(request, context),\n        filter(result => !result.hasNext),\n        take(1),\n        toPromise\n      );\n    },\n    key\n  );\n}\n"
  },
  {
    "path": "packages/solid-start-urql/src/createQuery.test.tsx",
    "content": "// @vitest-environment jsdom\n\nimport { expect, it, describe, vi } from 'vitest';\nimport { createQuery } from './createQuery';\nimport { renderHook } from '@solidjs/testing-library';\nimport { createClient } from '@urql/core';\nimport { createSignal } from 'solid-js';\nimport { makeSubject, pipe, toPromise } from 'wonka';\nimport { OperationResult, OperationResultSource } from '@urql/core';\n\nconst client = createClient({\n  url: '/graphql',\n  exchanges: [],\n});\n\nvi.mock('./context', () => {\n  const useClient = () => {\n    return client!;\n  };\n\n  const useQuery = () => {\n    // Return a mock query function that wraps with SolidStart's query primitive\n    return (fn: any, _key: string) => {\n      // Store the query function for later execution\n      const queryFn = fn;\n      // Return a function that executes the query\n      return () => queryFn();\n    };\n  };\n\n  return { useClient, useQuery };\n});\n\nvi.mock('@solidjs/router', () => {\n  return {\n    query: (fn: any) => fn,\n    createAsync: (fn: any) => {\n      const [data, setData] = createSignal<any>();\n      fn().then(setData);\n      return data;\n    },\n  };\n});\n\ndescribe('createQuery', () => {\n  it('should execute a query', async () => {\n    const subject =\n      makeSubject<Pick<OperationResult<{ test: boolean }, any>, 'data'>>();\n    const executeQuery = vi\n      .spyOn(client, 'executeQuery')\n      .mockImplementation(() => {\n        const source = subject.source as OperationResultSource<OperationResult>;\n        // Return an object with toPromise method\n        return {\n          toPromise: () => pipe(source, toPromise),\n        } as any;\n      });\n\n    const result = renderHook(() =>\n      createQuery<{ test: boolean }>('{ test }', 'test-query')\n    );\n\n    // Trigger the query\n    subject.next({ data: { test: true } });\n\n    await vi.waitFor(() => {\n      const data = result.result();\n      expect(data).toBeDefined();\n    });\n\n    executeQuery.mockRestore();\n  });\n\n  it('should respect pause option', () => {\n    const executeQuery = vi.spyOn(client, 'executeQuery');\n\n    renderHook(() =>\n      createQuery('{ test }', 'test-query-pause', {\n        pause: true,\n      } as any)\n    );\n\n    expect(executeQuery).not.toHaveBeenCalled();\n    executeQuery.mockRestore();\n  });\n\n  it.skip('should re-execute when reactive variables change', async () => {\n    // This test is skipped because SolidStart's query() primitive doesn't\n    // automatically re-execute when variables change. This would require\n    // using createAsync with a reactive dependency or manually refetching.\n    // This is expected behavior for SolidStart.\n  });\n});\n"
  },
  {
    "path": "packages/solid-start-urql/src/createQuery.ts",
    "content": "import {\n  type AnyVariables,\n  type DocumentInput,\n  type OperationContext,\n  type RequestPolicy,\n  createRequest,\n  type Client,\n} from '@urql/core';\nimport { useClient, useQuery } from './context';\n\n/**\n * Creates a cached query function using SolidStart's query primitive.\n *\n * @remarks\n * This function creates a reusable query function that executes a GraphQL query.\n * It uses SolidStart's query primitive for caching and deduplication.\n * Call this at module level, then use the returned function with createAsync in your component.\n *\n * @example\n * ```tsx\n * import { createQuery } from '@urql/solid-start';\n * import { createAsync } from '@solidjs/router';\n * import { gql } from '@urql/core';\n *\n * const POKEMONS_QUERY = gql`\n *   query Pokemons {\n *     pokemons(limit: 10) {\n *       id\n *       name\n *     }\n *   }\n * `;\n *\n * const queryPokemons = createQuery(POKEMONS_QUERY, 'list-pokemons');\n *\n * export default function PokemonList() {\n *   const client = useClient();\n *   const pokemons = createAsync(() => queryPokemons(client));\n *\n *   return (\n *     <Show when={pokemons()?.data}>\n *       <For each={pokemons()!.data.pokemons}>\n *         {pokemon => <li>{pokemon.name}</li>}\n *       </For>\n *     </Show>\n *   );\n * }\n * ```\n */\nexport function createQuery<\n  Data = any,\n  Variables extends AnyVariables = AnyVariables,\n>(\n  queryDocument: DocumentInput<Data, Variables>,\n  key: string,\n  options?: {\n    variables?: Variables;\n    requestPolicy?: RequestPolicy;\n    context?: Partial<OperationContext>;\n  }\n) {\n  // Get the query function from context\n  const queryFn = useQuery();\n\n  // Return the result of calling the query function\n  return queryFn(\n    async (\n      clientOrVariables?: Client | Variables,\n      variablesOrContext?: Variables | Partial<OperationContext>,\n      contextOverride?: Partial<OperationContext>\n    ) => {\n      // Determine if first arg is client or variables\n      let client: Client;\n      let variables: Variables | undefined;\n      let context: Partial<OperationContext> | undefined;\n\n      if (\n        clientOrVariables &&\n        typeof (clientOrVariables as any).executeQuery === 'function'\n      ) {\n        // First arg is client\n        client = clientOrVariables as Client;\n        variables = variablesOrContext as Variables | undefined;\n        context = contextOverride;\n      } else {\n        // First arg is variables (or nothing), use useClient\n        client = useClient();\n        variables = clientOrVariables as Variables | undefined;\n        context = variablesOrContext as Partial<OperationContext> | undefined;\n      }\n\n      const finalVariables =\n        variables !== undefined ? variables : options && options.variables;\n      const request = createRequest(queryDocument, finalVariables as Variables);\n      const finalContext: Partial<OperationContext> = {\n        requestPolicy: options && options.requestPolicy,\n        ...(options && options.context),\n        ...context,\n      };\n\n      return await client.executeQuery(request, finalContext).toPromise();\n    },\n    key\n  );\n}\n"
  },
  {
    "path": "packages/solid-start-urql/src/createSubscription.test.ts",
    "content": "// @vitest-environment jsdom\n\nimport { renderHook } from '@solidjs/testing-library';\nimport {\n  OperationResult,\n  OperationResultSource,\n  createClient,\n  gql,\n} from '@urql/core';\nimport { expect, it, describe, vi } from 'vitest';\nimport { makeSubject } from 'wonka';\nimport { createSubscription } from './index';\n\nconst QUERY = gql`\n  subscription {\n    value\n  }\n`;\n\nconst client = createClient({\n  url: '/graphql',\n  exchanges: [],\n  suspense: false,\n});\n\nvi.mock('./context', () => {\n  const useClient = () => client;\n\n  return { useClient };\n});\n\ndescribe('createSubscription', () => {\n  it('should execute against solid-start context client', () => {\n    const subject =\n      makeSubject<Pick<OperationResult<{ value: number }, any>, 'data'>>();\n    const executeSubscription = vi\n      .spyOn(client, 'executeSubscription')\n      .mockImplementation(\n        () => subject.source as OperationResultSource<OperationResult>\n      );\n\n    const {\n      result: [state],\n    } = renderHook(() =>\n      createSubscription<{ value: number }, { variable: number }>({\n        query: QUERY,\n      })\n    );\n\n    expect(executeSubscription).toHaveBeenCalledOnce();\n\n    subject.next({ data: { value: 1 } });\n\n    expect(state.data).toEqual({ value: 1 });\n  });\n});\n"
  },
  {
    "path": "packages/solid-start-urql/src/createSubscription.ts",
    "content": "import { type MaybeAccessor, asAccessor } from './utils';\nimport {\n  type AnyVariables,\n  type DocumentInput,\n  type Operation,\n  type OperationContext,\n  type OperationResult,\n  type CombinedError,\n  createRequest,\n} from '@urql/core';\nimport { useClient } from './context';\nimport { createStore, produce, reconcile } from 'solid-js/store';\nimport {\n  batch,\n  createComputed,\n  createSignal,\n  onCleanup,\n  untrack,\n} from 'solid-js';\nimport { type Source, onEnd, pipe, subscribe } from 'wonka';\n\nexport type CreateSubscriptionExecute = (\n  opts?: Partial<OperationContext>\n) => void;\n\nexport type CreateSubscriptionArgs<\n  Data,\n  Variables extends AnyVariables = AnyVariables,\n> = {\n  query: DocumentInput<Data, Variables>;\n  variables?: MaybeAccessor<Variables>;\n  context?: MaybeAccessor<Partial<OperationContext>>;\n  pause?: MaybeAccessor<boolean>;\n};\n\nexport type CreateSubscriptionState<\n  Data = any,\n  Variables extends AnyVariables = AnyVariables,\n> = {\n  fetching: boolean;\n  stale: boolean;\n  data?: Data;\n  error?: CombinedError;\n  extensions?: Record<string, any>;\n  operation?: Operation<Data, Variables>;\n};\n\nexport type SubscriptionHandler<T, R> = (prev: R | undefined, data: T) => R;\n\nexport type CreateSubscriptionResult<\n  Data,\n  Variables extends AnyVariables = AnyVariables,\n> = [CreateSubscriptionState<Data, Variables>, CreateSubscriptionExecute];\n\nexport const createSubscription = <\n  Data,\n  Result = Data,\n  Variables extends AnyVariables = AnyVariables,\n>(\n  args: CreateSubscriptionArgs<Data, Variables>,\n  handler?: SubscriptionHandler<Data, Result>\n): CreateSubscriptionResult<Result, Variables> => {\n  const getContext = asAccessor(args.context);\n  const getPause = asAccessor(args.pause);\n  const getVariables = asAccessor(args.variables);\n\n  const client = useClient();\n\n  const request = createRequest(args.query, getVariables() as Variables);\n  const operation = client.createRequestOperation(\n    'subscription',\n    request,\n    getContext()\n  );\n  const initialState: CreateSubscriptionState<Result, Variables> = {\n    operation,\n    fetching: false,\n    data: undefined,\n    error: undefined,\n    extensions: undefined,\n    stale: false,\n  };\n\n  const [source, setSource] = createSignal<\n    Source<OperationResult<Data, Variables>> | undefined\n  >(undefined, { equals: false });\n\n  const [state, setState] =\n    createStore<CreateSubscriptionState<Result, Variables>>(initialState);\n\n  createComputed(() => {\n    if (getPause() === true) {\n      setSource(undefined);\n      return;\n    }\n\n    const context = getContext();\n    const request = createRequest(args.query, getVariables() as Variables);\n    setSource(() => client.executeSubscription(request, context));\n  });\n\n  createComputed(() => {\n    const s = source();\n    if (s === undefined) {\n      setState('fetching', false);\n\n      return;\n    }\n\n    setState('fetching', true);\n    onCleanup(\n      pipe(\n        s,\n        onEnd(() => {\n          setState(\n            produce(draft => {\n              draft.fetching = false;\n            })\n          );\n        }),\n        subscribe(res => {\n          batch(() => {\n            if (res.data !== undefined) {\n              const newData =\n                typeof handler === 'function'\n                  ? handler(\n                      untrack(() => state.data),\n                      res.data\n                    )\n                  : (res.data as Result);\n              setState('data', reconcile(newData));\n            }\n            setState(\n              produce(draft => {\n                draft.stale = !!res.stale;\n                draft.fetching = true;\n                draft.error = res.error;\n                draft.operation = res.operation;\n                draft.extensions = res.extensions;\n              })\n            );\n          });\n        })\n      ).unsubscribe\n    );\n  });\n\n  const executeSubscription = (opts?: Partial<OperationContext>) => {\n    const context: Partial<OperationContext> = {\n      ...getContext(),\n      ...opts,\n    };\n    const request = createRequest(args.query, getVariables() as Variables);\n\n    setSource(() => client.executeSubscription(request, context));\n  };\n\n  return [state, executeSubscription];\n};\n"
  },
  {
    "path": "packages/solid-start-urql/src/index.ts",
    "content": "// Re-export everything from @urql/core\nexport * from '@urql/core';\n\n// Context exports\nexport {\n  type UseAction,\n  type UseClient,\n  type UseQuery,\n  type UrqlContext,\n} from './context';\nexport { useAction, useClient, useQuery, Provider } from './context';\n\n// Query exports\nexport { createQuery } from './createQuery';\n\n// Mutation exports\nexport { type CreateMutationAction } from './createMutation';\nexport { createMutation } from './createMutation';\n\n// Subscription exports\nexport {\n  type CreateSubscriptionArgs,\n  type CreateSubscriptionState,\n  type CreateSubscriptionExecute,\n  type CreateSubscriptionResult,\n  type SubscriptionHandler,\n} from './createSubscription';\nexport { createSubscription } from './createSubscription';\n\n// Utility exports\nexport { type MaybeAccessor } from './utils';\n"
  },
  {
    "path": "packages/solid-start-urql/src/utils.ts",
    "content": "// Re-export utility types and functions from @solid-primitives/utils\nexport {\n  access,\n  asAccessor,\n  type MaybeAccessor,\n} from '@solid-primitives/utils';\n"
  },
  {
    "path": "packages/solid-start-urql/tsconfig.json",
    "content": "{\n  \"extends\": \"../../tsconfig.json\",\n  \"include\": [\"src\"],\n  \"compilerOptions\": {\n    \"jsx\": \"preserve\",\n    \"jsxImportSource\": \"solid-js\"\n  }\n}\n"
  },
  {
    "path": "packages/solid-start-urql/vitest.config.ts",
    "content": "import { mergeConfig } from 'vitest/config';\nimport solidPlugin from 'vite-plugin-solid';\nimport baseConfig from '../../vitest.config';\n\nexport default mergeConfig(baseConfig, {\n  plugins: [solidPlugin({ hot: false })],\n  esbuild: {\n    jsxImportSource: 'solid-js',\n  },\n});\n"
  },
  {
    "path": "packages/solid-urql/CHANGELOG.md",
    "content": "# @urql/solid\n\n## 1.0.1\n\n### Patch Changes\n\n- Use `@solid-primitives/utils` for `access` and `MaybeAccessor` utilities instead of custom implementations. This aligns the package with standard Solid ecosystem conventions\n  Submitted by [@davedbase](https://github.com/davedbase) (See [#3837](https://github.com/urql-graphql/urql/pull/3837))\n\n## 1.0.0\n\n### Patch Changes\n\n- Updated dependencies (See [#3789](https://github.com/urql-graphql/urql/pull/3789) and [#3807](https://github.com/urql-graphql/urql/pull/3807))\n  - @urql/core@6.0.0\n\n## 0.1.2\n\n### Patch Changes\n\n- Omit minified files and sourcemaps' `sourcesContent` in published packages\n  Submitted by [@kitten](https://github.com/kitten) (See [#3755](https://github.com/urql-graphql/urql/pull/3755))\n- Updated dependencies (See [#3755](https://github.com/urql-graphql/urql/pull/3755))\n  - @urql/core@5.1.1\n\n## 0.1.1\n\n### Patch Changes\n\n- Add type for `hasNext` to the query and mutation results\n  Submitted by [@JoviDeCroock](https://github.com/JoviDeCroock) (See [#3703](https://github.com/urql-graphql/urql/pull/3703))\n\n## 0.1.0\n\n### Minor Changes\n\n- Initial release\n  Submitted by [@stefanmaric](https://github.com/stefanmaric) (See [#3607](https://github.com/urql-graphql/urql/pull/3607))\n\n### Patch Changes\n\n- Export Provider from the entry\n  Submitted by [@XiNiHa](https://github.com/XiNiHa) (See [#3670](https://github.com/urql-graphql/urql/pull/3670))\n- Correctly track query data reads with suspense\n  Submitted by [@XiNiHa](https://github.com/XiNiHa) (See [#3672](https://github.com/urql-graphql/urql/pull/3672))\n- feat(solid): reconcile data updates\n  Submitted by [@XiNiHa](https://github.com/XiNiHa) (See [#3674](https://github.com/urql-graphql/urql/pull/3674))\n"
  },
  {
    "path": "packages/solid-urql/README.md",
    "content": "# @urql/solid\n\nA highly customizable and versatile GraphQL client for SolidJS.\n\n> **Note:** This package is for client-side SolidJS applications. If you're building a SolidStart application with SSR, use [`@urql/solid-start`](../solid-start-urql) instead. See the [comparison section](../solid-start-urql#solidjs-vs-solidstart) in the SolidStart package for key differences.\n\n## Installation\n\n```bash\nnpm install @urql/solid @urql/core graphql\n# or\npnpm add @urql/solid @urql/core graphql\n# or\nyarn add @urql/solid @urql/core graphql\n```\n\n## Documentation\n\nFull documentation is available at [formidable.com/open-source/urql/docs/](https://formidable.com/open-source/urql/docs/).\n\n## Quick Start\n\n```tsx\nimport { createClient, Provider, createQuery } from '@urql/solid';\nimport { cacheExchange, fetchExchange } from '@urql/core';\nimport { gql } from '@urql/core';\n\nconst client = createClient({\n  url: 'https://api.example.com/graphql',\n  exchanges: [cacheExchange, fetchExchange],\n});\n\nconst TodosQuery = gql`\n  query {\n    todos {\n      id\n      title\n    }\n  }\n`;\n\nfunction App() {\n  return (\n    <Provider value={client}>\n      <TodoList />\n    </Provider>\n  );\n}\n\nfunction TodoList() {\n  const [result] = createQuery({ query: TodosQuery });\n\n  return (\n    <div>\n      {result().data?.todos.map(todo => (\n        <div>{todo.title}</div>\n      ))}\n    </div>\n  );\n}\n```\n\n## When to Use @urql/solid vs @urql/solid-start\n\n| Use Case | Package |\n|----------|---------|\n| Client-side SPA | `@urql/solid` |\n| SolidStart with SSR | `@urql/solid-start` |\n\nFor a detailed comparison of the APIs and when to use each package, see the [SolidJS vs SolidStart comparison](../solid-start-urql#solidjs-vs-solidstart) in the `@urql/solid-start` documentation.\n\n## License\n\nMIT\n"
  },
  {
    "path": "packages/solid-urql/jsr.json",
    "content": "{\n  \"name\": \"@urql/solid\",\n  \"version\": \"1.0.1\",\n  \"exports\": {\n    \".\": \"./src/index.ts\"\n  },\n  \"exclude\": [\n    \"node_modules\",\n    \"cypress\",\n    \"**/*.test.*\",\n    \"**/*.spec.*\",\n    \"**/*.test.*.snap\",\n    \"**/*.spec.*.snap\"\n  ]\n}"
  },
  {
    "path": "packages/solid-urql/package.json",
    "content": "{\n  \"name\": \"@urql/solid\",\n  \"version\": \"1.0.1\",\n  \"description\": \"A highly customizable and versatile GraphQL client for Solid\",\n  \"sideEffects\": false,\n  \"homepage\": \"https://formidable.com/open-source/urql/docs/\",\n  \"bugs\": \"https://github.com/urql-graphql/urql/issues\",\n  \"license\": \"MIT\",\n  \"author\": \"urql GraphQL Contributors\",\n  \"repository\": {\n    \"type\": \"git\",\n    \"url\": \"https://github.com/urql-graphql/urql.git\",\n    \"directory\": \"packages/solid-urql\"\n  },\n  \"keywords\": [\n    \"graphql client\",\n    \"state management\",\n    \"cache\",\n    \"graphql\",\n    \"exchanges\",\n    \"solid\"\n  ],\n  \"main\": \"dist/urql-solid\",\n  \"module\": \"dist/urql-solid.mjs\",\n  \"types\": \"dist/urql-solid.d.ts\",\n  \"source\": \"src/index.ts\",\n  \"exports\": {\n    \".\": {\n      \"types\": \"./dist/urql-solid.d.ts\",\n      \"import\": \"./dist/urql-solid.mjs\",\n      \"require\": \"./dist/urql-solid.js\",\n      \"source\": \"./src/index.ts\"\n    },\n    \"./package.json\": \"./package.json\"\n  },\n  \"files\": [\n    \"LICENSE\",\n    \"CHANGELOG.md\",\n    \"README.md\",\n    \"dist/\"\n  ],\n  \"scripts\": {\n    \"test\": \"vitest\",\n    \"clean\": \"rimraf dist\",\n    \"check\": \"tsc --noEmit\",\n    \"lint\": \"eslint --ext=js,jsx,ts,tsx .\",\n    \"build\": \"rollup -c ../../scripts/rollup/config.mjs\",\n    \"prepare\": \"node ../../scripts/prepare/index.js\",\n    \"prepublishOnly\": \"run-s clean build\"\n  },\n  \"devDependencies\": {\n    \"@solidjs/testing-library\": \"^0.8.2\",\n    \"@urql/core\": \"workspace:*\",\n    \"graphql\": \"^16.0.0\",\n    \"jsdom\": \"^22.1.0\",\n    \"vite-plugin-solid\": \"^2.7.0\"\n  },\n  \"peerDependencies\": {\n    \"@urql/core\": \"^6.0.0\",\n    \"solid-js\": \"^1.7.7\"\n  },\n  \"dependencies\": {\n    \"@solid-primitives/utils\": \"^6.2.1\",\n    \"@urql/core\": \"workspace:^6.0.1\",\n    \"wonka\": \"^6.3.2\"\n  },\n  \"publishConfig\": {\n    \"access\": \"public\",\n    \"provenance\": true\n  }\n}\n"
  },
  {
    "path": "packages/solid-urql/src/context.ts",
    "content": "import type { Client } from '@urql/core';\nimport { createContext, useContext } from 'solid-js';\n\nexport const Context = createContext<Client>();\nexport const Provider = Context.Provider;\n\nexport type UseClient = () => Client;\nexport const useClient: UseClient = () => {\n  const client = useContext(Context);\n\n  if (process.env.NODE_ENV !== 'production' && client === undefined) {\n    const error =\n      \"No client has been specified using urql's Provider. please create a client and add a Provider.\";\n\n    console.error(error);\n    throw new Error(error);\n  }\n\n  return client!;\n};\n"
  },
  {
    "path": "packages/solid-urql/src/createMutation.test.ts",
    "content": "// @vitest-environment jsdom\n\nimport { testEffect } from '@solidjs/testing-library';\nimport { expect, it, describe, vi } from 'vitest';\nimport { CreateMutationState, createMutation } from './createMutation';\nimport {\n  OperationResult,\n  OperationResultSource,\n  createClient,\n  gql,\n} from '@urql/core';\nimport { makeSubject } from 'wonka';\nimport { createEffect } from 'solid-js';\n\nconst QUERY = gql`\n  mutation {\n    test\n  }\n`;\n\nconst client = createClient({\n  url: '/graphql',\n  exchanges: [],\n  suspense: false,\n});\n\nvi.mock('./context', () => {\n  const useClient = () => {\n    return client!;\n  };\n\n  return { useClient };\n});\n\n// Given that it is not possible to directly listen to all store changes it is necessary\n// to access all relevant parts on which `createEffect` should listen on\nconst markStateDependencies = (state: CreateMutationState<any, any>) => {\n  state.data;\n  state.error;\n  state.extensions;\n  state.fetching;\n  state.operation;\n  state.stale;\n};\n\ndescribe('createMutation', () => {\n  it('should have expected state before and after finish', () => {\n    const subject = makeSubject<any>();\n    const clientMutation = vi\n      .spyOn(client, 'executeMutation')\n      .mockImplementation(\n        () => subject.source as OperationResultSource<OperationResult>\n      );\n\n    return testEffect(done => {\n      const [state, execute] = createMutation<\n        { test: boolean },\n        { variable: number }\n      >(QUERY);\n\n      createEffect((run: number = 0) => {\n        markStateDependencies(state);\n\n        switch (run) {\n          case 0: {\n            expect(state).toMatchObject({\n              data: undefined,\n              stale: false,\n              fetching: false,\n              error: undefined,\n              extensions: undefined,\n              operation: undefined,\n            });\n\n            execute({ variable: 1 });\n            break;\n          }\n\n          case 1: {\n            expect(state).toMatchObject({\n              data: undefined,\n              stale: false,\n              fetching: true,\n              error: undefined,\n              extensions: undefined,\n              operation: undefined,\n            });\n\n            expect(clientMutation).toHaveBeenCalledTimes(1);\n            subject.next({ data: { test: true }, stale: false });\n\n            break;\n          }\n\n          case 2: {\n            expect(state).toMatchObject({\n              data: { test: true },\n              stale: false,\n              fetching: false,\n              error: undefined,\n              extensions: undefined,\n            });\n\n            done();\n            break;\n          }\n        }\n\n        return run + 1;\n      });\n    });\n  });\n});\n"
  },
  {
    "path": "packages/solid-urql/src/createMutation.ts",
    "content": "import { createStore, reconcile } from 'solid-js/store';\nimport {\n  type AnyVariables,\n  type DocumentInput,\n  type OperationContext,\n  type Operation,\n  type OperationResult,\n  type CombinedError,\n  createRequest,\n} from '@urql/core';\nimport { useClient } from './context';\nimport { pipe, onPush, filter, take, toPromise } from 'wonka';\nimport { batch } from 'solid-js';\n\nexport type CreateMutationState<\n  Data = any,\n  Variables extends AnyVariables = AnyVariables,\n> = {\n  /** Indicates whether `createMutation` is currently executing a mutation. */\n  fetching: boolean;\n\n  /** Indicates that the mutation result is not fresh.\n   *\n   * @remarks\n   * The `stale` flag is set to `true` when a new result for the mutation\n   * is expected.\n   * This is mostly unused for mutations and will rarely affect you, and\n   * is more relevant for queries.\n   *\n   * @see {@link OperationResult.stale} for the source of this value.\n   */\n  stale: boolean;\n  /** The {@link OperationResult.data} for the executed mutation. */\n  data?: Data;\n  /** The {@link OperationResult.error} for the executed mutation. */\n  error?: CombinedError;\n  /** The {@link OperationResult.extensions} for the executed mutation. */\n  extensions?: Record<string, any>;\n  /** The {@link Operation} that the current state is for.\n   *\n   * @remarks\n   * This is the mutation {@link Operation} that has last been executed.\n   * When {@link CreateMutationState.fetching} is `true`, this is the\n   * last `Operation` that the current state was for.\n   */\n  operation?: Operation<Data, Variables>;\n  /** The {@link OperationResult.hasNext} for the executed query. */\n  hasNext: boolean;\n};\n\n/** Triggers {@link createMutation} to execute its GraphQL mutation operation.\n *\n * @param variables - variables using which the mutation will be executed.\n * @param context - optionally, context options that will be merged with the hook's\n * context options and the `Client`’s options.\n * @returns the {@link OperationResult} of the mutation.\n *\n * @remarks\n * When called, {@link createMutation} will start the GraphQL mutation\n * it currently holds and use the `variables` passed to it.\n *\n * Once the mutation response comes back from the API, its\n * returned promise will resolve to the mutation’s {@link OperationResult}\n * and the {@link CreateMutationState} will be updated with the result.\n *\n * @example\n * ```ts\n * const [result, executeMutation] = createMutation(UpdateTodo);\n * const start = async ({ id, title }) => {\n *   const result = await executeMutation({ id, title });\n * };\n */\nexport type CreateMutationExecute<\n  Data = any,\n  Variables extends AnyVariables = AnyVariables,\n> = (\n  variables: Variables,\n  context?: Partial<OperationContext>\n) => Promise<OperationResult<Data, Variables>>;\n\n/** Result tuple returned by the {@link createMutation} hook.\n *\n * @remarks\n * Similarly to a `createSignal` hook’s return value,\n * the first element is the {@link createMutation}’s state, updated\n * as mutations are executed with the second value, which is\n * used to start mutations and is a {@link CreateMutationExecute}\n * function.\n */\nexport type CreateMutationResult<\n  Data = any,\n  Variables extends AnyVariables = AnyVariables,\n> = [\n  CreateMutationState<Data, Variables>,\n  CreateMutationExecute<Data, Variables>,\n];\n\n/** Hook to create a GraphQL mutation, run by passing variables to the returned execute function.\n *\n * @param query - a GraphQL mutation document which `createMutation` will execute.\n * @returns a {@link CreateMutationResult} tuple of a {@link CreateMutationState} result,\n * and an execute function to start the mutation.\n *\n * @remarks\n * `createMutation` allows GraphQL mutations to be defined and keeps its state\n * after the mutation is started with the returned execute function.\n *\n * Given a GraphQL mutation document it returns state to keep track of the\n * mutation state and a {@link CreateMutationExecute} function, which accepts\n * variables for the mutation to be executed.\n * Once called, the mutation executes and the state will be updated with\n * the mutation’s result.\n *\n * @example\n * ```ts\n * import { gql, createMutation } from '@urql/solid';\n *\n * const UpdateTodo = gql`\n *   mutation ($id: ID!, $title: String!) {\n *     updateTodo(id: $id, title: $title) {\n *       id, title\n *     }\n *   }\n * `;\n *\n * const UpdateTodo = () => {\n *   const [result, executeMutation] = createMutation(UpdateTodo);\n *   const start = async ({ id, title }) => {\n *     const result = await executeMutation({ id, title });\n *   };\n *   // ...\n * };\n * ```\n */\nexport const createMutation = <\n  Data = any,\n  Variables extends AnyVariables = AnyVariables,\n>(\n  query: DocumentInput<Data, Variables>\n): CreateMutationResult<Data, Variables> => {\n  const client = useClient();\n  const initialResult: CreateMutationState<Data, Variables> = {\n    operation: undefined,\n    fetching: false,\n    hasNext: false,\n    stale: false,\n    data: undefined,\n    error: undefined,\n    extensions: undefined,\n  };\n\n  const [state, setState] =\n    createStore<CreateMutationState<Data, Variables>>(initialResult);\n\n  const execute = (\n    variables: Variables,\n    context?: Partial<OperationContext>\n  ) => {\n    setState({ ...initialResult, fetching: true });\n\n    const request = createRequest(query, variables);\n    return pipe(\n      client.executeMutation(request, context),\n      onPush(result => {\n        batch(() => {\n          setState('data', reconcile(result.data));\n          setState({\n            fetching: false,\n            stale: result.stale,\n            error: result.error,\n            extensions: result.extensions,\n            operation: result.operation,\n            hasNext: result.hasNext,\n          });\n        });\n      }),\n      filter(result => !result.hasNext),\n      take(1),\n      toPromise\n    );\n  };\n\n  return [state, execute];\n};\n"
  },
  {
    "path": "packages/solid-urql/src/createQuery.test.tsx",
    "content": "// @vitest-environment jsdom\n\nimport { expect, it, describe, vi } from 'vitest';\nimport { CreateQueryState, createQuery } from './createQuery';\nimport { renderHook, testEffect } from '@solidjs/testing-library';\nimport { createClient } from '@urql/core';\nimport { createEffect, createSignal } from 'solid-js';\nimport { makeSubject } from 'wonka';\nimport { OperationResult, OperationResultSource } from '@urql/core';\n\nconst client = createClient({\n  url: '/graphql',\n  exchanges: [],\n  suspense: false,\n});\n\nvi.mock('./context', () => {\n  const useClient = () => {\n    return client!;\n  };\n\n  return { useClient };\n});\n\n// Given that it is not possible to directly listen to all store changes it is necessary\n// to access all relevant parts on which `createEffect` should listen on\nconst markStateDependencies = (state: CreateQueryState<any, any>) => {\n  state.data;\n  state.error;\n  state.extensions;\n  state.fetching;\n  state.operation;\n  state.stale;\n};\n\ndescribe('createQuery', () => {\n  it('should fetch when query is resumed', () => {\n    const subject =\n      makeSubject<Pick<OperationResult<{ test: boolean }, any>, 'data'>>();\n    const executeQuery = vi\n      .spyOn(client, 'executeQuery')\n      .mockImplementation(\n        () => subject.source as OperationResultSource<OperationResult>\n      );\n\n    return testEffect(done => {\n      const [pause, setPause] = createSignal<boolean>(true);\n      const [state] = createQuery<{ test: boolean }, { variable: number }>({\n        query: '{ test }',\n        pause: pause,\n      });\n\n      createEffect((run: number = 0) => {\n        markStateDependencies(state);\n\n        switch (run) {\n          case 0: {\n            expect(state.fetching).toEqual(false);\n            expect(executeQuery).not.toHaveBeenCalled();\n            setPause(false);\n            break;\n          }\n          case 1: {\n            expect(state.fetching).toEqual(true);\n            expect(executeQuery).toHaveBeenCalledOnce();\n            subject.next({ data: { test: true } });\n            break;\n          }\n          case 2: {\n            expect(state.fetching).toEqual(false);\n            expect(state.data).toStrictEqual({ test: true });\n            done();\n            break;\n          }\n        }\n\n        return run + 1;\n      });\n    });\n  });\n\n  it('should override pause when execute via refetch', () => {\n    const subject =\n      makeSubject<Pick<OperationResult<{ test: boolean }, any>, 'data'>>();\n    const executeQuery = vi\n      .spyOn(client, 'executeQuery')\n      .mockImplementation(\n        () => subject.source as OperationResultSource<OperationResult>\n      );\n\n    return testEffect(done => {\n      const [state, refetch] = createQuery<\n        { test: boolean },\n        { variable: number }\n      >({\n        query: '{ test }',\n        pause: true,\n      });\n\n      createEffect((run: number = 0) => {\n        markStateDependencies(state);\n\n        switch (run) {\n          case 0: {\n            expect(state.fetching).toEqual(false);\n            expect(executeQuery).not.toBeCalled();\n            refetch();\n            break;\n          }\n          case 1: {\n            expect(state.fetching).toEqual(true);\n            expect(executeQuery).toHaveBeenCalledOnce();\n            subject.next({ data: { test: true } });\n            break;\n          }\n          case 2: {\n            expect(state.fetching).toEqual(false);\n            expect(state.data).toStrictEqual({ test: true });\n            done();\n            break;\n          }\n        }\n\n        return run + 1;\n      });\n    });\n  });\n\n  it('should trigger refetch on variables change', () => {\n    const subject =\n      makeSubject<Pick<OperationResult<{ test: boolean }, any>, 'data'>>();\n    const executeQuery = vi\n      .spyOn(client, 'executeQuery')\n      .mockImplementation(\n        () => subject.source as OperationResultSource<OperationResult>\n      );\n\n    return testEffect(done => {\n      const [variables, setVariables] = createSignal<{ variable: number }>({\n        variable: 1,\n      });\n\n      const [state] = createQuery<{ test: boolean }, { variable: number }>({\n        query: '{ test }',\n        variables: variables,\n      });\n\n      createEffect((run: number = 0) => {\n        markStateDependencies(state);\n\n        switch (run) {\n          case 0: {\n            expect(state.fetching).toEqual(true);\n\n            subject.next({ data: { test: true } });\n\n            break;\n          }\n          case 1: {\n            expect(state.fetching).toEqual(false);\n            expect(state.data).toEqual({ test: true });\n            setVariables({ variable: 2 });\n            break;\n          }\n          case 2: {\n            expect(state.fetching).toEqual(true);\n            expect(executeQuery).toHaveBeenCalledTimes(2);\n\n            subject.next({ data: { test: false } });\n            break;\n          }\n          case 3: {\n            expect(state.fetching).toEqual(false);\n            expect(state.data).toEqual({ test: false });\n            done();\n            break;\n          }\n        }\n\n        return run + 1;\n      });\n    });\n  });\n\n  it('should receive data', () => {\n    const subject =\n      makeSubject<Pick<OperationResult<{ test: boolean }, any>, 'data'>>();\n    const executeQuery = vi\n      .spyOn(client, 'executeQuery')\n      .mockImplementation(\n        () => subject.source as OperationResultSource<OperationResult>\n      );\n\n    return testEffect(done => {\n      const [state] = createQuery<{ test: boolean }, { variable: number }>({\n        query: '{ test }',\n      });\n\n      createEffect((run: number = 0) => {\n        markStateDependencies(state);\n\n        switch (run) {\n          case 0: {\n            expect(state.fetching).toEqual(true);\n            expect(state.data).toBeUndefined();\n\n            subject.next({ data: { test: true } });\n            break;\n          }\n\n          case 1: {\n            expect(state.fetching).toEqual(false);\n            expect(state.data).toStrictEqual({ test: true });\n            expect(executeQuery).toHaveBeenCalledTimes(1);\n            done();\n            break;\n          }\n        }\n\n        return run + 1;\n      });\n    });\n  });\n\n  it('should unsubscribe on teardown', () => {\n    const subject =\n      makeSubject<Pick<OperationResult<{ value: number }, any>, 'data'>>();\n    vi.spyOn(client, 'executeQuery').mockImplementation(\n      () => subject.source as OperationResultSource<OperationResult>\n    );\n\n    const {\n      result: [state],\n      cleanup,\n    } = renderHook(() =>\n      createQuery<{ test: number }, { variable: number }>({\n        query: '{ test }',\n      })\n    );\n\n    return testEffect(done => {\n      markStateDependencies(state);\n\n      createEffect((run: number = 0) => {\n        switch (run) {\n          case 0: {\n            expect(state.fetching).toEqual(true);\n            cleanup();\n            break;\n          }\n          case 1: {\n            expect(state.fetching).toEqual(false);\n            done();\n            break;\n          }\n        }\n\n        return run + 1;\n      });\n    });\n  });\n});\n"
  },
  {
    "path": "packages/solid-urql/src/createQuery.ts",
    "content": "import {\n  type AnyVariables,\n  type OperationContext,\n  type DocumentInput,\n  type OperationResult,\n  type RequestPolicy,\n  createRequest,\n} from '@urql/core';\nimport {\n  batch,\n  createComputed,\n  createMemo,\n  createResource,\n  createSignal,\n  onCleanup,\n} from 'solid-js';\nimport { createStore, produce, reconcile } from 'solid-js/store';\nimport { useClient } from './context';\nimport { type MaybeAccessor, asAccessor } from './utils';\nimport type { Source, Subscription } from 'wonka';\nimport { onEnd, pipe, subscribe } from 'wonka';\n\n/** Triggers {@link createQuery} to execute a new GraphQL query operation.\n *\n * @remarks\n * When called, {@link createQuery} will re-execute the GraphQL query operation\n * it currently holds, even if {@link CreateQueryArgs.pause} is set to `true`.\n *\n * This is useful for executing a paused query or re-executing a query\n * and get a new network result, by passing a new request policy.\n *\n * ```ts\n * const [result, reExecuteQuery] = createQuery({ query });\n *\n * const refresh = () => {\n *   // Re-execute the query with a network-only policy, skipping the cache\n *   reExecuteQuery({ requestPolicy: 'network-only' });\n * };\n * ```\n *\n */\nexport type CreateQueryExecute = (opts?: Partial<OperationContext>) => void;\n\n/** State of the current query, your {@link createQuery} hook is executing.\n *\n * @remarks\n * `CreateQueryState` is returned (in a tuple) by {@link createQuery} and\n * gives you the updating {@link OperationResult} of GraphQL queries.\n *\n * Even when the query and variables passed to {@link createQuery} change,\n * this state preserves the prior state and sets the `fetching` flag to\n * `true`.\n * This allows you to display the previous state, while implementing\n * a separate loading indicator separately.\n */\nexport type CreateQueryState<\n  Data = any,\n  Variables extends AnyVariables = AnyVariables,\n> = OperationResult<Data, Variables> & {\n  /** Indicates whether `createQuery` is waiting for a new result.\n   *\n   * @remarks\n   * When `createQuery` is passed a new query and/or variables, it will\n   * start executing the new query operation and `fetching` is set to\n   * `true` until a result arrives.\n   *\n   * Hint: This is subtly different than whether the query is actually\n   * fetching, and doesn’t indicate whether a query is being re-executed\n   * in the background. For this, see {@link CreateQueryState.stale}.\n   */\n  fetching: boolean;\n};\n\n/**\n * Input arguments for the {@link createQuery} hook.\n */\nexport type CreateQueryArgs<\n  Data = any,\n  Variables extends AnyVariables = AnyVariables,\n> = {\n  /** The GraphQL query that `createQuery` executes. */\n  query: DocumentInput<Data, Variables>;\n\n  /** The variables for the GraphQL {@link CreateQueryArgs.query} that `createQuery` executes. */\n  variables?: MaybeAccessor<Variables>;\n\n  /** Updates the {@link RequestPolicy} for the executed GraphQL query operation.\n   *\n   * @remarks\n   * `requestPolicy` modifies the {@link RequestPolicy} of the GraphQL query operation\n   * that `createQuery` executes, and indicates a caching strategy for cache exchanges.\n   *\n   * For example, when set to `'cache-and-network'`, {@link createQuery} will\n   * receive a cached result with `stale: true` and an API request will be\n   * sent in the background.\n   *\n   * @see {@link OperationContext.requestPolicy} for where this value is set.\n   */\n  requestPolicy?: MaybeAccessor<RequestPolicy>;\n\n  /** Updates the {@link OperationContext} for the executed GraphQL query operation.\n   *\n   * @remarks\n   * `context` may be passed to {@link createQuery}, to update the {@link OperationContext}\n   * of a query operation. This may be used to update the `context` that exchanges\n   * will receive for a single hook.\n   *\n   * In order to re-execute query on context change pass {@link Accessor} instead\n   * of raw value.\n   */\n  context?: MaybeAccessor<Partial<OperationContext>>;\n\n  /** Prevents {@link createQuery} from automatically executing GraphQL query operations.\n   *\n   * @remarks\n   * `pause` may be set to `true` to stop {@link createQuery} from executing\n   * automatically. The hook will stop receiving updates from the {@link Client}\n   * and won’t execute the query operation, until either it’s set to `false`\n   * or the {@link CreateQueryExecute} function is called.\n   */\n  pause?: MaybeAccessor<boolean>;\n};\n\n/** Result tuple returned by the {@link createQuery} hook.\n *\n * @remarks\n * the first element is the {@link createQuery}’s result and state,\n * a {@link CreateQueryState} object,\n * and the second is used to imperatively re-execute the query\n * via a {@link CreateQueryExecute} function.\n */\nexport type CreateQueryResult<\n  Data = any,\n  Variables extends AnyVariables = AnyVariables,\n> = [CreateQueryState<Data, Variables>, CreateQueryExecute];\n\n/** Hook to run a GraphQL query and get updated GraphQL results.\n *\n * @param args - a {@link CreateQueryArgs} object, to pass a `query`, `variables`, and options.\n * @returns a {@link CreateQueryResult} tuple of a {@link CreateQueryState} result, and re-execute function.\n *\n * @remarks\n * `createQuery` allows GraphQL queries to be defined and executed.\n * Given {@link CreateQueryArgs.query}, it executes the GraphQL query with the\n * context’s {@link Client}.\n *\n * The returned result updates when the `Client` has new results\n * for the query, and changes when your input `args` change.\n *\n * Additionally, if the `suspense` option is enabled on the `Client`,\n * the `createQuery` hook will suspend instead of indicating that it’s\n * waiting for a result via {@link CreateQueryState.fetching}.\n *\n * @example\n * ```tsx\n * import { gql, createQuery } from '@urql/solid';\n *\n * const TodosQuery = gql`\n *   query { todos { id, title } }\n * `;\n *\n * const Todos = () => {\n *   const [result, reExecuteQuery] = createQuery({\n *     query: TodosQuery,\n *   });\n *   // ...\n * };\n * ```\n */\nexport const createQuery = <\n  Data = any,\n  Variables extends AnyVariables = AnyVariables,\n>(\n  args: CreateQueryArgs<Data, Variables>\n): CreateQueryResult<Data, Variables> => {\n  const client = useClient();\n  const getContext = asAccessor(args.context);\n  const getPause = asAccessor(args.pause);\n  const getRequestPolicy = asAccessor(args.requestPolicy);\n  const getVariables = asAccessor(args.variables);\n\n  const [source, setSource] = createSignal<\n    Source<OperationResult<Data, Variables>> | undefined\n  >(undefined, { equals: false });\n\n  // Combine suspense param coming from context and client with context being priority\n  const isSuspense = createMemo(() => {\n    const ctx = getContext();\n    if (ctx !== undefined && ctx.suspense !== undefined) {\n      return ctx.suspense;\n    }\n\n    return client.suspense;\n  });\n\n  const request = createRequest(args.query, getVariables() as any);\n  const context: Partial<OperationContext> = {\n    requestPolicy: getRequestPolicy(),\n    ...getContext(),\n  };\n  const operation = client.createRequestOperation('query', request, context);\n  const initialResult: CreateQueryState<Data, Variables> = {\n    operation: operation,\n    fetching: false,\n    data: undefined,\n    error: undefined,\n    extensions: undefined,\n    hasNext: false,\n    stale: false,\n  };\n\n  const [result, setResult] =\n    createStore<CreateQueryState<Data, Variables>>(initialResult);\n\n  createComputed(() => {\n    if (getPause() === true) {\n      setSource(undefined);\n      return;\n    }\n\n    const request = createRequest(args.query, getVariables() as any);\n    const context: Partial<OperationContext> = {\n      requestPolicy: getRequestPolicy(),\n      ...getContext(),\n    };\n\n    setSource(() => client.executeQuery(request, context));\n  });\n\n  createComputed(() => {\n    const s = source();\n    if (s === undefined) {\n      setResult(\n        produce(draft => {\n          draft.fetching = false;\n          draft.stale = false;\n          draft.hasNext = false;\n        })\n      );\n\n      return;\n    }\n\n    setResult(\n      produce(draft => {\n        draft.fetching = true;\n        draft.stale = false;\n        draft.hasNext = false;\n      })\n    );\n\n    onCleanup(\n      pipe(\n        s,\n        onEnd(() => {\n          setResult(\n            produce(draft => {\n              draft.fetching = false;\n              draft.stale = false;\n              draft.hasNext = false;\n            })\n          );\n        }),\n        subscribe(res => {\n          batch(() => {\n            setResult('data', reconcile(res.data));\n            setResult(\n              produce(draft => {\n                draft.stale = !!res.stale;\n                draft.fetching = false;\n                draft.error = res.error;\n                draft.operation = res.operation;\n                draft.extensions = res.extensions;\n                draft.hasNext = res.hasNext;\n              })\n            );\n          });\n        })\n      ).unsubscribe\n    );\n  });\n\n  const [dataResource, { refetch }] = createResource<\n    CreateQueryState<Data, Variables>,\n    Source<OperationResult<Data, Variables>> | undefined\n  >(source, source => {\n    let sub: Subscription | void;\n    if (source === undefined) {\n      return Promise.resolve(result);\n    }\n\n    return new Promise<CreateQueryState<Data, Variables>>(resolve => {\n      let hasResult = false;\n      sub = pipe(\n        source,\n        subscribe(() => {\n          if (!result.fetching && !result.stale) {\n            if (sub) sub.unsubscribe();\n            hasResult = true;\n            resolve(result);\n          }\n        })\n      );\n      if (hasResult) {\n        sub.unsubscribe();\n      }\n    });\n  });\n\n  const executeQuery: CreateQueryExecute = opts => {\n    const request = createRequest(args.query, getVariables() as any);\n    const context: Partial<OperationContext> = {\n      requestPolicy: getRequestPolicy(),\n      ...getContext(),\n      ...opts,\n    };\n\n    setSource(() => client.executeQuery(request, context));\n    if (isSuspense()) {\n      refetch();\n    }\n  };\n\n  const handler = {\n    get(\n      target: CreateQueryState<Data, Variables>,\n      prop: keyof CreateQueryState<Data, Variables>\n    ): any {\n      if (isSuspense() && prop === 'data') {\n        const resource = dataResource();\n        if (resource === undefined) return undefined;\n      }\n\n      return Reflect.get(target, prop);\n    },\n  };\n\n  const proxy = new Proxy(result, handler);\n  return [proxy, executeQuery];\n};\n"
  },
  {
    "path": "packages/solid-urql/src/createSubscription.test.ts",
    "content": "// @vitest-environment jsdom\n\nimport { renderHook, testEffect } from '@solidjs/testing-library';\nimport {\n  OperationResult,\n  OperationResultSource,\n  createClient,\n  createRequest,\n  gql,\n} from '@urql/core';\nimport { expect, it, describe, vi } from 'vitest';\nimport { makeSubject } from 'wonka';\nimport {\n  CreateSubscriptionState,\n  createSubscription,\n} from './createSubscription';\nimport { createEffect, createSignal } from 'solid-js';\n\nconst QUERY = gql`\n  subscription {\n    value\n  }\n`;\n\nconst client = createClient({\n  url: '/graphql',\n  exchanges: [],\n  suspense: false,\n});\n\nvi.mock('./context', () => {\n  const useClient = () => {\n    return client!;\n  };\n\n  return { useClient };\n});\n\n// Given that it is not possible to directly listen to all store changes it is necessary\n// to access all relevant parts on which `createEffect` should listen on\nconst markStateDependencies = (state: CreateSubscriptionState<any, any>) => {\n  state.data;\n  state.error;\n  state.extensions;\n  state.fetching;\n  state.operation;\n  state.stale;\n};\n\ndescribe('createSubscription', () => {\n  it('should receive data', () => {\n    return testEffect(done => {\n      const subject =\n        makeSubject<Pick<OperationResult<{ value: number }, any>, 'data'>>();\n      const executeQuery = vi\n        .spyOn(client, 'executeSubscription')\n        .mockImplementation(\n          () => subject.source as OperationResultSource<OperationResult>\n        );\n\n      const request = createRequest(QUERY, undefined);\n      const operation = client.createRequestOperation('subscription', request);\n\n      const [state] = createSubscription<\n        { value: number },\n        { value: number },\n        { variable: number }\n      >({\n        query: QUERY,\n      });\n\n      createEffect((run: number = 0) => {\n        markStateDependencies(state);\n\n        switch (run) {\n          case 0: {\n            expect(state).toMatchObject({\n              data: undefined,\n              stale: false,\n              operation: operation,\n              error: undefined,\n              extensions: undefined,\n              fetching: true,\n            });\n            expect(executeQuery).toEqual(expect.any(Function));\n            expect(executeQuery).toHaveBeenCalledOnce();\n            expect(client.executeSubscription).toBeCalledWith(\n              {\n                key: expect.any(Number),\n                query: expect.any(Object),\n                variables: {},\n              },\n              undefined\n            );\n            subject.next({ data: { value: 0 } });\n            break;\n          }\n          case 1: {\n            expect(state.data).toEqual({ value: 0 });\n            subject.next({ data: { value: 1 } });\n            break;\n          }\n          case 2: {\n            expect(state.data).toEqual({ value: 1 });\n            // expect(state.fetching).toEqual(true);\n            subject.complete();\n            break;\n          }\n          case 3: {\n            expect(state.fetching).toEqual(false);\n            expect(state.data).toEqual({ value: 1 });\n            done();\n          }\n        }\n\n        return run + 1;\n      });\n    });\n  });\n\n  it('should call handler', () => {\n    const handler = vi.fn();\n    const subject =\n      makeSubject<Pick<OperationResult<{ value: number }, any>, 'data'>>();\n    vi.spyOn(client, 'executeSubscription').mockImplementation(\n      () => subject.source as OperationResultSource<OperationResult>\n    );\n\n    return testEffect(done => {\n      const [state] = createSubscription<\n        { value: number },\n        { value: number },\n        { variable: number }\n      >(\n        {\n          query: QUERY,\n        },\n        handler\n      );\n\n      createEffect((run: number = 0) => {\n        markStateDependencies(state);\n        switch (run) {\n          case 0: {\n            expect(state.fetching).toEqual(true);\n            subject.next({ data: { value: 0 } });\n\n            break;\n          }\n          case 1: {\n            expect(handler).toHaveBeenCalledOnce();\n            expect(handler).toBeCalledWith(undefined, { value: 0 });\n            done();\n            break;\n          }\n        }\n\n        return run + 1;\n      });\n    });\n  });\n\n  it('should unsubscribe on teardown', () => {\n    const subject =\n      makeSubject<Pick<OperationResult<{ value: number }, any>, 'data'>>();\n    vi.spyOn(client, 'executeSubscription').mockImplementation(\n      () => subject.source as OperationResultSource<OperationResult>\n    );\n\n    const {\n      result: [state],\n      cleanup,\n    } = renderHook(() =>\n      createSubscription<{ value: number }, { variable: number }>({\n        query: QUERY,\n      })\n    );\n\n    return testEffect(done =>\n      createEffect((run: number = 0) => {\n        if (run === 0) {\n          expect(state.fetching).toEqual(true);\n          cleanup();\n        }\n\n        if (run === 1) {\n          expect(state.fetching).toEqual(false);\n          done();\n        }\n\n        return run + 1;\n      })\n    );\n  });\n\n  it('should skip executing query when paused', () => {\n    const subject =\n      makeSubject<Pick<OperationResult<{ value: number }, any>, 'data'>>();\n    vi.spyOn(client, 'executeSubscription').mockImplementation(\n      () => subject.source as OperationResultSource<OperationResult>\n    );\n\n    return testEffect(done => {\n      const [pause, setPause] = createSignal<boolean>(true);\n\n      const [state] = createSubscription<\n        { value: number },\n        { value: number },\n        { variable: number }\n      >({ query: QUERY, pause: pause });\n\n      createEffect((run: number = 0) => {\n        switch (run) {\n          case 0: {\n            expect(state.fetching).toBe(false);\n            setPause(false);\n            break;\n          }\n          case 1: {\n            expect(state.fetching).toBe(true);\n            expect(state.data).toBeUndefined();\n            subject.next({ data: { value: 1 } });\n\n            break;\n          }\n          case 2: {\n            expect(state.data).toStrictEqual({ value: 1 });\n            done();\n            break;\n          }\n        }\n\n        return run + 1;\n      });\n    });\n  });\n\n  it('should override pause when execute executeSubscription', () => {\n    const subject =\n      makeSubject<Pick<OperationResult<{ value: number }, any>, 'data'>>();\n    const executeQuery = vi\n      .spyOn(client, 'executeSubscription')\n      .mockImplementation(\n        () => subject.source as OperationResultSource<OperationResult>\n      );\n\n    return testEffect(done => {\n      const [state, executeSubscription] = createSubscription<\n        { value: number },\n        { value: number },\n        { variable: number }\n      >({\n        query: QUERY,\n        pause: true,\n      });\n\n      createEffect((run: number = 0) => {\n        markStateDependencies(state);\n\n        switch (run) {\n          case 0: {\n            expect(state.fetching).toEqual(false);\n            expect(executeQuery).not.toBeCalled();\n\n            executeSubscription();\n\n            break;\n          }\n          case 1: {\n            expect(state.fetching).toEqual(true);\n            expect(executeQuery).toHaveBeenCalledOnce();\n            subject.next({ data: { value: 1 } });\n            break;\n          }\n          case 2: {\n            expect(state.data).toStrictEqual({ value: 1 });\n            done();\n            break;\n          }\n        }\n\n        return run + 1;\n      });\n    });\n  });\n\n  it('should aggregate results', () => {\n    const subject =\n      makeSubject<Pick<OperationResult<{ value: number }, any>, 'data'>>();\n    vi.spyOn(client, 'executeSubscription').mockImplementation(\n      () => subject.source as OperationResultSource<OperationResult>\n    );\n\n    return testEffect(done => {\n      const [state] = createSubscription<\n        { value: number },\n        { merged: number },\n        { variable: number }\n      >(\n        {\n          query: QUERY,\n        },\n        (prev, next) => {\n          if (prev === undefined) {\n            return {\n              merged: 0 + next.value,\n            };\n          }\n\n          return { merged: prev.merged + next.value };\n        }\n      );\n\n      createEffect((run: number = 0) => {\n        markStateDependencies(state);\n        switch (run) {\n          case 0: {\n            expect(state.fetching).toEqual(true);\n            subject.next({ data: { value: 1 } });\n\n            break;\n          }\n          case 1: {\n            expect(state.data).toEqual({ merged: 1 });\n            subject.next({ data: { value: 2 } });\n\n            break;\n          }\n          case 2: {\n            expect(state.data).toEqual({ merged: 3 });\n\n            done();\n            break;\n          }\n        }\n\n        return run + 1;\n      });\n    });\n  });\n});\n"
  },
  {
    "path": "packages/solid-urql/src/createSubscription.ts",
    "content": "import { type MaybeAccessor, asAccessor } from './utils';\nimport {\n  type AnyVariables,\n  type DocumentInput,\n  type Operation,\n  type OperationContext,\n  type OperationResult,\n  type CombinedError,\n  createRequest,\n} from '@urql/core';\nimport { useClient } from './context';\nimport { createStore, produce, reconcile } from 'solid-js/store';\nimport {\n  batch,\n  createComputed,\n  createSignal,\n  onCleanup,\n  untrack,\n} from 'solid-js';\nimport { type Source, onEnd, pipe, subscribe } from 'wonka';\n\n/** Triggers {@link createSubscription} to re-execute a GraphQL subscription operation.\n *\n * @param opts - optionally, context options that will be merged with the hook's\n * {@link CreateSubscriptionArgs.context} options and the `Client`’s options.\n *\n * @remarks\n * When called, {@link createSubscription} will restart the GraphQL subscription\n * operation it currently holds. If {@link CreateSubscriptionArgs.pause} is set\n * to `true`, it will start executing the subscription.\n *\n * ```ts\n * const [result, executeSubscription] = createSubscription({\n *   query,\n *   pause: true,\n * });\n *\n * const start = () => {\n *   executeSubscription();\n * };\n * ```\n */\nexport type CreateSubscriptionExecute = (\n  opts?: Partial<OperationContext>\n) => void;\n\n/** Input arguments for the {@link createSubscription} hook. */\nexport type CreateSubscriptionArgs<\n  Data,\n  Variables extends AnyVariables = AnyVariables,\n> = {\n  /** The GraphQL subscription document that `createSubscription` executes. */\n  query: DocumentInput<Data, Variables>;\n\n  /** The variables for the GraphQL subscription that `createSubscription` executes. */\n  variables?: MaybeAccessor<Variables>;\n\n  /** Updates the {@link OperationContext} for the executed GraphQL subscription operation.\n   *\n   * @remarks\n   * `context` may be passed to {@link createSubscription}, to update the {@link OperationContext}\n   * of a subscription operation. This may be used to update the `context` that exchanges\n   * will receive for a single hook.\n   */\n  context?: MaybeAccessor<Partial<OperationContext>>;\n\n  /** Prevents {@link createSubscription} from automatically starting GraphQL subscriptions.\n   *\n   * @remarks\n   * `pause` may be set to `true` to stop {@link createSubscription} from starting its subscription\n   * automatically. The hook will stop receiving updates from the {@link Client}\n   * and won’t start the subscription operation, until either it’s set to `false`\n   * or the {@link CreateSubscriptionExecute} function is called.\n   */\n  pause?: MaybeAccessor<boolean>;\n};\n\nexport type CreateSubscriptionState<\n  Data = any,\n  Variables extends AnyVariables = AnyVariables,\n> = {\n  /** Indicates whether `createSubscription`’s subscription is active.\n   *\n   * @remarks\n   * When `createSubscription` starts a subscription, the `fetching` flag\n   * is set to `true` and will remain `true` until the subscription\n   * completes on the API, or the {@link CreateSubscriptionArgs.pause}\n   * flag is set to `true`.\n   */\n  fetching: boolean;\n\n  /** Indicates that the subscription result is not fresh.\n   *\n   * @remarks\n   * This is mostly unused for subscriptions and will rarely affect you, and\n   * is more relevant for queries.\n   *\n   * @see {@link OperationResult.stale} for the source of this value.\n   */\n  stale: boolean;\n\n  /** The {@link OperationResult.data} for the executed subscription, or data returned by a handler.\n   *\n   * @remarks\n   * `data` will be set to the last {@link OperationResult.data} value\n   * received for the subscription.\n   *\n   * It will instead be set to the values that {@link SubscriptionHandler}\n   * returned, if a handler has been passed to {@link CreateSubscription}.\n   */\n  data?: Data;\n\n  /** The {@link OperationResult.error} for the executed subscription. */\n  error?: CombinedError;\n\n  /** The {@link OperationResult.extensions} for the executed mutation. */\n  extensions?: Record<string, any>;\n\n  /** The {@link Operation} that the current state is for.\n   *\n   * @remarks\n   * This is the subscription {@link Operation} that is currently active.\n   * When {@link CreateSubscriptionState.fetching} is `true`, this is the\n   * last `Operation` that the current state was for.\n   */\n  operation?: Operation<Data, Variables>;\n};\n\n/** Combines previous data with an incoming subscription result’s data.\n *\n * @remarks\n * A `SubscriptionHandler` may be passed to {@link createSubscription} to\n * aggregate subscription results into a combined {@link CreateSubscriptionState.data}\n * value.\n *\n * This is useful when a subscription event delivers a single item, while\n * you’d like to display a list of events.\n *\n * @example\n * ```ts\n * const NotificationsSubscription = gql`\n *   subscription { newNotification { id, text } }\n * `;\n *\n * const combineNotifications = (notifications = [], data) => {\n *   return [...notifications, data.newNotification];\n * };\n *\n * const [result, executeSubscription] = createSubscription(\n *   { query: NotificationsSubscription },\n *   combineNotifications,\n * );\n * ```\n */\nexport type SubscriptionHandler<T, R> = (prev: R | undefined, data: T) => R;\n\n/** Result tuple returned by the {@link createSubscription} hook.\n *\n * @remarks\n * Similarly to a `createSignal` hook’s return value,\n * the first element is the {@link createSubscription}’s state,\n * a {@link CreateSubscriptionState} object,\n * and the second is used to imperatively re-execute or start the subscription\n * via a {@link CreateMutationExecute} function.\n */\nexport type CreateSubscriptionResult<\n  Data,\n  Variables extends AnyVariables = AnyVariables,\n> = [CreateSubscriptionState<Data, Variables>, CreateSubscriptionExecute];\n\n/** Hook to run a GraphQL subscription and get updated GraphQL results.\n *\n * @param args - a {@link CreateSubscriptionArgs} object, to pass a `query`, `variables`, and options.\n * @param handler - optionally, a {@link SubscriptionHandler} function to combine multiple subscription results.\n * @returns a {@link CreateSubscriptionResponse} tuple of a {@link CreateSubscriptionState} result,\n * and an execute function.\n *\n * @remarks\n * `createSubscription` allows GraphQL subscriptions to be defined and executed.\n * Given {@link CreateSubscriptionArgs.query}, it executes the GraphQL subscription with the\n * context’s {@link Client}.\n *\n * The returned result updates when the `Client` has new results\n * for the subscription, and `data` is updated with the result’s data\n * or with the `data` that a `handler` returns.\n *\n * @example\n * ```ts\n * import { gql, createSubscription } from '@urql/solid';\n *\n * const NotificationsSubscription = gql`\n *   subscription { newNotification { id, text } }\n * `;\n *\n * const combineNotifications = (notifications = [], data) => {\n *   return [...notifications, data.newNotification];\n * };\n *\n * const Notifications = () => {\n *   const [result, executeSubscription] = createSubscription(\n *     { query: NotificationsSubscription },\n *     combineNotifications,\n *   );\n *   // ...\n * };\n * ```\n */\nexport const createSubscription = <\n  Data,\n  Result = Data,\n  Variables extends AnyVariables = AnyVariables,\n>(\n  args: CreateSubscriptionArgs<Data, Variables>,\n  handler?: SubscriptionHandler<Data, Result>\n): CreateSubscriptionResult<Result, Variables> => {\n  const getContext = asAccessor(args.context);\n  const getPause = asAccessor(args.pause);\n  const getVariables = asAccessor(args.variables);\n\n  const client = useClient();\n\n  const request = createRequest(args.query, getVariables() as Variables);\n  const operation = client.createRequestOperation(\n    'subscription',\n    request,\n    getContext()\n  );\n  const initialState: CreateSubscriptionState<Result, Variables> = {\n    operation,\n    fetching: false,\n    data: undefined,\n    error: undefined,\n    extensions: undefined,\n    stale: false,\n  };\n\n  const [source, setSource] = createSignal<\n    Source<OperationResult<Data, Variables>> | undefined\n  >(undefined, { equals: false });\n\n  const [state, setState] =\n    createStore<CreateSubscriptionState<Result, Variables>>(initialState);\n\n  createComputed(() => {\n    if (getPause() === true) {\n      setSource(undefined);\n      return;\n    }\n\n    const context = getContext();\n    const request = createRequest(args.query, getVariables() as Variables);\n    setSource(() => client.executeSubscription(request, context));\n  });\n\n  createComputed(() => {\n    const s = source();\n    if (s === undefined) {\n      setState('fetching', false);\n\n      return;\n    }\n\n    setState('fetching', true);\n    onCleanup(\n      pipe(\n        s,\n        onEnd(() => {\n          setState(\n            produce(draft => {\n              draft.fetching = false;\n            })\n          );\n        }),\n        subscribe(res => {\n          batch(() => {\n            if (res.data !== undefined) {\n              const newData =\n                typeof handler === 'function'\n                  ? handler(\n                      untrack(() => state.data),\n                      res.data\n                    )\n                  : (res.data as Result);\n              setState('data', reconcile(newData));\n            }\n            setState(\n              produce(draft => {\n                draft.stale = !!res.stale;\n                draft.fetching = true;\n                draft.error = res.error;\n                draft.operation = res.operation;\n                draft.extensions = res.extensions;\n              })\n            );\n          });\n        })\n      ).unsubscribe\n    );\n  });\n\n  const executeSubscription = (opts?: Partial<OperationContext>) => {\n    const context: Partial<OperationContext> = {\n      ...getContext(),\n      ...opts,\n    };\n    const request = createRequest(args.query, getVariables() as Variables);\n\n    setSource(() => client.executeSubscription(request, context));\n  };\n\n  return [state, executeSubscription];\n};\n"
  },
  {
    "path": "packages/solid-urql/src/index.ts",
    "content": "export * from '@urql/core';\n\nexport { type UseClient } from './context';\nexport { useClient, Provider } from './context';\n\nexport {\n  type CreateMutationState,\n  type CreateMutationExecute,\n  type CreateMutationResult,\n} from './createMutation';\nexport { createMutation } from './createMutation';\n\nexport {\n  type CreateQueryArgs,\n  type CreateQueryState,\n  type CreateQueryExecute,\n  type CreateQueryResult,\n} from './createQuery';\nexport { createQuery } from './createQuery';\n\nexport {\n  type CreateSubscriptionArgs,\n  type CreateSubscriptionState,\n  type CreateSubscriptionExecute,\n  type CreateSubscriptionResult,\n  type SubscriptionHandler,\n} from './createSubscription';\n\nexport { createSubscription } from './createSubscription';\n"
  },
  {
    "path": "packages/solid-urql/src/suspense.test.tsx",
    "content": "/** @jsxImportSource solid-js */\n// @vitest-environment jsdom\n\nimport { describe, it, vi } from 'vitest';\nimport {\n  OperationResult,\n  OperationResultSource,\n  createClient,\n} from '@urql/core';\nimport { createQuery } from './createQuery';\nimport { fireEvent, render, screen, waitFor } from '@solidjs/testing-library';\nimport { Provider } from './context';\nimport { Suspense } from 'solid-js';\nimport { makeSubject } from 'wonka';\n\ndescribe('createQuery suspense', () => {\n  it('should not suspend', async () => {\n    const client = createClient({\n      url: '/graphql',\n      exchanges: [],\n      suspense: false,\n    });\n\n    const subject =\n      makeSubject<Pick<OperationResult<{ test: boolean }, any>, 'data'>>();\n    vi.spyOn(client, 'executeQuery').mockImplementation(\n      () => subject.source as OperationResultSource<OperationResult>\n    );\n\n    const Page = () => {\n      const [state, refetch] = createQuery<\n        { test: boolean },\n        { variable: number }\n      >({\n        query: '{ test }',\n      });\n\n      return (\n        <div>\n          <button data-testid=\"refetch\" onClick={refetch} />\n          data: {String(state.data?.test)}\n        </div>\n      );\n    };\n\n    render(() => (\n      <Provider value={client}>\n        <Suspense fallback=\"loading\">\n          <Page />\n        </Suspense>\n      </Provider>\n    ));\n\n    subject.next({ data: { test: true } });\n    await waitFor(() => screen.getByText('data: true'));\n\n    fireEvent.click(screen.getByTestId('refetch'));\n\n    subject.next({ data: { test: false } });\n    await waitFor(() => screen.getByText('data: false'));\n  });\n\n  it('should suspend', async () => {\n    const client = createClient({\n      url: '/graphql',\n      exchanges: [],\n      suspense: true,\n    });\n\n    const subject =\n      makeSubject<Pick<OperationResult<{ test: boolean }, any>, 'data'>>();\n    vi.spyOn(client, 'executeQuery').mockImplementation(\n      () => subject.source as OperationResultSource<OperationResult>\n    );\n\n    const Page = () => {\n      const [state] = createQuery<{ test: boolean }, { variable: number }>({\n        query: '{ test }',\n      });\n\n      return <div>data: {String(state.data?.test)}</div>;\n    };\n\n    render(() => (\n      <Provider value={client}>\n        <Suspense fallback=\"loading\">\n          <Page />\n        </Suspense>\n      </Provider>\n    ));\n\n    await waitFor(() => screen.getByText('loading'));\n\n    subject.next({ data: { test: true } });\n    await waitFor(() => screen.getByText('data: true'));\n  });\n\n  it('context suspend should override client suspend', async () => {\n    const client = createClient({\n      url: '/graphql',\n      exchanges: [],\n      suspense: false,\n    });\n\n    const subject =\n      makeSubject<Pick<OperationResult<{ test: boolean }, any>, 'data'>>();\n    vi.spyOn(client, 'executeQuery').mockImplementation(\n      () => subject.source as OperationResultSource<OperationResult>\n    );\n\n    const Page = () => {\n      const [state] = createQuery<{ test: boolean }, { variable: number }>({\n        query: '{ test }',\n        context: {\n          suspense: true,\n        },\n      });\n\n      return <div>data: {String(state.data?.test)}</div>;\n    };\n\n    render(() => (\n      <Provider value={client}>\n        <Suspense fallback=\"loading\">\n          <Page />\n        </Suspense>\n      </Provider>\n    ));\n\n    await waitFor(() => screen.getByText('loading'));\n\n    subject.next({ data: { test: true } });\n    await waitFor(() => screen.getByText('data: true'));\n  });\n});\n"
  },
  {
    "path": "packages/solid-urql/src/utils.ts",
    "content": "// Re-export utility types and functions from @solid-primitives/utils\nexport {\n  access,\n  asAccessor,\n  type MaybeAccessor,\n} from '@solid-primitives/utils';\n"
  },
  {
    "path": "packages/solid-urql/tsconfig.json",
    "content": "{\n  \"extends\": \"../../tsconfig.json\",\n  \"include\": [\"src\"],\n  \"compilerOptions\": {\n    \"jsx\": \"preserve\",\n    \"jsxImportSource\": \"solid-js\"\n  }\n}\n"
  },
  {
    "path": "packages/solid-urql/vitest.config.ts",
    "content": "import { mergeConfig } from 'vitest/config';\nimport solidPlugin from 'vite-plugin-solid';\nimport baseConfig from '../../vitest.config';\n\nexport default mergeConfig(baseConfig, {\n  plugins: [solidPlugin({ hot: false })],\n});\n"
  },
  {
    "path": "packages/storage-rn/CHANGELOG.md",
    "content": "# Changelog\n\n## 1.1.2\n\n### Patch Changes\n\n- Add support for `@react-native-async-storage/async-storage` v2.0.0\n  Submitted by [@nhangeland](https://github.com/nhangeland) (See [#3836](https://github.com/urql-graphql/urql/pull/3836))\n\n## 1.1.1\n\n### Patch Changes\n\n- Omit minified files and sourcemaps' `sourcesContent` in published packages\n  Submitted by [@kitten](https://github.com/kitten) (See [#3755](https://github.com/urql-graphql/urql/pull/3755))\n\n## 1.1.0\n\n### Minor Changes\n\n- Bump peer-dependency of `@react-native-community/netinfo` to allow v11\n  Submitted by [@albinhubsch](https://github.com/albinhubsch) (See [#3485](https://github.com/urql-graphql/urql/pull/3485))\n\n## 1.0.3\n\n### Patch Changes\n\n- Switch `react` imports to namespace imports, and update build process for CommonJS outputs to interoperate with `__esModule` marked modules again\n  Submitted by [@kitten](https://github.com/kitten) (See [#3251](https://github.com/urql-graphql/urql/pull/3251))\n\n## 1.0.2\n\n### Patch Changes\n\n- Publish with npm provenance\n  Submitted by [@kitten](https://github.com/kitten) (See [#3180](https://github.com/urql-graphql/urql/pull/3180))\n\n## 1.0.1\n\n### Patch Changes\n\n- Add TSDocs to `@urql/*` packages\n  Submitted by [@kitten](https://github.com/kitten) (See [#3079](https://github.com/urql-graphql/urql/pull/3079))\n\n## 1.0.0\n\n### Major Changes\n\n- **Goodbye IE11!** 👋 This major release removes support for IE11. All code that is shipped will be transpiled much less and will _not_ be ES5-compatible anymore, by [@kitten](https://github.com/kitten) (See [#2504](https://github.com/FormidableLabs/urql/pull/2504))\n\n## 0.1.1\n\n### Patch Changes\n\n- ⚠️ Fix issue where the in-memory cache would not be cleared, by [@benmechen](https://github.com/benmechen) (See [#2222](https://github.com/FormidableLabs/urql/pull/2222))\n\n## v0.1.0\n\n**Initial Release**\n"
  },
  {
    "path": "packages/storage-rn/LICENCE",
    "content": "MIT License\n\nCopyright (c) 2018–2020 Formidable\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": "packages/storage-rn/README.md",
    "content": "# @urql/storage-rn\n\n`@urql/storage-rn` is a Graphcache offline storage for React Native.\n\nIt is compatible for both plain React Native and Expo apps (including managed workflow), but it has a two peer dependencies - [Async Storage](https://react-native-async-storage.github.io/async-storage/) and [NetInfo](https://github.com/react-native-netinfo/react-native-netinfo) - which must be installed separately. AsyncStorage will be used to persist the data, and NetInfo will be used to determine when the app is online and offline.\n\n## Quick Start Guide\n\nInstall NetInfo ([RN](https://github.com/react-native-netinfo/react-native-netinfo) | [Expo](https://docs.expo.dev/versions/latest/sdk/netinfo/)) and AsyncStorage ([RN](https://react-native-async-storage.github.io/async-storage/docs/install) | [Expo](https://docs.expo.dev/versions/v42.0.0/sdk/async-storage/)).\n\nInstall `@urql/storage-rn` alongside `urql` and `@urql/exchange-graphcache`:\n\n```sh\nyarn add @urql/storage-rn\n# or\nnpm install --save @urql/storage-rn\n```\n\nThen add it to the offline exchange:\n\n```js\nimport { createClient, fetchExchange } from 'urql';\nimport { offlineExchange } from '@urql/exchange-graphcache';\nimport { makeAsyncStorage } from '@urql/storage-rn';\n\nconst storage = makeAsyncStorage({\n  dataKey: 'graphcache-data', // The AsyncStorage key used for the data (defaults to graphcache-data)\n  metadataKey: 'graphcache-metadata', // The AsyncStorage key used for the metadata (defaults to graphcache-metadata)\n  maxAge: 7, // How long to persist the data in storage (defaults to 7 days)\n});\n\nconst cache = offlineExchange({\n  schema,\n  storage,\n  updates: {\n    /* ... */\n  },\n  optimistic: {\n    /* ... */\n  },\n});\n\nconst client = createClient({\n  url: 'http://localhost:3000/graphql',\n  exchanges: [cache, fetchExchange],\n});\n```\n"
  },
  {
    "path": "packages/storage-rn/jsr.json",
    "content": "{\n  \"name\": \"@urql/storage-rn\",\n  \"version\": \"1.1.2\",\n  \"exports\": {\n    \".\": \"./src/index.ts\"\n  },\n  \"exclude\": [\n    \"node_modules\",\n    \"cypress\",\n    \"**/*.test.*\",\n    \"**/*.spec.*\",\n    \"**/*.test.*.snap\",\n    \"**/*.spec.*.snap\"\n  ]\n}"
  },
  {
    "path": "packages/storage-rn/package.json",
    "content": "{\n  \"name\": \"@urql/storage-rn\",\n  \"version\": \"1.1.2\",\n  \"sideEffects\": false,\n  \"description\": \"Graphcache offline storage for React Native\",\n  \"homepage\": \"https://formidable.com/open-source/urql/docs/\",\n  \"bugs\": \"https://github.com/urql-graphql/urql/issues\",\n  \"license\": \"MIT\",\n  \"author\": \"urql GraphQL Contributors\",\n  \"repository\": {\n    \"type\": \"git\",\n    \"url\": \"https://github.com/urql-graphql/urql.git\",\n    \"directory\": \"packages/storage-rn\"\n  },\n  \"keywords\": [\n    \"urql\",\n    \"graphql client\",\n    \"graphql\",\n    \"exchanges\",\n    \"react native\",\n    \"offline\",\n    \"storage\"\n  ],\n  \"main\": \"dist/urql-storage-rn\",\n  \"module\": \"dist/urql-storage-rn.mjs\",\n  \"types\": \"dist/urql-storage-rn.d.ts\",\n  \"source\": \"src/index.ts\",\n  \"files\": [\n    \"LICENSE\",\n    \"CHANGELOG.md\",\n    \"README.md\",\n    \"dist/\"\n  ],\n  \"exports\": {\n    \".\": {\n      \"types\": \"./dist/urql-storage-rn.d.ts\",\n      \"import\": \"./dist/urql-storage-rn.mjs\",\n      \"require\": \"./dist/urql-storage-rn.js\",\n      \"source\": \"./src/index.ts\"\n    },\n    \"./package.json\": \"./package.json\"\n  },\n  \"scripts\": {\n    \"clean\": \"rimraf dist\",\n    \"check\": \"tsc --noEmit\",\n    \"lint\": \"eslint --ext=js,jsx,ts,tsx .\",\n    \"build\": \"rollup -c ../../scripts/rollup/config.mjs\",\n    \"prepare\": \"node ../../scripts/prepare/index.js\",\n    \"prepublishOnly\": \"run-s clean build\"\n  },\n  \"peerDependencies\": {\n    \"@react-native-async-storage/async-storage\": \"^1.15.5 || ^2.0.0\",\n    \"@react-native-community/netinfo\": \"^6.0.0 || ^7.0.0 || ^8.0.0 || ^9.0.0 || ^11.0.0\",\n    \"@urql/exchange-graphcache\": \">=5.0.0\"\n  },\n  \"devDependencies\": {\n    \"@react-native-async-storage/async-storage\": \"^2.2.0\",\n    \"@react-native-community/netinfo\": \"^11.2.1\",\n    \"@urql/core\": \"workspace:*\",\n    \"@urql/exchange-graphcache\": \"workspace:*\"\n  },\n  \"publishConfig\": {\n    \"access\": \"public\",\n    \"provenance\": true\n  }\n}\n"
  },
  {
    "path": "packages/storage-rn/src/index.ts",
    "content": "export { makeAsyncStorage } from './makeAsyncStorage';\n"
  },
  {
    "path": "packages/storage-rn/src/makeAsyncStorage.test.ts",
    "content": "import { vi, expect, it, describe } from 'vitest';\n\nvi.mock('@react-native-community/netinfo', () => ({\n  addEventListener: () => 'addEventListener',\n  default: {\n    addEventListener: () => 'addEventListener',\n  },\n}));\n\nvi.mock('@react-native-async-storage/async-storage', () => ({\n  default: {\n    setItem: () => 'setItem',\n    getItem: () => 'getItem',\n    getAllKeys: () => 'getAllKeys',\n    removeItem: () => 'removeItem',\n  },\n  setItem: () => 'setItem',\n  getItem: () => 'getItem',\n  getAllKeys: () => 'getAllKeys',\n  removeItem: () => 'removeItem',\n}));\n\nimport AsyncStorage from '@react-native-async-storage/async-storage';\nimport NetInfo from '@react-native-community/netinfo';\nimport { makeAsyncStorage } from './makeAsyncStorage';\n\nconst request = [\n  {\n    query: 'something something',\n    variables: { foo: 'bar' },\n  },\n];\n\nconst serializedRequest =\n  '[{\"query\":\"something something\",\"variables\":{\"foo\":\"bar\"}}]';\n\nconst entires = {\n  hello: 'world',\n};\nconst serializedEntries = '{\"hello\":\"world\"}';\n\ndescribe('makeAsyncStorage', () => {\n  describe('writeMetadata', () => {\n    it('writes metadata to async storage', async () => {\n      const setItemSpy = vi.fn();\n      vi.spyOn(AsyncStorage, 'setItem').mockImplementationOnce(setItemSpy);\n\n      const storage = makeAsyncStorage();\n\n      if (storage && storage.writeMetadata) {\n        await storage.writeMetadata(request);\n      }\n\n      expect(setItemSpy).toHaveBeenCalledWith(\n        'graphcache-metadata',\n        serializedRequest\n      );\n    });\n\n    it('writes metadata using a custom key', async () => {\n      const setItemSpy = vi.fn();\n      vi.spyOn(AsyncStorage, 'setItem').mockImplementationOnce(setItemSpy);\n\n      const storage = makeAsyncStorage({ metadataKey: 'my-custom-key' });\n\n      if (storage && storage.writeMetadata) {\n        await storage.writeMetadata(request);\n      }\n\n      expect(setItemSpy).toHaveBeenCalledWith(\n        'my-custom-key',\n        serializedRequest\n      );\n    });\n  });\n\n  describe('readMetadata', () => {\n    it('returns an empty array if no metadata is found', async () => {\n      const getItemSpy = vi.fn().mockResolvedValue(null);\n      vi.spyOn(AsyncStorage, 'getItem').mockImplementationOnce(getItemSpy);\n\n      const storage = makeAsyncStorage();\n\n      if (storage && storage.readMetadata) {\n        const result = await storage.readMetadata();\n        expect(getItemSpy).toHaveBeenCalledWith('graphcache-metadata');\n        expect(result).toEqual([]);\n      }\n    });\n\n    it('returns the parsed JSON correctly', async () => {\n      const getItemSpy = vi.fn().mockResolvedValue(serializedRequest);\n      vi.spyOn(AsyncStorage, 'getItem').mockImplementationOnce(getItemSpy);\n\n      const storage = makeAsyncStorage();\n\n      if (storage && storage.readMetadata) {\n        const result = await storage.readMetadata();\n        expect(getItemSpy).toHaveBeenCalledWith('graphcache-metadata');\n        expect(result).toEqual(request);\n      }\n    });\n\n    it('reads metadata using a custom key', async () => {\n      const getItemSpy = vi.fn().mockResolvedValue(serializedRequest);\n      vi.spyOn(AsyncStorage, 'getItem').mockImplementationOnce(getItemSpy);\n\n      const storage = makeAsyncStorage({ metadataKey: 'my-custom-key' });\n\n      if (storage && storage.readMetadata) {\n        const result = await storage.readMetadata();\n        expect(getItemSpy).toHaveBeenCalledWith('my-custom-key');\n        expect(result).toEqual(request);\n      }\n    });\n\n    it('returns an empty array if json.parse errors', async () => {\n      const getItemSpy = vi.fn().mockResolvedValue('surprise!');\n      vi.spyOn(AsyncStorage, 'getItem').mockImplementationOnce(getItemSpy);\n      const storage = makeAsyncStorage();\n\n      if (storage && storage.readMetadata) {\n        const result = await storage.readMetadata();\n        expect(getItemSpy).toHaveBeenCalledWith('graphcache-metadata');\n        expect(result).toEqual([]);\n      }\n    });\n  });\n\n  describe('writeData', () => {\n    it('writes data to async storage', async () => {\n      vi.spyOn(Date.prototype, 'valueOf').mockReturnValueOnce(1632209690641);\n      const dayStamp = 18891;\n\n      const setItemSpy = vi.fn();\n      vi.spyOn(AsyncStorage, 'setItem').mockImplementationOnce(setItemSpy);\n\n      const storage = makeAsyncStorage();\n\n      if (storage && storage.writeData) {\n        await storage.writeData(entires);\n      }\n\n      expect(setItemSpy).toHaveBeenCalledWith(\n        'graphcache-data',\n        `{\"${dayStamp}\":${serializedEntries}}`\n      );\n    });\n\n    it('writes data to async storage using custom key', async () => {\n      vi.spyOn(Date.prototype, 'valueOf').mockReturnValueOnce(1632209690641);\n      const dayStamp = 18891;\n\n      const setItemSpy = vi.fn();\n      vi.spyOn(AsyncStorage, 'setItem').mockImplementationOnce(setItemSpy);\n\n      const storage = makeAsyncStorage({ dataKey: 'my-custom-key' });\n\n      if (storage && storage.writeData) {\n        await storage.writeData(entires);\n      }\n\n      expect(setItemSpy).toHaveBeenCalledWith(\n        'my-custom-key',\n        `{\"${dayStamp}\":${serializedEntries}}`\n      );\n    });\n\n    it('merges previous writes', async () => {\n      vi.spyOn(Date.prototype, 'valueOf').mockReturnValueOnce(1632209690641);\n      const dayStamp = 18891;\n\n      const setItemSpy = vi.fn();\n      vi.spyOn(AsyncStorage, 'setItem').mockImplementationOnce(setItemSpy);\n\n      const storage = makeAsyncStorage();\n\n      // write once\n      if (storage && storage.writeData) {\n        await storage.writeData(entires);\n      }\n\n      expect(setItemSpy).toHaveBeenCalledWith(\n        'graphcache-data',\n        `{\"${dayStamp}\":${serializedEntries}}`\n      );\n\n      // write twice\n      const secondSetItemSpy = vi.fn();\n      vi.spyOn(AsyncStorage, 'setItem').mockImplementationOnce(\n        secondSetItemSpy\n      );\n\n      if (storage && storage.writeData) {\n        storage.writeData({ foo: 'bar' });\n      }\n      expect(secondSetItemSpy).toHaveBeenCalledWith(\n        'graphcache-data',\n        `{\"${dayStamp}\":${JSON.stringify({ hello: 'world', foo: 'bar' })}}`\n      );\n    });\n\n    it('keeps items from previous days', async () => {\n      vi.spyOn(Date.prototype, 'valueOf').mockReturnValueOnce(1632209690641);\n      const dayStamp = 18891;\n      const oldDayStamp = 18857;\n      vi.spyOn(AsyncStorage, 'getItem').mockResolvedValueOnce(\n        JSON.stringify({ [oldDayStamp]: { foo: 'bar' } })\n      );\n\n      const setItemSpy = vi.fn();\n      vi.spyOn(AsyncStorage, 'setItem').mockImplementationOnce(setItemSpy);\n\n      const storage = makeAsyncStorage();\n\n      if (storage && storage.writeData) {\n        await storage.writeData(entires);\n      }\n\n      expect(setItemSpy).toHaveBeenCalledWith(\n        'graphcache-data',\n        JSON.stringify({ [oldDayStamp]: { foo: 'bar' }, [dayStamp]: entires })\n      );\n    });\n\n    it('propagates deleted keys to previous days', async () => {\n      vi.spyOn(Date.prototype, 'valueOf').mockReturnValueOnce(1632209690641);\n      const dayStamp = 18891;\n      vi.spyOn(AsyncStorage, 'getItem').mockResolvedValueOnce(\n        JSON.stringify({\n          [dayStamp]: { foo: 'bar', hello: 'world' },\n          [dayStamp - 1]: { foo: 'bar', hello: 'world' },\n          [dayStamp - 2]: { foo: 'bar', hello: 'world' },\n        })\n      );\n\n      const setItemSpy = vi.fn();\n      vi.spyOn(AsyncStorage, 'setItem').mockImplementationOnce(setItemSpy);\n\n      const storage = makeAsyncStorage();\n\n      if (storage && storage.writeData) {\n        await storage.writeData({ foo: 'new', hello: undefined });\n      }\n\n      expect(setItemSpy).toHaveBeenCalledWith(\n        'graphcache-data',\n        JSON.stringify({\n          [dayStamp]: { foo: 'new' },\n          [dayStamp - 1]: { foo: 'bar' },\n          [dayStamp - 2]: { foo: 'bar' },\n        })\n      );\n    });\n  });\n\n  describe('readData', () => {\n    it('returns an empty object if no data is found', async () => {\n      const getItemSpy = vi.fn().mockResolvedValue(null);\n      vi.spyOn(AsyncStorage, 'getItem').mockImplementationOnce(getItemSpy);\n\n      const storage = makeAsyncStorage();\n\n      if (storage && storage.readData) {\n        const result = await storage.readData();\n        expect(getItemSpy).toHaveBeenCalledWith('graphcache-data');\n        expect(result).toEqual({});\n      }\n    });\n\n    it(\"returns today's data correctly\", async () => {\n      vi.spyOn(Date.prototype, 'valueOf').mockReturnValueOnce(1632209690641);\n      const dayStamp = 18891;\n      const mockData = JSON.stringify({ [dayStamp]: entires });\n      const getItemSpy = vi.fn().mockResolvedValue(mockData);\n      vi.spyOn(AsyncStorage, 'getItem').mockImplementationOnce(getItemSpy);\n\n      const storage = makeAsyncStorage();\n\n      if (storage && storage.readData) {\n        const result = await storage.readData();\n        expect(getItemSpy).toHaveBeenCalledWith('graphcache-data');\n        expect(result).toEqual(entires);\n      }\n    });\n\n    it('merges data from past days correctly', async () => {\n      vi.spyOn(Date.prototype, 'valueOf').mockReturnValueOnce(1632209690641);\n      const dayStamp = 18891;\n      const mockData = JSON.stringify({\n        [dayStamp]: { one: 'one' },\n        [dayStamp - 1]: { two: 'two' },\n        [dayStamp - 3]: { three: 'three' },\n        [dayStamp - 4]: { two: 'old' },\n      });\n      const getItemSpy = vi.fn().mockResolvedValue(mockData);\n      vi.spyOn(AsyncStorage, 'getItem').mockImplementationOnce(getItemSpy);\n\n      const storage = makeAsyncStorage();\n\n      if (storage && storage.readData) {\n        const result = await storage.readData();\n        expect(getItemSpy).toHaveBeenCalledWith('graphcache-data');\n        expect(result).toEqual({\n          one: 'one',\n          two: 'two',\n          three: 'three',\n        });\n      }\n    });\n\n    it('cleans up old data', async () => {\n      vi.spyOn(Date.prototype, 'valueOf').mockReturnValueOnce(1632209690641);\n      const dayStamp = 18891;\n      const maxAge = 5;\n      const mockData = JSON.stringify({\n        [dayStamp]: entires, // should be kept\n        [dayStamp - maxAge + 1]: entires, // should be kept\n        [dayStamp - maxAge - 1]: { old: 'data' }, // should get deleted\n      });\n      vi.spyOn(AsyncStorage, 'getItem').mockResolvedValueOnce(mockData);\n      const setItemSpy = vi.fn();\n      vi.spyOn(AsyncStorage, 'setItem').mockImplementationOnce(setItemSpy);\n\n      const storage = makeAsyncStorage({ maxAge });\n\n      if (storage && storage.readData) {\n        const result = await storage.readData();\n        expect(result).toEqual(entires);\n        expect(setItemSpy).toBeCalledWith(\n          'graphcache-data',\n          JSON.stringify({\n            [dayStamp]: entires,\n            [dayStamp - maxAge + 1]: entires,\n          })\n        );\n      }\n    });\n  });\n\n  describe('onOnline', () => {\n    it('sets up an event listener for the network change event', () => {\n      const addEventListenerSpy = vi.fn();\n      vi.spyOn(NetInfo, 'addEventListener').mockImplementationOnce(\n        addEventListenerSpy\n      );\n\n      const storage = makeAsyncStorage();\n\n      if (storage && storage.onOnline) {\n        storage.onOnline(() => null);\n      }\n\n      expect(addEventListenerSpy).toBeCalledTimes(1);\n    });\n\n    it('calls the callback when the device comes online', () => {\n      const callbackSpy = vi.fn();\n      let networkCallback;\n      vi.spyOn(NetInfo, 'addEventListener').mockImplementationOnce(callback => {\n        networkCallback = callback;\n        return () => null;\n      });\n\n      const storage = makeAsyncStorage();\n\n      if (storage && storage.onOnline) {\n        storage.onOnline(callbackSpy);\n      }\n\n      networkCallback({ isConnected: true });\n\n      expect(callbackSpy).toBeCalledTimes(1);\n    });\n\n    it('does not call the callback when the device is offline', () => {\n      const callbackSpy = vi.fn();\n      let networkCallback;\n      vi.spyOn(NetInfo, 'addEventListener').mockImplementationOnce(callback => {\n        networkCallback = callback;\n        return () => null;\n      });\n\n      const storage = makeAsyncStorage();\n\n      if (storage && storage.onOnline) {\n        storage.onOnline(callbackSpy);\n      }\n\n      networkCallback({ isConnected: false });\n\n      expect(callbackSpy).toBeCalledTimes(0);\n    });\n  });\n\n  describe('clear', () => {\n    it('clears all data and metadata', async () => {\n      const removeItemSpy = vi.fn();\n      const secondRemoveItemSpy = vi.fn();\n      vi.spyOn(AsyncStorage, 'removeItem')\n        .mockImplementationOnce(removeItemSpy)\n        .mockImplementationOnce(secondRemoveItemSpy);\n\n      const storage = makeAsyncStorage({\n        dataKey: 'my-data',\n        metadataKey: 'my-metadata',\n      });\n\n      if (storage && storage.clear) {\n        await storage.clear();\n      }\n\n      expect(removeItemSpy).toHaveBeenCalledWith('my-data');\n      expect(secondRemoveItemSpy).toHaveBeenCalledWith('my-metadata');\n    });\n  });\n});\n"
  },
  {
    "path": "packages/storage-rn/src/makeAsyncStorage.ts",
    "content": "import type { StorageAdapter } from '@urql/exchange-graphcache';\nimport AsyncStorage from '@react-native-async-storage/async-storage';\nimport NetInfo from '@react-native-community/netinfo';\n\nexport interface StorageOptions {\n  /** Name of the `AsyncStorage` key that’s used for persisted data.\n   * @defaultValue `'graphcache-data'`\n   */\n  dataKey?: string;\n  /** Name of the `AsyncStorage` key that’s used for persisted metadata.\n   * @defaultValue `'graphcache-metadata'`\n   */\n  metadataKey?: string;\n  /** Maximum age of cache entries (in days) after which data is discarded.\n   * @defaultValue `7` days\n   */\n  maxAge?: number;\n}\n\nconst parseData = (persistedData: any, fallback: any) => {\n  try {\n    if (persistedData) {\n      return JSON.parse(persistedData);\n    }\n  } catch (_err) {}\n\n  return fallback;\n};\n\nlet disconnect;\n\n/** React Native storage adapter persisting to `AsyncStorage`. */\nexport interface DefaultAsyncStorage extends StorageAdapter {\n  /** Clears the entire `AsyncStorage`. */\n  clear(): Promise<any>;\n}\n\n/** Creates a {@link StorageAdapter} which uses React Native’s `AsyncStorage`.\n *\n * @param opts - A {@link StorageOptions} configuration object.\n * @returns the created {@link DefaultAsyncStorage} adapter.\n *\n * @remarks\n * `makeAsyncStorage` creates a storage adapter for React Native,\n * which persisted to `AsyncStorage` via the `@react-native-async-storage/async-storage`\n * package.\n *\n * Note: We have no data on stability of this storage and our Offline Support\n * for large APIs or longterm use. Proceed with caution.\n */\nexport const makeAsyncStorage: (\n  ops?: StorageOptions\n) => DefaultAsyncStorage = ({\n  dataKey = 'graphcache-data',\n  metadataKey = 'graphcache-metadata',\n  maxAge = 7,\n} = {}) => {\n  const todayDayStamp = Math.floor(\n    new Date().valueOf() / (1000 * 60 * 60 * 24)\n  );\n  let allData = {};\n\n  return {\n    readData: async () => {\n      if (!Object.keys(allData).length) {\n        let persistedData: string | null = null;\n        try {\n          persistedData = await AsyncStorage.getItem(dataKey);\n        } catch (_err) {}\n        const parsed = parseData(persistedData, {});\n\n        Object.assign(allData, parsed);\n      }\n\n      // clean up old data\n      let syncNeeded = false;\n      Object.keys(allData).forEach(dayStamp => {\n        if (todayDayStamp - Number(dayStamp) > maxAge) {\n          syncNeeded = true;\n          delete allData[dayStamp];\n        }\n      });\n\n      if (syncNeeded) {\n        try {\n          await AsyncStorage.setItem(dataKey, JSON.stringify(allData));\n        } catch (_err) {}\n      }\n\n      return Object.assign(\n        {},\n        ...Object.keys(allData).map(key => allData[key])\n      );\n    },\n\n    writeData: async delta => {\n      if (!Object.keys(allData).length) {\n        let persistedData: string | null = null;\n        try {\n          persistedData = await AsyncStorage.getItem(dataKey);\n        } catch (_err) {}\n        const parsed = parseData(persistedData, {});\n        Object.assign(allData, parsed);\n      }\n\n      const deletedKeys = {};\n      Object.keys(delta).forEach(key => {\n        if (delta[key] === undefined) {\n          deletedKeys[key] = undefined;\n        }\n      });\n\n      for (const key in allData) {\n        allData[key] = Object.assign(allData[key], deletedKeys);\n      }\n\n      allData[todayDayStamp] = Object.assign(\n        allData[todayDayStamp] || {},\n        delta\n      );\n\n      try {\n        await AsyncStorage.setItem(dataKey, JSON.stringify(allData));\n      } catch (_err) {}\n    },\n\n    writeMetadata: async data => {\n      try {\n        await AsyncStorage.setItem(metadataKey, JSON.stringify(data));\n      } catch (_err) {}\n    },\n\n    readMetadata: async () => {\n      let persistedData: string | null = null;\n      try {\n        persistedData = await AsyncStorage.getItem(metadataKey);\n      } catch (_err) {}\n      return parseData(persistedData, []);\n    },\n\n    onOnline: cb => {\n      if (disconnect) {\n        disconnect();\n        disconnect = undefined;\n      }\n\n      disconnect = NetInfo.addEventListener(({ isConnected }) => {\n        if (isConnected) {\n          cb();\n        }\n      });\n    },\n\n    clear: async () => {\n      try {\n        allData = {};\n        await AsyncStorage.removeItem(dataKey);\n        await AsyncStorage.removeItem(metadataKey);\n      } catch (_err) {}\n    },\n  };\n};\n"
  },
  {
    "path": "packages/storage-rn/tsconfig.json",
    "content": "{\n  \"extends\": \"../../tsconfig.json\",\n  \"include\": [\"src\"]\n}\n"
  },
  {
    "path": "packages/storage-rn/vitest.config.ts",
    "content": "import { mergeConfig } from 'vitest/config';\nimport baseConfig from '../../vitest.config';\n\nexport default mergeConfig(baseConfig, {});\n"
  },
  {
    "path": "packages/svelte-urql/CHANGELOG.md",
    "content": "# @urql/svelte\n\n## 5.0.0\n\n### Patch Changes\n\n- Updated dependencies (See [#3789](https://github.com/urql-graphql/urql/pull/3789) and [#3807](https://github.com/urql-graphql/urql/pull/3807))\n  - @urql/core@6.0.0\n\n## 4.2.3\n\n### Patch Changes\n\n- Omit minified files and sourcemaps' `sourcesContent` in published packages\n  Submitted by [@kitten](https://github.com/kitten) (See [#3755](https://github.com/urql-graphql/urql/pull/3755))\n- Updated dependencies (See [#3755](https://github.com/urql-graphql/urql/pull/3755))\n  - @urql/core@5.1.1\n\n## 4.2.2\n\n### Patch Changes\n\n- Add type for `hasNext` to the query and mutation results\n  Submitted by [@JoviDeCroock](https://github.com/JoviDeCroock) (See [#3703](https://github.com/urql-graphql/urql/pull/3703))\n\n## 4.2.1\n\n### Patch Changes\n\n- add support for Svelte 5 in the `peerDependencies`\n  Submitted by [@itssumitrai](https://github.com/itssumitrai) (See [#3634](https://github.com/urql-graphql/urql/pull/3634))\n\n## 4.2.0\n\n### Minor Changes\n\n- Mark `@urql/core` as a peer dependency as well as a regular dependency\n  Submitted by [@kitten](https://github.com/kitten) (See [#3579](https://github.com/urql-graphql/urql/pull/3579))\n\n### Patch Changes\n\n- ⚠️ Fix subscription handlers to not receive `null` values\n  Submitted by [@kitten](https://github.com/kitten) (See [#3581](https://github.com/urql-graphql/urql/pull/3581))\n\n## 4.1.1\n\n### Patch Changes\n\n- Updated dependencies (See [#3520](https://github.com/urql-graphql/urql/pull/3520), [#3553](https://github.com/urql-graphql/urql/pull/3553), and [#3520](https://github.com/urql-graphql/urql/pull/3520))\n  - @urql/core@5.0.0\n\n## 4.1.0\n\n### Minor Changes\n\n- Add back the `reexecute` function\n  Submitted by [@JoviDeCroock](https://github.com/JoviDeCroock) (See [#3472](https://github.com/urql-graphql/urql/pull/3472))\n\n### Patch Changes\n\n- Updated dependencies (See [#3514](https://github.com/urql-graphql/urql/pull/3514), [#3505](https://github.com/urql-graphql/urql/pull/3505), [#3499](https://github.com/urql-graphql/urql/pull/3499), and [#3515](https://github.com/urql-graphql/urql/pull/3515))\n  - @urql/core@4.3.0\n\n## 4.0.4\n\n### Patch Changes\n\n- ⚠️ Fix `queryStore` and `subscriptionStore` not subscribing when `writable` calls its `StartStopNotifier`. This caused both stores to be inactive and become unresponsive when they’ve been unsubscribed from once, as they wouldn’t be able to restart their subscriptions to the `Client`\n  Submitted by [@kitten](https://github.com/kitten) (See [#3331](https://github.com/urql-graphql/urql/pull/3331))\n\n## 4.0.3\n\n### Patch Changes\n\n- Updated peer dependency range to include support for Svelte `^4.0.0`\n  Submitted by [@ategen3rt](https://github.com/ategen3rt) (See [#3302](https://github.com/urql-graphql/urql/pull/3302))\n\n## 4.0.2\n\n### Patch Changes\n\n- Update build process to generate correct source maps\n  Submitted by [@kitten](https://github.com/kitten) (See [#3201](https://github.com/urql-graphql/urql/pull/3201))\n\n## 4.0.1\n\n### Patch Changes\n\n- Publish with npm provenance\n  Submitted by [@kitten](https://github.com/kitten) (See [#3180](https://github.com/urql-graphql/urql/pull/3180))\n\n## 4.0.0\n\n### Major Changes\n\n- Update `OperationResult.hasNext` and `OperationResult.stale` to be required fields. If you have a custom exchange creating results, you'll have to add these fields or use the `makeResult`, `mergeResultPatch`, or `makeErrorResult` helpers\n  Submitted by [@kitten](https://github.com/kitten) (See [#3061](https://github.com/urql-graphql/urql/pull/3061))\n- Move `handler`, which combines subscription events, from `mutationStore` to `subscriptionStore`. It’s accidentally been defined and implemented on the wrong store and was meant to be on `subscriptionStore`\n  Submitted by [@kitten](https://github.com/kitten) (See [#3078](https://github.com/urql-graphql/urql/pull/3078))\n\n### Minor Changes\n\n- Allow mutations to update their results in bindings when `hasNext: true` is set, which indicates deferred or streamed results\n  Submitted by [@kitten](https://github.com/kitten) (See [#3103](https://github.com/urql-graphql/urql/pull/3103))\n\n### Patch Changes\n\n- ⚠️ Fix source maps included with recently published packages, which lost their `sourcesContent`, including additional source files, and had incorrect paths in some of them\n  Submitted by [@kitten](https://github.com/kitten) (See [#3053](https://github.com/urql-graphql/urql/pull/3053))\n- Upgrade to `wonka@^6.3.0`\n  Submitted by [@kitten](https://github.com/kitten) (See [#3104](https://github.com/urql-graphql/urql/pull/3104))\n- Add TSDocs to all `urql` bindings packages\n  Submitted by [@kitten](https://github.com/kitten) (See [#3079](https://github.com/urql-graphql/urql/pull/3079))\n- Updated dependencies (See [#3101](https://github.com/urql-graphql/urql/pull/3101), [#3033](https://github.com/urql-graphql/urql/pull/3033), [#3054](https://github.com/urql-graphql/urql/pull/3054), [#3053](https://github.com/urql-graphql/urql/pull/3053), [#3060](https://github.com/urql-graphql/urql/pull/3060), [#3081](https://github.com/urql-graphql/urql/pull/3081), [#3039](https://github.com/urql-graphql/urql/pull/3039), [#3104](https://github.com/urql-graphql/urql/pull/3104), [#3082](https://github.com/urql-graphql/urql/pull/3082), [#3097](https://github.com/urql-graphql/urql/pull/3097), [#3061](https://github.com/urql-graphql/urql/pull/3061), [#3055](https://github.com/urql-graphql/urql/pull/3055), [#3085](https://github.com/urql-graphql/urql/pull/3085), [#3079](https://github.com/urql-graphql/urql/pull/3079), [#3087](https://github.com/urql-graphql/urql/pull/3087), [#3059](https://github.com/urql-graphql/urql/pull/3059), [#3055](https://github.com/urql-graphql/urql/pull/3055), [#3057](https://github.com/urql-graphql/urql/pull/3057), [#3050](https://github.com/urql-graphql/urql/pull/3050), [#3062](https://github.com/urql-graphql/urql/pull/3062), [#3051](https://github.com/urql-graphql/urql/pull/3051), [#3043](https://github.com/urql-graphql/urql/pull/3043), [#3063](https://github.com/urql-graphql/urql/pull/3063), [#3054](https://github.com/urql-graphql/urql/pull/3054), [#3102](https://github.com/urql-graphql/urql/pull/3102), [#3097](https://github.com/urql-graphql/urql/pull/3097), [#3106](https://github.com/urql-graphql/urql/pull/3106), [#3058](https://github.com/urql-graphql/urql/pull/3058), and [#3062](https://github.com/urql-graphql/urql/pull/3062))\n  - @urql/core@4.0.0\n\n## 3.0.4\n\n### Patch Changes\n\n- ⚠️ Fix type utilities turning the `variables` properties optional when a type from `TypedDocumentNode` has no `Variables` or all optional `Variables`. Previously this would break for wrappers, e.g. in code generators, or when the type didn't quite match what we'd expect\n  Submitted by [@kitten](https://github.com/kitten) (See [#3022](https://github.com/urql-graphql/urql/pull/3022))\n- Updated dependencies (See [#3007](https://github.com/urql-graphql/urql/pull/3007), [#2962](https://github.com/urql-graphql/urql/pull/2962), [#3007](https://github.com/urql-graphql/urql/pull/3007), [#3015](https://github.com/urql-graphql/urql/pull/3015), and [#3022](https://github.com/urql-graphql/urql/pull/3022))\n  - @urql/core@3.2.0\n\n## 3.0.3\n\n### Patch Changes\n\n- ⚠️ Fix type-generation, with a change in TS/Rollup the type generation took the paths as src and resolved them into the types dir, by [@JoviDeCroock](https://github.com/JoviDeCroock) (See [#2870](https://github.com/urql-graphql/urql/pull/2870))\n- Updated dependencies (See [#2872](https://github.com/urql-graphql/urql/pull/2872), [#2870](https://github.com/urql-graphql/urql/pull/2870), and [#2871](https://github.com/urql-graphql/urql/pull/2871))\n  - @urql/core@3.1.1\n\n## 3.0.2\n\n### Patch Changes\n\n- Move remaining `Variables` generics over from `object` default to `Variables extends AnyVariables = AnyVariables`. This has been introduced previously in [#2607](https://github.com/urql-graphql/urql/pull/2607) but some missing ports have been missed due to TypeScript not catching them previously. Depending on your TypeScript version the `object` default is incompatible with `AnyVariables`, by [@kitten](https://github.com/kitten) (See [#2843](https://github.com/urql-graphql/urql/pull/2843))\n- Updated dependencies (See [#2843](https://github.com/urql-graphql/urql/pull/2843), [#2847](https://github.com/urql-graphql/urql/pull/2847), [#2850](https://github.com/urql-graphql/urql/pull/2850), and [#2846](https://github.com/urql-graphql/urql/pull/2846))\n  - @urql/core@3.1.0\n\n## 3.0.1\n\n### Patch Changes\n\n- Tweak the variables type for when generics only contain nullable keys, by [@JoviDeCroock](https://github.com/JoviDeCroock) (See [#2623](https://github.com/FormidableLabs/urql/pull/2623))\n\n## 3.0.0\n\n### Major Changes\n\n- **Goodbye IE11!** 👋 This major release removes support for IE11. All code that is shipped will be transpiled much less and will _not_ be ES5-compatible anymore, by [@kitten](https://github.com/kitten) (See [#2504](https://github.com/FormidableLabs/urql/pull/2504))\n- Implement stricter variables types, which require variables to always be passed and match TypeScript types when the generic is set or inferred. This is a breaking change for TypeScript users potentially, unless all types are adhered to, by [@kitten](https://github.com/kitten) (See [#2607](https://github.com/FormidableLabs/urql/pull/2607))\n- Upgrade to [Wonka v6](https://github.com/0no-co/wonka) (`wonka@^6.0.0`), which has no breaking changes but is built to target ES2015 and comes with other minor improvements.\n  The library has fully been migrated to TypeScript which will hopefully help with making contributions easier!, by [@kitten](https://github.com/kitten) (See [#2504](https://github.com/FormidableLabs/urql/pull/2504))\n\n### Patch Changes\n\n- Updated dependencies (See [#2551](https://github.com/FormidableLabs/urql/pull/2551), [#2504](https://github.com/FormidableLabs/urql/pull/2504), [#2619](https://github.com/FormidableLabs/urql/pull/2619), [#2607](https://github.com/FormidableLabs/urql/pull/2607), and [#2504](https://github.com/FormidableLabs/urql/pull/2504))\n  - @urql/core@3.0.0\n\n## 2.0.2\n\n### Patch Changes\n\n- Made variables optional for all operations, by [@mpiorowski](https://github.com/mpiorowski) (See [#2496](https://github.com/FormidableLabs/urql/pull/2496))\n- ⚠️ Fix issue with `subscriptionStore` and `queryStore` eagerly terminating the subscription due to `derived`, by [@JoviDeCroock](https://github.com/JoviDeCroock) (See [#2514](https://github.com/FormidableLabs/urql/pull/2514))\n\n## 2.0.1\n\n### Patch Changes\n\n- ⚠️ Fix Node.js ESM re-export detection for `@urql/core` in `urql` package and CommonJS output for all other CommonJS-first packages. This ensures that Node.js' `cjs-module-lexer` can correctly identify re-exports and report them properly. Otherwise, this will lead to a runtime error, by [@kitten](https://github.com/kitten) (See [#2485](https://github.com/FormidableLabs/urql/pull/2485))\n\n## 2.0.0\n\n### Major Changes\n\n- Reimplement Svelte with functional-only API.\n  We've gotten plenty of feedback and issues from the Svelte community about our prior\n  Svelte bindings. These bindings favoured a Store singleton to read and write to,\n  and a separate signal to start an operation.\n  Svelte usually however calls for a lot more flexibility, so we're returning the\n  API to a functional-only API again that serves to only create stores, which is more\n  similar to the original implementation, by [@jonathanstanley](https://github.com/jonathanstanley) (See [#2370](https://github.com/FormidableLabs/urql/pull/2370))\n\n### Patch Changes\n\n- Updated dependencies (See [#2446](https://github.com/FormidableLabs/urql/pull/2446), [#2456](https://github.com/FormidableLabs/urql/pull/2456), and [#2457](https://github.com/FormidableLabs/urql/pull/2457))\n  - @urql/core@2.5.0\n\n## 1.3.3\n\n### Patch Changes\n\n- Extend peer dependency range of `graphql` to include `^16.0.0`.\n  As always when upgrading across many packages of `urql`, especially including `@urql/core` we recommend you to deduplicate dependencies after upgrading, using `npm dedupe` or `npx yarn-deduplicate`, by [@kitten](https://github.com/kitten) (See [#2133](https://github.com/FormidableLabs/urql/pull/2133))\n- Updated dependencies (See [#2133](https://github.com/FormidableLabs/urql/pull/2133))\n  - @urql/core@2.3.6\n\n## 1.3.2\n\n### Patch Changes\n\n- ⚠️ Fix initialize `operationStore` with `fetching: false`, the invocation of `query` or any other operation will mark it as `true`\n  when deemed appropriate, by [@JoviDeCroock](https://github.com/JoviDeCroock) (See [#2048](https://github.com/FormidableLabs/urql/pull/2048))\n- Updated dependencies (See [#2027](https://github.com/FormidableLabs/urql/pull/2027) and [#1998](https://github.com/FormidableLabs/urql/pull/1998))\n  - @urql/core@2.3.4\n\n## 1.3.1\n\n### Patch Changes\n\n- Add missing `pause` on the `operationStore` return value, by [@JoviDeCroock](https://github.com/JoviDeCroock) (See [#1925](https://github.com/FormidableLabs/urql/pull/1925))\n- Updated dependencies (See [#1944](https://github.com/FormidableLabs/urql/pull/1944))\n  - @urql/core@2.3.2\n\n## 1.3.0\n\n### Minor Changes\n\n- Improve granularity of `operationStore` updates when `query`, `variables`, and `context` are changed. This also adds an `operationStore(...).reexecute()` method, which optionally accepts a new context value and forces an update on the store, so that a query may reexecute, by [@kitten](https://github.com/kitten) (See [#1780](https://github.com/FormidableLabs/urql/pull/1780))\n\n### Patch Changes\n\n- Loosen `subscription(...)` type further to allow any `operationStore` input, regardless of the `Result` produced, by [@kitten](https://github.com/kitten) (See [#1779](https://github.com/FormidableLabs/urql/pull/1779))\n- Updated dependencies (See [#1776](https://github.com/FormidableLabs/urql/pull/1776) and [#1755](https://github.com/FormidableLabs/urql/pull/1755))\n  - @urql/core@2.1.5\n\n## 1.2.3\n\n### Patch Changes\n\n- Improve `OperationStore` and `subscription` types to allow for result types of `data` that differ from the original `Data` type, which may be picked up from `TypedDocumentNode`, by [@kitten](https://github.com/kitten) (See [#1731](https://github.com/FormidableLabs/urql/pull/1731))\n- Use client.executeMutation rather than client.mutation, by [@JoviDeCroock](https://github.com/JoviDeCroock) (See [#1732](https://github.com/FormidableLabs/urql/pull/1732))\n- Updated dependencies (See [#1709](https://github.com/FormidableLabs/urql/pull/1709))\n  - @urql/core@2.1.4\n\n## 1.2.2\n\n### Patch Changes\n\n- Remove closure-compiler from the build step (See [#1570](https://github.com/FormidableLabs/urql/pull/1570))\n- Updated dependencies (See [#1570](https://github.com/FormidableLabs/urql/pull/1570), [#1509](https://github.com/FormidableLabs/urql/pull/1509), [#1600](https://github.com/FormidableLabs/urql/pull/1600), and [#1515](https://github.com/FormidableLabs/urql/pull/1515))\n  - @urql/core@2.1.0\n\n## 1.2.1\n\n### Patch Changes\n\n- Allow `mutation` to accept a more partial `GraphQLRequest` object without a `key` or `variables`, by [@JoviDeCroock](https://github.com/JoviDeCroock) (See [#1473](https://github.com/FormidableLabs/urql/pull/1473))\n\n## 1.2.0\n\n### Minor Changes\n\n- Remove deprecated `operationName` property from `Operation`s. The new `Operation.kind` property is now preferred. If you're creating new operations you may also use the `makeOperation` utility instead.\n  When upgrading `@urql/core` please ensure that your package manager didn't install any duplicates of it. You may deduplicate it manually using `npx yarn-deduplicate` (for Yarn) or `npm dedupe` (for npm), by [@kitten](https://github.com/kitten) (See [#1357](https://github.com/FormidableLabs/urql/pull/1357))\n\n### Patch Changes\n\n- Updated dependencies (See [#1374](https://github.com/FormidableLabs/urql/pull/1374), [#1357](https://github.com/FormidableLabs/urql/pull/1357), and [#1375](https://github.com/FormidableLabs/urql/pull/1375))\n  - @urql/core@2.0.0\n\n## 1.1.4\n\n### Patch Changes\n\n- Add a built-in `gql` tag function helper to `@urql/core`. This behaves similarly to `graphql-tag` but only warns about _locally_ duplicated fragment names rather than globally. It also primes `@urql/core`'s key cache with the parsed `DocumentNode`, by [@kitten](https://github.com/kitten) (See [#1187](https://github.com/FormidableLabs/urql/pull/1187))\n- Updated dependencies (See [#1187](https://github.com/FormidableLabs/urql/pull/1187), [#1186](https://github.com/FormidableLabs/urql/pull/1186), and [#1186](https://github.com/FormidableLabs/urql/pull/1186))\n  - @urql/core@1.16.0\n\n## 1.1.3\n\n### Patch Changes\n\n- Add support for `TypedDocumentNode` to infer the type of the `OperationResult` and `Operation` for all methods, functions, and hooks that either directly or indirectly accept a `DocumentNode`. See [`graphql-typed-document-node` and the corresponding blog post for more information.](https://github.com/dotansimha/graphql-typed-document-node), by [@kitten](https://github.com/kitten) (See [#1113](https://github.com/FormidableLabs/urql/pull/1113))\n- Updated dependencies (See [#1119](https://github.com/FormidableLabs/urql/pull/1119), [#1113](https://github.com/FormidableLabs/urql/pull/1113), [#1104](https://github.com/FormidableLabs/urql/pull/1104), and [#1123](https://github.com/FormidableLabs/urql/pull/1123))\n  - @urql/core@1.15.0\n\n## 1.1.2\n\n### Patch Changes\n\n- Replace `void` union types with `undefined` in `OperationStore` to allow nullish property access in TypeScript, by [@kitten](https://github.com/kitten) (See [#1053](https://github.com/FormidableLabs/urql/pull/1053))\n\n## 1.1.1\n\n### Patch Changes\n\n- ⚠️ Fix missing `stale` flag updates on query results, by [@JoviDeCroock](https://github.com/JoviDeCroock) (See [#1044](https://github.com/FormidableLabs/urql/pull/1044))\n\n## 1.1.0\n\n### Minor Changes\n\n- Support passing `pause` to stop executing queries or subscriptions, by [@kitten](https://github.com/kitten) (See [#1046](https://github.com/FormidableLabs/urql/pull/1046))\n\n### Patch Changes\n\n- ⚠️ Fix an issue where updated `context` options wouldn't cause a new query to be executed, or updates to the store would erroneously throw a debug error, by [@kitten](https://github.com/kitten) (See [#1046](https://github.com/FormidableLabs/urql/pull/1046))\n\n## 1.0.1\n\n### Patch Changes\n\n- ⚠️ Fix `stale` keeping a `truthy` value on a `cache-and-network` operation, by [@JoviDeCroock](https://github.com/JoviDeCroock) (See [#1032](https://github.com/FormidableLabs/urql/pull/1032))\n\n## 1.0.0\n\nThe new `@urql/svelte` API features the `query`, `mutation`, and `subscription` utilities, which are\ncalled as part of a component's normal lifecycle and accept `operationStore` stores. These are\nwritable stores that encapsulate both a GraphQL operation's inputs and outputs (the result)!\nLearn more about how to use `@urql/svelte` [in our new API\ndocs](https://formidable.com/open-source/urql/docs/api/svelte/) or starting from the [Basics\npages.](https://formidable.com/open-source/urql/docs/basics/)\n\n### Major Changes\n\n- Reimplement the `@urql/svelte` API, which is now marked as stable, by [@kitten](https://github.com/kitten) (See [#1016](https://github.com/FormidableLabs/urql/pull/1016))\n\n## 0.4.0\n\n### Minor Changes\n\n- Add the operation to the query, mutation and subscription result, by [@JoviDeCroock](https://github.com/JoviDeCroock) (See [#924](https://github.com/FormidableLabs/urql/pull/924))\n\n### Patch Changes\n\n- Updated dependencies (See [#911](https://github.com/FormidableLabs/urql/pull/911) and [#908](https://github.com/FormidableLabs/urql/pull/908))\n  - @urql/core@1.12.3\n\n## 0.3.0\n\n### Minor Changes\n\n- Refactor all operations to allow for more use-cases which preserve state and allow all modes of Svelte to be applied to urql.\n  ```\n  // Standard Usage:\n  mutate({ query, variables })()\n  // Subscribable Usage:\n  $: result = mutate({ query, variables });\n  // Curried Usage\n  const executeMutation = mutate({ query, variables });\n  const onClick = () => executeMutation();\n  // Curried Usage with overrides\n  const executeMutation = mutate({ query });\n  const onClick = () => await executeMutation({ variables });\n  // Subscribable Usage (as before):\n  $: result = query({ query: TestQuery, variables });\n  // Subscribable Usage which preserves state over time:\n  const testQuery = query({ query: TestQuery });\n  // - this preserves the state even when the variables change!\n  $: result = testQuery({ variables });\n  // Promise-based callback usage:\n  const testQuery = query({ query: TestQuery });\n  const doQuery = async () => await testQuery;\n  // Promise-based usage updates the subscribables!\n  const testQuery = query({ query: TestQuery });\n  const doQuery = async () => await testQuery;\n  // - doQuery will also update this result\n  $: result = query({ query: TestQuery, variables });\n  ```\n\n### Patch Changes\n\n- Updated dependencies (See [#860](https://github.com/FormidableLabs/urql/pull/860) and [#861](https://github.com/FormidableLabs/urql/pull/861))\n  - @urql/core@1.12.1\n\n## 0.2.4\n\n### Patch Changes\n\n- Upgrade to a minimum version of wonka@^4.0.14 to work around issues with React Native's minification builds, which use uglify-es and could lead to broken bundles, by [@kitten](https://github.com/kitten) (See [#842](https://github.com/FormidableLabs/urql/pull/842))\n- Updated dependencies (See [#838](https://github.com/FormidableLabs/urql/pull/838) and [#842](https://github.com/FormidableLabs/urql/pull/842))\n  - @urql/core@1.12.0\n\n## 0.2.3\n\n### Patch Changes\n\n- Add a `\"./package.json\"` entry to the `package.json`'s `\"exports\"` field for Node 14. This seems to be required by packages like `rollup-plugin-svelte` to function properly, by [@JoviDeCroock](https://github.com/JoviDeCroock) (See [#771](https://github.com/FormidableLabs/urql/pull/771))\n- Updated dependencies (See [#771](https://github.com/FormidableLabs/urql/pull/771))\n  - @urql/core@1.11.6\n\n## 0.2.2\n\n### Patch Changes\n\n- Update `mutate` helper to return a Promise directly rather than a lazy Promise-like object, by [@JoviDeCroock](https://github.com/JoviDeCroock) (See [#758](https://github.com/FormidableLabs/urql/pull/758))\n\n## 0.2.1\n\n### Patch Changes\n\n- Bump @urql/core to ensure exchanges have dispatchDebug, this could formerly result in a crash, by [@JoviDeCroock](https://github.com/JoviDeCroock) (See [#726](https://github.com/FormidableLabs/urql/pull/726))\n\n## 0.2.0\n\n### Minor Changes\n\n- Update `mutate()` API to accept an options argument, instead of separate arguments, to increase consistency, by [@kitten](https://github.com/kitten) (See [#705](https://github.com/FormidableLabs/urql/pull/705))\n\n## 0.1.3\n\n### Patch Changes\n\n- Add graphql@^15.0.0 to peer dependency range, by [@kitten](https://github.com/kitten) (See [#688](https://github.com/FormidableLabs/urql/pull/688))\n- Forcefully bump @urql/core package in all bindings and in @urql/exchange-graphcache.\n  We're aware that in some cases users may not have upgraded to @urql/core, even though that's within\n  the typical patch range. Since the latest @urql/core version contains a patch that is required for\n  `cache-and-network` to work, we're pushing another patch that now forcefully bumps everyone to the\n  new version that includes this fix, by [@kitten](https://github.com/kitten) (See [#684](https://github.com/FormidableLabs/urql/pull/684))\n- Updated dependencies (See [#688](https://github.com/FormidableLabs/urql/pull/688) and [#678](https://github.com/FormidableLabs/urql/pull/678))\n  - @urql/core@1.10.8\n\n## 0.1.2\n\n### Patch Changes\n\n- ⚠️ Fix node resolution when using Webpack, which experiences a bug where it only resolves\n  `package.json:main` instead of `module` when an `.mjs` file imports a package, by [@JoviDeCroock](https://github.com/JoviDeCroock) (See [#642](https://github.com/FormidableLabs/urql/pull/642))\n- Updated dependencies (See [#642](https://github.com/FormidableLabs/urql/pull/642))\n  - @urql/core@1.10.4\n\n## 0.1.1\n\n### Patch Changes\n\n- ⚠️ Fix Node.js Module support for v13 (experimental-modules) and v14. If your bundler doesn't support\n  `.mjs` files and fails to resolve the new version, please double check your configuration for\n  Webpack, or similar tools, by [@JoviDeCroock](https://github.com/JoviDeCroock) (See [#637](https://github.com/FormidableLabs/urql/pull/637))\n- Updated dependencies (See [#637](https://github.com/FormidableLabs/urql/pull/637))\n  - @urql/core@1.10.3\n\n## 0.1.0\n\n### Patch Changes\n\n- Bumps the `@urql/core` dependency minor version to ^1.10.1 for React, Preact and Svelte, by [@JoviDeCroock](https://github.com/JoviDeCroock) (See [#623](https://github.com/FormidableLabs/urql/pull/623))\n- Updated dependencies (See [#621](https://github.com/FormidableLabs/urql/pull/621))\n  - @urql/core@1.10.2\n\n## 0.1.0-alpha.0\n\nInitial Alpha Release\n"
  },
  {
    "path": "packages/svelte-urql/README.md",
    "content": "# @urql/svelte\n\n> A highly customizable and versatile GraphQL client **for Svelte**\n\nMore documentation is available at [formidable.com/open-source/urql](https://formidable.com/open-source/urql/).\n"
  },
  {
    "path": "packages/svelte-urql/jsr.json",
    "content": "{\n  \"name\": \"@urql/svelte\",\n  \"version\": \"5.0.0\",\n  \"exports\": {\n    \".\": \"./src/index.ts\"\n  },\n  \"exclude\": [\n    \"node_modules\",\n    \"cypress\",\n    \"**/*.test.*\",\n    \"**/*.spec.*\",\n    \"**/*.test.*.snap\",\n    \"**/*.spec.*.snap\"\n  ]\n}"
  },
  {
    "path": "packages/svelte-urql/package.json",
    "content": "{\n  \"name\": \"@urql/svelte\",\n  \"version\": \"5.0.0\",\n  \"description\": \"A highly customizable and versatile GraphQL client for Svelte\",\n  \"sideEffects\": false,\n  \"homepage\": \"https://formidable.com/open-source/urql/docs/\",\n  \"bugs\": \"https://github.com/urql-graphql/urql/issues\",\n  \"license\": \"MIT\",\n  \"author\": \"urql GraphQL Contributors\",\n  \"repository\": {\n    \"type\": \"git\",\n    \"url\": \"https://github.com/urql-graphql/urql.git\",\n    \"directory\": \"packages/svelte-urql\"\n  },\n  \"keywords\": [\n    \"graphql client\",\n    \"state management\",\n    \"cache\",\n    \"graphql\",\n    \"exchanges\",\n    \"svelte\"\n  ],\n  \"main\": \"dist/urql-svelte\",\n  \"module\": \"dist/urql-svelte.mjs\",\n  \"types\": \"dist/urql-svelte.d.ts\",\n  \"source\": \"src/index.ts\",\n  \"exports\": {\n    \".\": {\n      \"types\": \"./dist/urql-svelte.d.ts\",\n      \"import\": \"./dist/urql-svelte.mjs\",\n      \"require\": \"./dist/urql-svelte.js\",\n      \"source\": \"./src/index.ts\"\n    },\n    \"./package.json\": \"./package.json\"\n  },\n  \"files\": [\n    \"LICENSE\",\n    \"CHANGELOG.md\",\n    \"README.md\",\n    \"dist/\"\n  ],\n  \"scripts\": {\n    \"test\": \"vitest\",\n    \"clean\": \"rimraf dist\",\n    \"check\": \"tsc --noEmit\",\n    \"lint\": \"eslint --ext=js,jsx,ts,tsx .\",\n    \"build\": \"rollup -c ../../scripts/rollup/config.mjs\",\n    \"prepare\": \"node ../../scripts/prepare/index.js\",\n    \"prepublishOnly\": \"run-s clean build\"\n  },\n  \"peerDependencies\": {\n    \"@urql/core\": \"^6.0.0\",\n    \"svelte\": \"^3.0.0 || ^4.0.0 || ^5.0.0\"\n  },\n  \"dependencies\": {\n    \"@urql/core\": \"workspace:^6.0.1\",\n    \"wonka\": \"^6.3.2\"\n  },\n  \"devDependencies\": {\n    \"@urql/core\": \"workspace:*\",\n    \"graphql\": \"^16.0.0\",\n    \"svelte\": \"^3.20.0\"\n  },\n  \"publishConfig\": {\n    \"access\": \"public\",\n    \"provenance\": true\n  }\n}\n"
  },
  {
    "path": "packages/svelte-urql/src/common.ts",
    "content": "import type { Readable, Writable } from 'svelte/store';\nimport type { AnyVariables, OperationResult } from '@urql/core';\nimport type { Source } from 'wonka';\nimport { make } from 'wonka';\n\n/** An {@link OperationResult} with an added {@link OperationResultState.fetching} flag.\n *\n * @remarks\n * Stores will contain a readable state based on {@link OperationResult | OperationResults}\n * they received.\n */\nexport interface OperationResultState<\n  Data = any,\n  Variables extends AnyVariables = AnyVariables,\n> extends OperationResult<Data, Variables> {\n  /** Indicates whether the store is waiting for a new {@link OperationResult}.\n   *\n   * @remarks\n   * When a store starts executing a GraphQL operation, `fetching` is\n   * set to `true` until a result arrives.\n   *\n   * Hint: This is subtly different than whether the operation is actually\n   * fetching, and doesn’t indicate whether an operation is being re-executed\n   * in the background. For this, see {@link OperationResult.stale}.\n   */\n  fetching: boolean;\n}\n\n/** A Readable store of {@link OperationResultState}. */\nexport type OperationResultStore<\n  Data = any,\n  Variables extends AnyVariables = AnyVariables,\n> = Readable<OperationResultState<Data, Variables>>;\n\n/** Consumes a {@link Readable} as a {@link Source}.\n * @internal\n */\nexport const fromStore = <T>(store$: Readable<T>): Source<T> =>\n  make(observer => store$.subscribe(observer.next));\n\nexport const initialResult = {\n  operation: undefined,\n  fetching: false,\n  data: undefined,\n  error: undefined,\n  extensions: undefined,\n  hasNext: false,\n  stale: false,\n};\n\n/** A pausable Svelte store.\n *\n * @remarks\n * The {@link queryStore} and {@link useSubscription} store allow\n * you to pause execution and resume it later on, which is managed\n * by a `pause` option passed to them.\n *\n * A `Pauseable` allows execution of GraphQL operations to be paused,\n * which means a {@link OperationResultStore} won’t update with new\n * results or execute new operations, and to be resumed later on.\n */\nexport interface Pausable {\n  /** Indicates whether a store is currently paused.\n   *\n   * @remarks\n   * When a {@link OperationResultStore} has been paused, it will stop\n   * receiving updates from the {@link Client} and won’t execute GraphQL\n   * operations, until this writable becomes `true` or\n   * {@link Pausable.resume} is called.\n   *\n   * @see {@link https://urql.dev/goto/docs/basics/svelte#pausing-queries} for\n   * documentation on the `Pausable`.\n   */\n  isPaused$: Writable<boolean>;\n  /** Pauses a GraphQL operation to stop it from executing.\n   *\n   * @remarks\n   * Pauses an {@link OperationResultStore}’s GraphQL operation, which\n   * stops it from receiving updates from the {@link Client} and to stop\n   * an ongoing operation.\n   *\n   * @see {@link https://urql.dev/goto/docs/basics/svelte#pausing-queries} for\n   * documentation on the `Pausable`.\n   */\n  pause(): void;\n  /** Resumes a paused GraphQL operation if it’s currently paused.\n   *\n   * @remarks\n   * Resumes or starts {@link OperationResultStore}’s GraphQL operation,\n   * if it’s currently paused.\n   *\n   * @see {@link https://urql.dev/goto/docs/basics/svelte#pausing-queries} for\n   * documentation on the `Pausable`.\n   */\n  resume(): void;\n}\n\n/** Creates a {@link Pausable}.\n * @internal\n */\nexport const createPausable = (isPaused$: Writable<boolean>): Pausable => ({\n  isPaused$,\n  pause() {\n    isPaused$.set(true);\n  },\n  resume() {\n    isPaused$.set(false);\n  },\n});\n"
  },
  {
    "path": "packages/svelte-urql/src/context.ts",
    "content": "import { setContext, getContext } from 'svelte';\nimport type { ClientOptions } from '@urql/core';\nimport { Client } from '@urql/core';\n\nconst _contextKey = '$$_urql';\n\n/** Returns a provided {@link Client}.\n *\n * @remarks\n * `getContextClient` returns the {@link Client} that’s previously\n * been provided on Svelte’s context with {@link setContextClient}.\n *\n * This is useful to create a `Client` on Svelte’s context once, and\n * then pass it to all GraphQL store functions without importing it\n * from a singleton export.\n *\n * @throws\n * In development, if `getContextClient` can’t get a {@link Client}\n * from Svelte’s context, an error will be thrown.\n */\nexport const getContextClient = (): Client => {\n  const client = getContext(_contextKey);\n  if (process.env.NODE_ENV !== 'production' && !client) {\n    throw new Error(\n      'No urql Client was found in Svelte context. Did you forget to call setContextClient?'\n    );\n  }\n\n  return client as Client;\n};\n\n/** Provides a {@link Client} to a component’s children.\n *\n * @remarks\n * `setContextClient` updates the Svelte context to provide\n * a {@link Client} to be later retrieved using the\n * {@link getContextClient} function.\n */\nexport const setContextClient = (client: Client): void => {\n  setContext(_contextKey, client);\n};\n\n/** Creates a {@link Client} and provides it to a component’s children.\n *\n * @param args - a {@link ClientOptions} object to create a `Client` with.\n * @returns the created {@link Client}.\n *\n * @remarks\n * `initContextClient` is a convenience wrapper around\n * `setContextClient` that accepts {@link ClientOptions},\n * creates a {@link Client} and provides it to be later\n * retrieved using the {@link getContextClient} function.\n */\nexport const initContextClient = (args: ClientOptions): Client => {\n  const client = new Client(args);\n  setContextClient(client);\n  return client;\n};\n"
  },
  {
    "path": "packages/svelte-urql/src/index.ts",
    "content": "export * from '@urql/core';\n\nexport type {\n  Pausable,\n  OperationResultStore,\n  OperationResultState,\n} from './common';\n\nexport * from './queryStore';\nexport * from './mutationStore';\nexport * from './subscriptionStore';\nexport * from './context';\n"
  },
  {
    "path": "packages/svelte-urql/src/mutationStore.test.ts",
    "content": "import { print } from 'graphql';\nimport { createClient } from '@urql/core';\nimport { get } from 'svelte/store';\nimport { vi, expect, it, describe } from 'vitest';\n\nimport { mutationStore } from './mutationStore';\n\ndescribe('mutationStore', () => {\n  const client = createClient({\n    url: 'noop',\n    exchanges: [],\n  });\n\n  const variables = {};\n  const context = {};\n\n  const query =\n    'mutation ($input: Example!) { doExample(input: $input) { id } }';\n  const store = mutationStore({\n    client,\n    query,\n    variables,\n    context,\n  });\n\n  it('creates a svelte store', () => {\n    const subscriber = vi.fn();\n    store.subscribe(subscriber);\n    expect(subscriber).toHaveBeenCalledTimes(1);\n  });\n\n  it('fills the store with correct values', () => {\n    expect(get(store).operation.kind).toBe('mutation');\n    expect(get(store).operation.context.url).toBe('noop');\n    expect(get(store).operation.variables).toBe(variables);\n\n    expect(print(get(store).operation.query)).toMatchInlineSnapshot(`\n      \"mutation ($input: Example!) {\n        doExample(input: $input) {\n          id\n        }\n      }\"\n    `);\n  });\n});\n"
  },
  {
    "path": "packages/svelte-urql/src/mutationStore.ts",
    "content": "import { pipe, map, scan, subscribe } from 'wonka';\nimport { derived, writable } from 'svelte/store';\n\nimport type {\n  AnyVariables,\n  GraphQLRequestParams,\n  Client,\n  OperationContext,\n} from '@urql/core';\nimport { createRequest } from '@urql/core';\n\nimport type { OperationResultState, OperationResultStore } from './common';\nimport { initialResult } from './common';\n\n/** Input arguments for the {@link mutationStore} function.\n *\n * @param query - The GraphQL mutation that the `mutationStore` executes.\n * @param variables - The variables for the GraphQL mutation that `mutationStore` executes.\n */\nexport type MutationArgs<\n  Data = any,\n  Variables extends AnyVariables = AnyVariables,\n> = {\n  /** The {@link Client} using which the subscription will be started.\n   *\n   * @remarks\n   * If you’ve previously provided a {@link Client} on Svelte’s context\n   * this can be set to {@link getContextClient}’s return value.\n   */\n  client: Client;\n  /** Updates the {@link OperationContext} for the GraphQL mutation operation.\n   *\n   * @remarks\n   * `context` may be passed to {@link mutationStore}, to update the\n   * {@link OperationContext} of a mutation operation. This may be used to update\n   * the `context` that exchanges will receive for a single hook.\n   *\n   * @example\n   * ```ts\n   * mutationStore({\n   *   query,\n   *   context: {\n   *     additionalTypenames: ['Item'],\n   *   },\n   * });\n   * ```\n   */\n  context?: Partial<OperationContext>;\n} & GraphQLRequestParams<Data, Variables>;\n\n/** Function to create a `mutationStore` that runs a GraphQL mutation and updates with a GraphQL result.\n *\n * @param args - a {@link MutationArgs} object, to pass a `query`, `variables`, and options.\n * @returns a {@link OperationResultStore} of the mutation’s result.\n *\n * @remarks\n * `mutationStore` allows a GraphQL mutation to be defined as a Svelte store.\n * Given {@link MutationArgs.query}, it executes the GraphQL mutation on the\n * {@link MutationArgs.client}.\n *\n * The returned store updates with an {@link OperationResult} when\n * the `Client` returns a result for the mutation.\n *\n * Hint: It’s often easier to use {@link Client.mutation} if you’re\n * creating a mutation imperatively and don’t need a store.\n *\n * @see {@link https://urql.dev/goto/docs/basics/svelte#mutations} for\n * `mutationStore` docs.\n *\n * @example\n * ```ts\n * import { mutationStore, gql, getContextClient } from '@urql/svelte';\n *\n * const client = getContextClient();\n *\n * let result;\n * function updateTodo({ id, title }) {\n *   result = queryStore({\n *     client,\n *     query: gql`\n *       mutation($id: ID!, $title: String!) {\n *         updateTodo(id: $id, title: $title) { id, title }\n *       }\n *     `,\n *     variables: { id, title },\n *   });\n * }\n * ```\n */\nexport function mutationStore<\n  Data = any,\n  Variables extends AnyVariables = AnyVariables,\n>(args: MutationArgs<Data, Variables>): OperationResultStore<Data, Variables> {\n  const request = createRequest(args.query, args.variables as Variables);\n  const operation = args.client.createRequestOperation(\n    'mutation',\n    request,\n    args.context\n  );\n  const initialState: OperationResultState<Data, Variables> = {\n    ...initialResult,\n    operation,\n    fetching: true,\n  };\n  const result$ = writable(initialState);\n\n  const subscription = pipe(\n    pipe(\n      args.client.executeRequestOperation(operation),\n      map(({ stale, data, error, extensions, operation, hasNext }) => ({\n        fetching: false,\n        stale,\n        data,\n        error,\n        operation,\n        extensions,\n        hasNext,\n      }))\n    ),\n    scan(\n      (result: OperationResultState<Data, Variables>, partial) => ({\n        ...result,\n        ...partial,\n      }),\n      initialState\n    ),\n    subscribe(result => {\n      result$.set(result);\n    })\n  );\n\n  return derived(result$, (result, set) => {\n    set(result);\n    return subscription.unsubscribe;\n  });\n}\n"
  },
  {
    "path": "packages/svelte-urql/src/queryStore.test.ts",
    "content": "import { createClient } from '@urql/core';\nimport { vi, expect, it, describe } from 'vitest';\nimport { get } from 'svelte/store';\n\nimport { queryStore } from './queryStore';\n\ndescribe('queryStore', () => {\n  const client = createClient({\n    url: 'https://example.com',\n    exchanges: [],\n  });\n\n  const variables = {};\n  const context = {};\n  const query = '{ test }';\n  const store = queryStore({ client, query, variables, context });\n\n  it('creates a svelte store', () => {\n    const subscriber = vi.fn();\n    store.subscribe(subscriber);\n    expect(subscriber).toHaveBeenCalledTimes(1);\n  });\n\n  it('fills the store with correct values', () => {\n    expect(get(store).operation.kind).toBe('query');\n    expect(get(store).operation.context.url).toBe('https://example.com');\n    expect(get(store).operation.variables).toBe(variables);\n\n    expect(get(store).operation.query.loc?.source.body).toMatchInlineSnapshot(`\n      \"{\n        test\n      }\"\n    `);\n  });\n\n  it('adds pause handles', () => {\n    expect(get(store.isPaused$)).toBe(false);\n\n    store.pause();\n    expect(get(store.isPaused$)).toBe(true);\n\n    store.resume();\n    expect(get(store.isPaused$)).toBe(false);\n  });\n});\n"
  },
  {
    "path": "packages/svelte-urql/src/queryStore.ts",
    "content": "import type {\n  Client,\n  GraphQLRequestParams,\n  AnyVariables,\n  OperationContext,\n  RequestPolicy,\n} from '@urql/core';\nimport { createRequest } from '@urql/core';\n\nimport type { Source } from 'wonka';\nimport {\n  pipe,\n  map,\n  fromValue,\n  switchMap,\n  subscribe,\n  concat,\n  scan,\n  never,\n} from 'wonka';\n\nimport { derived, writable } from 'svelte/store';\n\nimport type {\n  OperationResultState,\n  OperationResultStore,\n  Pausable,\n} from './common';\nimport { initialResult, createPausable, fromStore } from './common';\n\n/** Input arguments for the {@link queryStore} function.\n *\n * @param query - The GraphQL query that the `queryStore` executes.\n * @param variables - The variables for the GraphQL query that `queryStore` executes.\n */\nexport type QueryArgs<\n  Data = any,\n  Variables extends AnyVariables = AnyVariables,\n> = {\n  /** The {@link Client} using which the query will be executed.\n   *\n   * @remarks\n   * If you’ve previously provided a {@link Client} on Svelte’s context\n   * this can be set to {@link getContextClient}’s return value.\n   */\n  client: Client;\n  /** Updates the {@link OperationContext} for the executed GraphQL query operation.\n   *\n   * @remarks\n   * `context` may be passed to {@link queryStore}, to update the {@link OperationContext}\n   * of a query operation. This may be used to update the `context` that exchanges\n   * will receive for a single hook.\n   *\n   * @example\n   * ```ts\n   * queryStore({\n   *   query,\n   *   context: {\n   *     additionalTypenames: ['Item'],\n   *   },\n   * });\n   * ```\n   */\n  context?: Partial<OperationContext>;\n  /** Sets the {@link RequestPolicy} for the executed GraphQL query operation.\n   *\n   * @remarks\n   * `requestPolicy` modifies the {@link RequestPolicy} of the GraphQL query operation\n   * that the {@link queryStore} executes, and indicates a caching strategy for cache exchanges.\n   *\n   * For example, when set to `'cache-and-network'`, the `queryStore` will\n   * receive a cached result with `stale: true` and an API request will be\n   * sent in the background.\n   *\n   * @see {@link OperationContext.requestPolicy} for where this value is set.\n   */\n  requestPolicy?: RequestPolicy;\n  /** Prevents the {@link queryStore} from automatically executing GraphQL query operations.\n   *\n   * @remarks\n   * `pause` may be set to `true` to stop the {@link queryStore} from executing\n   * automatically. The store will stop receiving updates from the {@link Client}\n   * and won’t execute the query operation, until either it’s set to `false`\n   * or {@link Pausable.resume} is called.\n   *\n   * @see {@link https://urql.dev/goto/docs/basics/svelte#pausing-queries} for\n   * documentation on the `pause` option.\n   */\n  pause?: boolean;\n} & GraphQLRequestParams<Data, Variables>;\n\n/** Function to create a `queryStore` that runs a GraphQL query and updates with GraphQL results.\n *\n * @param args - a {@link QueryArgs} object, to pass a `query`, `variables`, and options.\n * @returns a {@link OperationResultStore} of query results, which implements {@link Pausable}.\n *\n * @remarks\n * `queryStore` allows GraphQL queries to be defined as Svelte stores.\n * Given {@link QueryArgs.query}, it executes the GraphQL query on the\n * {@link QueryArgs.client}.\n *\n * The returned store updates with {@link OperationResult} values when\n * the `Client` has new results for the query.\n *\n * @see {@link https://urql.dev/goto/docs/basics/svelte#queries} for `queryStore` docs.\n *\n * @example\n * ```ts\n * import { queryStore, gql, getContextClient } from '@urql/svelte';\n *\n * const todos = queryStore({\n *   client: getContextClient(),\n *   query: gql`{ todos { id, title } }`,\n * });\n * ```\n */\nexport function queryStore<\n  Data = any,\n  Variables extends AnyVariables = AnyVariables,\n>(\n  args: QueryArgs<Data, Variables>\n): OperationResultStore<Data, Variables> &\n  Pausable & { reexecute: (context: Partial<OperationContext>) => void } {\n  const request = createRequest(args.query, args.variables as Variables);\n\n  const context: Partial<OperationContext> = {\n    requestPolicy: args.requestPolicy,\n    ...args.context,\n  };\n\n  const operation = args.client.createRequestOperation(\n    'query',\n    request,\n    context\n  );\n\n  const operation$ = writable(operation);\n\n  const initialState: OperationResultState<Data, Variables> = {\n    ...initialResult,\n    operation,\n  };\n\n  const isPaused$ = writable(!!args.pause);\n\n  const result$ = writable(initialState, () => {\n    return pipe(\n      fromStore(isPaused$),\n      switchMap(\n        (isPaused): Source<Partial<OperationResultState<Data, Variables>>> => {\n          if (isPaused) {\n            return never as any;\n          }\n\n          return pipe(\n            fromStore(operation$),\n            switchMap(operation => {\n              return concat<Partial<OperationResultState<Data, Variables>>>([\n                fromValue({ fetching: true, stale: false, hasNext: false }),\n                pipe(\n                  args.client.executeRequestOperation(operation),\n                  map(\n                    ({\n                      stale,\n                      data,\n                      error,\n                      extensions,\n                      operation,\n                      hasNext,\n                    }) => ({\n                      fetching: false,\n                      stale: !!stale,\n                      data,\n                      error,\n                      operation,\n                      extensions,\n                      hasNext,\n                    })\n                  )\n                ),\n                fromValue({ fetching: false, hasNext: false }),\n              ]);\n            })\n          );\n        }\n      ),\n      scan(\n        (result: OperationResultState<Data, Variables>, partial) => ({\n          ...result,\n          ...partial,\n        }),\n        initialState\n      ),\n      subscribe(result => {\n        result$.set(result);\n      })\n    ).unsubscribe;\n  });\n\n  const reexecute = (context: Partial<OperationContext>) => {\n    const newContext = { ...context, ...args.context };\n    const operation = args.client.createRequestOperation(\n      'query',\n      request,\n      newContext\n    );\n    isPaused$.set(false);\n    operation$.set(operation);\n  };\n\n  return {\n    ...derived(result$, (result, set) => {\n      set(result);\n    }),\n    ...createPausable(isPaused$),\n    reexecute,\n  };\n}\n"
  },
  {
    "path": "packages/svelte-urql/src/subscriptionStore.test.ts",
    "content": "import { createClient } from '@urql/core';\nimport { get } from 'svelte/store';\nimport { vi, expect, it, describe } from 'vitest';\n\nimport { subscriptionStore } from './subscriptionStore';\n\ndescribe('subscriptionStore', () => {\n  const client = createClient({\n    url: 'https://example.com',\n    exchanges: [],\n  });\n\n  const variables = {};\n  const context = {};\n  const query = `subscription ($input: ExampleInput) { exampleSubscribe(input: $input) { data } }`;\n  const store = subscriptionStore({\n    client,\n    query,\n    variables,\n    context,\n  });\n\n  it('creates a svelte store', () => {\n    const subscriber = vi.fn();\n    store.subscribe(subscriber);\n    expect(subscriber).toHaveBeenCalledTimes(1);\n  });\n\n  it('fills the store with correct values', () => {\n    expect(get(store).operation.kind).toBe('subscription');\n    expect(get(store).operation.context.url).toBe('https://example.com');\n    expect(get(store).operation.variables).toBe(variables);\n\n    expect(get(store).operation.query.loc?.source.body).toMatchInlineSnapshot(`\n      \"subscription ($input: ExampleInput) {\n        exampleSubscribe(input: $input) {\n          data\n        }\n      }\"\n    `);\n  });\n\n  it('adds pause handles', () => {\n    expect(get(store.isPaused$)).toBe(false);\n\n    store.pause();\n    expect(get(store.isPaused$)).toBe(true);\n\n    store.resume();\n    expect(get(store.isPaused$)).toBe(false);\n  });\n});\n"
  },
  {
    "path": "packages/svelte-urql/src/subscriptionStore.ts",
    "content": "import type {\n  AnyVariables,\n  GraphQLRequestParams,\n  Client,\n  OperationContext,\n} from '@urql/core';\nimport { createRequest } from '@urql/core';\n\nimport type { Source } from 'wonka';\nimport {\n  pipe,\n  map,\n  fromValue,\n  switchMap,\n  subscribe,\n  concat,\n  scan,\n  never,\n} from 'wonka';\n\nimport { derived, writable } from 'svelte/store';\n\nimport type {\n  OperationResultState,\n  OperationResultStore,\n  Pausable,\n} from './common';\nimport { initialResult, createPausable, fromStore } from './common';\n\n/** Combines previous data with an incoming subscription result’s data.\n *\n * @remarks\n * A `SubscriptionHandler` may be passed to {@link subscriptionStore} to\n * aggregate subscription results into a combined `data` value on the\n * {@link OperationResultStore}.\n *\n * This is useful when a subscription event delivers a single item, while\n * you’d like to display a list of events.\n *\n * @example\n * ```ts\n * const NotificationsSubscription = gql`\n *   subscription { newNotification { id, text } }\n * `;\n *\n * subscriptionStore(\n *   { query: NotificationsSubscription },\n *   function combineNotifications(notifications = [], data) {\n *     return [...notifications, data.newNotification];\n *   },\n * );\n * ```\n */\nexport type SubscriptionHandler<T, R> = (prev: R | undefined, data: T) => R;\n\n/** Input arguments for the {@link subscriptionStore} function.\n *\n * @param query - The GraphQL subscription that the `subscriptionStore` executes.\n * @param variables - The variables for the GraphQL subscription that `subscriptionStore` executes.\n */\nexport type SubscriptionArgs<\n  Data = any,\n  Variables extends AnyVariables = AnyVariables,\n> = {\n  /** The {@link Client} using which the subscription will be started.\n   *\n   * @remarks\n   * If you’ve previously provided a {@link Client} on Svelte’s context\n   * this can be set to {@link getContextClient}’s return value.\n   */\n  client: Client;\n  /** Updates the {@link OperationContext} for the GraphQL subscription operation.\n   *\n   * @remarks\n   * `context` may be passed to {@link subscriptionStore}, to update the\n   * {@link OperationContext} of a subscription operation. This may be used to update\n   * the `context` that exchanges will receive for a single hook.\n   *\n   * @example\n   * ```ts\n   * subscriptionStore({\n   *   query,\n   *   context: {\n   *     additionalTypenames: ['Item'],\n   *   },\n   * });\n   * ```\n   */\n  context?: Partial<OperationContext>;\n  /** Prevents the {@link subscriptionStore} from automatically starting the GraphQL subscription.\n   *\n   * @remarks\n   * `pause` may be set to `true` to stop the {@link subscriptionStore} from starting\n   * its subscription automatically. The store won't execute the subscription operation,\n   * until either it’s set to `false` or {@link Pausable.resume} is called.\n   */\n  pause?: boolean;\n} & GraphQLRequestParams<Data, Variables>;\n\n/** Function to create a `subscriptionStore` that starts a GraphQL subscription.\n *\n * @param args - a {@link QueryArgs} object, to pass a `query`, `variables`, and options.\n * @param handler - optionally, a {@link SubscriptionHandler} function to combine multiple subscription results.\n * @returns a {@link OperationResultStore} of subscription results, which implements {@link Pausable}.\n *\n * @remarks\n * `subscriptionStore` allows GraphQL subscriptions to be defined as Svelte stores.\n * Given {@link SubscriptionArgs.query}, it executes the GraphQL subsription on the\n * {@link SubscriptionArgs.client}.\n *\n * The returned store updates with {@link OperationResult} values when\n * the `Client` has new results for the subscription.\n *\n * @see {@link https://urql.dev/goto/docs/advanced/subscriptions#svelte} for\n * `subscriptionStore` docs.\n *\n * @example\n * ```ts\n * import { subscriptionStore, gql, getContextClient } from '@urql/svelte';\n *\n * const todos = subscriptionStore({\n *   client: getContextClient(),\n *   query: gql`\n *     subscription {\n *       newNotification { id, text }\n *     }\n *   `,\n *   },\n *   function combineNotifications(notifications = [], data) {\n *     return [...notifications, data.newNotification];\n *   },\n * );\n * ```\n */\nexport function subscriptionStore<\n  Data,\n  Result = Data,\n  Variables extends AnyVariables = AnyVariables,\n>(\n  args: SubscriptionArgs<Data, Variables>,\n  handler?: SubscriptionHandler<Data, Result>\n): OperationResultStore<Result, Variables> & Pausable {\n  const request = createRequest(args.query, args.variables as Variables);\n\n  const operation = args.client.createRequestOperation(\n    'subscription',\n    request,\n    args.context\n  );\n  const initialState: OperationResultState<Result, Variables> = {\n    ...initialResult,\n    operation,\n    fetching: true,\n  };\n\n  const isPaused$ = writable(!!args.pause);\n\n  const result$ = writable(initialState, () => {\n    return pipe(\n      fromStore(isPaused$),\n      switchMap(\n        (isPaused): Source<Partial<OperationResultState<Data, Variables>>> => {\n          if (isPaused) {\n            return never as any;\n          }\n\n          return concat<Partial<OperationResultState<Data, Variables>>>([\n            fromValue({ fetching: true, stale: false }),\n            pipe(\n              args.client.executeRequestOperation(operation),\n              map(({ stale, data, error, extensions, operation }) => ({\n                fetching: true,\n                stale: !!stale,\n                data,\n                error,\n                operation,\n                extensions,\n              }))\n            ),\n            fromValue({ fetching: false }),\n          ]);\n        }\n      ),\n      scan((result: OperationResultState<Result, Variables>, partial) => {\n        const data =\n          partial.data != null\n            ? typeof handler === 'function'\n              ? handler(result.data, partial.data)\n              : partial.data\n            : result.data;\n        return {\n          ...result,\n          ...partial,\n          data,\n        } as OperationResultState<Result, Variables>;\n      }, initialState),\n      subscribe(result => {\n        result$.set(result);\n      })\n    ).unsubscribe;\n  });\n\n  return {\n    ...derived(result$, (result, set) => {\n      set(result);\n    }),\n    ...createPausable(isPaused$),\n  };\n}\n"
  },
  {
    "path": "packages/svelte-urql/tsconfig.json",
    "content": "{\n  \"extends\": \"../../tsconfig.json\",\n  \"include\": [\"src\"]\n}\n"
  },
  {
    "path": "packages/svelte-urql/vitest.config.ts",
    "content": "import { mergeConfig } from 'vitest/config';\nimport baseConfig from '../../vitest.config';\n\nexport default mergeConfig(baseConfig, {});\n"
  },
  {
    "path": "packages/vue-urql/CHANGELOG.md",
    "content": "# @urql/vue\n\n## 2.0.0\n\n### Major Changes\n\n- Bump Vue to 3.2+ and replace getCurrentInstance with getCurrentScope\n  Submitted by [@arkandias](https://github.com/arkandias) (See [#3806](https://github.com/urql-graphql/urql/pull/3806))\n\n### Minor Changes\n\n- Fix regression breaking `variables` typing\n  Submitted by [@arkandias](https://github.com/arkandias) (See [#3734](https://github.com/urql-graphql/urql/pull/3734))\n\n### Patch Changes\n\n- Updated dependencies (See [#3789](https://github.com/urql-graphql/urql/pull/3789) and [#3807](https://github.com/urql-graphql/urql/pull/3807))\n  - @urql/core@6.0.0\n\n## 1.4.3\n\n### Patch Changes\n\n- Omit minified files and sourcemaps' `sourcesContent` in published packages\n  Submitted by [@kitten](https://github.com/kitten) (See [#3755](https://github.com/urql-graphql/urql/pull/3755))\n- Updated dependencies (See [#3755](https://github.com/urql-graphql/urql/pull/3755))\n  - @urql/core@5.1.1\n\n## 1.4.2\n\n### Patch Changes\n\n- Add type for `hasNext` to the query and mutation results\n  Submitted by [@JoviDeCroock](https://github.com/JoviDeCroock) (See [#3703](https://github.com/urql-graphql/urql/pull/3703))\n\n## 1.4.1\n\n### Patch Changes\n\n- Use `shallowRef` for data variable to avoid extra overhead for heavy objects\n  Submitted by [@yurks](https://github.com/yurks) (See [#3641](https://github.com/urql-graphql/urql/pull/3641))\n\n## 1.4.0\n\n### Minor Changes\n\n- Refactor composable functions with a focus on avoiding memory leaks and Vue best practices\n  Submitted by [@yurks](https://github.com/yurks) (See [#3619](https://github.com/urql-graphql/urql/pull/3619))\n\n## 1.3.2\n\n### Patch Changes\n\n- ⚠️ Fix deep options reactivity for subscriptions\n  Submitted by [@JoviDeCroock](https://github.com/JoviDeCroock) (See [#3616](https://github.com/urql-graphql/urql/pull/3616))\n\n## 1.3.1\n\n### Patch Changes\n\n- ⚠️ Fix variables losing reactivity\n  Submitted by [@JoviDeCroock](https://github.com/JoviDeCroock) (See [#3614](https://github.com/urql-graphql/urql/pull/3614))\n\n## 1.3.0\n\n### Minor Changes\n\n- Use `shallowRef` to avoid creating deeply reactive objects for heavy objects\n  Submitted by [@negezor](https://github.com/negezor) (See [#3611](https://github.com/urql-graphql/urql/pull/3611))\n- Remove wrapping request `args` in `reactive` to fix memory leak\n  Submitted by [@negezor](https://github.com/negezor) (See [#3612](https://github.com/urql-graphql/urql/pull/3612))\n\n## 1.2.2\n\n### Patch Changes\n\n- ⚠️ Fix reactaive typings for `variables` (See [#3605](https://github.com/urql-graphql/urql/pull/3605))\n  Submitted by [@JoviDeCroock](https://github.com/JoviDeCroock) (See [`118d74b2`](https://github.com/urql-graphql/urql/commit/118d74b238007264cacfb91fc12de74370d5766e))\n- Restore the possibility to use a getter for the pause property\n  Submitted by [@arkandias](https://github.com/arkandias) (See [#3598](https://github.com/urql-graphql/urql/pull/3598))\n\n## 1.2.1\n\n### Patch Changes\n\n- ⚠️ Fix regression causing `pause` argument on `useQuery` and `useSubscription` to not be reactive\n  Submitted by [@arkandias](https://github.com/arkandias) (See [#3595](https://github.com/urql-graphql/urql/pull/3595))\n\n## 1.2.0\n\n### Minor Changes\n\n- Mark `@urql/core` as a peer dependency as well as a regular dependency\n  Submitted by [@kitten](https://github.com/kitten) (See [#3579](https://github.com/urql-graphql/urql/pull/3579))\n\n### Patch Changes\n\n- ⚠️ Fix subscription handlers to not receive `null` values\n  Submitted by [@kitten](https://github.com/kitten) (See [#3581](https://github.com/urql-graphql/urql/pull/3581))\n- Add missing support for getter functions as input arguments values to `useQuery`, `useSubscription`, and `useMutation`\n  Submitted by [@kitten](https://github.com/kitten) (See [#3582](https://github.com/urql-graphql/urql/pull/3582))\n\n## 1.1.3\n\n### Patch Changes\n\n- Updated dependencies (See [#3520](https://github.com/urql-graphql/urql/pull/3520), [#3553](https://github.com/urql-graphql/urql/pull/3553), and [#3520](https://github.com/urql-graphql/urql/pull/3520))\n  - @urql/core@5.0.0\n\n## 1.1.2\n\n### Patch Changes\n\n- Update build process to generate correct source maps\n  Submitted by [@kitten](https://github.com/kitten) (See [#3201](https://github.com/urql-graphql/urql/pull/3201))\n- Prevent multiple operations being executed in a row when multiple inputs change simultaneously (e.g. `isPaused` and query inputs)\n  Submitted by [@kitten](https://github.com/kitten) (See [#3231](https://github.com/urql-graphql/urql/pull/3231))\n\n## 1.1.1\n\n### Patch Changes\n\n- Publish with npm provenance\n  Submitted by [@kitten](https://github.com/kitten) (See [#3180](https://github.com/urql-graphql/urql/pull/3180))\n\n## 1.1.0\n\n### Minor Changes\n\n- Allow mutations to update their results in bindings when `hasNext: true` is set, which indicates deferred or streamed results\n  Submitted by [@kitten](https://github.com/kitten) (See [#3103](https://github.com/urql-graphql/urql/pull/3103))\n\n### Patch Changes\n\n- ⚠️ Fix source maps included with recently published packages, which lost their `sourcesContent`, including additional source files, and had incorrect paths in some of them\n  Submitted by [@kitten](https://github.com/kitten) (See [#3053](https://github.com/urql-graphql/urql/pull/3053))\n- Upgrade to `wonka@^6.3.0`\n  Submitted by [@kitten](https://github.com/kitten) (See [#3104](https://github.com/urql-graphql/urql/pull/3104))\n- Add TSDocs to all `urql` bindings packages\n  Submitted by [@kitten](https://github.com/kitten) (See [#3079](https://github.com/urql-graphql/urql/pull/3079))\n- Updated dependencies (See [#3101](https://github.com/urql-graphql/urql/pull/3101), [#3033](https://github.com/urql-graphql/urql/pull/3033), [#3054](https://github.com/urql-graphql/urql/pull/3054), [#3053](https://github.com/urql-graphql/urql/pull/3053), [#3060](https://github.com/urql-graphql/urql/pull/3060), [#3081](https://github.com/urql-graphql/urql/pull/3081), [#3039](https://github.com/urql-graphql/urql/pull/3039), [#3104](https://github.com/urql-graphql/urql/pull/3104), [#3082](https://github.com/urql-graphql/urql/pull/3082), [#3097](https://github.com/urql-graphql/urql/pull/3097), [#3061](https://github.com/urql-graphql/urql/pull/3061), [#3055](https://github.com/urql-graphql/urql/pull/3055), [#3085](https://github.com/urql-graphql/urql/pull/3085), [#3079](https://github.com/urql-graphql/urql/pull/3079), [#3087](https://github.com/urql-graphql/urql/pull/3087), [#3059](https://github.com/urql-graphql/urql/pull/3059), [#3055](https://github.com/urql-graphql/urql/pull/3055), [#3057](https://github.com/urql-graphql/urql/pull/3057), [#3050](https://github.com/urql-graphql/urql/pull/3050), [#3062](https://github.com/urql-graphql/urql/pull/3062), [#3051](https://github.com/urql-graphql/urql/pull/3051), [#3043](https://github.com/urql-graphql/urql/pull/3043), [#3063](https://github.com/urql-graphql/urql/pull/3063), [#3054](https://github.com/urql-graphql/urql/pull/3054), [#3102](https://github.com/urql-graphql/urql/pull/3102), [#3097](https://github.com/urql-graphql/urql/pull/3097), [#3106](https://github.com/urql-graphql/urql/pull/3106), [#3058](https://github.com/urql-graphql/urql/pull/3058), and [#3062](https://github.com/urql-graphql/urql/pull/3062))\n  - @urql/core@4.0.0\n\n## 1.0.5\n\n### Patch Changes\n\n- Allow a `Client` provided using `provideClient` to be used in the same component it's been provided in\n  Submitted by [@kitten](https://github.com/kitten) (See [#3018](https://github.com/urql-graphql/urql/pull/3018))\n- ⚠️ Fix type utilities turning the `variables` properties optional when a type from `TypedDocumentNode` has no `Variables` or all optional `Variables`. Previously this would break for wrappers, e.g. in code generators, or when the type didn't quite match what we'd expect\n  Submitted by [@kitten](https://github.com/kitten) (See [#3022](https://github.com/urql-graphql/urql/pull/3022))\n- Updated dependencies (See [#3007](https://github.com/urql-graphql/urql/pull/3007), [#2962](https://github.com/urql-graphql/urql/pull/2962), [#3007](https://github.com/urql-graphql/urql/pull/3007), [#3015](https://github.com/urql-graphql/urql/pull/3015), and [#3022](https://github.com/urql-graphql/urql/pull/3022))\n  - @urql/core@3.2.0\n\n## 1.0.4\n\n### Patch Changes\n\n- ⚠️ Fix type-generation, with a change in TS/Rollup the type generation took the paths as src and resolved them into the types dir, by [@JoviDeCroock](https://github.com/JoviDeCroock) (See [#2870](https://github.com/urql-graphql/urql/pull/2870))\n- Updated dependencies (See [#2872](https://github.com/urql-graphql/urql/pull/2872), [#2870](https://github.com/urql-graphql/urql/pull/2870), and [#2871](https://github.com/urql-graphql/urql/pull/2871))\n  - @urql/core@3.1.1\n\n## 1.0.3\n\n### Patch Changes\n\n- Move remaining `Variables` generics over from `object` default to `Variables extends AnyVariables = AnyVariables`. This has been introduced previously in [#2607](https://github.com/urql-graphql/urql/pull/2607) but some missing ports have been missed due to TypeScript not catching them previously. Depending on your TypeScript version the `object` default is incompatible with `AnyVariables`, by [@kitten](https://github.com/kitten) (See [#2843](https://github.com/urql-graphql/urql/pull/2843))\n- Updated dependencies (See [#2843](https://github.com/urql-graphql/urql/pull/2843), [#2847](https://github.com/urql-graphql/urql/pull/2847), [#2850](https://github.com/urql-graphql/urql/pull/2850), and [#2846](https://github.com/urql-graphql/urql/pull/2846))\n  - @urql/core@3.1.0\n\n## 1.0.2\n\n### Patch Changes\n\n- ⚠️ Fix an issue that caused `useQuery` to fail for promise-based access, if a result is delivered by the `Client` immediately, by [@kitten](https://github.com/kitten) (See [#2629](https://github.com/FormidableLabs/urql/pull/2629))\n\n## 1.0.1\n\n### Patch Changes\n\n- Tweak the variables type for when generics only contain nullable keys, by [@JoviDeCroock](https://github.com/JoviDeCroock) (See [#2623](https://github.com/FormidableLabs/urql/pull/2623))\n\n## 1.0.0\n\n### Major Changes\n\n- **Goodbye IE11!** 👋 This major release removes support for IE11. All code that is shipped will be transpiled much less and will _not_ be ES5-compatible anymore, by [@kitten](https://github.com/kitten) (See [#2504](https://github.com/FormidableLabs/urql/pull/2504))\n- Implement stricter variables types, which require variables to always be passed and match TypeScript types when the generic is set or inferred. This is a breaking change for TypeScript users potentially, unless all types are adhered to, by [@kitten](https://github.com/kitten) (See [#2607](https://github.com/FormidableLabs/urql/pull/2607))\n- Upgrade to [Wonka v6](https://github.com/0no-co/wonka) (`wonka@^6.0.0`), which has no breaking changes but is built to target ES2015 and comes with other minor improvements.\n  The library has fully been migrated to TypeScript which will hopefully help with making contributions easier!, by [@kitten](https://github.com/kitten) (See [#2504](https://github.com/FormidableLabs/urql/pull/2504))\n\n### Patch Changes\n\n- Support nested refs in variables, by [@JoviDeCroock](https://github.com/JoviDeCroock) (See [#2608](https://github.com/FormidableLabs/urql/pull/2608))\n- Updated dependencies (See [#2551](https://github.com/FormidableLabs/urql/pull/2551), [#2504](https://github.com/FormidableLabs/urql/pull/2504), [#2619](https://github.com/FormidableLabs/urql/pull/2619), [#2607](https://github.com/FormidableLabs/urql/pull/2607), and [#2504](https://github.com/FormidableLabs/urql/pull/2504))\n  - @urql/core@3.0.0\n\n## 0.6.4\n\n### Patch Changes\n\n- Allow Vue 2.7 as peer dependency to prevent peer dependency errors e.g. with pnpm, by [@dargmuesli](https://github.com/dargmuesli) (See [#2561](https://github.com/FormidableLabs/urql/pull/2561))\n\n## 0.6.3\n\n### Patch Changes\n\n- ⚠️ Fix Node.js ESM re-export detection for `@urql/core` in `urql` package and CommonJS output for all other CommonJS-first packages. This ensures that Node.js' `cjs-module-lexer` can correctly identify re-exports and report them properly. Otherwise, this will lead to a runtime error, by [@kitten](https://github.com/kitten) (See [#2485](https://github.com/FormidableLabs/urql/pull/2485))\n\n## 0.6.2\n\n### Patch Changes\n\n- ⚠️ Fix wait for the first non-stale result when using `await executeQuery`, by [@JoviDeCroock](https://github.com/JoviDeCroock) (See [#2410](https://github.com/FormidableLabs/urql/pull/2410))\n\n## 0.6.1\n\n### Patch Changes\n\n- Extend peer dependency range of `graphql` to include `^16.0.0`.\n  As always when upgrading across many packages of `urql`, especially including `@urql/core` we recommend you to deduplicate dependencies after upgrading, using `npm dedupe` or `npx yarn-deduplicate`, by [@kitten](https://github.com/kitten) (See [#2133](https://github.com/FormidableLabs/urql/pull/2133))\n- Updated dependencies (See [#2133](https://github.com/FormidableLabs/urql/pull/2133))\n  - @urql/core@2.3.6\n\n## 0.6.0\n\n### Minor Changes\n\n- Provide the client as a ref so it can observe changes. This change is potentially breaking for\n  anyone using the `useClient` import as it will now return a `Ref<Client>` rather than a `Client`, by [@JoviDeCroock](https://github.com/JoviDeCroock) (See [#2047](https://github.com/FormidableLabs/urql/pull/2047))\n\n### Patch Changes\n\n- Updated dependencies (See [#2027](https://github.com/FormidableLabs/urql/pull/2027) and [#1998](https://github.com/FormidableLabs/urql/pull/1998))\n  - @urql/core@2.3.4\n\n## 0.5.0\n\n### Minor Changes\n\n- Allow passing in a Ref of client to `provideClient` and `install`, by [@JoviDeCroock](https://github.com/JoviDeCroock) (See [#1962](https://github.com/FormidableLabs/urql/pull/1962))\n\n### Patch Changes\n\n- Updated dependencies (See [#1944](https://github.com/FormidableLabs/urql/pull/1944))\n  - @urql/core@2.3.2\n\n## 0.4.3\n\n### Patch Changes\n\n- Unwrap the `variables` proxy before we send it into the client, by [@JoviDeCroock](https://github.com/JoviDeCroock) (See [#1810](https://github.com/FormidableLabs/urql/pull/1810))\n\n## 0.4.2\n\n### Patch Changes\n\n- Refactor `useQuery` implementation to utilise the single-source implementation of `@urql/core@2.1.0`. This should improve the stability of promisified `useQuery()` calls and prevent operations from not being issued in some edge cases, by [@kitten](https://github.com/kitten) (See [#1758](https://github.com/FormidableLabs/urql/pull/1758))\n- Updated dependencies (See [#1776](https://github.com/FormidableLabs/urql/pull/1776) and [#1755](https://github.com/FormidableLabs/urql/pull/1755))\n  - @urql/core@2.1.5\n\n## 0.4.1\n\n### Patch Changes\n\n- Use client.executeMutation rather than client.mutation in useMutation, by [@JoviDeCroock](https://github.com/JoviDeCroock) (See [#1680](https://github.com/FormidableLabs/urql/pull/1680))\n- Updated dependencies (See [#1709](https://github.com/FormidableLabs/urql/pull/1709))\n  - @urql/core@2.1.4\n\n## 0.4.0\n\n### Minor Changes\n\n- A `useClientHandle()` function has been added. This creates a `handle` on which all `use*` hooks can be called, like `await handle.useQuery(...)` or `await handle.useSubscription(...)` which is useful for sequentially chaining hook calls in an `async setup()` function or preserve the right instance of a `Client` across lifecycle hooks, by [@kitten](https://github.com/kitten) (See [#1599](https://github.com/FormidableLabs/urql/pull/1599))\n\n### Patch Changes\n\n- Remove closure-compiler from the build step (See [#1570](https://github.com/FormidableLabs/urql/pull/1570))\n- The `useClient()` function will now throw a more helpful error when it's called outside of any lifecycle hooks, by [@kitten](https://github.com/kitten) (See [#1599](https://github.com/FormidableLabs/urql/pull/1599))\n- Updated dependencies (See [#1570](https://github.com/FormidableLabs/urql/pull/1570), [#1509](https://github.com/FormidableLabs/urql/pull/1509), [#1600](https://github.com/FormidableLabs/urql/pull/1600), and [#1515](https://github.com/FormidableLabs/urql/pull/1515))\n  - @urql/core@2.1.0\n\n## 0.3.0\n\n### Minor Changes\n\n- **Breaking**: Remove `pollInterval` option from `useQuery`. Please consider adding an interval manually calling `executeQuery()`, by [@kitten](https://github.com/kitten) (See [#1374](https://github.com/FormidableLabs/urql/pull/1374))\n- Remove deprecated `operationName` property from `Operation`s. The new `Operation.kind` property is now preferred. If you're creating new operations you may also use the `makeOperation` utility instead.\n  When upgrading `@urql/core` please ensure that your package manager didn't install any duplicates of it. You may deduplicate it manually using `npx yarn-deduplicate` (for Yarn) or `npm dedupe` (for npm), by [@kitten](https://github.com/kitten) (See [#1357](https://github.com/FormidableLabs/urql/pull/1357))\n\n### Patch Changes\n\n- Updated dependencies (See [#1374](https://github.com/FormidableLabs/urql/pull/1374), [#1357](https://github.com/FormidableLabs/urql/pull/1357), and [#1375](https://github.com/FormidableLabs/urql/pull/1375))\n  - @urql/core@2.0.0\n\n## 0.2.1\n\n### Patch Changes\n\n- Add a built-in `gql` tag function helper to `@urql/core`. This behaves similarly to `graphql-tag` but only warns about _locally_ duplicated fragment names rather than globally. It also primes `@urql/core`'s key cache with the parsed `DocumentNode`, by [@kitten](https://github.com/kitten) (See [#1187](https://github.com/FormidableLabs/urql/pull/1187))\n- Updated dependencies (See [#1187](https://github.com/FormidableLabs/urql/pull/1187), [#1186](https://github.com/FormidableLabs/urql/pull/1186), and [#1186](https://github.com/FormidableLabs/urql/pull/1186))\n  - @urql/core@1.16.0\n\n## 0.2.0\n\n### Minor Changes\n\n- Export a Vue plugin function as the default export, by [@LinusBorg](https://github.com/LinusBorg) (See [#1152](https://github.com/FormidableLabs/urql/pull/1152))\n- Refactor `useQuery` to resolve the lazy promise for Vue Suspense to the latest result that has been requested as per the input to `useQuery`, by [@kitten](https://github.com/kitten) (See [#1162](https://github.com/FormidableLabs/urql/pull/1162))\n\n### Patch Changes\n\n- ⚠️ Fix pausing feature of `useQuery` by turning `isPaused` into a ref again, by [@LinusBorg](https://github.com/LinusBorg) (See [#1155](https://github.com/FormidableLabs/urql/pull/1155))\n- ⚠️ Fix implementation of Vue's Suspense feature by making the lazy `PromiseLike` on the returned state passive, by [@kitten](https://github.com/kitten) (See [#1159](https://github.com/FormidableLabs/urql/pull/1159))\n\n## 0.1.0\n\nInitial release\n"
  },
  {
    "path": "packages/vue-urql/README.md",
    "content": "<div align=\"center\">\n  <br />\n  <br />\n  <a href=\"https://www.npmjs.com/package/@urql/vue\">\n    <img alt=\"Npm version\" src=\"https://badgen.net/npm/v/@urql/vue\" />\n  </a>\n  <a href=\"https://bundlephobia.com/result?p=@urql/vue\">\n    <img alt=\"Minified gzip size\" src=\"https://img.shields.io/bundlephobia/minzip/@urql/vue.svg?label=gzip%20size\" />\n  </a>\n  <a href=\"https://github.com/urql-graphql/urql/discussions\">\n    <img alt=\"GitHub Discussions: Chat With Us\" src=\"https://badgen.net/badge/discussions/chat%20with%20us/purple\" />\n  </a>\n  <br />\n  <br />\n</div>\n\n## Installation\n\n```sh\nyarn add @urql/vue graphql\n# or\nnpm install --save @urql/vue graphql\n```\n\n> **Note:** `@urql/vue` has a peer dependency on `vue@^3.0.0` (Not v2) and doesn't currently plan to\n> be backwards compatible to Vue 2.\n"
  },
  {
    "path": "packages/vue-urql/jsr.json",
    "content": "{\n  \"name\": \"@urql/vue\",\n  \"version\": \"2.0.0\",\n  \"exports\": {\n    \".\": \"./src/index.ts\"\n  },\n  \"exclude\": [\n    \"node_modules\",\n    \"cypress\",\n    \"**/*.test.*\",\n    \"**/*.spec.*\",\n    \"**/*.test.*.snap\",\n    \"**/*.spec.*.snap\"\n  ]\n}"
  },
  {
    "path": "packages/vue-urql/package.json",
    "content": "{\n  \"name\": \"@urql/vue\",\n  \"version\": \"2.0.0\",\n  \"description\": \"A highly customizable and versatile GraphQL client for vue\",\n  \"sideEffects\": false,\n  \"homepage\": \"https://formidable.com/open-source/urql/docs/\",\n  \"bugs\": \"https://github.com/urql-graphql/urql/issues\",\n  \"license\": \"MIT\",\n  \"author\": \"urql GraphQL Contributors\",\n  \"repository\": {\n    \"type\": \"git\",\n    \"url\": \"https://github.com/urql-graphql/urql.git\",\n    \"directory\": \"packages/vue-urql\"\n  },\n  \"keywords\": [\n    \"graphql client\",\n    \"state management\",\n    \"cache\",\n    \"graphql\",\n    \"exchanges\",\n    \"vue\"\n  ],\n  \"main\": \"dist/urql-vue\",\n  \"module\": \"dist/urql-vue.mjs\",\n  \"types\": \"dist/urql-vue.d.ts\",\n  \"source\": \"src/index.ts\",\n  \"exports\": {\n    \".\": {\n      \"types\": \"./dist/urql-vue.d.ts\",\n      \"import\": \"./dist/urql-vue.mjs\",\n      \"require\": \"./dist/urql-vue.js\",\n      \"source\": \"./src/index.ts\"\n    },\n    \"./package.json\": \"./package.json\"\n  },\n  \"files\": [\n    \"LICENSE\",\n    \"CHANGELOG.md\",\n    \"README.md\",\n    \"dist/\"\n  ],\n  \"scripts\": {\n    \"test\": \"vitest\",\n    \"clean\": \"rimraf dist\",\n    \"check\": \"tsc --noEmit\",\n    \"lint\": \"eslint --ext=js,jsx,ts,tsx .\",\n    \"build\": \"rollup -c ../../scripts/rollup/config.mjs\",\n    \"prepare\": \"node ../../scripts/prepare/index.js\",\n    \"prepublishOnly\": \"run-s clean build\"\n  },\n  \"devDependencies\": {\n    \"@urql/core\": \"workspace:*\",\n    \"@vue/test-utils\": \"^2.3.0\",\n    \"graphql\": \"^16.0.0\",\n    \"vue\": \"^3.2.47\"\n  },\n  \"peerDependencies\": {\n    \"@urql/core\": \"^6.0.0\",\n    \"vue\": \"^3.2.0\"\n  },\n  \"dependencies\": {\n    \"@urql/core\": \"workspace:^6.0.1\",\n    \"wonka\": \"^6.3.2\"\n  },\n  \"publishConfig\": {\n    \"access\": \"public\",\n    \"provenance\": true\n  }\n}\n"
  },
  {
    "path": "packages/vue-urql/src/index.ts",
    "content": "export * from '@urql/core';\n\nexport * from './useClientHandle';\nexport { install, provideClient } from './useClient';\n\nexport { useQuery } from './useQuery';\n\nexport type { UseQueryArgs, UseQueryResponse, UseQueryState } from './useQuery';\n\nexport { useSubscription } from './useSubscription';\n\nexport type {\n  UseSubscriptionArgs,\n  UseSubscriptionResponse,\n  SubscriptionHandlerArg,\n  SubscriptionHandler,\n} from './useSubscription';\n\nexport { useMutation } from './useMutation';\n\nexport type { UseMutationResponse } from './useMutation';\n\nimport { install } from './useClient';\n\nexport default install;\n"
  },
  {
    "path": "packages/vue-urql/src/useClient.test.ts",
    "content": "// @vitest-environment jsdom\n\nimport { expect, it, describe } from 'vitest';\nimport { defineComponent, effectScope, h } from 'vue';\nimport { mount } from '@vue/test-utils';\nimport { Client } from '@urql/core';\nimport { useClient, provideClient } from './useClient';\n\ndescribe('provideClient and useClient', () => {\n  it('provides client to current component instance', async () => {\n    const TestComponent = defineComponent({\n      setup() {\n        provideClient(\n          new Client({\n            url: 'test',\n            exchanges: [],\n          })\n        );\n\n        const client = useClient();\n        expect(client).toBeDefined();\n        return null;\n      },\n    });\n\n    mount(TestComponent);\n  });\n\n  it('provides client to child components via provide/inject', async () => {\n    const ChildComponent = defineComponent({\n      setup() {\n        const client = useClient();\n        expect(client).toBeDefined();\n        return () => null;\n      },\n    });\n\n    const ParentComponent = defineComponent({\n      components: { ChildComponent },\n      setup() {\n        provideClient(\n          new Client({\n            url: 'test',\n            exchanges: [],\n          })\n        );\n        return () => h(ChildComponent);\n      },\n    });\n\n    mount(ParentComponent);\n  });\n\n  it('works in effect scopes outside components', () => {\n    const scope = effectScope();\n\n    scope.run(() => {\n      provideClient(\n        new Client({\n          url: 'test',\n          exchanges: [],\n        })\n      );\n\n      const client = useClient();\n      expect(client).toBeDefined();\n    });\n  });\n\n  it('throws error when no client is provided', () => {\n    expect(() => {\n      const TestComponent = defineComponent({\n        setup() {\n          // No provideClient called\n          useClient(); // Should throw\n          return null;\n        },\n      });\n\n      mount(TestComponent);\n    }).toThrow('No urql Client was provided');\n  });\n\n  it('throws error when called outside reactive context', () => {\n    expect(() => {\n      // Called outside any component or scope\n      useClient();\n    }).toThrow('reactive context');\n  });\n});\n"
  },
  {
    "path": "packages/vue-urql/src/useClient.ts",
    "content": "import { type App, getCurrentScope, type Ref } from 'vue';\nimport { inject, provide, isRef, shallowRef } from 'vue';\nimport type { ClientOptions } from '@urql/core';\nimport { Client } from '@urql/core';\n\n// WeakMap to store client instances as fallback when client is provided and used in the same component\nconst clientsPerScope = new WeakMap<{}, Ref<Client>>();\n\n/** Provides a {@link Client} to a component and it’s children.\n *\n * @param opts - {@link ClientOptions}, a {@link Client}, or a reactive ref object of a `Client`.\n *\n * @remarks\n * `provideClient` provides a {@link Client} to `@urql/vue`’s GraphQL\n * functions in children components.\n *\n * Hint: GraphQL functions and {@link useClient} will see the\n * provided `Client`, even if `provideClient` has been called\n * in the same component’s `setup` function.\n *\n * @example\n * ```ts\n * <script setup>\n *   import { provideClient } from '@urql/vue';\n *   // All of `@urql/core` is also re-exported by `@urql/vue`:\n *   import { Client, cacheExchange, fetchExchange } from '@urql/core';\n *\n *   provideClient(new Client({\n *     url: 'https://API',\n *     exchanges: [cacheExchange, fetchExchange],\n *   }));\n * </script>\n * ```\n */\nexport function provideClient(opts: ClientOptions | Client | Ref<Client>) {\n  let client: Ref<Client>;\n  if (!isRef(opts)) {\n    client = shallowRef(opts instanceof Client ? opts : new Client(opts));\n  } else {\n    client = opts;\n  }\n\n  const scope = getCurrentScope();\n  if (scope) {\n    clientsPerScope.set(scope, client);\n  }\n\n  provide('$urql', client);\n  return client.value;\n}\n\n/** Provides a {@link Client} to a Vue app.\n *\n * @param app - the Vue {@link App}\n * @param opts - {@link ClientOptions}, a {@link Client}, or a reactive ref object of a `Client`.\n *\n * @remarks\n * `install` provides a {@link Client} to `@urql/vue`’s GraphQL\n * functions in a Vue app.\n *\n * @example\n * ```ts\n * import * as urql from '@urql/vue';\n * // All of `@urql/core` is also re-exported by `@urql/vue`:\n * import { cacheExchange, fetchExchange } from '@urql/core';\n *\n * import { createApp } from 'vue';\n * import Root from './App.vue';\n *\n * const app = createApp(Root);\n * app.use(urql, {\n *   url: 'http://localhost:3000/graphql',\n *   exchanges: [cacheExchange, fetchExchange],\n * });\n * ```\n */\nexport function install(app: App, opts: ClientOptions | Client | Ref<Client>) {\n  let client: Ref<Client>;\n  if (!isRef(opts)) {\n    client = shallowRef(opts instanceof Client ? opts : new Client(opts));\n  } else {\n    client = opts;\n  }\n  app.provide('$urql', client);\n}\n\n/** Returns a provided reactive ref object of a {@link Client}.\n *\n * @remarks\n * `useClient` may be called in a reactive context to retrieve a\n * reactive ref object of a {@link Client} that’s previously been\n * provided with {@link provideClient} in the current or a parent’s\n * `setup` function.\n *\n * @throws\n * In development, if `useClient` is called outside of a reactive context\n * or no {@link Client} was provided, an error will be thrown.\n */\nexport function useClient(): Ref<Client> {\n  const scope = getCurrentScope();\n  if (process.env.NODE_ENV !== 'production' && !scope) {\n    throw new Error(\n      'use* function must be called within a reactive context (component setup, composable, or effect scope).'\n    );\n  }\n\n  let client = inject('$urql') as Ref<Client> | undefined;\n  if (!client) {\n    client = clientsPerScope.get(scope!);\n  }\n\n  if (process.env.NODE_ENV !== 'production' && !client) {\n    throw new Error(\n      'No urql Client was provided. Did you forget to install the plugin or call `provideClient` in a parent?'\n    );\n  }\n\n  return client!;\n}\n"
  },
  {
    "path": "packages/vue-urql/src/useClientHandle.ts",
    "content": "import type { AnyVariables, Client, DocumentInput } from '@urql/core';\nimport type { WatchStopHandle } from 'vue';\nimport { getCurrentInstance, onMounted, onBeforeUnmount } from 'vue';\n\nimport { useClient } from './useClient';\n\nimport type { UseQueryArgs, UseQueryResponse } from './useQuery';\nimport { callUseQuery } from './useQuery';\n\nimport type { UseMutationResponse } from './useMutation';\nimport { callUseMutation } from './useMutation';\n\nimport type {\n  UseSubscriptionArgs,\n  SubscriptionHandlerArg,\n  UseSubscriptionResponse,\n} from './useSubscription';\nimport { callUseSubscription } from './useSubscription';\n\n/** Handle to create GraphQL operations outside of Vue’s `setup` functions.\n *\n * @remarks\n * The `ClientHandle` object is created inside a Vue `setup` function but\n * allows its methods to be called outside of `setup` functions, delaying\n * the creation of GraphQL operations, as an alternative to pausing queries\n * or subscriptions.\n *\n * This is also important when chaining multiple functions inside an\n * `async setup()` function.\n *\n * Hint: If you only need a single, non-updating result and want to execute\n * queries programmatically, it may be easier to call the {@link Client.query}\n * method.\n */\nexport interface ClientHandle {\n  /** The {@link Client} that’ll be used to execute GraphQL operations. */\n  client: Client;\n\n  /** Calls {@link useQuery} outside of a synchronous Vue `setup` function.\n   *\n   * @param args - a {@link UseQueryArgs} object, to pass a `query`, `variables`, and options.\n   * @returns a {@link UseQueryResponse} object.\n   *\n   * @remarks\n   * Creates a {@link UseQueryResponse} outside of a synchronous Vue `setup`\n   * function or when chained in an `async setup()` function.\n   */\n  useQuery<T = any, V extends AnyVariables = AnyVariables>(\n    args: UseQueryArgs<T, V>\n  ): UseQueryResponse<T, V>;\n\n  /** Calls {@link useSubscription} outside of a synchronous Vue `setup` function.\n   *\n   * @param args - a {@link UseSubscriptionArgs} object, to pass a `query`, `variables`, and options.\n   * @param handler - optionally, a {@link SubscriptionHandler} function to combine multiple subscription results.\n   * @returns a {@link UseSubscriptionResponse} object.\n   *\n   * @remarks\n   * Creates a {@link UseSubscriptionResponse} outside of a synchronous Vue `setup`\n   * function or when chained in an `async setup()` function.\n   */\n  useSubscription<T = any, R = T, V extends AnyVariables = AnyVariables>(\n    args: UseSubscriptionArgs<T, V>,\n    handler?: SubscriptionHandlerArg<T, R>\n  ): UseSubscriptionResponse<T, R, V>;\n\n  /** Calls {@link useMutation} outside of a synchronous Vue `setup` function.\n   *\n   * @param query - a GraphQL mutation document which `useMutation` will execute.\n   * @returns a {@link UseMutationResponse} object.\n   *\n   * @remarks\n   * Creates a {@link UseMutationResponse} outside of a synchronous Vue `setup`\n   * function or when chained in an `async setup()` function.\n   */\n  useMutation<T = any, V extends AnyVariables = AnyVariables>(\n    query: DocumentInput<T, V>\n  ): UseMutationResponse<T, V>;\n}\n\n/** Creates a {@link ClientHandle} inside a Vue `setup` function.\n *\n * @remarks\n * `useClientHandle` creates and returns a {@link ClientHandle}\n * when called in a Vue `setup` function, which allows queries,\n * mutations, and subscriptions to be created _outside_ of\n * `setup` functions.\n *\n * This is also important when chaining multiple functions inside an\n * `async setup()` function.\n *\n * {@link useQuery} and other GraphQL functions must usually\n * be created in Vue `setup` functions so they can stop GraphQL\n * operations when your component unmounts. However, while they\n * queries and subscriptions can be paused, sometimes it’s easier\n * to delay the creation of their response objects.\n *\n *\n * @example\n * ```ts\n * import { ref, computed } from 'vue';\n * import { gql, useClientHandle } from '@urql/vue';\n *\n * export default {\n *   async setup() {\n *     const handle = useClientHandle();\n *\n *     const pokemons = await handle.useQuery({\n *       query: gql`{ pokemons(limit: 10) { id, name } }`,\n *     });\n *\n *     const index = ref(0);\n *\n *     // The `handle` allows another `useQuery` call to now be setup again\n *     const pokemon = await handle.useQuery({\n *       query: gql`\n *         query ($id: ID!) {\n *           pokemon(id: $id) { id, name }\n *         }\n *       `,\n *       variables: computed(() => ({\n *         id: pokemons.data.value.pokemons[index.value].id,\n *       }),\n *     });\n *   }\n * };\n * ```\n */\nexport function useClientHandle(): ClientHandle {\n  const client = useClient();\n  const stops: WatchStopHandle[] = [];\n\n  onBeforeUnmount(() => {\n    let stop: WatchStopHandle | void;\n    while ((stop = stops.shift())) stop();\n  });\n\n  const handle: ClientHandle = {\n    client: client.value,\n\n    useQuery<T = any, V extends AnyVariables = AnyVariables>(\n      args: UseQueryArgs<T, V>\n    ): UseQueryResponse<T, V> {\n      return callUseQuery(args, client, stops);\n    },\n\n    useSubscription<T = any, R = T, V extends AnyVariables = AnyVariables>(\n      args: UseSubscriptionArgs<T, V>,\n      handler?: SubscriptionHandlerArg<T, R>\n    ): UseSubscriptionResponse<T, R, V> {\n      return callUseSubscription(args, handler, client, stops);\n    },\n\n    useMutation<T = any, V extends AnyVariables = AnyVariables>(\n      query: DocumentInput<T, V>\n    ): UseMutationResponse<T, V> {\n      return callUseMutation(query, client);\n    },\n  };\n\n  if (process.env.NODE_ENV !== 'production') {\n    onMounted(() => {\n      Object.assign(handle, {\n        useQuery<T = any, V extends AnyVariables = AnyVariables>(\n          args: UseQueryArgs<T, V>\n        ): UseQueryResponse<T, V> {\n          if (process.env.NODE_ENV !== 'production' && !getCurrentInstance()) {\n            throw new Error(\n              '`handle.useQuery()` should only be called in the `setup()` or a lifecycle hook.'\n            );\n          }\n\n          return callUseQuery(args, client, stops);\n        },\n\n        useSubscription<T = any, R = T, V extends AnyVariables = AnyVariables>(\n          args: UseSubscriptionArgs<T, V>,\n          handler?: SubscriptionHandlerArg<T, R>\n        ): UseSubscriptionResponse<T, R, V> {\n          if (process.env.NODE_ENV !== 'production' && !getCurrentInstance()) {\n            throw new Error(\n              '`handle.useSubscription()` should only be called in the `setup()` or a lifecycle hook.'\n            );\n          }\n\n          return callUseSubscription(args, handler, client, stops);\n        },\n      });\n    });\n  }\n\n  return handle;\n}\n"
  },
  {
    "path": "packages/vue-urql/src/useMutation.test.ts",
    "content": "import { OperationResult, OperationResultSource } from '@urql/core';\nimport { readonly } from 'vue';\nimport { vi, expect, it, beforeEach, describe } from 'vitest';\n\nvi.mock('./useClient.ts', async () => {\n  const { ref } = await vi.importActual<typeof import('vue')>('vue');\n  return {\n    __esModule: true,\n    ...((await vi.importActual('./useClient.ts')) as object),\n    useClient: () => ref(client),\n  };\n});\n\nimport { makeSubject } from 'wonka';\nimport { createClient, gql } from '@urql/core';\nimport { useMutation } from './useMutation';\n\nconst client = createClient({ url: '/graphql', exchanges: [] });\n\nbeforeEach(() => {\n  vi.resetAllMocks();\n});\n\ndescribe('useMutation', () => {\n  it('provides an execute method that resolves a promise', async () => {\n    const subject = makeSubject<any>();\n    const clientMutation = vi\n      .spyOn(client, 'executeMutation')\n      .mockImplementation(\n        () => subject.source as OperationResultSource<OperationResult>\n      );\n\n    const mutation = useMutation(gql`\n      mutation {\n        test\n      }\n    `);\n\n    expect(readonly(mutation)).toMatchObject({\n      data: undefined,\n      stale: false,\n      fetching: false,\n      error: undefined,\n      extensions: undefined,\n      operation: undefined,\n      executeMutation: expect.any(Function),\n    });\n\n    const promise = mutation.executeMutation({ test: true });\n\n    expect(mutation.fetching.value).toBe(true);\n    expect(mutation.stale.value).toBe(false);\n    expect(mutation.error.value).toBe(undefined);\n\n    expect(clientMutation).toHaveBeenCalledTimes(1);\n\n    subject.next({ data: { test: true }, stale: false });\n\n    await promise;\n    expect(mutation.fetching.value).toBe(false);\n    expect(mutation.stale.value).toBe(false);\n    expect(mutation.error.value).toBe(undefined);\n    expect(mutation.data.value).toHaveProperty('test', true);\n  });\n});\n"
  },
  {
    "path": "packages/vue-urql/src/useMutation.ts",
    "content": "/* eslint-disable react-hooks/rules-of-hooks */\n\nimport type { Ref } from 'vue';\nimport { shallowRef } from 'vue';\nimport { pipe, onPush, filter, toPromise, take } from 'wonka';\n\nimport type {\n  Client,\n  AnyVariables,\n  CombinedError,\n  Operation,\n  OperationContext,\n  OperationResult,\n  DocumentInput,\n} from '@urql/core';\n\nimport { useClient } from './useClient';\nimport {\n  createRequestWithArgs,\n  type MaybeRefOrGetter,\n  useRequestState,\n} from './utils';\n\n/** State of the last mutation executed by {@link useMutation}.\n *\n * @remarks\n * `UseMutationResponse` is returned by {@link useMutation} and\n * gives you the {@link OperationResult} of the last executed mutation,\n * and a {@link UseMutationResponse.executeMutation} method to\n * start mutations.\n *\n * Even if the mutation document passed to {@link useMutation} changes,\n * the state isn’t reset, so you can keep displaying the previous result.\n */\nexport interface UseMutationResponse<T, V extends AnyVariables = AnyVariables> {\n  /** Indicates whether `useMutation` is currently executing a mutation. */\n  fetching: Ref<boolean>;\n  /** Indicates that the mutation result is not fresh.\n   *\n   * @remarks\n   * The `stale` flag is set to `true` when a new result for the mutation\n   * is expected.\n   * This is mostly unused for mutations and will rarely affect you, and\n   * is more relevant for queries.\n   *\n   * @see {@link OperationResult.stale} for the source of this value.\n   */\n  stale: Ref<boolean>;\n  /** Reactive {@link OperationResult.data} for the executed mutation. */\n  data: Ref<T | undefined>;\n  /** Reactive {@link OperationResult.error} for the executed mutation. */\n  error: Ref<CombinedError | undefined>;\n  /** Reactive {@link OperationResult.extensions} for the executed mutation. */\n  extensions: Ref<Record<string, any> | undefined>;\n  /** Reactive {@link Operation} that the current state is for.\n   *\n   * @remarks\n   * This is the mutation {@link Operation} that has last been executed.\n   * When {@link UseQueryState.fetching} is `true`, this is the\n   * last `Operation` that the current state was for.\n   */\n  operation: Ref<Operation<T, V> | undefined>;\n  /** The {@link OperationResult.hasNext} for the executed query. */\n  hasNext: Ref<boolean>;\n  /** Triggers {@link useMutation} to execute its GraphQL mutation operation.\n   *\n   * @param variables - variables using which the mutation will be executed.\n   * @param context - optionally, context options that will be merged with\n   * the `Client`’s options.\n   * @returns the {@link OperationResult} of the mutation.\n   *\n   * @remarks\n   * When called, {@link useMutation} will start the GraphQL mutation\n   * it currently holds and use the `variables` passed to it.\n   *\n   * Once the mutation response comes back from the API, its\n   * returned promise will resolve to the mutation’s {@link OperationResult}\n   * and the {@link UseMutationResponse} will be updated with the result.\n   *\n   * @example\n   * ```ts\n   * const result = useMutation(UpdateTodo);\n   * const start = async ({ id, title }) => {\n   *   const result = await result.executeMutation({ id, title });\n   * };\n   */\n  executeMutation(\n    variables: V,\n    context?: Partial<OperationContext>\n  ): Promise<OperationResult<T>>;\n}\n\n/** Function to create a GraphQL mutation, run by passing variables to {@link UseMutationResponse.executeMutation}\n *\n * @param query - a GraphQL mutation document which `useMutation` will execute.\n * @returns a {@link UseMutationResponse} object.\n *\n * @remarks\n * `useMutation` allows GraphQL mutations to be defined inside Vue `setup` functions,\n * and keeps its state after the mutation is started. Mutations can be started by calling\n * {@link UseMutationResponse.executeMutation} with variables.\n *\n * The returned result updates when a mutation is executed and keeps\n * track of the last mutation result.\n *\n * @see {@link https://urql.dev/goto/docs/basics/vue#mutations} for `useMutation` docs.\n *\n * @example\n * ```ts\n * import { gql, useMutation } from '@urql/vue';\n *\n * const UpdateTodo = gql`\n *   mutation ($id: ID!, $title: String!) {\n *     updateTodo(id: $id, title: $title) {\n *       id, title\n *     }\n *   }\n * `;\n *\n * export default {\n *   setup() {\n *     const result = useMutation(UpdateTodo);\n *     const start = async ({ id, title }) => {\n *       const result = await result.executeMutation({ id, title });\n *     };\n *     // ...\n *   },\n * };\n * ```\n */\nexport function useMutation<T = any, V extends AnyVariables = AnyVariables>(\n  query: DocumentInput<T, V>\n): UseMutationResponse<T, V> {\n  return callUseMutation(query);\n}\n\nexport function callUseMutation<T = any, V extends AnyVariables = AnyVariables>(\n  query: MaybeRefOrGetter<DocumentInput<T, V>>,\n  client: Ref<Client> = useClient()\n): UseMutationResponse<T, V> {\n  const data: Ref<T | undefined> = shallowRef();\n\n  const { fetching, operation, extensions, stale, error, hasNext } =\n    useRequestState<T, V>();\n\n  return {\n    data,\n    stale,\n    fetching,\n    error,\n    operation,\n    extensions,\n    hasNext,\n    executeMutation(\n      variables: V,\n      context?: Partial<OperationContext>\n    ): Promise<OperationResult<T, V>> {\n      fetching.value = true;\n\n      return pipe(\n        client.value.executeMutation<T, V>(\n          createRequestWithArgs<T, V>({ query, variables }),\n          context || {}\n        ),\n        onPush(result => {\n          data.value = result.data;\n          stale.value = result.stale;\n          fetching.value = false;\n          error.value = result.error;\n          operation.value = result.operation;\n          extensions.value = result.extensions;\n          hasNext.value = result.hasNext;\n        }),\n        filter(result => !result.hasNext),\n        take(1),\n        toPromise\n      );\n    },\n  };\n}\n"
  },
  {
    "path": "packages/vue-urql/src/useQuery.test.ts",
    "content": "import {\n  OperationResult,\n  OperationResultSource,\n  RequestPolicy,\n} from '@urql/core';\nimport { computed, nextTick, reactive, readonly, ref } from 'vue';\nimport { vi, expect, it, describe } from 'vitest';\n\nvi.mock('./useClient.ts', async () => ({\n  __esModule: true,\n  ...(await vi.importActual<typeof import('./useClient')>('./useClient.ts')),\n  useClient: () => ref(client),\n}));\n\nimport { pipe, makeSubject, fromValue, delay } from 'wonka';\nimport { createClient } from '@urql/core';\nimport { useQuery, UseQueryArgs } from './useQuery';\n\nconst client = createClient({ url: '/graphql', exchanges: [] });\n\nconst createQuery = (args: UseQueryArgs) => {\n  const executeQuery = vi\n    .spyOn(client, 'executeQuery')\n    .mockImplementation(request => {\n      return pipe(\n        fromValue({ operation: request, data: { test: true } }),\n        delay(1)\n      ) as any;\n    });\n\n  const query$ = useQuery(args);\n\n  return {\n    query$,\n    executeQuery,\n  };\n};\n\ndescribe('useQuery', () => {\n  it('runs a query and updates data', async () => {\n    const subject = makeSubject<any>();\n    const executeQuery = vi\n      .spyOn(client, 'executeQuery')\n      .mockImplementation(\n        () => subject.source as OperationResultSource<OperationResult>\n      );\n\n    const query = useQuery({\n      query: `{ test }`,\n    });\n\n    expect(readonly(query)).toMatchObject({\n      data: undefined,\n      stale: false,\n      fetching: true,\n      error: undefined,\n      extensions: undefined,\n      operation: undefined,\n      isPaused: false,\n      pause: expect.any(Function),\n      resume: expect.any(Function),\n      executeQuery: expect.any(Function),\n      then: expect.any(Function),\n    });\n\n    expect(executeQuery).toHaveBeenCalledWith(\n      {\n        key: expect.any(Number),\n        query: expect.any(Object),\n        variables: {},\n        context: undefined,\n      },\n      {\n        requestPolicy: undefined,\n      }\n    );\n\n    expect(query.fetching.value).toBe(true);\n\n    subject.next({ data: { test: true } });\n\n    expect(query.fetching.value).toBe(false);\n    expect(query.data.value).toHaveProperty('test', true);\n  });\n\n  it('runs queries as a promise-like that resolves when used', async () => {\n    const executeQuery = vi\n      .spyOn(client, 'executeQuery')\n      .mockImplementation(() => {\n        return pipe(fromValue({ data: { test: true } }), delay(1)) as any;\n      });\n\n    const query = await useQuery({\n      query: `{ test }`,\n    });\n\n    expect(executeQuery).toHaveBeenCalledTimes(1);\n    expect(query.fetching.value).toBe(false);\n    expect(query.data.value).toEqual({ test: true });\n  });\n\n  it('runs queries as a promise-like that resolves even when the query changes', async () => {\n    const doc = ref('{ test }');\n\n    const { executeQuery, query$ } = createQuery({\n      query: doc,\n    });\n\n    doc.value = '{ test2 }';\n\n    await query$;\n\n    expect(executeQuery).toHaveBeenCalledTimes(2);\n    expect(query$.fetching.value).toBe(false);\n    expect(query$.data.value).toEqual({ test: true });\n\n    expect(query$.operation.value).toHaveProperty(\n      'query.definitions.0.selectionSet.selections.0.name.value',\n      'test2'\n    );\n  });\n\n  it('reacts to ref variables changing', async () => {\n    const variables = ref({ prop: 1 });\n\n    const { executeQuery, query$ } = createQuery({\n      query: ref('{ test }'),\n      variables,\n    });\n\n    await query$;\n    expect(executeQuery).toHaveBeenCalledTimes(1);\n    expect(query$.operation.value).toHaveProperty('variables.prop', 1);\n\n    variables.value.prop++;\n    await query$;\n    expect(executeQuery).toHaveBeenCalledTimes(2);\n    expect(query$.operation.value).toHaveProperty('variables.prop', 2);\n\n    variables.value = { prop: 3 };\n    await query$;\n    expect(executeQuery).toHaveBeenCalledTimes(3);\n    expect(query$.operation.value).toHaveProperty('variables.prop', 3);\n  });\n\n  it('reacts to ref variables changing', async () => {\n    const foo = ref(1);\n    const bar = ref(1);\n\n    const { executeQuery, query$ } = createQuery({\n      query: ref('{ test }'),\n      variables: ref({\n        prop: foo,\n        nested: {\n          prop: bar,\n        },\n      }),\n    });\n\n    await query$;\n    expect(executeQuery).toHaveBeenCalledTimes(1);\n    expect(query$.operation.value).toHaveProperty('variables.prop', 1);\n\n    foo.value++;\n    await query$;\n    expect(executeQuery).toHaveBeenCalledTimes(2);\n    expect(query$.operation.value).toHaveProperty('variables.prop', 2);\n\n    bar.value++;\n    await query$;\n    expect(executeQuery).toHaveBeenCalledTimes(3);\n    expect(query$.operation.value).toHaveProperty('variables.nested.prop', 2);\n  });\n\n  it('reacts to getter variables changing', async () => {\n    const foo = ref(1);\n    const bar = ref(1);\n\n    const { executeQuery, query$ } = createQuery({\n      query: ref('{ test }'),\n      variables: () => ({\n        prop: foo.value,\n        nested: {\n          prop: bar.value,\n        },\n      }),\n    });\n\n    await query$;\n    expect(executeQuery).toHaveBeenCalledTimes(1);\n    expect(query$.operation.value).toHaveProperty('variables.prop', 1);\n\n    foo.value++;\n    await query$;\n    expect(executeQuery).toHaveBeenCalledTimes(2);\n    expect(query$.operation.value).toHaveProperty('variables.prop', 2);\n\n    bar.value++;\n    await query$;\n    expect(executeQuery).toHaveBeenCalledTimes(3);\n    expect(query$.operation.value).toHaveProperty('variables.nested.prop', 2);\n  });\n\n  it('reacts to reactive variables changing', async () => {\n    const prop = ref(1);\n    const variables = reactive({ prop: 1, deep: { nested: { prop } } });\n\n    const { executeQuery, query$ } = createQuery({\n      query: ref('{ test }'),\n      variables,\n    });\n\n    await query$;\n    expect(executeQuery).toHaveBeenCalledTimes(1);\n    expect(query$.operation.value).toHaveProperty('variables.prop', 1);\n\n    variables.prop++;\n    await query$;\n    expect(executeQuery).toHaveBeenCalledTimes(2);\n    expect(query$.operation.value).toHaveProperty('variables.prop', 2);\n\n    prop.value++;\n    await query$;\n    expect(executeQuery).toHaveBeenCalledTimes(3);\n    expect(query$.operation.value).toHaveProperty(\n      'variables.deep.nested.prop',\n      2\n    );\n  });\n\n  it('reacts to computed variables changing', async () => {\n    const foo = ref(1);\n    const bar = ref(1);\n    const variables = computed(() => ({\n      prop: foo.value,\n      deep: { nested: { prop: bar.value } },\n    }));\n\n    const { executeQuery, query$ } = createQuery({\n      query: ref('{ test }'),\n      variables,\n    });\n\n    await query$;\n    expect(executeQuery).toHaveBeenCalledTimes(1);\n    expect(query$.operation.value).toHaveProperty('variables.prop', 1);\n\n    foo.value++;\n    await query$;\n    expect(executeQuery).toHaveBeenCalledTimes(2);\n    expect(query$.operation.value).toHaveProperty('variables.prop', 2);\n\n    bar.value++;\n    await query$;\n    expect(executeQuery).toHaveBeenCalledTimes(3);\n    expect(query$.operation.value).toHaveProperty(\n      'variables.deep.nested.prop',\n      2\n    );\n  });\n\n  it('reacts to reactive context argument', async () => {\n    const context = ref<{ requestPolicy: RequestPolicy }>({\n      requestPolicy: 'cache-only',\n    });\n\n    const { executeQuery, query$ } = createQuery({\n      query: ref('{ test }'),\n      context,\n    });\n\n    await query$;\n    expect(executeQuery).toHaveBeenCalledTimes(1);\n\n    context.value.requestPolicy = 'network-only';\n    await query$;\n    expect(executeQuery).toHaveBeenCalledTimes(2);\n  });\n\n  it('reacts to callback context argument', async () => {\n    const requestPolicy = ref<RequestPolicy>('cache-only');\n\n    const { executeQuery, query$ } = createQuery({\n      query: ref('{ test }'),\n      context: () => ({\n        requestPolicy: requestPolicy.value,\n      }),\n    });\n\n    await query$;\n    expect(executeQuery).toHaveBeenCalledTimes(1);\n\n    requestPolicy.value = 'network-only';\n    await query$;\n    expect(executeQuery).toHaveBeenCalledTimes(2);\n  });\n\n  it('pauses query when asked to do so', async () => {\n    const subject = makeSubject<any>();\n    const executeQuery = vi\n      .spyOn(client, 'executeQuery')\n      .mockImplementation(\n        () => subject.source as OperationResultSource<OperationResult>\n      );\n\n    const query = useQuery({\n      query: `{ test }`,\n      pause: true,\n    });\n\n    expect(executeQuery).not.toHaveBeenCalled();\n\n    query.resume();\n    await nextTick();\n    expect(query.fetching.value).toBe(true);\n\n    subject.next({ data: { test: true } });\n\n    expect(query.fetching.value).toBe(false);\n    expect(query.data.value).toHaveProperty('test', true);\n  });\n\n  it('pauses query with ref variable', async () => {\n    const pause = ref(true);\n\n    const { executeQuery, query$ } = createQuery({\n      query: ref('{ test }'),\n      pause,\n    });\n\n    await query$;\n    expect(executeQuery).not.toHaveBeenCalled();\n\n    pause.value = false;\n    await query$;\n    expect(executeQuery).toHaveBeenCalledTimes(1);\n\n    query$.pause();\n    query$.resume();\n    await query$;\n    expect(executeQuery).toHaveBeenCalledTimes(2);\n  });\n\n  it('pauses query with computed variable', async () => {\n    const pause = ref(true);\n\n    const { executeQuery, query$ } = createQuery({\n      query: ref('{ test }'),\n      pause: computed(() => pause.value),\n    });\n\n    await query$;\n    expect(executeQuery).not.toHaveBeenCalled();\n\n    pause.value = false;\n    await query$;\n    expect(executeQuery).toHaveBeenCalledTimes(1);\n\n    query$.pause();\n    query$.resume();\n    await query$;\n    // this shouldn't be called, as pause/resume functionality should works in sync with passed `pause` variable, e.g.:\n    // if we pass readonly computed variable, then we want to make sure that its value fully controls the state of the request.\n    expect(executeQuery).toHaveBeenCalledTimes(1);\n  });\n\n  it('pauses query with callback', async () => {\n    const pause = ref(true);\n\n    const { executeQuery, query$ } = createQuery({\n      query: ref('{ test }'),\n      pause: () => pause.value,\n    });\n\n    await query$;\n    expect(executeQuery).not.toHaveBeenCalled();\n\n    pause.value = false;\n    await query$;\n    expect(executeQuery).toHaveBeenCalledTimes(1);\n\n    query$.pause();\n    query$.resume();\n    await query$;\n    // the same as computed variable example - user has full control over the request state if using callback\n    expect(executeQuery).toHaveBeenCalledTimes(1);\n  });\n});\n"
  },
  {
    "path": "packages/vue-urql/src/useQuery.ts",
    "content": "/* eslint-disable react-hooks/rules-of-hooks */\n\nimport type { Ref, WatchStopHandle } from 'vue';\nimport { shallowRef, watchEffect } from 'vue';\n\nimport type { Subscription } from 'wonka';\nimport { pipe, subscribe, onEnd } from 'wonka';\n\nimport type {\n  Client,\n  AnyVariables,\n  GraphQLRequestParams,\n  CombinedError,\n  OperationContext,\n  RequestPolicy,\n  Operation,\n} from '@urql/core';\n\nimport { useClient } from './useClient';\n\nimport type { MaybeRefOrGetter, MaybeRefOrGetterObj } from './utils';\nimport { useRequestState, useClientState } from './utils';\n\n/** Input arguments for the {@link useQuery} function.\n *\n * @param query - The GraphQL query that `useQuery` executes.\n * @param variables - The variables for the GraphQL query that `useQuery` executes.\n */\nexport type UseQueryArgs<\n  Data = any,\n  Variables extends AnyVariables = AnyVariables,\n> = {\n  /** Updates the {@link RequestPolicy} for the executed GraphQL query operation.\n   *\n   * @remarks\n   * `requestPolicy` modifies the {@link RequestPolicy} of the GraphQL query operation\n   * that `useQuery` executes, and indicates a caching strategy for cache exchanges.\n   *\n   * For example, when set to `'cache-and-network'`, {@link useQuery} will\n   * receive a cached result with `stale: true` and an API request will be\n   * sent in the background.\n   *\n   * @see {@link OperationContext.requestPolicy} for where this value is set.\n   */\n  requestPolicy?: MaybeRefOrGetter<RequestPolicy>;\n  /** Updates the {@link OperationContext} for the executed GraphQL query operation.\n   *\n   * @remarks\n   * `context` may be passed to {@link useQuery}, to update the {@link OperationContext}\n   * of a query operation. This may be used to update the `context` that exchanges\n   * will receive for a single hook.\n   *\n   * @example\n   * ```ts\n   * const result = useQuery({\n   *   query,\n   *   context: {\n   *     additionalTypenames: ['Item'],\n   *   },\n   * });\n   * ```\n   */\n  context?: MaybeRefOrGetter<Partial<OperationContext>>;\n  /** Prevents {@link useQuery} from automatically executing GraphQL query operations.\n   *\n   * @remarks\n   * `pause` may be set to `true` to stop {@link useQuery} from executing\n   * automatically. This will pause the query until {@link UseQueryState.resume}\n   * is called, or, if `pause` is a reactive ref of a boolean, until this\n   * ref changes to `true`.\n   *\n   * @see {@link https://urql.dev/goto/docs/basics/vue#pausing-usequery} for\n   * documentation on the `pause` option.\n   */\n  pause?: MaybeRefOrGetter<boolean>;\n} & MaybeRefOrGetterObj<GraphQLRequestParams<Data, Variables>>;\n\n/** State of the current query, your {@link useQuery} function is executing.\n *\n * @remarks\n * `UseQueryState` is returned by {@link useQuery} and\n * gives you the updating {@link OperationResult} of\n * GraphQL queries.\n *\n * Each value that is part of the result is wrapped in a reactive ref\n * and updates as results come in.\n *\n * Hint: Even when the query and variables update, the previous state of\n * the last result is preserved, which allows you to display the\n * previous state, while implementing a loading indicator separately.\n */\nexport interface UseQueryState<T = any, V extends AnyVariables = AnyVariables> {\n  /** Indicates whether `useQuery` is waiting for a new result.\n   *\n   * @remarks\n   * When `useQuery` receives a new query and/or variables, it will\n   * start executing the new query operation and `fetching` is set to\n   * `true` until a result arrives.\n   *\n   * Hint: This is subtly different than whether the query is actually\n   * fetching, and doesn’t indicate whether a query is being re-executed\n   * in the background. For this, see {@link UseQueryState.stale}.\n   */\n  fetching: Ref<boolean>;\n  /** Indicates that the state is not fresh and a new result will follow.\n   *\n   * @remarks\n   * The `stale` flag is set to `true` when a new result for the query\n   * is expected and `useQuery` is waiting for it. This may indicate that\n   * a new request is being requested in the background.\n   *\n   * @see {@link OperationResult.stale} for the source of this value.\n   */\n  stale: Ref<boolean>;\n  /** Reactive {@link OperationResult.data} for the executed query. */\n  data: Ref<T | undefined>;\n  /** Reactive {@link OperationResult.error} for the executed query. */\n  error: Ref<CombinedError | undefined>;\n  /** Reactive {@link OperationResult.extensions} for the executed query. */\n  extensions: Ref<Record<string, any> | undefined>;\n  /** Reactive {@link Operation} that the current state is for.\n   *\n   * @remarks\n   * This is the {@link Operation} that is currently being executed.\n   * When {@link UseQueryState.fetching} is `true`, this is the\n   * last `Operation` that the current state was for.\n   */\n  operation: Ref<Operation<T, V> | undefined>;\n  /** Indicates whether {@link useQuery} is currently paused.\n   *\n   * @remarks\n   * When `useQuery` has been paused, it will stop receiving updates\n   * from the {@link Client} and won’t execute query operations, until\n   * {@link UseQueryArgs.pause} becomes `true` or {@link UseQueryState.resume}\n   * is called.\n   *\n   * @see {@link https://urql.dev/goto/docs/basics/vue#pausing-usequery} for\n   * documentation on the `pause` option.\n   */\n  isPaused: Ref<boolean>;\n  /** The {@link OperationResult.hasNext} for the executed query. */\n  hasNext: Ref<boolean>;\n  /** Resumes {@link useQuery} if it’s currently paused.\n   *\n   * @remarks\n   * Resumes or starts {@link useQuery}’s query, if it’s currently paused.\n   *\n   * @see {@link https://urql.dev/goto/docs/basics/vue#pausing-usequery} for\n   * documentation on the `pause` option.\n   */\n  resume(): void;\n  /** Pauses {@link useQuery} to stop it from executing the query.\n   *\n   * @remarks\n   * Pauses {@link useQuery}’s query, which stops it from receiving updates\n   * from the {@link Client} and to stop the ongoing query operation.\n   *\n   * @see {@link https://urql.dev/goto/docs/basics/vue#pausing-usequery} for\n   * documentation on the `pause` option.\n   */\n  pause(): void;\n  /** Triggers {@link useQuery} to execute a new GraphQL query operation.\n   *\n   * @param opts - optionally, context options that will be merged with\n   * {@link UseQueryArgs.context} and the `Client`’s options.\n   *\n   * @remarks\n   * When called, {@link useQuery} will re-execute the GraphQL query operation\n   * it currently holds, unless it’s currently paused.\n   *\n   * This is useful for re-executing a query and get a new network result,\n   * by passing a new request policy.\n   *\n   * ```ts\n   * const result = useQuery({ query });\n   *\n   * const refresh = () => {\n   *   // Re-execute the query with a network-only policy, skipping the cache\n   *   result.executeQuery({ requestPolicy: 'network-only' });\n   * };\n   * ```\n   */\n  executeQuery(opts?: Partial<OperationContext>): UseQueryResponse<T, V>;\n}\n\n/** Return value of {@link useQuery}, which is an awaitable {@link UseQueryState}.\n *\n * @remarks\n * {@link useQuery} returns a {@link UseQueryState} but may also be\n * awaited inside a Vue `async setup()` function. If it’s awaited\n * the query is executed before resolving.\n */\nexport type UseQueryResponse<\n  T,\n  V extends AnyVariables = AnyVariables,\n> = UseQueryState<T, V> & PromiseLike<UseQueryState<T, V>>;\n\n/** Function to run a GraphQL query and get reactive GraphQL results.\n *\n * @param args - a {@link UseQueryArgs} object, to pass a `query`, `variables`, and options.\n * @returns a {@link UseQueryResponse} object.\n *\n * @remarks\n * `useQuery` allows GraphQL queries to be defined and executed inside\n * Vue `setup` functions.\n * Given {@link UseQueryArgs.query}, it executes the GraphQL query with the\n * provided {@link Client}.\n *\n * The returned result’s reactive values update when the `Client` has\n * new results for the query, and changes when your input `args` change.\n *\n * Additionally, `useQuery` may also be awaited inside an `async setup()`\n * function to use Vue’s Suspense feature.\n *\n * @see {@link https://urql.dev/goto/docs/basics/vue#queries} for `useQuery` docs.\n *\n * @example\n * ```ts\n * import { gql, useQuery } from '@urql/vue';\n *\n * const TodosQuery = gql`\n *   query { todos { id, title } }\n * `;\n *\n * export default {\n *   setup() {\n *     const result = useQuery({ query: TodosQuery });\n *     return { data: result.data };\n *   },\n * };\n * ```\n */\nexport function useQuery<T = any, V extends AnyVariables = AnyVariables>(\n  args: UseQueryArgs<T, V>\n): UseQueryResponse<T, V> {\n  return callUseQuery(args);\n}\n\nexport function callUseQuery<T = any, V extends AnyVariables = AnyVariables>(\n  args: UseQueryArgs<T, V>,\n  client: Ref<Client> = useClient(),\n  stops?: WatchStopHandle[]\n): UseQueryResponse<T, V> {\n  const data: Ref<T | undefined> = shallowRef();\n\n  const { fetching, operation, extensions, stale, error, hasNext } =\n    useRequestState<T, V>();\n\n  const { isPaused, source, pause, resume, execute, teardown } = useClientState<\n    T,\n    V\n  >(args, client, 'executeQuery');\n\n  const teardownQuery = watchEffect(\n    onInvalidate => {\n      if (source.value) {\n        fetching.value = true;\n        stale.value = false;\n\n        onInvalidate(\n          pipe(\n            source.value,\n            onEnd(() => {\n              fetching.value = false;\n              stale.value = false;\n              hasNext.value = false;\n            }),\n            subscribe(res => {\n              data.value = res.data;\n              stale.value = !!res.stale;\n              fetching.value = false;\n              error.value = res.error;\n              operation.value = res.operation;\n              extensions.value = res.extensions;\n              hasNext.value = res.hasNext;\n            })\n          ).unsubscribe\n        );\n      } else {\n        fetching.value = false;\n        stale.value = false;\n        hasNext.value = false;\n      }\n    },\n    {\n      // NOTE: This part of the query pipeline is only initialised once and will need\n      // to do so synchronously\n      flush: 'sync',\n    }\n  );\n\n  stops && stops.push(teardown, teardownQuery);\n\n  const then: UseQueryResponse<T, V>['then'] = (onFulfilled, onRejected) => {\n    let sub: Subscription | void;\n\n    const promise = new Promise<UseQueryState<T, V>>(resolve => {\n      if (!source.value) {\n        return resolve(state);\n      }\n      let hasResult = false;\n      sub = pipe(\n        source.value,\n        subscribe(() => {\n          if (!state.fetching.value && !state.stale.value) {\n            if (sub) sub.unsubscribe();\n            hasResult = true;\n            resolve(state);\n          }\n        })\n      );\n      if (hasResult) sub.unsubscribe();\n    });\n\n    return promise.then(onFulfilled, onRejected);\n  };\n\n  const state: UseQueryState<T, V> = {\n    data,\n    stale,\n    error,\n    operation,\n    extensions,\n    fetching,\n    isPaused,\n    hasNext,\n    pause,\n    resume,\n    executeQuery(opts?: Partial<OperationContext>): UseQueryResponse<T, V> {\n      execute(opts);\n      return { ...state, then };\n    },\n  };\n\n  return { ...state, then };\n}\n"
  },
  {
    "path": "packages/vue-urql/src/useSubscription.test.ts",
    "content": "// @vitest-environment jsdom\n\nimport { OperationResult, OperationResultSource } from '@urql/core';\nimport { nextTick, readonly, ref } from 'vue';\nimport { vi, expect, it, describe } from 'vitest';\n\nvi.mock('./useClient.ts', async () => ({\n  __esModule: true,\n  ...(await vi.importActual<typeof import('./useClient')>('./useClient.ts')),\n  useClient: () => ref(client),\n}));\n\nimport { makeSubject } from 'wonka';\nimport { createClient } from '@urql/core';\nimport { useSubscription } from './useSubscription';\n\nconst client = createClient({ url: '/graphql', exchanges: [] });\n\ndescribe('useSubscription', () => {\n  it('subscribes to a subscription and updates data', async () => {\n    const subject = makeSubject<any>();\n    const executeQuery = vi\n      .spyOn(client, 'executeSubscription')\n      .mockImplementation(\n        () => subject.source as OperationResultSource<OperationResult>\n      );\n\n    const sub = useSubscription({\n      query: `{ test }`,\n    });\n\n    expect(readonly(sub)).toMatchObject({\n      data: undefined,\n      stale: false,\n      fetching: true,\n      error: undefined,\n      extensions: undefined,\n      operation: undefined,\n      isPaused: false,\n      pause: expect.any(Function),\n      resume: expect.any(Function),\n      executeSubscription: expect.any(Function),\n    });\n\n    expect(executeQuery).toHaveBeenCalledWith(\n      {\n        key: expect.any(Number),\n        query: expect.any(Object),\n        variables: {},\n      },\n      expect.any(Object)\n    );\n\n    expect(sub.fetching.value).toBe(true);\n\n    subject.next({ data: { test: true } });\n    expect(sub.data.value).toHaveProperty('test', true);\n\n    subject.complete();\n    expect(sub.fetching.value).toBe(false);\n  });\n\n  it('updates the executed subscription when inputs change', async () => {\n    const subject = makeSubject<any>();\n    const executeSubscription = vi\n      .spyOn(client, 'executeSubscription')\n      .mockImplementation(\n        () => subject.source as OperationResultSource<OperationResult>\n      );\n\n    const variables = ref({});\n    const sub = useSubscription({\n      query: `{ test }`,\n      variables,\n    });\n\n    expect(executeSubscription).toHaveBeenCalledWith(\n      {\n        key: expect.any(Number),\n        query: expect.any(Object),\n        variables: {},\n      },\n      expect.any(Object)\n    );\n\n    subject.next({ data: { test: true } });\n    expect(sub.data.value).toHaveProperty('test', true);\n\n    variables.value = { test: true };\n    await nextTick();\n    expect(executeSubscription).toHaveBeenCalledTimes(2);\n    expect(executeSubscription).toHaveBeenCalledWith(\n      {\n        key: expect.any(Number),\n        query: expect.any(Object),\n        variables: { test: true },\n      },\n      expect.any(Object)\n    );\n\n    expect(sub.fetching.value).toBe(true);\n    expect(sub.data.value).toHaveProperty('test', true);\n  });\n\n  it('supports a custom scanning handler', async () => {\n    const subject = makeSubject<any>();\n    const executeSubscription = vi\n      .spyOn(client, 'executeSubscription')\n      .mockImplementation(\n        () => subject.source as OperationResultSource<OperationResult>\n      );\n\n    const scanHandler = (currentState: any, nextState: any) => ({\n      counter: (currentState ? currentState.counter : 0) + nextState.counter,\n    });\n\n    const sub = useSubscription(\n      {\n        query: `subscription { counter }`,\n      },\n      scanHandler\n    );\n\n    expect(executeSubscription).toHaveBeenCalledWith(\n      {\n        key: expect.any(Number),\n        query: expect.any(Object),\n        variables: {},\n      },\n      expect.any(Object)\n    );\n\n    subject.next({ data: { counter: 1 } });\n    expect(sub.data.value).toHaveProperty('counter', 1);\n\n    subject.next({ data: { counter: 2 } });\n    expect(sub.data.value).toHaveProperty('counter', 3);\n  });\n});\n"
  },
  {
    "path": "packages/vue-urql/src/useSubscription.ts",
    "content": "/* eslint-disable react-hooks/rules-of-hooks */\n\nimport { pipe, subscribe, onEnd } from 'wonka';\n\nimport type { Ref, WatchStopHandle } from 'vue';\nimport { shallowRef, isRef, watchEffect } from 'vue';\n\nimport type {\n  Client,\n  GraphQLRequestParams,\n  AnyVariables,\n  CombinedError,\n  OperationContext,\n  Operation,\n} from '@urql/core';\n\nimport { useClient } from './useClient';\n\nimport type { MaybeRefOrGetter, MaybeRefOrGetterObj } from './utils';\nimport { useRequestState, useClientState } from './utils';\n\n/** Input arguments for the {@link useSubscription} function.\n *\n * @param query - The GraphQL subscription document that `useSubscription` executes.\n * @param variables - The variables for the GraphQL subscription that `useSubscription` executes.\n */\nexport type UseSubscriptionArgs<\n  Data = any,\n  Variables extends AnyVariables = AnyVariables,\n> = {\n  /** Prevents {@link useSubscription} from automatically executing GraphQL subscription operations.\n   *\n   * @remarks\n   * `pause` may be set to `true` to stop {@link useSubscription} from starting\n   * its subscription automatically. This will pause the subscription until\n   * {@link UseSubscriptionResponse.resume} is called, or, if `pause` is a reactive\n   * ref of a boolean, until this ref changes to `true`.\n   */\n  pause?: MaybeRefOrGetter<boolean>;\n  /** Updates the {@link OperationContext} for the executed GraphQL subscription operation.\n   *\n   * @remarks\n   * `context` may be passed to {@link useSubscription}, to update the {@link OperationContext}\n   * of a subscription operation. This may be used to update the `context` that exchanges\n   * will receive for a single hook.\n   *\n   * @example\n   * ```ts\n   * const result = useQuery({\n   *   query,\n   *   context: {\n   *     additionalTypenames: ['Item'],\n   *   },\n   * });\n   * ```\n   */\n  context?: MaybeRefOrGetter<Partial<OperationContext>>;\n} & MaybeRefOrGetterObj<GraphQLRequestParams<Data, Variables>>;\n\n/** Combines previous data with an incoming subscription result’s data.\n *\n * @remarks\n * A `SubscriptionHandler` may be passed to {@link useSubscription} to\n * aggregate subscription results into a combined {@link UseSubscriptionResponse.data}\n * value.\n *\n * This is useful when a subscription event delivers a single item, while\n * you’d like to display a list of events.\n *\n * @example\n * ```ts\n * const NotificationsSubscription = gql`\n *   subscription { newNotification { id, text } }\n * `;\n *\n * const combineNotifications = (notifications = [], data) => {\n *   return [...notifications, data.newNotification];\n * };\n *\n * const result = useSubscription(\n *   { query: NotificationsSubscription },\n *   combineNotifications,\n * );\n * ```\n */\nexport type SubscriptionHandler<T, R> = (prev: R | undefined, data: T) => R;\n\n/** A {@link SubscriptionHandler} or a reactive ref of one. */\nexport type SubscriptionHandlerArg<T, R> =\n  | Ref<SubscriptionHandler<T, R>>\n  | SubscriptionHandler<T, R>;\n\n/** State of the current query, your {@link useSubscription} function is executing.\n *\n * @remarks\n * `UseSubscriptionResponse` is returned by {@link useSubscription} and\n * gives you the updating {@link OperationResult} of GraphQL subscriptions.\n *\n * Each value that is part of the result is wrapped in a reactive ref\n * and updates as results come in.\n *\n * Hint: Even when the query and variables update, the prior state of\n * the last result is preserved.\n */\nexport interface UseSubscriptionResponse<\n  T = any,\n  R = T,\n  V extends AnyVariables = AnyVariables,\n> {\n  /** Indicates whether `useSubscription`’s subscription is active.\n   *\n   * @remarks\n   * When `useSubscription` starts a subscription, the `fetching` flag\n   * is set to `true` and will remain `true` until the subscription\n   * completes on the API, or `useSubscription` is paused.\n   */\n  fetching: Ref<boolean>;\n  /** Indicates that the subscription result is not fresh.\n   *\n   * @remarks\n   * This is mostly unused for subscriptions and will rarely affect you, and\n   * is more relevant for queries.\n   *\n   * @see {@link OperationResult.stale} for the source of this value.\n   */\n  stale: Ref<boolean>;\n  /** Reactive {@link OperationResult.data} for the executed subscription, or data returned by the handler.\n   *\n   * @remarks\n   * `data` will be set to the last {@link OperationResult.data} value\n   * received for the subscription.\n   *\n   * It will instead be set to the values that {@link SubscriptionHandler}\n   * returned, if a handler has been passed to {@link useSubscription}.\n   */\n  data: Ref<R | undefined>;\n  /** Reactive {@link OperationResult.error} for the executed subscription. */\n  error: Ref<CombinedError | undefined>;\n  /** Reactive {@link OperationResult.extensions} for the executed mutation. */\n  extensions: Ref<Record<string, any> | undefined>;\n  /** Reactive {@link Operation} that the current state is for.\n   *\n   * @remarks\n   * This is the subscription {@link Operation} that is currently active.\n   * When {@link UseSubscriptionResponse.fetching} is `true`, this is the\n   * last `Operation` that the current state was for.\n   */\n  operation: Ref<Operation<T, V> | undefined>;\n  /** Indicates whether {@link useSubscription} is currently paused.\n   *\n   * @remarks\n   * When `useSubscription` has been paused, it will stop receiving updates\n   * from the {@link Client} and won’t execute the subscription, until\n   * {@link UseSubscriptionArgs.pause} becomes true or\n   * {@link UseSubscriptionResponse.resume} is called.\n   */\n  isPaused: Ref<boolean>;\n  /** Resumes {@link useSubscription} if it’s currently paused.\n   *\n   * @remarks\n   * Resumes or starts {@link useSubscription}’s subscription, if it’s currently paused.\n   */\n  resume(): void;\n  /** Pauses {@link useSubscription} to stop the subscription.\n   *\n   * @remarks\n   * Pauses {@link useSubscription}’s subscription, which stops it\n   * from receiving updates from the {@link Client} and to stop executing\n   * the subscription operation.\n   */\n  pause(): void;\n  /** Triggers {@link useQuery} to reexecute a GraphQL subscription operation.\n   *\n   * @param opts - optionally, context options that will be merged with\n   * {@link UseQueryArgs.context} and the `Client`’s options.\n   *\n   * @remarks\n   * When called, {@link useSubscription} will re-execute the GraphQL subscription\n   * operation it currently holds, unless it’s currently paused.\n   */\n  executeSubscription(opts?: Partial<OperationContext>): void;\n}\n\n/** Function to run a GraphQL subscription and get reactive GraphQL results.\n *\n * @param args - a {@link UseSubscriptionArgs} object, to pass a `query`, `variables`, and options.\n * @param handler - optionally, a {@link SubscriptionHandler} function to combine multiple subscription results.\n * @returns a {@link UseSubscriptionResponse} object.\n *\n * @remarks\n * `useSubscription` allows GraphQL subscriptions to be defined and executed inside\n * Vue `setup` functions.\n * Given {@link UseSubscriptionArgs.query}, it executes the GraphQL subscription with the\n * provided {@link Client}.\n *\n * The returned result updates when the `Client` has new results\n * for the subscription, and `data` is updated with the result’s data\n * or with the `data` that a `handler` returns.\n *\n * @example\n * ```ts\n * import { gql, useSubscription } from '@urql/vue';\n *\n * const NotificationsSubscription = gql`\n *   subscription { newNotification { id, text } }\n * `;\n *\n * export default {\n *   setup() {\n *     const result = useSubscription(\n *       { query: NotificationsSubscription },\n *       function combineNotifications(notifications = [], data) {\n *         return [...notifications, data.newNotification];\n *       },\n *     );\n *     // ...\n *   },\n * };\n * ```\n */\nexport function useSubscription<\n  T = any,\n  R = T,\n  V extends AnyVariables = AnyVariables,\n>(\n  args: UseSubscriptionArgs<T, V>,\n  handler?: SubscriptionHandlerArg<T, R>\n): UseSubscriptionResponse<T, R, V> {\n  return callUseSubscription(args, handler);\n}\n\nexport function callUseSubscription<\n  T = any,\n  R = T,\n  V extends AnyVariables = AnyVariables,\n>(\n  args: UseSubscriptionArgs<T, V>,\n  handler?: SubscriptionHandlerArg<T, R>,\n  client: Ref<Client> = useClient(),\n  stops?: WatchStopHandle[]\n): UseSubscriptionResponse<T, R, V> {\n  const data: Ref<R | undefined> = shallowRef();\n\n  const { fetching, operation, extensions, stale, error } = useRequestState<\n    T,\n    V\n  >();\n\n  const { isPaused, source, pause, resume, execute, teardown } = useClientState<\n    T,\n    V\n  >(args, client, 'executeSubscription');\n\n  const teardownSubscription = watchEffect(onInvalidate => {\n    if (source.value) {\n      fetching.value = true;\n\n      onInvalidate(\n        pipe(\n          source.value,\n          onEnd(() => {\n            fetching.value = false;\n          }),\n          subscribe(result => {\n            fetching.value = true;\n            error.value = result.error;\n            extensions.value = result.extensions;\n            stale.value = !!result.stale;\n            operation.value = result.operation;\n\n            if (result.data != null && handler) {\n              const cb = isRef(handler) ? handler.value : handler;\n              if (typeof cb === 'function') {\n                data.value = cb(data.value, result.data);\n                return;\n              }\n            }\n            data.value = result.data as R;\n          })\n        ).unsubscribe\n      );\n    } else {\n      fetching.value = false;\n    }\n  });\n\n  stops && stops.push(teardown, teardownSubscription);\n\n  const state: UseSubscriptionResponse<T, R, V> = {\n    data,\n    stale,\n    error,\n    operation,\n    extensions,\n    fetching,\n    isPaused,\n    pause,\n    resume,\n    executeSubscription(\n      opts?: Partial<OperationContext>\n    ): UseSubscriptionResponse<T, R, V> {\n      execute(opts);\n      return state;\n    },\n  };\n\n  return state;\n}\n"
  },
  {
    "path": "packages/vue-urql/src/utils.ts",
    "content": "import type {\n  AnyVariables,\n  Client,\n  CombinedError,\n  DocumentInput,\n  GraphQLRequest,\n  Operation,\n  OperationContext,\n  OperationResult,\n  OperationResultSource,\n} from '@urql/core';\nimport { createRequest } from '@urql/core';\nimport { type Ref, unref } from 'vue';\nimport { watchEffect, isReadonly, computed, ref, shallowRef, isRef } from 'vue';\nimport type { UseSubscriptionArgs } from './useSubscription';\nimport type { UseQueryArgs } from './useQuery';\n\nexport type MaybeRefOrGetter<T> = T | (() => T) | Ref<T>;\nexport type MaybeRefOrGetterObj<T extends {}> =\n  T extends Record<string, never>\n    ? T\n    : { [K in keyof T]: MaybeRefOrGetter<T[K]> };\n\nconst isFunction = <T>(val: MaybeRefOrGetter<T>): val is () => T =>\n  typeof val === 'function';\n\nconst toValue = <T>(source: MaybeRefOrGetter<T>): T =>\n  isFunction(source) ? source() : unref(source);\n\nexport const createRequestWithArgs = <\n  T = any,\n  V extends AnyVariables = AnyVariables,\n>(\n  args:\n    | UseQueryArgs<T, V>\n    | UseSubscriptionArgs<T, V>\n    | { query: MaybeRefOrGetter<DocumentInput<T, V>>; variables: V }\n): GraphQLRequest<T, V> => {\n  const _args = toValue(args);\n  return createRequest<T, V>(\n    toValue(_args.query),\n    toValue(_args.variables as MaybeRefOrGetter<V>)\n  );\n};\n\nexport const useRequestState = <\n  T = any,\n  V extends AnyVariables = AnyVariables,\n>() => {\n  const hasNext: Ref<boolean> = ref(false);\n  const stale: Ref<boolean> = ref(false);\n  const fetching: Ref<boolean> = ref(false);\n  const error: Ref<CombinedError | undefined> = shallowRef();\n  const operation: Ref<Operation<T, V> | undefined> = shallowRef();\n  const extensions: Ref<Record<string, any> | undefined> = shallowRef();\n  return {\n    hasNext,\n    stale,\n    fetching,\n    error,\n    operation,\n    extensions,\n  };\n};\n\nexport function useClientState<T = any, V extends AnyVariables = AnyVariables>(\n  args: UseQueryArgs<T, V> | UseSubscriptionArgs<T, V>,\n  client: Ref<Client>,\n  method: keyof Pick<Client, 'executeSubscription' | 'executeQuery'>\n) {\n  const source: Ref<OperationResultSource<OperationResult<T, V>> | undefined> =\n    shallowRef();\n\n  const isPaused: Ref<boolean> = isRef(args.pause)\n    ? args.pause\n    : typeof args.pause === 'function'\n      ? computed(args.pause)\n      : ref(!!args.pause);\n\n  const request = computed(() => createRequestWithArgs<T, V>(args));\n\n  const requestOptions = computed(() => {\n    return 'requestPolicy' in args\n      ? {\n          requestPolicy: toValue(args.requestPolicy),\n          ...toValue(args.context),\n        }\n      : {\n          ...toValue(args.context),\n        };\n  });\n\n  const pause = () => {\n    if (!isReadonly(isPaused)) {\n      isPaused.value = true;\n    }\n  };\n\n  const resume = () => {\n    if (!isReadonly(isPaused)) {\n      isPaused.value = false;\n    }\n  };\n\n  const executeRaw = (opts?: Partial<OperationContext>) => {\n    return client.value[method]<T, V>(request.value, {\n      ...requestOptions.value,\n      ...opts,\n    });\n  };\n\n  const execute = (opts?: Partial<OperationContext>) => {\n    source.value = executeRaw(opts);\n  };\n\n  // it's important to use `watchEffect()` here instead of `watch()`\n  // because it listening for reactive variables inside `executeRaw()` function\n  const teardown = watchEffect(() => {\n    source.value = !isPaused.value ? executeRaw() : undefined;\n  });\n\n  return {\n    source,\n    isPaused,\n    pause,\n    resume,\n    execute,\n    teardown,\n  };\n}\n"
  },
  {
    "path": "packages/vue-urql/tsconfig.json",
    "content": "{\n  \"extends\": \"../../tsconfig.json\",\n  \"include\": [\"src\"]\n}\n"
  },
  {
    "path": "packages/vue-urql/vitest.config.ts",
    "content": "import { mergeConfig } from 'vitest/config';\nimport baseConfig from '../../vitest.config';\n\nexport default mergeConfig(baseConfig, {});\n"
  },
  {
    "path": "pnpm-workspace.yaml",
    "content": "packages:\n  - 'packages/*'\n  - 'exchanges/*'\n  - '!examples/*'\n"
  },
  {
    "path": "scripts/actions/build-all.mjs",
    "content": "#!/usr/bin/env node\n\nimport { listPackages } from './lib/packages.mjs';\nimport { buildPackage } from './lib/commands.mjs';\n\n(async () => {\n  try {\n    const packages = await listPackages();\n    const builds = packages.map(buildPackage);\n    await Promise.all(builds);\n  } catch (e) {\n    console.error(e.message);\n    process.exit(1);\n  }\n})();\n"
  },
  {
    "path": "scripts/actions/lib/commands.mjs",
    "content": "import * as stream from 'stream';\nimport * as path from 'path';\nimport * as fs from 'fs';\nimport { promisify } from 'util';\n\nimport * as tar from 'tar';\nimport { execa, execaNode } from 'execa';\nimport Arborist from '@npmcli/arborist';\nimport packlist from 'npm-packlist';\n\nimport { workspaceRoot, require } from './constants.mjs';\nimport { getPackageManifest, getPackageArtifact } from './packages.mjs';\n\nconst pipeline = promisify(stream.pipeline);\n\nconst buildPackage = async cwd => {\n  const manifest = getPackageManifest(cwd);\n  console.log('> Building', manifest.name);\n\n  try {\n    await execa('run-s', ['build'], {\n      preferLocal: true,\n      localDir: workspaceRoot,\n      cwd,\n    });\n  } catch (error) {\n    console.error('> Build failed', manifest.name);\n    throw error;\n  }\n};\n\nconst preparePackage = async cwd => {\n  const manifest = getPackageManifest(cwd);\n  console.log('> Preparing', manifest.name);\n\n  try {\n    await execaNode(require.resolve('../../prepare/index.js'), { cwd });\n  } catch (error) {\n    console.error('> Preparing failed', manifest.name);\n    throw error;\n  }\n};\n\nconst packPackage = async cwd => {\n  const manifest = getPackageManifest(cwd);\n  const artifact = getPackageArtifact(cwd);\n  console.log('> Packing', manifest.name);\n\n  const arborist = new Arborist({ path: cwd });\n  const tree = await arborist.loadActual();\n\n  try {\n    await pipeline(\n      tar.create(\n        {\n          cwd,\n          prefix: 'package/',\n          portable: true,\n          gzip: true,\n        },\n        (await packlist(tree)).map(f => `./${f}`)\n      ),\n      fs.createWriteStream(path.resolve(cwd, artifact))\n    );\n  } catch (error) {\n    console.error('> Packing failed', manifest.name);\n    throw error;\n  }\n};\n\nexport { buildPackage, preparePackage, packPackage };\n"
  },
  {
    "path": "scripts/actions/lib/constants.mjs",
    "content": "import * as url from 'url';\nimport * as path from 'path';\nimport { createRequire } from 'node:module';\n\nconst __dirname = path.dirname(url.fileURLToPath(import.meta.url));\nexport const workspaceRoot = path.resolve(__dirname, '../../../');\n\nexport const workspaces = ['packages/*', 'exchanges/*'];\n\nexport const require = createRequire(import.meta.url);\n"
  },
  {
    "path": "scripts/actions/lib/github.mjs",
    "content": "import * as path from 'path';\nimport { getPackageManifest, getPackageArtifact } from './packages.mjs';\nimport { DefaultArtifactClient } from '@actions/artifact';\n\nexport const uploadArtifact = async cwd => {\n  const manifest = getPackageManifest(cwd);\n  const artifact = getPackageArtifact(cwd);\n  console.log('> Uploading', manifest.name);\n\n  try {\n    const client = new DefaultArtifactClient();\n    await client.uploadArtifact(artifact, [path.resolve(cwd, artifact)], cwd, {\n      continueOnError: false,\n    });\n  } catch (error) {\n    console.error('> Uploading failed', manifest.name);\n    throw error;\n  }\n};\n"
  },
  {
    "path": "scripts/actions/lib/packages.mjs",
    "content": "import * as path from 'path';\nimport * as fs from 'fs/promises';\nimport glob from 'glob';\n\nimport { workspaceRoot, workspaces, require } from './constants.mjs';\n\nconst getPackageManifest = cwd => require(path.resolve(cwd, 'package.json'));\n\nconst updatePackageManifest = async (cwd, manifest) => {\n  const sortDependencies = dependencies => {\n    if (dependencies == null) return undefined;\n    return Object.keys(dependencies)\n      .sort()\n      .reduce((acc, key) => {\n        acc[key] = dependencies[key];\n        return acc;\n      }, {});\n  };\n\n  try {\n    if (!!getPackageManifest(cwd)) {\n      manifest.dependencies = sortDependencies(manifest.dependencies);\n      manifest.devDependencies = sortDependencies(manifest.devDependencies);\n      await fs.writeFile(\n        path.resolve(cwd, 'package.json'),\n        JSON.stringify(manifest, null, 2) + '\\n'\n      );\n    }\n  } catch (_error) {\n    throw new Error('package.json does not exist in: ' + cwd);\n  }\n};\n\nconst getPackageArtifact = cwd => {\n  const pkg = getPackageManifest(cwd);\n  const name =\n    pkg.name[0] === '@' ? pkg.name.slice(1).replace(/\\//g, '-') : pkg.name;\n  return `${name}-v${pkg.version}.tgz`;\n};\n\nconst listPackages = async () => {\n  let manifests = await Promise.all(\n    workspaces.map(dir => glob(`${dir}/package.json`))\n  );\n\n  manifests = manifests.reduce((acc, manifests) => {\n    acc.push(...manifests);\n    return acc;\n  }, []);\n\n  let packages = manifests\n    .filter(pkg => !require(path.join(workspaceRoot, pkg)).private)\n    .map(pkg => path.resolve(pkg, '../'));\n\n  if (process.env.NODE_TOTAL) {\n    const nodeTotal = parseInt(process.env.NODE_TOTAL, 10) || 1;\n    const nodeIndex = parseInt(process.env.NODE_INDEX, 10) % nodeTotal;\n    packages = packages.filter((_, i) => i % nodeTotal === nodeIndex);\n    console.log(`> Node ${nodeIndex + 1} of ${nodeTotal}.`);\n  }\n\n  return packages;\n};\n\nconst listArtifacts = async () => {\n  return (await listPackages()).map(cwd => {\n    const artifact = getPackageArtifact(cwd);\n    return path.resolve(cwd, artifact);\n  });\n};\n\nexport {\n  getPackageManifest,\n  updatePackageManifest,\n  getPackageArtifact,\n  listPackages,\n  listArtifacts,\n};\n"
  },
  {
    "path": "scripts/actions/pack-all.mjs",
    "content": "#!/usr/bin/env node\n\nimport { listPackages } from './lib/packages.mjs';\nimport { preparePackage, packPackage } from './lib/commands.mjs';\nimport { uploadArtifact } from './lib/github.mjs';\n\n(async () => {\n  try {\n    const isPR = process.env.GITHUB_EVENT_NAME === 'pull_request';\n    const packages = await listPackages();\n    const packs = packages.map(async cwd => {\n      await preparePackage(cwd);\n      await packPackage(cwd);\n      if (isPR) {\n        await uploadArtifact(cwd);\n      }\n    });\n\n    await Promise.all(packs);\n  } catch (e) {\n    console.error(e.message);\n    process.exit(1);\n  }\n})();\n"
  },
  {
    "path": "scripts/babel/transform-debug-target.mjs",
    "content": "const visited = 'visitedByDebugTargetTransformer';\n\nconst warningDevCheckTemplate = `\n  process.env.NODE_ENV !== 'production' ? NODE : undefined\n`.trim();\n\nconst plugin = ({ template, types: t }) => {\n  const wrapWithDevCheck = template.expression(warningDevCheckTemplate, {\n    placeholderPattern: /^NODE$/,\n  });\n\n  let name = 'unknownExchange';\n\n  return {\n    visitor: {\n      ExportNamedDeclaration(path) {\n        if (\n          path.node.declaration &&\n          path.node.declaration.declarations &&\n          path.node.declaration.declarations[0] &&\n          path.node.declaration.declarations[0].id\n        ) {\n          const exportName = path.node.declaration.declarations[0].id.name;\n          if (/Exchange$/i.test(exportName)) name = exportName;\n        }\n      },\n      CallExpression(path, meta) {\n        if (path.node[visited] || !path.node.callee) return;\n\n        if (path.node.callee.name === 'dispatchDebug') {\n          path.node[visited] = true;\n          if (\n            t.isObjectExpression(path.node.arguments[0]) &&\n            !meta.filename.endsWith('compose.ts')\n          ) {\n            path.node.arguments[0].properties.push(\n              t.objectProperty(t.stringLiteral('source'), t.stringLiteral(name))\n            );\n          }\n\n          path.replaceWith(wrapWithDevCheck({ NODE: path.node }));\n        }\n      },\n    },\n  };\n};\n\nexport default plugin;\n"
  },
  {
    "path": "scripts/babel/transform-invariant-warning.mjs",
    "content": "const visited = 'visitedByInvariantWarningTransformer';\n\nconst warningDevCheckTemplate = `\n  if (process.env.NODE_ENV !== 'production') {\n    NODE;\n  }\n`.trim();\n\nconst plugin = ({ template, types: t }) => {\n  const wrapWithDevCheck = template(warningDevCheckTemplate, {\n    placeholderPattern: /^NODE$/,\n  });\n\n  return {\n    visitor: {\n      CallExpression(path) {\n        const { name } = path.node.callee;\n        if (\n          (name === 'warn' || name === 'deprecationWarning') &&\n          !path.node[visited]\n        ) {\n          path.node[visited] = true;\n\n          // The production-check may be hoisted if the parent\n          // is already an if-statement only containing the\n          // warn call\n          let p = path;\n          while (t.isExpressionStatement(p.parentPath.node)) {\n            if (\n              t.isBlockStatement(p.parentPath.parentPath.node) &&\n              p.parentPath.parentPath.node.body.length === 1 &&\n              p.parentPath.parentPath.node.body[0] === path.parentPath.node &&\n              t.isIfStatement(p.parentPath.parentPath.parentPath.node) &&\n              p.parentPath.parentPath.parentPath.node.consequent ===\n                p.parentPath.parentPath.node &&\n              !p.parentPath.parentPath.node.alternate\n            ) {\n              p = p.parentPath.parentPath.parentPath;\n            } else if (\n              t.isIfStatement(p.parentPath.parentPath.node) &&\n              p.parentPath.parentPath.node.consequent === p.parentPath.node &&\n              !p.parentPath.parentPath.node.alternate\n            ) {\n              p = path.parentPath.parentPath;\n            } else {\n              break;\n            }\n          }\n\n          p.replaceWith(wrapWithDevCheck({ NODE: p.node }));\n        } else if (name === 'invariant' && !path.node[visited]) {\n          path.node[visited] = true;\n          const formerNode = path.node.arguments[1];\n          path.node.arguments[1] = t.conditionalExpression(\n            t.binaryExpression(\n              '!==',\n              t.memberExpression(\n                t.memberExpression(\n                  t.identifier('process'),\n                  t.identifier('env')\n                ),\n                t.identifier('NODE_ENV')\n              ),\n              t.stringLiteral('production')\n            ),\n            formerNode,\n            t.stringLiteral('')\n          );\n        }\n      },\n    },\n  };\n};\n\nexport default plugin;\n"
  },
  {
    "path": "scripts/babel/transform-pipe.mjs",
    "content": "const pipeExpression = (t, pipeline) => {\n  let x = pipeline[0];\n  for (let i = 1; i < pipeline.length; i++)\n    x = t.callExpression(pipeline[i], [x]);\n  return x;\n};\n\nconst pipePlugin = ({ types: t }) => ({\n  visitor: {\n    ImportDeclaration(path, state) {\n      if (path.node.source.value === 'wonka') {\n        const { specifiers } = path.node;\n        const pipeSpecifierIndex = specifiers.findIndex(spec => {\n          return spec.imported.name === 'pipe';\n        });\n\n        if (pipeSpecifierIndex > -1) {\n          const pipeSpecifier = specifiers[pipeSpecifierIndex];\n          state.pipeName = pipeSpecifier.local.name;\n          if (specifiers.length > 1) {\n            path.node.specifiers.splice(pipeSpecifierIndex, 1);\n          } else {\n            path.remove();\n          }\n        }\n      }\n    },\n    CallExpression(path, state) {\n      if (state.pipeName) {\n        const callee = path.node.callee;\n        const args = path.node.arguments;\n        if (callee.name !== state.pipeName) {\n          return;\n        } else if (args.length === 0) {\n          path.replaceWith(t.identifier('undefined'));\n        } else {\n          path.replaceWith(pipeExpression(t, args));\n        }\n      }\n    },\n  },\n});\n\nexport default pipePlugin;\n"
  },
  {
    "path": "scripts/changesets/changelog.js",
    "content": "const { config } = require('dotenv');\nconst { getInfo } = require('@changesets/get-github-info');\n\nconfig();\n\nconst REPO = 'urql-graphql/urql';\nconst SEE_LINE = /^See:\\s*(.*)/i;\nconst TRAILING_CHAR = /[.;:]$/g;\nconst listFormatter = new Intl.ListFormat('en-US');\n\nconst getSummaryLines = cs => {\n  let lines = cs.summary.trim().split(/\\r?\\n/);\n  if (!lines.some(line => /```/.test(line))) {\n    lines = lines.map(l => l.trim()).filter(Boolean);\n    const size = lines.length;\n    if (size > 0) {\n      lines[size - 1] = lines[size - 1].replace(TRAILING_CHAR, '');\n    }\n  }\n  return lines;\n};\n\n/** Creates a \"(See X)\" string from a template */\nconst templateSeeRef = links => {\n  const humanReadableLinks = links.filter(Boolean).map(link => {\n    if (typeof link === 'string') return link;\n    return link.pull || link.commit;\n  });\n\n  const size = humanReadableLinks.length;\n  if (size === 0) return '';\n\n  const str = listFormatter.format(humanReadableLinks);\n  return `(See ${str})`;\n};\n\nconst changelogFunctions = {\n  getDependencyReleaseLine: async (changesets, dependenciesUpdated) => {\n    if (dependenciesUpdated.length === 0) return '';\n\n    const dependenciesLinks = await Promise.all(\n      changesets.map(async cs => {\n        if (!cs.commit) return undefined;\n\n        const lines = getSummaryLines(cs);\n        const prLine = lines.find(line => SEE_LINE.test(line));\n        if (prLine) {\n          const match = prLine.match(SEE_LINE);\n          return (match && match[1].trim()) || undefined;\n        }\n\n        const { links } = await getInfo({\n          repo: REPO,\n          commit: cs.commit,\n        });\n\n        return links;\n      })\n    );\n\n    let changesetLink = '- Updated dependencies';\n\n    const seeRef = templateSeeRef(dependenciesLinks);\n    if (seeRef) changesetLink += ` ${seeRef}`;\n\n    const detailsLinks = dependenciesUpdated.map(dep => {\n      return `  - ${dep.name}@${dep.newVersion}`;\n    });\n\n    return [changesetLink, ...detailsLinks].join('\\n');\n  },\n  getReleaseLine: async (changeset, type) => {\n    let pull, commit, user;\n\n    const lines = getSummaryLines(changeset);\n    const prLineIndex = lines.findIndex(line => SEE_LINE.test(line));\n    if (prLineIndex > -1) {\n      const match = lines[prLineIndex].match(SEE_LINE);\n      pull = (match && match[1].trim()) || undefined;\n      lines.splice(prLineIndex, 1);\n    }\n\n    const [firstLine, ...futureLines] = lines;\n\n    if (changeset.commit && !pull) {\n      const { links } = await getInfo({\n        repo: REPO,\n        commit: changeset.commit,\n      });\n\n      pull = links.pull || undefined;\n      commit = links.commit || undefined;\n      user = links.user || undefined;\n    }\n\n    let annotation = '';\n    if (type === 'patch' && /^\\s*fix/i.test(firstLine)) {\n      annotation = '⚠️ ';\n    }\n\n    let str = `- ${annotation}${firstLine}`;\n    if (futureLines.length > 0) {\n      str += `\\n${futureLines.map(l => `  ${l}`).join('\\n')}`;\n    }\n\n    const endsWithParagraph = /(?<=(?:[!;?.]|```) *)$/g;\n    if (user && !endsWithParagraph) {\n      str += `, by ${user}`;\n    } else {\n      str += `\\nSubmitted by ${user}`;\n    }\n\n    if (pull || commit) {\n      const seeRef = templateSeeRef([pull || commit]);\n      if (seeRef) str += ` ${seeRef}`;\n    }\n\n    return str;\n  },\n};\n\nmodule.exports = {\n  ...changelogFunctions,\n  default: changelogFunctions,\n};\n"
  },
  {
    "path": "scripts/changesets/jsr.mjs",
    "content": "#!/usr/bin/env node\n\nimport fs from 'node:fs';\nimport path from 'node:path';\n\nimport { getPackageManifest, listPackages } from '../actions/lib/packages.mjs';\n\nconst getExports = exports => {\n  const exportNames = Object.keys(exports);\n  const eventualExports = {};\n  for (const exportName of exportNames) {\n    if (exportName.includes('package.json')) continue;\n    const exp = exports[exportName];\n    eventualExports[exportName] = exp.source;\n  }\n  return eventualExports;\n};\n\nexport const updateJsr = async () => {\n  (await listPackages()).forEach(dir => {\n    const manifest = getPackageManifest(dir);\n    const jsrManifest = {\n      name: manifest.name,\n      version: manifest.version,\n      exports: manifest.exports\n        ? getExports(manifest.exports)\n        : manifest.source,\n      exclude: [\n        'node_modules',\n        'cypress',\n        '**/*.test.*',\n        '**/*.spec.*',\n        '**/*.test.*.snap',\n        '**/*.spec.*.snap',\n      ],\n    };\n\n    fs.writeFileSync(\n      path.resolve(dir, 'jsr.json'),\n      JSON.stringify(jsrManifest, undefined, 2)\n    );\n  });\n};\n"
  },
  {
    "path": "scripts/changesets/version.mjs",
    "content": "#!/usr/bin/env node\n\nimport glob from 'glob';\nimport { execa } from 'execa';\n\nimport {\n  getPackageManifest,\n  updatePackageManifest,\n  listPackages,\n} from '../actions/lib/packages.mjs';\nimport { updateJsr } from './jsr.mjs';\n\nconst versionRe = /^\\d+\\.\\d+\\.\\d+/i;\nconst execaOpts = { stdio: 'inherit' };\n\nawait execa('changeset', ['version'], execaOpts);\nawait execa('pnpm', ['install', '--lockfile-only'], execaOpts);\n\nconst packages = (await listPackages()).reduce((map, dir) => {\n  const manifest = getPackageManifest(dir);\n  const versionMatch = manifest.version.match(versionRe);\n  if (versionMatch) {\n    const { name } = manifest;\n    const version = `^${versionMatch[0]}`;\n    map[name] = version;\n  }\n  return map;\n}, {});\n\nconst examples = (await glob('./examples/*/')).filter(\n  x => !/node_modules$/.test(x)\n);\nfor (const example of examples) {\n  let hadMatch = false;\n\n  const manifest = getPackageManifest(example);\n\n  if (manifest.dependencies) {\n    for (const name in manifest.dependencies) {\n      hadMatch = hadMatch || !!packages[name];\n      if (packages[name] && packages[name] !== manifest.dependencies)\n        manifest.dependencies[name] = packages[name];\n    }\n  }\n\n  if (manifest.devDependencies) {\n    for (const name in manifest.devDependencies) {\n      hadMatch = hadMatch || !!packages[name];\n      if (packages[name] && packages[name] !== manifest.devDependencies)\n        manifest.devDependencies[name] = packages[name];\n    }\n  }\n\n  if (\n    hadMatch &&\n    !(manifest.devDependencies || {})['@urql/core'] &&\n    !(manifest.dependencies || {})['@urql/core']\n  ) {\n    (manifest.dependencies || manifest.devDependencies || {})['@urql/core'] =\n      packages['@urql/core'];\n  }\n\n  await updatePackageManifest(example, manifest);\n}\n\nawait updateJsr();\n"
  },
  {
    "path": "scripts/eslint/preset.js",
    "content": "module.exports = {\n  parser: '@typescript-eslint/parser',\n  parserOptions: {\n    ecmaVersion: 9,\n    sourceType: 'module',\n    ecmaFeatures: {\n      modules: true,\n      jsx: true,\n    },\n  },\n\n  ignorePatterns: [\n    'node_modules/',\n    'dist/',\n    'dist-prod/',\n    'build/',\n    'coverage/',\n    'benchmark/',\n    'docs/',\n  ],\n\n  settings: {\n    react: {\n      version: 'detect',\n    },\n  },\n\n  extends: ['eslint:recommended', 'prettier'],\n\n  plugins: ['@typescript-eslint', 'prettier', 'es5'],\n\n  rules: {\n    'no-undef': 'off',\n    'no-empty': 'off',\n    'sort-keys': 'off',\n    'no-console': ['error', { allow: ['warn', 'error'] }],\n    'prefer-arrow/prefer-arrow-functions': 'off',\n\n    'es5/no-for-of': 'off',\n    'es5/no-generators': 'off',\n    'es5/no-typeof-symbol': 'warn',\n\n    'no-unused-vars': [\n      'warn',\n      {\n        argsIgnorePattern: '^_',\n      },\n    ],\n\n    'prettier/prettier': [\n      'error',\n      {\n        singleQuote: true,\n        arrowParens: 'avoid',\n        trailingComma: 'es5',\n      },\n    ],\n  },\n\n  overrides: [\n    {\n      extends: ['plugin:@typescript-eslint/recommended'],\n      files: ['*.ts', '*.tsx'],\n      rules: {\n        '@typescript-eslint/explicit-module-boundary-types': 'off',\n        '@typescript-eslint/no-use-before-define': 'off',\n        '@typescript-eslint/ban-types': 'off',\n        '@typescript-eslint/ban-ts-comment': 'off',\n        '@typescript-eslint/member-ordering': 'off',\n        '@typescript-eslint/explicit-member-accessibility': 'off',\n        '@typescript-eslint/no-object-literal-type-assertion': 'off',\n        '@typescript-eslint/explicit-function-return-type': 'off',\n        '@typescript-eslint/interface-name-prefix': 'off',\n        '@typescript-eslint/no-non-null-assertion': 'off',\n        '@typescript-eslint/no-misused-new': 'off',\n        '@typescript-eslint/no-explicit-any': 'off',\n        '@typescript-eslint/array-type': 'off',\n        'import/no-internal-modules': 'off',\n\n        'no-restricted-syntax': [\n          'error',\n          {\n            selector: 'PropertyDefinition[value]',\n            message:\n              'Property definitions with value initializers aren’t transpiled',\n          },\n          {\n            selector: 'MemberExpression[optional=true]',\n            message:\n              'Optional chaining (?.) operator is outside of specified browser support',\n          },\n          {\n            selector: 'LogicalExpression[operator=\"??\"]',\n            message:\n              'Nullish coalescing (??) operator is outside of specified browser support',\n          },\n          {\n            selector: 'AssignmentExpression[operator=\"??=\"]',\n            message:\n              'Nullish coalescing assignment (??=) is outside of specified browser support',\n          },\n          {\n            selector: 'SequenceExpression',\n            message:\n              'Sequence expressions are to be avoided since they can be confusing',\n          },\n          {\n            selector:\n              ':not(ForStatement) > VariableDeclaration[declarations.length>1]',\n            message:\n              'Only one variable declarator per variable declaration is preferred',\n          },\n        ],\n\n        '@typescript-eslint/no-import-type-side-effects': 'error',\n        '@typescript-eslint/consistent-type-imports': [\n          'error',\n          {\n            disallowTypeAnnotations: false,\n            fixStyle: 'separate-type-imports',\n          },\n        ],\n\n        '@typescript-eslint/no-unused-vars': [\n          'error',\n          {\n            argsIgnorePattern: '^_',\n          },\n        ],\n      },\n    },\n\n    {\n      extends: ['plugin:react/recommended'],\n      files: ['*.tsx'],\n      plugins: ['react-hooks'],\n      rules: {\n        'react-hooks/rules-of-hooks': 'error',\n        'react-hooks/exhaustive-deps': 'warn',\n        'react/react-in-jsx-scope': 'off',\n        'react/prop-types': 'off',\n        'react/no-children-prop': 'off',\n      },\n    },\n\n    {\n      files: ['*.test.ts', '*.test.tsx', '*.spec.ts', '*.spec.tsx'],\n      globals: { vi: true },\n      rules: {\n        'no-restricted-syntax': 'off',\n        '@typescript-eslint/ban-ts-comment': 'off',\n        '@typescript-eslint/no-import-type-side-effects': 'off',\n        '@typescript-eslint/consistent-type-imports': 'off',\n        'react-hooks/rules-of-hooks': 'off',\n        'react-hooks/exhaustive-deps': 'off',\n        'es5/no-for-of': 'off',\n        'es5/no-generators': 'off',\n        'es5/no-typeof-symbol': 'off',\n      },\n    },\n\n    {\n      files: ['*.js'],\n      rules: {\n        '@typescript-eslint/no-var-requires': 'off',\n        'consistent-return': 'warn',\n        'no-magic-numbers': 'off',\n        'es5/no-es6-methods': 'off',\n      },\n    },\n\n    {\n      files: ['*.jsx'],\n      extends: ['plugin:react/recommended'],\n      rules: {\n        'consistent-return': 'warn',\n        'no-magic-numbers': 'off',\n        'react/jsx-key': 'off',\n        'react/jsx-handler-names': 'off',\n        'es5/no-es6-methods': 'off',\n      },\n    },\n\n    {\n      files: ['examples/**/*.jsx'],\n      rules: {\n        'react/prop-types': 'off',\n      },\n    },\n  ],\n};\n"
  },
  {
    "path": "scripts/prepare/index.js",
    "content": "#!/usr/bin/env node\n\nconst invariant = require('invariant');\nconst path = require('path');\nconst fs = require('fs');\n\nconst cwd = process.cwd();\nconst workspaceRoot = path.resolve(__dirname, '../../');\nconst pkg = require(path.resolve(cwd, 'package.json'));\n\nconst hasReact = [\n  'dependencies',\n  'optionalDependencies',\n  'peerDependencies',\n].some(dep => pkg[dep] && pkg[dep].react);\n\nconst hasNext = [\n  'dependencies',\n  'optionalDependencies',\n  'peerDependencies',\n].some(dep => pkg[dep] && pkg[dep].next);\n\nconst normalize = name =>\n  name\n    .replace(/[@\\s/.]+/g, ' ')\n    .trim()\n    .replace(/\\s+/, '-')\n    .toLowerCase();\n\nconst name = normalize(pkg.name);\n\nconst posixPath = x => path.normalize(x).split(path.sep).join('/');\n\nconst is = (a, b) => posixPath(a) === posixPath(b);\n\ninvariant(\n  pkg.publishConfig.provenance === true,\n  'package.json:publishConfig.provenance must be set to true'\n);\n\nif (pkg.name.startsWith('@urql/')) {\n  invariant(\n    pkg.publishConfig.access === 'public',\n    'package.json:publishConfig.access must be set to public for @urql/* packages'\n  );\n}\n\ninvariant(!is(cwd, workspaceRoot), 'prepare-pkg must be run in a package.');\n\ninvariant(\n  fs.existsSync(pkg.source || 'src/index.ts'),\n  'package.json:source must exist'\n);\n\nif (hasReact && !hasNext) {\n  invariant(\n    is(pkg.main, path.join('dist', `${name}.js`)),\n    'package.json:main path must end in `.js` for packages depending on React.'\n  );\n\n  invariant(\n    is(pkg.module, path.join('dist', `${name}.es.js`)),\n    'package.json:module path must end in `.es.js` for packages depending on React.'\n  );\n} else {\n  invariant(\n    is(pkg.main, path.join('dist', `${name}`)),\n    'package.json:main path must be valid and have no extension'\n  );\n\n  invariant(\n    is(pkg.module, path.join('dist', `${name}.mjs`)),\n    'package.json:module path must be valid and ending in .mjs'\n  );\n}\n\ninvariant(\n  is(pkg.types, path.join('dist', `${name}.d.ts`)),\n  'package.json:types path must be valid'\n);\n\ninvariant(\n  is(pkg.repository.directory, path.relative(workspaceRoot, cwd)),\n  'package.json:repository.directory path is invalid'\n);\n\ninvariant(pkg.sideEffects === false, 'package.json:sideEffects must be false');\n\ninvariant(!!pkg.author, 'package.json:author must be defined');\n\ninvariant(pkg.license === 'MIT', 'package.json:license must be \"MIT\"');\n\ninvariant(\n  Array.isArray(pkg.files) &&\n    pkg.files.some(x => path.normalize(x).startsWith('dist')) &&\n    pkg.files.some(x => path.normalize(x) === 'LICENSE'),\n  'package.json:files must include \"dist\" and \"LICENSE\"'\n);\n\nif (pkg.dependencies && pkg.dependencies['@urql/core']) {\n  invariant(\n    !!pkg.peerDependencies && !!pkg.peerDependencies['@urql/core'],\n    'package.json:peerDependencies must contain @urql/core.'\n  );\n}\n\nif (pkg.peerDependencies && pkg.peerDependencies['@urql/core']) {\n  invariant(\n    !!pkg.dependencies && !!pkg.dependencies['@urql/core'],\n    'package.json:dependencies must contain @urql/core.'\n  );\n}\n\nfor (const key in pkg.peerDependencies || {}) {\n  const dependency = pkg.peerDependencies[key];\n  invariant(\n    key !== 'react' || key !== 'preact' || !dependency.includes('>='),\n    `Peer Dependency \"${key}\" must not contain \">=\" (greater than) range`\n  );\n}\n\nif (hasReact && !hasNext) {\n  invariant(\n    !pkg.exports,\n    'package.json:exports must not be added for packages depending on React.'\n  );\n} else {\n  invariant(\n    !!pkg.exports,\n    'package.json:exports must be added and have a \".\" entry'\n  );\n  invariant(!!pkg.exports['.'], 'package.json:exports must have a \".\" entry');\n  invariant(\n    !!pkg.exports['./package.json'],\n    'package.json:exports must have a \"./package.json\" entry'\n  );\n\n  for (const key in pkg.exports) {\n    const entry = pkg.exports[key];\n    if (entry === './package.json') continue;\n\n    const entryName = normalize(key);\n    const bundleName = entryName ? `${name}-${entryName}` : name;\n    invariant(\n      fs.existsSync(entry.source),\n      `package.json:exports[\"${key}\"].source must exist`\n    );\n\n    invariant(\n      is(entry.require, `./dist/${bundleName}.js`),\n      `package.json:exports[\"${key}\"].require must be valid`\n    );\n\n    invariant(\n      is(entry.import, `./dist/${bundleName}.mjs`),\n      `package.json:exports[\"${key}\"].import must be valid`\n    );\n\n    invariant(\n      is(entry.types, `./dist/${bundleName}.d.ts`),\n      'package.json:types path must be valid'\n    );\n\n    invariant(\n      Object.keys(entry)[0] === 'types',\n      'package.json:types must come first'\n    );\n  }\n}\n\nfs.copyFileSync(\n  path.resolve(workspaceRoot, 'LICENSE'),\n  path.resolve(cwd, 'LICENSE'),\n  0\n);\n"
  },
  {
    "path": "scripts/prepare/postinstall.js",
    "content": "const path = require('path');\nconst fs = require('fs');\n\ntry {\n  const hookSource = path.resolve(\n    __dirname,\n    '../../node_modules/husky-v4/sh/husky.sh'\n  );\n  const hook = path.resolve(__dirname, '../../.git/hooks/husky.sh');\n  const localHook = path.resolve(__dirname, '../../.git/hooks/husky.local.sh');\n  const gitConfig = path.resolve(__dirname, '../../.git/config');\n\n  let script = fs.readFileSync(hookSource, { encoding: 'utf-8' });\n  script = script.replace(`$(basename \"$0\")`, `$(basename \"$0\" .sh)`);\n\n  let config = fs.readFileSync(gitConfig, { encoding: 'utf-8' });\n  config = config.replace(/\\s*hooksPath\\s*=\\s*\\.husky\\n?/g, '\\n');\n\n  fs.writeFileSync(hook, script);\n  fs.writeFileSync(gitConfig, config);\n\n  fs.writeFileSync(localHook, 'packageManager=yarn\\n' + 'cd \".\"\\n');\n} catch {\n  // Ignore errors in ci etc\n}\n"
  },
  {
    "path": "scripts/rollup/cleanup-plugin.mjs",
    "content": "import { createFilter } from '@rollup/pluginutils';\n\nfunction cleanup() {\n  const emptyImportRe = /import\\s+(?:'[^']+'|\"[^\"]+\")\\s*;?/g;\n  const gqlImportRe = /(import\\s+(?:[*\\s{}\\w\\d]+)\\s*from\\s*'graphql';?)/g;\n  const dtsFilter = createFilter(/\\.d\\.ts(\\.map)?$/, null, { resolve: false });\n\n  return {\n    name: 'cleanup',\n\n    renderChunk(input, chunk) {\n      if (dtsFilter(chunk.fileName)) {\n        return input\n          .replace(emptyImportRe, '')\n          .replace(gqlImportRe, x => '/*@ts-ignore*/\\n' + x);\n      }\n    },\n  };\n}\n\nexport default cleanup;\n"
  },
  {
    "path": "scripts/rollup/config.mjs",
    "content": "import dts from 'rollup-plugin-dts';\n\nimport * as fs from 'fs/promises';\nimport { relative, join, dirname, basename } from 'path';\n\nimport { makePlugins, makeBasePlugins, makeOutputPlugins } from './plugins.mjs';\nimport cleanup from './cleanup-plugin.mjs';\nimport * as settings from './settings.mjs';\n\nconst plugins = makePlugins();\nconst isCI = !!process.env.CI;\n\nconst chunkFileNames = extension => {\n  let hasDynamicChunk = false;\n  return chunkInfo => {\n    if (\n      chunkInfo.isDynamicEntry ||\n      chunkInfo.isEntry ||\n      chunkInfo.isImplicitEntry\n    ) {\n      return `[name]${extension}`;\n    } else if (!hasDynamicChunk) {\n      hasDynamicChunk = true;\n      return `${settings.name}-chunk${extension}`;\n    } else {\n      return `[name]-chunk${extension}`;\n    }\n  };\n};\n\nconst input = settings.sources.reduce((acc, source) => {\n  acc[source.name] = source.source;\n  if (source.name !== settings.name) {\n    const rel = relative(source.dir, process.cwd());\n    plugins.push({\n      async writeBundle() {\n        const packageJson = JSON.stringify(\n          {\n            name: source.name,\n            private: true,\n            version: '0.0.0',\n            main: join(rel, dirname(source.main), basename(source.main, '.js')),\n            module: join(rel, source.module),\n            types: join(rel, source.types),\n            source: join(rel, source.source),\n            exports: {\n              '.': {\n                types: join(rel, source.types),\n                import: join(rel, source.module),\n                require: join(rel, source.main),\n                source: join(rel, source.source),\n              },\n              './package.json': './package.json',\n            },\n          },\n          null,\n          2\n        ).trim();\n\n        await fs.mkdir(source.dir, { recursive: true });\n        await fs.writeFile(\n          join(source.dir, 'package.json'),\n          packageJson + '\\n'\n        );\n      },\n    });\n  }\n\n  return acc;\n}, {});\n\nconst output = ({ format, isProduction }) => {\n  if (typeof isProduction !== 'boolean')\n    throw new Error('Invalid option `isProduction` at output({ ... })');\n  if (format !== 'cjs' && format !== 'esm')\n    throw new Error('Invalid option `format` at output({ ... })');\n\n  let extension =\n    format === 'esm'\n      ? settings.hasReact && !settings.hasNext\n        ? '.es.js'\n        : '.mjs'\n      : '.js';\n  if (isProduction) {\n    extension = '.min' + extension;\n  }\n\n  return {\n    entryFileNames: `[name]${extension}`,\n    chunkFileNames: chunkFileNames(extension),\n    dir: './dist',\n    exports: 'named',\n    sourcemap: true,\n    banner: chunk => (chunk.name === 'urql-next' ? '\"use client\"' : undefined),\n    sourcemapExcludeSources: isCI,\n    hoistTransitiveImports: false,\n    indent: false,\n    freeze: false,\n    strict: false,\n    format,\n    plugins: makeOutputPlugins({\n      isProduction,\n      extension: format === 'esm' ? '.mjs' : '.js',\n    }),\n    // NOTE: All below settings are important for cjs-module-lexer to detect the export\n    // When this changes (and terser mangles the output) this will interfere with Node.js ESM intercompatibility\n    esModule: format !== 'esm',\n    externalLiveBindings: format !== 'esm',\n    interop(id) {\n      if (format === 'esm') {\n        return 'esModule';\n      } else if (id === 'react') {\n        return 'esModule';\n      } else {\n        return 'auto';\n      }\n    },\n    generatedCode: {\n      preset: 'es5',\n      reservedNamesAsProps: false,\n      objectShorthand: false,\n      constBindings: false,\n    },\n  };\n};\n\nconst commonConfig = {\n  input,\n  external: settings.isExternal,\n  onwarn() {},\n  treeshake: {\n    unknownGlobalSideEffects: false,\n    tryCatchDeoptimization: false,\n    moduleSideEffects: false,\n  },\n};\n\nexport default [\n  {\n    ...commonConfig,\n    plugins,\n    output: [\n      output({ format: 'cjs', isProduction: false }),\n      output({ format: 'esm', isProduction: false }),\n      !isCI && output({ format: 'cjs', isProduction: true }),\n      !isCI && output({ format: 'esm', isProduction: true }),\n    ].filter(Boolean),\n  },\n  {\n    ...commonConfig,\n    plugins: [\n      ...makeBasePlugins(),\n      dts({\n        compilerOptions: {\n          preserveSymlinks: false,\n        },\n      }),\n    ],\n    output: {\n      minifyInternalExports: false,\n      entryFileNames: '[name].d.ts',\n      chunkFileNames: chunkFileNames('.d.ts'),\n      dir: './dist',\n      plugins: [cleanup()],\n    },\n  },\n];\n"
  },
  {
    "path": "scripts/rollup/plugins.mjs",
    "content": "import * as path from 'path';\nimport * as React from 'react';\n\nimport commonjs from '@rollup/plugin-commonjs';\nimport resolve from '@rollup/plugin-node-resolve';\nimport replace from '@rollup/plugin-replace';\nimport babel from '@rollup/plugin-babel';\nimport visualizer from 'rollup-plugin-visualizer';\nimport terser from '@rollup/plugin-terser';\nimport cjsCheck from 'rollup-plugin-cjs-check';\n\nimport cleanup from './cleanup-plugin.mjs';\nimport babelPluginTransformPipe from '../babel/transform-pipe.mjs';\nimport babelPluginTransformInvariant from '../babel/transform-invariant-warning.mjs';\nimport babelPluginTransformDebugTarget from '../babel/transform-debug-target.mjs';\n\nimport * as settings from './settings.mjs';\n\nexport const makeBasePlugins = () => [\n  resolve({\n    dedupe: settings.externalModules,\n    extensions: ['.js', '.ts', '.tsx'],\n    mainFields: ['module', 'jsnext', 'main'],\n    preferBuiltins: false,\n    browser: true,\n  }),\n  commonjs({\n    ignoreGlobal: true,\n    include: /\\/node_modules\\//,\n  }),\n];\n\nexport const makePlugins = () => [\n  ...makeBasePlugins(),\n  babel({\n    babelrc: false,\n    babelHelpers: 'bundled',\n    extensions: ['js', 'jsx', 'ts', 'tsx'],\n    exclude: 'node_modules/**',\n    presets: [],\n    plugins: [\n      '@babel/plugin-transform-typescript',\n      '@babel/plugin-transform-block-scoping',\n      babelPluginTransformDebugTarget,\n      babelPluginTransformPipe,\n      babelPluginTransformInvariant,\n      settings.hasReact && [\n        '@babel/plugin-transform-react-jsx',\n        {\n          pragma: 'React.createElement',\n          pragmaFrag: 'React.Fragment',\n          useBuiltIns: true,\n        },\n      ],\n      !settings.hasReact &&\n        settings.hasPreact && [\n          '@babel/plugin-transform-react-jsx',\n          {\n            pragma: 'h',\n            useBuiltIns: true,\n          },\n        ],\n    ].filter(Boolean),\n  }),\n];\n\nexport const makeOutputPlugins = ({ isProduction, extension }) => {\n  if (typeof isProduction !== 'boolean')\n    throw new Error(\n      'Missing option `isProduction` on makeOutputPlugins({ ... })'\n    );\n  if (extension !== '.mjs' && extension !== '.js')\n    throw new Error('Missing option `extension` on makeOutputPlugins({ ... })');\n\n  return [\n    isProduction &&\n      replace({\n        'process.env.NODE_ENV': JSON.stringify('production'),\n      }),\n    cjsCheck({ extension }),\n    cleanup(),\n    isProduction ? terserMinified : extension !== '.js' ? terserPretty : null,\n    isProduction &&\n      settings.isAnalyze &&\n      visualizer({\n        filename: path.resolve(\n          settings.cwd,\n          'node_modules/.cache/analyze.html'\n        ),\n        sourcemap: true,\n      }),\n  ].filter(Boolean);\n};\n\nconst terserPretty = terser({\n  warnings: true,\n  ecma: 2015,\n  keep_fnames: true,\n  ie8: false,\n  compress: {\n    pure_getters: true,\n    toplevel: true,\n    booleans_as_integers: false,\n    keep_fnames: true,\n    keep_fargs: true,\n    if_return: false,\n    ie8: false,\n    sequences: false,\n    loops: false,\n    conditionals: false,\n    join_vars: false,\n  },\n  mangle: {\n    module: true,\n    keep_fnames: true,\n  },\n  output: {\n    comments: false,\n    beautify: true,\n    braces: true,\n    indent_level: 2,\n  },\n});\n\nconst terserMinified = terser({\n  warnings: true,\n  ecma: 2015,\n  ie8: false,\n  toplevel: true,\n  compress: {\n    keep_infinity: true,\n    pure_getters: true,\n    passes: 10,\n  },\n  mangle: {\n    module: true,\n  },\n  output: {\n    comments: false,\n  },\n});\n"
  },
  {
    "path": "scripts/rollup/settings.mjs",
    "content": "import { readFileSync } from 'fs';\nimport path from 'path';\n\nexport const cwd = process.cwd();\nexport const pkg = JSON.parse(\n  readFileSync(path.resolve(cwd, './package.json'), 'utf-8')\n);\nexport const types = path.resolve(cwd, 'dist/types/');\n\nconst normalize = name =>\n  name\n    .replace(/[@\\s\\/\\.]+/g, ' ')\n    .trim()\n    .replace(/\\s+/, '-')\n    .toLowerCase();\n\nexport const name = normalize(pkg.name);\n\nexport const sources = pkg.exports\n  ? Object.keys(pkg.exports)\n      .map(entry => {\n        if (entry === './package.json') return undefined;\n        const exports = pkg.exports[entry];\n        const dir = normalize(entry);\n        return {\n          name: dir ? `${name}-${dir}` : name,\n          dir: dir || '.',\n          main: exports.require,\n          module: exports.import,\n          types: exports.types,\n          source: exports.source,\n        };\n      })\n      .filter(Boolean)\n  : [\n      {\n        name,\n        source: pkg.source || './src/index.ts',\n      },\n    ];\n\nexport const externalModules = ['dns', 'fs', 'path', 'url'];\nif (pkg.peerDependencies)\n  externalModules.push(...Object.keys(pkg.peerDependencies));\nif (pkg.devDependencies)\n  externalModules.push(...Object.keys(pkg.devDependencies));\nif (pkg.dependencies) externalModules.push(...Object.keys(pkg.dependencies));\nif (pkg.optionalDependencies)\n  externalModules.push(...Object.keys(pkg.optionalDependencies));\n\nconst prodDependencies = new Set([\n  ...Object.keys(pkg.peerDependencies || {}),\n  ...Object.keys(pkg.dependencies || {}),\n]);\n\nconst externalPredicate = new RegExp(`^(${externalModules.join('|')})($|/)`);\n\nexport const isExternal = id => {\n  if (id === 'babel-plugin-transform-async-to-promises/helpers') return false;\n  return externalPredicate.test(id);\n};\n\nexport const hasNext = prodDependencies.has('next');\nexport const hasReact = prodDependencies.has('react');\nexport const hasPreact = prodDependencies.has('preact');\nexport const hasSvelte = prodDependencies.has('svelte');\nexport const hasVue = prodDependencies.has('vue');\nexport const mayReexport = hasReact || hasPreact || hasSvelte || hasVue;\nexport const isAnalyze = !!process.env.ANALYZE;\n"
  },
  {
    "path": "scripts/vitest/setup.js",
    "content": "// This script is run before each `.test.ts` file.\nglobalThis.AbortController = undefined;\nglobalThis.fetch = vi.fn();\n\nprocess.on('unhandledRejection', error => {\n  throw error;\n});\n\nconst originalConsole = console;\nglobalThis.console = {\n  ...originalConsole,\n  warn: (vi.SpyInstance = () => {\n    /* noop */\n  }),\n  error: (vi.SpyInstance = message => {\n    throw new Error(message);\n  }),\n};\n\nvi.spyOn(console, 'log');\nvi.spyOn(console, 'warn');\nvi.spyOn(console, 'error');\n"
  },
  {
    "path": "tsconfig.json",
    "content": "{\n  \"compilerOptions\": {\n    \"baseUrl\": \"./\",\n    \"paths\": {\n      \"urql\": [\"node_modules/urql/src\", \"packages/react-urql/src\"],\n      \"*-urql\": [\"node_modules/*-urql/src\", \"packages/*-urql/src\"],\n      \"@urql/exchange-*\": [\n        \"node_modules/@urql/exchange-*/src\",\n        \"exchanges/*/src\"\n      ],\n      \"@urql/core/*\": [\"node_modules/@urql/core/src/*\", \"packages/core/src/*\"],\n      \"@urql/devtools\": [\"node_modules/@urql/devtools\"],\n      \"@urql/*\": [\n        \"node_modules/@urql/*/src\",\n        \"packages/*-urql/src\",\n        \"packages/*/src\"\n      ]\n    },\n    \"esModuleInterop\": true,\n    \"isolatedModules\": true,\n    \"forceConsistentCasingInFileNames\": true,\n    \"noUnusedLocals\": true,\n    \"noEmit\": true,\n    \"lib\": [\"dom\", \"esnext\"],\n    \"jsx\": \"react\",\n    \"module\": \"es2015\",\n    \"moduleResolution\": \"node\",\n    \"target\": \"esnext\",\n    \"strict\": true,\n    \"noImplicitAny\": false,\n    \"noUnusedParameters\": true,\n    \"skipLibCheck\": true\n  },\n  \"include\": [\"packages\", \"exchanges\"],\n  \"exclude\": [\n    \"**/e2e-tests\",\n    \"**/examples\",\n    \"**/dist\",\n    \"**/node_modules\",\n    \"node_modules\",\n    \"scripts\"\n  ]\n}\n"
  },
  {
    "path": "vercel.json",
    "content": "{\n  \"github\": {\n    \"silent\": true\n  }\n}\n"
  },
  {
    "path": "vitest.config.ts",
    "content": "import { resolve } from 'path';\nimport { defineConfig } from 'vitest/config';\nimport tsconfigPaths from 'vite-tsconfig-paths';\n\nexport default defineConfig({\n  resolve: {\n    alias: {\n      'preact/hooks':\n        __dirname +\n        '/packages/preact-urql/node_modules/preact/hooks/dist/hooks.js',\n      preact:\n        __dirname + '/packages/preact-urql/node_modules/preact/dist/preact.js',\n    },\n  },\n  plugins: [tsconfigPaths()],\n  test: {\n    globals: true,\n    setupFiles: [resolve(__dirname, 'scripts/vitest/setup.js')],\n    clearMocks: true,\n    exclude: [\n      'packages/solid-urql/**',\n      'packages/solid-start-urql/**',\n      '**/node_modules/**',\n      '**/dist/**',\n      '**/cypress/**',\n      '**/e2e-tests/**',\n      '**/.{idea,git,cache,output,temp}/**',\n      '**/{karma,rollup,webpack,vite,vitest,jest,ava,babel,nyc,cypress}.config.*',\n    ],\n  },\n});\n"
  }
]