[
  {
    "path": ".eslintignore",
    "content": "node_modules\n"
  },
  {
    "path": ".eslintrc.js",
    "content": "/* eslint-env node */\nmodule.exports = {\n    \"env\": {\n        \"browser\": true,\n        \"es2021\": true\n    },\n    \"extends\": \"eslint:recommended\",\n    \"parserOptions\": {\n        \"ecmaVersion\": 12,\n        \"sourceType\": \"module\"\n    },\n    \"rules\": {\n    }\n};\n"
  },
  {
    "path": ".github/dependabot.yml",
    "content": "version: 2\nupdates:\n  - package-ecosystem: github-actions\n    directory: /\n    schedule:\n      interval: daily\n    groups:\n      github-actions:\n        patterns:\n          - \"*\"\n    open-pull-requests-limit: 1\n"
  },
  {
    "path": ".github/workflows/lock.yml",
    "content": "name: 'Lock threads'\n\non:\n  schedule:\n    - cron: '0 0 * * *'\n\npermissions: {}\n\njobs:\n  lock:\n    runs-on: ubuntu-latest\n    permissions:\n      issues: write\n      pull-requests: write\n    steps:\n      - uses: dessant/lock-threads@1bf7ec25051fe7c00bdd17e6a7cf3d7bfb7dc771 # v5.0.1\n        with:\n          github-token: ${{ github.token }}\n          issue-lock-inactive-days: '180'\n"
  },
  {
    "path": ".github/workflows/node.js.yml",
    "content": "# This workflow will do a clean install of node dependencies, build the source code and run tests across different versions of node\n# For more information see: https://help.github.com/actions/language-and-framework-guides/using-nodejs-with-github-actions\n\nname: Node.js CI\n\non:\n  push:\n    branches: [ main ]\n  pull_request:\n    branches: [ main ]\n    \npermissions:\n  contents: read\n\njobs:\n  build:\n\n    runs-on: ubuntu-latest\n\n    strategy:\n      matrix:\n        node-version: [18.x, 20.x]\n\n    steps:\n    - uses: actions/checkout@9bb56186c3b09b4f86b1c65136769dd318469633 # v4.1.2\n    - name: Use Node.js ${{ matrix.node-version }}\n      uses: actions/setup-node@60edb5dd545a775178f52524783378180af0d1f8 # v4.0.2\n      with:\n        node-version: ${{ matrix.node-version }}\n    - run: npm i\n    - run: npm run build --if-present\n    - run: npm test\n"
  },
  {
    "path": ".github/workflows/release.yml",
    "content": "on:\n  push:\n    branches:\n      - main\n\npermissions:\n  contents: write\n  pull-requests: write\n\nname: release-please\n\njobs:\n  release-please:\n    runs-on: ubuntu-latest\n    steps:\n      - uses: google-github-actions/release-please-action@a37ac6e4f6449ce8b3f7607e4d97d0146028dc0b # v4.1.0\n        with:\n          release-type: node\n          package-name: release-please-action\n"
  },
  {
    "path": ".github/workflows/scorecard.yml",
    "content": "# This workflow uses actions that are not certified by GitHub. They are provided\n# by a third-party and are governed by separate terms of service, privacy\n# policy, and support documentation.\n\nname: Scorecard supply-chain security\non:\n  # For Branch-Protection check. Only the default branch is supported. See\n  # https://github.com/ossf/scorecard/blob/main/docs/checks.md#branch-protection\n  branch_protection_rule:\n  # To guarantee Maintained check is occasionally updated. See\n  # https://github.com/ossf/scorecard/blob/main/docs/checks.md#maintained\n  schedule:\n    - cron: '17 14 * * 1'\n  push:\n    branches: [ main ]\n\n# Declare default permissions as read only.\npermissions: read-all\n\njobs:\n  analysis:\n    name: Scorecard analysis\n    runs-on: ubuntu-latest\n    permissions:\n      security-events: write # to upload the results to code-scanning dashboard\n      id-token: write # to publish results and get a badge (see publish_results below)\n\n    steps:\n      - name: \"Checkout code\"\n        uses: actions/checkout@9bb56186c3b09b4f86b1c65136769dd318469633 # v3.1.0\n        with:\n          persist-credentials: false\n\n      - name: \"Run analysis\"\n        uses: ossf/scorecard-action@0864cf19026789058feabb7e87baa5f140aac736 # v2.3.1\n        with:\n          results_file: results.sarif\n          results_format: sarif\n          #  Publish results to OpenSSF REST API for easy access by consumers and\n          #  allows the repository to include the Scorecard badge.\n          #  See https://github.com/ossf/scorecard-action#publishing-results.\n          publish_results: true\n\n      # Upload the results as artifacts (optional). Commenting out will disable uploads of run results in SARIF\n      # format to the repository Actions tab.\n      - name: \"Upload artifact\"\n        uses: actions/upload-artifact@5d5d22a31266ced268874388b861e4b58bb5c2f3 # v4.3.1\n        with:\n          name: SARIF file\n          path: results.sarif\n          retention-days: 5\n\n      # Upload the results to GitHub's code scanning dashboard.\n      - name: \"Upload to code-scanning\"\n        uses: github/codeql-action/upload-sarif@4355270be187e1b672a7a1c7c7bae5afdc1ab94a # v3.24.10\n        with:\n          sarif_file: results.sarif\n"
  },
  {
    "path": ".gitignore",
    "content": ".env\npackage-lock.json\ndist/\nbower_components/\nnode_modules/\nsauce_connect/\nsauce_connect.log\n"
  },
  {
    "path": ".npmignore",
    "content": ".env\npackage-lock.json\nbower_components/\nnode_modules/\nsauce_connect/\nsauce_connect.log\n"
  },
  {
    "path": "CHANGELOG.md",
    "content": "# Changelog\n\nAll notable changes to this project will be documented in this file. Dates are displayed in UTC.\n\n## [3.6.20](https://github.com/JakeChampion/fetch/compare/v3.6.19...v3.6.20) (2023-12-13)\n\n\n### Bug Fixes\n\n* Response.error().ok === false ([#1412](https://github.com/JakeChampion/fetch/issues/1412)) ([27e1c75](https://github.com/JakeChampion/fetch/commit/27e1c75f830f0b70a40b511e03652776951aca75))\n\n## [3.6.19](https://github.com/JakeChampion/fetch/compare/v3.6.18...v3.6.19) (2023-09-11)\n\n\n### Bug Fixes\n\n* Have unique error messages for xhr timeouts and errors ([#1380](https://github.com/JakeChampion/fetch/issues/1380)) ([7170f0b](https://github.com/JakeChampion/fetch/commit/7170f0b127d16c5895aba61c9168482834809046))\n\n\n## [v3.6.18](https://github.com/JakeChampion/fetch/compare/v3.6.17...v3.6.18)\n\n- Fix - File fetching broken since commit 0c1d2b9 [`#1375`](https://github.com/JakeChampion/fetch/pull/1375)\n- Remove broken links [`1dc07c6`](https://github.com/JakeChampion/fetch/commit/1dc07c6064a32e989306fb2324204c56c93140fe)\n- automatically generate a changelog [`0e7d1dd`](https://github.com/JakeChampion/fetch/commit/0e7d1dd95826b3b76510f0832784207f2609145e)\n\n## [v3.6.17](https://github.com/JakeChampion/fetch/compare/v3.6.16...v3.6.17)\n\n> 20 July 2023\n\n- Revert \"Resolves https://github.com/JakeChampion/fetch/issues/928\" [`#928`](https://github.com/JakeChampion/fetch/issues/928)\n\n## [v3.6.16](https://github.com/JakeChampion/fetch/compare/v3.6.15...v3.6.16)\n\n> 18 July 2023\n\n- Resolves https://github.com/JakeChampion/fetch/issues/928 [`#928`](https://github.com/JakeChampion/fetch/issues/928)\n\n## [v3.6.15](https://github.com/JakeChampion/fetch/compare/v3.6.14...v3.6.15)\n\n> 18 July 2023\n\n- fix https://github.com/JakeChampion/fetch/issues/997 [`#997`](https://github.com/JakeChampion/fetch/issues/997)\n\n## [v3.6.14](https://github.com/JakeChampion/fetch/compare/v3.6.13...v3.6.14)\n\n> 18 July 2023\n\n- Fix https://github.com/JakeChampion/fetch/issues/1076 [`#1076`](https://github.com/JakeChampion/fetch/issues/1076)\n\n## [v3.6.13](https://github.com/JakeChampion/fetch/compare/v3.6.12...v3.6.13)\n\n> 18 July 2023\n\n- respect charset within readBlobAsText [`#1059`](https://github.com/JakeChampion/fetch/issues/1059)\n\n## [v3.6.12](https://github.com/JakeChampion/fetch/compare/v3.6.11...v3.6.12)\n\n> 18 July 2023\n\n- fix: Headers only accepts array which have nested array of length 2 [`#1235`](https://github.com/JakeChampion/fetch/issues/1235)\n\n## [v3.6.11](https://github.com/JakeChampion/fetch/compare/v3.6.10...v3.6.11)\n\n> 18 July 2023\n\n- Define Body.arrayBuffer even if support.blob is false [`#992`](https://github.com/JakeChampion/fetch/issues/992)\n\n## [v3.6.10](https://github.com/JakeChampion/fetch/compare/v3.6.9...v3.6.10)\n\n> 18 July 2023\n\n- use globals if they exist [`dffc542`](https://github.com/JakeChampion/fetch/commit/dffc542fe7140f35ee7fec29e3da67f3bf080910)\n\n## [v3.6.9](https://github.com/JakeChampion/fetch/compare/v3.6.8...v3.6.9)\n\n> 18 July 2023\n\n- fix: when no body supplied, do not set bodyUsed to true [`7d92dff`](https://github.com/JakeChampion/fetch/commit/7d92dff12d7c4058b57c7e77adeb0a76ffab639f)\n\n## [v3.6.8](https://github.com/JakeChampion/fetch/compare/v3.6.7...v3.6.8)\n\n> 18 July 2023\n\n- validate status is in range [`#1213`](https://github.com/JakeChampion/fetch/issues/1213)\n\n## [v3.6.7](https://github.com/JakeChampion/fetch/compare/v3.6.6...v3.6.7)\n\n> 18 July 2023\n\n- dont shadow `global` [`#1026`](https://github.com/JakeChampion/fetch/issues/1026)\n- dont use github  eslint [`408d3b6`](https://github.com/JakeChampion/fetch/commit/408d3b60e27abef325dd898d899430c46a0012b2)\n- remove invalid-headers test [`e3f6590`](https://github.com/JakeChampion/fetch/commit/e3f65907924b7692af7c08cd92044456bc92ad8b)\n- Update lock.yml permissions [`e97321b`](https://github.com/JakeChampion/fetch/commit/e97321bc081e80275397fc4c7a990791aa8b3524)\n\n## [v3.6.6](https://github.com/JakeChampion/fetch/compare/v3.6.5...v3.6.6)\n\n> 18 July 2023\n\n- fix: ignore not throw on invalid response headers [`#930`](https://github.com/JakeChampion/fetch/issues/930)\n\n## [v3.6.5](https://github.com/JakeChampion/fetch/compare/v3.6.4...v3.6.5)\n\n> 18 July 2023\n\n- Add some missed methods which should be normalized as uppercase [`a43b628`](https://github.com/JakeChampion/fetch/commit/a43b6283833c403230bb1a5238e2d7ac435c52da)\n- Update caniuse link to use HTTPS and new pattern [`fb5b0cf`](https://github.com/JakeChampion/fetch/commit/fb5b0cf42b470faf8c5448ab461d561f34380a30)\n\n## [v3.6.4](https://github.com/JakeChampion/fetch/compare/v3.6.3...v3.6.4)\n\n> 18 July 2023\n\n- always set a signal on Request [`d1d09fb`](https://github.com/JakeChampion/fetch/commit/d1d09fb8039b4b8c7f2f5d6c844ea72d8a3cefe6)\n\n## [v3.6.3](https://github.com/JakeChampion/fetch/compare/v3.6.2...v3.6.3)\n\n> 18 July 2023\n\n- Compatible global equals to the false [`7727e50`](https://github.com/JakeChampion/fetch/commit/7727e50493eafae9a7005f10f18f81e5bbcbfdd3)\n\n## [v3.6.2](https://github.com/JakeChampion/fetch/compare/v3.6.1...v3.6.2)\n\n> 27 February 2021\n\n- Revert \"Represent non-stringified JSON request body as an [object Object] string\" [`e42f201`](https://github.com/JakeChampion/fetch/commit/e42f201b8b0af8b3f2615abe8161c8087f52f1b2)\n\n## [v3.6.1](https://github.com/JakeChampion/fetch/compare/v3.6.0...v3.6.1)\n\n> 18 February 2021\n\n- Fix MSIE compatibility [`da97bdb`](https://github.com/JakeChampion/fetch/commit/da97bdb462632288b21eeca67fc6b93c7077ebae)\n- use var instead of const [`5d3952d`](https://github.com/JakeChampion/fetch/commit/5d3952d10736a98a550043b933c50800643e2756)\n- Restore package.json [`6b4bd97`](https://github.com/JakeChampion/fetch/commit/6b4bd971b1e415a347cf20db4b925d1b845669a9)\n\n## [v3.6.0](https://github.com/JakeChampion/fetch/compare/v3.5.0...v3.6.0)\n\n> 18 February 2021\n\n- Fix statusText: undefined should give '' and null should give 'null' [`b5c8bd0`](https://github.com/JakeChampion/fetch/commit/b5c8bd0fee1530f1c204cc5c68b427a3498dbdad)\n- Represent non-stringified JSON request body as an [object Object] string [`5c6b055`](https://github.com/JakeChampion/fetch/commit/5c6b055e6ae6f718f416c94bfcdc89693d0abdcb)\n- Fix eslint and eslint-plugin-github dependency conflicts [`190e698`](https://github.com/JakeChampion/fetch/commit/190e698f8e737ad751a11de60f6b8b3301fa557b)\n\n## [v3.5.0](https://github.com/JakeChampion/fetch/compare/v3.4.1...v3.5.0)\n\n> 6 November 2020\n\n- Fixes #748 [`#748`](https://github.com/JakeChampion/fetch/issues/748)\n- Create lock.yml [`8767781`](https://github.com/JakeChampion/fetch/commit/87677811d543cfb44b124e026b50f710e95017ec)\n\n## [v3.4.1](https://github.com/JakeChampion/fetch/compare/v3.4.0...v3.4.1)\n\n> 7 September 2020\n\n- Add npmignore file to ensure we always publish the dist directory [`7ca02eb`](https://github.com/JakeChampion/fetch/commit/7ca02eb0234b0a61fd711d922b2e69d3c5390516)\n- Make the clean task remove the dist directory and the default task create it [`fd23745`](https://github.com/JakeChampion/fetch/commit/fd23745f3474cd23d88e5128d8bc74813be1aff0)\n\n## [v3.4.0](https://github.com/JakeChampion/fetch/compare/v3.3.1...v3.4.0)\n\n> 7 August 2020\n\n- Use globalThis as the global object if it exists [`96c2651`](https://github.com/JakeChampion/fetch/commit/96c26512608a0081d493df4fc17da4394bd1b410)\n\n## [v3.3.1](https://github.com/JakeChampion/fetch/compare/v3.3.0...v3.3.1)\n\n> 4 August 2020\n\n- rename variable to no longer shadow over function of same name [`c5db762`](https://github.com/JakeChampion/fetch/commit/c5db7621c3b1530683b8f706388d4ac210a2db02)\n- remove semicolon to pass linting [`f264aa5`](https://github.com/JakeChampion/fetch/commit/f264aa5704f7431c429ec16e6fdd3c7034c7f2d9)\n\n## [v3.3.0](https://github.com/JakeChampion/fetch/compare/v3.2.0...v3.3.0)\n\n> 4 August 2020\n\n- Make Response.arrayBuffer() always resolve with a `ArrayBuffer` [`#801`](https://github.com/github/fetch/issues/801)\n- Stop using top-level `this` to stop rollup warning [`#802`](https://github.com/github/fetch/issues/802)\n- Recommend an AbortController polyfill which is fully synchronous [`#800`](https://github.com/github/fetch/issues/800)\n- Add keepalive caveat [`#780`](https://github.com/github/fetch/issues/780)\n- Throw a TypeError if Request or Response functions are called without `new` [`5ef028d`](https://github.com/JakeChampion/fetch/commit/5ef028d61f6c1543603cdacbe0f8a0f00d5957c0)\n- If headers are passed in via a Record then do not normalise the header names as part of the request [`b65ed60`](https://github.com/JakeChampion/fetch/commit/b65ed608604492d605df2d62cd4c5050e2a8d508)\n- Update fetch.js [`37b55c2`](https://github.com/JakeChampion/fetch/commit/37b55c27413b902cef4e629892424ae469fb1ea2)\n\n## [v3.2.0](https://github.com/JakeChampion/fetch/compare/v3.1.1...v3.2.0)\n\n> 9 July 2020\n\n- Detect if DOMException exists via typeof instead of trying to call it and catching the exception which may get thrown [`#724`](https://github.com/github/fetch/issues/724)\n- use `this` if `self` is not defined [`#657`](https://github.com/github/fetch/issues/657)\n- create variable called `global` which is either `self` or `this` [`a0783a5`](https://github.com/JakeChampion/fetch/commit/a0783a5571018191578cc08d5b3bac61a0b64562)\n- Add support for no-cache and no-store via a cache-busting querystring parameter [`a0dcd85`](https://github.com/JakeChampion/fetch/commit/a0dcd853f8ed29d06a022f92c87c303bd0e1f1bf)\n- make global `this` correct when using rollup [`6e9fc0e`](https://github.com/JakeChampion/fetch/commit/6e9fc0ee026dd89d864c3d176c57789ee5615114)\n\n## [v3.1.1](https://github.com/JakeChampion/fetch/compare/v3.1.0...v3.1.1)\n\n> 8 July 2020\n\n- check if Content-Type header exists prior to  examining the value [`#792`](https://github.com/JakeChampion/fetch/pull/792)\n- Move from Travis to GitHub Actions [`#793`](https://github.com/JakeChampion/fetch/pull/793)\n\n## [v3.1.0](https://github.com/JakeChampion/fetch/compare/v3.0.1...v3.1.0)\n\n> 29 June 2020\n\n## [v3.0.1](https://github.com/JakeChampion/fetch/compare/v3.0.0...v3.0.1)\n\n> 8 July 2020\n\n- check if Content-Type header exists prior to  examining the value [`#792`](https://github.com/JakeChampion/fetch/pull/792)\n- Move from Travis to GitHub Actions [`#793`](https://github.com/JakeChampion/fetch/pull/793)\n- Co-authored-by: Jake Champion &lt;me@jakechampion.name&gt; [`#575`](https://github.com/JakeChampion/fetch/pull/575)\n- work around IE XHR bug with '' URL Fixes #618 [`#619`](https://github.com/JakeChampion/fetch/pull/619)\n- Allow exclamation mark as valid header character [`#745`](https://github.com/JakeChampion/fetch/pull/745)\n- Avoid blob conversion for specific requests [`#752`](https://github.com/JakeChampion/fetch/pull/752)\n- Compatibility for fetch-mock using proxy-pollyfill [`#736`](https://github.com/JakeChampion/fetch/pull/736)\n- Change default statusText for Response [`#698`](https://github.com/JakeChampion/fetch/pull/698)\n- Document more common pitfalls in the README [`#734`](https://github.com/JakeChampion/fetch/pull/734)\n- field name can not by empty [`#684`](https://github.com/JakeChampion/fetch/pull/684)\n- work around IE XHR bug with '' URL Fixes #618 (#619) [`#618`](https://github.com/JakeChampion/fetch/issues/618)\n- Clarify what parts of the standard we don't want to implement [`#661`](https://github.com/JakeChampion/fetch/issues/661)\n- Document more caveats [`9a0bce2`](https://github.com/JakeChampion/fetch/commit/9a0bce23454cdd5beefd9d4c599664003573e581)\n- Fix issue #533 [`7f030fa`](https://github.com/JakeChampion/fetch/commit/7f030fab4d79433204331cefe365f5fbbab9e992)\n- Compatibility with newer eslint-plugin-github [`1821b74`](https://github.com/JakeChampion/fetch/commit/1821b74b808152d4d6e787c21165f2d569c2a7c4)\n\n\n### [v3.0.0](https://github.com/JakeChampion/fetch/compare/v2.0.4...v3.0.0)\n\n> 7 September 2018\n\n- Add flow definitions [`#654`](https://github.com/JakeChampion/fetch/pull/654)\n- Match spec behavior re: unsupported body type [`#651`](https://github.com/JakeChampion/fetch/pull/651)\n- Update Karma and detect available browsers when testing [`#652`](https://github.com/JakeChampion/fetch/pull/652)\n- Adopt Contributor Covenant Code of Conduct [`#649`](https://github.com/JakeChampion/fetch/pull/649)\n- Change `credentials` default value to `same-origin` [`#640`](https://github.com/JakeChampion/fetch/pull/640)\n- Switch test suite from PhantomJS to Karma [`#626`](https://github.com/JakeChampion/fetch/pull/626)\n- Support abort API [`#592`](https://github.com/JakeChampion/fetch/pull/592)\n- build/distribute as UMD [`#616`](https://github.com/JakeChampion/fetch/pull/616)\n- Test signal reuse. Add AbortSignal polyfill. [`#2`](https://github.com/JakeChampion/fetch/pull/2)\n- Clear abort event listener for all xhr completion states. [`#1`](https://github.com/JakeChampion/fetch/pull/1)\n- Expand install & importing documentation [`#569`](https://github.com/JakeChampion/fetch/issues/569)\n- Match spec behavior re: unsupported body type [`#576`](https://github.com/JakeChampion/fetch/issues/576)\n- Run test files through prettier [`0a57487`](https://github.com/JakeChampion/fetch/commit/0a5748775d99f882172375693f56761383f8faf3)\n- Unwrap `fetch.js` to be a clean module file [`8aec47c`](https://github.com/JakeChampion/fetch/commit/8aec47cb6c67a9a321f1eb07457f70fc46235610)\n- Switch from PhantomJS to Karma + Chrome/Firefox for testing [`b539589`](https://github.com/JakeChampion/fetch/commit/b53958904649bfeb784083b9b7e0b89902c7d30e)\n\n## [v2.0.4](https://github.com/JakeChampion/fetch/compare/v2.0.3...v2.0.4)\n\n> 29 March 2018\n\n- Create CONTRIBUTING.md [`#604`](https://github.com/JakeChampion/fetch/pull/604)\n- Tweak the wording of the “Read this first” section [`#553`](https://github.com/JakeChampion/fetch/pull/553)\n- Allow undefined Response status [`#534`](https://github.com/JakeChampion/fetch/pull/534)\n- Ensure cookies aren't sent if `credentials: omit` [`#526`](https://github.com/JakeChampion/fetch/pull/526)\n- Added yarn command as option to installation [`#492`](https://github.com/JakeChampion/fetch/pull/492)\n- Add global replace for processing raw headers [`#496`](https://github.com/JakeChampion/fetch/pull/496)\n- Added safari to native fetch browser support. [`#469`](https://github.com/JakeChampion/fetch/pull/469)\n- Support obs-fold as header delimiter [`#491`](https://github.com/JakeChampion/fetch/pull/491)\n- Tweak the wording of \"Read this first\" [`54dc3f8`](https://github.com/JakeChampion/fetch/commit/54dc3f823fe3e6452da8d19bf7aad7eda4cd1dd8)\n- Add test for undefined Response status [`0ecdd40`](https://github.com/JakeChampion/fetch/commit/0ecdd40c50d4bcdfd4d2a09448a6d01089dc182a)\n- Fix cookie test with newer versions of Node [`7831671`](https://github.com/JakeChampion/fetch/commit/7831671b172435c52064f588cf7145236fecf5f2)\n\n## [v2.0.3](https://github.com/JakeChampion/fetch/compare/v2.0.2...v2.0.3)\n\n> 2 March 2017\n\n- Accept array in Headers constructor [`#485`](https://github.com/JakeChampion/fetch/pull/485)\n- Improve README language [`#483`](https://github.com/JakeChampion/fetch/pull/483)\n- Fix grammar mistake in README [`#468`](https://github.com/JakeChampion/fetch/pull/468)\n- Remove bower version from release instructions [`5cc72dd`](https://github.com/JakeChampion/fetch/commit/5cc72dd734bfd459a61a61e472c90654d71afc91)\n- Remove extra punctuation [`eebaa2a`](https://github.com/JakeChampion/fetch/commit/eebaa2a1bc21eeba98ee00c9f94a0a4c2007cff1)\n- Fetch 2.0.3 [`d4ed806`](https://github.com/JakeChampion/fetch/commit/d4ed806fdcbdeaef707d27f6c88943f0336a647d)\n\n## [v2.0.2](https://github.com/JakeChampion/fetch/compare/v2.0.1...v2.0.2)\n\n> 19 January 2017\n\n- Treat any non-Request arg to `new Request()` as string url [`#465`](https://github.com/JakeChampion/fetch/pull/465)\n- Support Tolerance Provision when parsing headers [`#449`](https://github.com/JakeChampion/fetch/pull/449)\n- Add test for cloning GET request [`#440`](https://github.com/JakeChampion/fetch/issues/440)\n- Detect broken URL support in PhantomJS and skip test [`b285e61`](https://github.com/JakeChampion/fetch/commit/b285e61fbc4dc21d4b5f7a498046bdff585abf1b)\n- Remove secrets [`9240ef4`](https://github.com/JakeChampion/fetch/commit/9240ef453a1ebc3670b8377f9deb771d684e7f68)\n- fetch 2.0.2 [`b337f95`](https://github.com/JakeChampion/fetch/commit/b337f9578fa8e21fa5c9fe8d6eb74baaa43a1c02)\n\n## [v2.0.1](https://github.com/JakeChampion/fetch/compare/v2.0.0...v2.0.1)\n\n> 17 November 2016\n\n- Fix misspelling of [ae]ffect [`#432`](https://github.com/JakeChampion/fetch/pull/432)\n- Fix reading ArrayBuffer into string on older browsers [`6f8529e`](https://github.com/JakeChampion/fetch/commit/6f8529e4c5ceacc92c97f58a9bc6538879978f3c)\n- Only define `arrayBuffer()` if Blob is also supported [`3d3bb0c`](https://github.com/JakeChampion/fetch/commit/3d3bb0ca72172b224e8101c0a5264adc41f53929)\n- Display uncaught errors on the test results page [`54ec096`](https://github.com/JakeChampion/fetch/commit/54ec0965c25a9889e5ba597421faf7b0790de026)\n\n### [v2.0.0](https://github.com/JakeChampion/fetch/compare/v1.1.1...v2.0.0)\n\n> 14 November 2016\n\n- Change Headers multiple value handling for spec compatibility [`#429`](https://github.com/JakeChampion/fetch/pull/429)\n- Firefox now implements `Headers.forEach` natively [`468f877`](https://github.com/JakeChampion/fetch/commit/468f877e4447a2b267236f2f8fa4f1492c0dd20b)\n- fetch 2.0.0 [`c576d61`](https://github.com/JakeChampion/fetch/commit/c576d61fee39bb34699bbe870460b6120011150a)\n\n## [v1.1.1](https://github.com/JakeChampion/fetch/compare/v1.1.0...v1.1.1)\n\n> 17 November 2016\n\n- Fix reading ArrayBuffer into string on older browsers [`1ddcadb`](https://github.com/JakeChampion/fetch/commit/1ddcadb2418c4cf0b206857f424a9af58c0ed57f)\n- Only define `arrayBuffer()` if Blob is also supported [`c2556f3`](https://github.com/JakeChampion/fetch/commit/c2556f3ed41a238df4ee384fd8e4c404f3971e64)\n- fetch 1.1.1 [`f7a5148`](https://github.com/JakeChampion/fetch/commit/f7a514829820fc77c0f884c74cf2d36356a781c0)\n\n## [v1.1.0](https://github.com/JakeChampion/fetch/compare/v1.0.0...v1.1.0)\n\n> 14 November 2016\n\n- Support ArrayBufferView types as POST body [`#430`](https://github.com/JakeChampion/fetch/pull/430)\n- Spec compatibility for Request/Response constructors and cloning [`#428`](https://github.com/JakeChampion/fetch/pull/428)\n- Improve Readme [`#427`](https://github.com/JakeChampion/fetch/pull/427)\n- Fix grammar [`#408`](https://github.com/JakeChampion/fetch/pull/408)\n- Fixed typo in README.md [`#403`](https://github.com/JakeChampion/fetch/pull/403)\n- make X-Request-URL header case-insensitive [`#384`](https://github.com/JakeChampion/fetch/pull/384)\n- Better error handling with Saucelabs [`#354`](https://github.com/JakeChampion/fetch/pull/354)\n- Update Webpack section in README [`#331`](https://github.com/JakeChampion/fetch/pull/331)\n- Attach FileReader event handlers before calling its `read*` method [`#353`](https://github.com/JakeChampion/fetch/issues/353)\n- Default Response status is 200 OK [`#376`](https://github.com/JakeChampion/fetch/issues/376)\n- Support ArrayBuffer in BodyInit [`#350`](https://github.com/JakeChampion/fetch/issues/350)\n- Avoid consuming body when cloning [`#308`](https://github.com/JakeChampion/fetch/issues/308) [`#335`](https://github.com/JakeChampion/fetch/issues/335)\n- Rework parsing of raw response HTTP headers [`#422`](https://github.com/JakeChampion/fetch/issues/422)\n- Allow reusing the same GET Request instance multiple times [`#411`](https://github.com/JakeChampion/fetch/issues/411)\n- Always construct a new Headers instance in Response [`#416`](https://github.com/JakeChampion/fetch/issues/416)\n- Rework the Installation section [`#415`](https://github.com/JakeChampion/fetch/issues/415)\n- More information about cookies [`#393`](https://github.com/JakeChampion/fetch/issues/393)\n- It looks like Safari 10 didn't ship with native fetch [`#401`](https://github.com/JakeChampion/fetch/issues/401)\n- Reorganize tests with the new \"fetch method\" suite [`ba7ffda`](https://github.com/JakeChampion/fetch/commit/ba7ffda7b2bf6b9183fbca04120c042babd17f00)\n- Share identical tests between Request & Response [`9a04a06`](https://github.com/JakeChampion/fetch/commit/9a04a0667b92dba567746b26b553ab9a329fa94d)\n- ArrayBuffer can now be consumed through `blob()`/`text()` [`9a703ba`](https://github.com/JakeChampion/fetch/commit/9a703ba38ff3bddc94c8929c1e8fae5d766462cd)\n\n### [v1.0.0](https://github.com/JakeChampion/fetch/compare/v0.11.1...v1.0.0)\n\n> 28 April 2016\n\n- refactor Header iterator methods [`#317`](https://github.com/JakeChampion/fetch/pull/317)\n- Add ES2015+ example [`#287`](https://github.com/JakeChampion/fetch/pull/287)\n- Switch to `mocha-phantomjs-core` and system PhantomJS [`#314`](https://github.com/JakeChampion/fetch/pull/314)\n- Reject promise on request timeout [`#306`](https://github.com/JakeChampion/fetch/pull/306)\n- Use uppercase methods in README [`#272`](https://github.com/JakeChampion/fetch/pull/272)\n- Guard against `xhr.getAllResponseHeaders()` being `null` [`#289`](https://github.com/JakeChampion/fetch/pull/289)\n- Add support for URLSearchParams POST body [`#304`](https://github.com/JakeChampion/fetch/pull/304)\n- Add Headers iterators [`#295`](https://github.com/JakeChampion/fetch/pull/295)\n- fix example [`#282`](https://github.com/JakeChampion/fetch/pull/282)\n- Drop IE-specific status codes workarounds and require IE10+ [`#270`](https://github.com/JakeChampion/fetch/pull/270)\n- Reject promise on request timeout [`#294`](https://github.com/JakeChampion/fetch/issues/294)\n- Make Headers iterable if Symbol is available [`a1b7674`](https://github.com/JakeChampion/fetch/commit/a1b7674b6942d4265ea47b74760a486b2bf5e3da)\n- Support URLSearchParams POST body [`d77810a`](https://github.com/JakeChampion/fetch/commit/d77810a15c78bbbaf2defd4ea3af6db21c8d117f)\n- Fix formatting [`edb7c73`](https://github.com/JakeChampion/fetch/commit/edb7c7336f53b5c0e08ef0ccb37e43c8d9de778f)\n\n## [v0.11.1](https://github.com/JakeChampion/fetch/compare/v0.11.0...v0.11.1)\n\n> 5 May 2016\n\n- Reject promise on request timeout [`#294`](https://github.com/JakeChampion/fetch/issues/294)\n- Fix formatting [`3fc66ed`](https://github.com/JakeChampion/fetch/commit/3fc66edc4c0f61a60b2debfca276a7a8140aa2c9)\n- Fetch 0.11.1 [`7d9a11d`](https://github.com/JakeChampion/fetch/commit/7d9a11deec5c0ea2d453390be647ba52695166f8)\n- Guard against `xhr.getAllResponseHeaders()` being `null` [`8deb829`](https://github.com/JakeChampion/fetch/commit/8deb8296681f6ad0990e0af47b99d71f2a1d1701)\n\n## [v0.11.0](https://github.com/JakeChampion/fetch/compare/v0.10.1...v0.11.0)\n\n> 19 January 2016\n\n- Handle cases where `self` isn't defined [`#253`](https://github.com/JakeChampion/fetch/pull/253)\n- Exercise both polyfill and native `fetch` in test suite [`#258`](https://github.com/JakeChampion/fetch/pull/258)\n- Make fetch add a `Content-Type` header based on the type of the body. [`1e4a615`](https://github.com/JakeChampion/fetch/commit/1e4a6151e6a1f4e2e792f7faa0a028498a7be973)\n- Cleanup in determining implicit content-type [`3b5dc9c`](https://github.com/JakeChampion/fetch/commit/3b5dc9c17f2be9ca1a2e7030dd8209f0b150bc70)\n- Render main test suite as root resource of test server [`b043384`](https://github.com/JakeChampion/fetch/commit/b043384e2d7b68b10172a64e5c5b00a593cd41c3)\n\n## [v0.10.1](https://github.com/JakeChampion/fetch/compare/v0.10.0...v0.10.1)\n\n> 2 November 2015\n\n- Allow making a POST request with an ArrayBuffer body [`#227`](https://github.com/JakeChampion/fetch/pull/227)\n- Run Sauce Labs CI for pull requests [`#220`](https://github.com/JakeChampion/fetch/pull/220)\n- Streamline Sauce Labs API interactions [`07dc8ae`](https://github.com/JakeChampion/fetch/commit/07dc8ae4cc9a46ad4af35c99a8bdc0b83fbae28b)\n- Download and start Sauce Connect manually [`b3885b4`](https://github.com/JakeChampion/fetch/commit/b3885b4eceb4a818e7f8d2d290f89f4d8eaeb0d3)\n- Switch to my credentials for npm publish from CI [`e0a4851`](https://github.com/JakeChampion/fetch/commit/e0a48518734aac116f49962c825522ab99da8338)\n\n## [v0.10.0](https://github.com/JakeChampion/fetch/compare/v0.9.0...v0.10.0)\n\n> 12 October 2015\n\n- Remove moot `version` property from bower.json [`#159`](https://github.com/JakeChampion/fetch/pull/159)\n- Use absolute URL in Response.redirect test [`#219`](https://github.com/JakeChampion/fetch/pull/219)\n- Support Response.error() and Response.redirect() [`#212`](https://github.com/JakeChampion/fetch/pull/212)\n- Reject the Promise returned by fetch() when Request ctor throws [`#217`](https://github.com/JakeChampion/fetch/pull/217)\n- Fix incorrect assertion [`#216`](https://github.com/JakeChampion/fetch/pull/216)\n- Remove superfluous assignment [`#213`](https://github.com/JakeChampion/fetch/pull/213)\n- Add webpack usage link. [`#195`](https://github.com/JakeChampion/fetch/pull/195)\n- Allow passing a Request instance to Request constructor [`#179`](https://github.com/JakeChampion/fetch/pull/179)\n- Properly convert undefined/null header values to strings. [`#156`](https://github.com/JakeChampion/fetch/pull/156)\n- Code of Conduct [`#174`](https://github.com/JakeChampion/fetch/pull/174)\n- Improve documentation for `fetch` caveats [`#164`](https://github.com/JakeChampion/fetch/pull/164)\n- Opt into new Travis infrastructure [`#158`](https://github.com/JakeChampion/fetch/pull/158)\n- Merge branch 'orphan-black' [`#209`](https://github.com/JakeChampion/fetch/issues/209) [`#185`](https://github.com/JakeChampion/fetch/issues/185)\n- Add include credentials example. [`#205`](https://github.com/JakeChampion/fetch/issues/205)\n- Add `Request.clone()` and `Response.clone()` methods [`46705f7`](https://github.com/JakeChampion/fetch/commit/46705f798e1c6e6c9ef03156a8ec8f64c9971d69)\n- Fix and simplify `Request.clone()` [`fd362dd`](https://github.com/JakeChampion/fetch/commit/fd362ddb1dcb6918cf8203c99f40d7fed019afc4)\n- Expand caveats with notes about cookies [`184b647`](https://github.com/JakeChampion/fetch/commit/184b64719f90ba0cc88c6eeb43c9a2a7ea5fb726)\n\n## [v0.9.0](https://github.com/JakeChampion/fetch/compare/v0.8.2...v0.9.0)\n\n> 29 May 2015\n\n- Implement Headers#forEach correctly [`#150`](https://github.com/JakeChampion/fetch/pull/150)\n- Test forEach. [`2f442ce`](https://github.com/JakeChampion/fetch/commit/2f442cebf84f3e7057e2d94408a1b9ec4643c783)\n- Fix forEach parameters. [`0449483`](https://github.com/JakeChampion/fetch/commit/0449483b4ab1e9184e74302e1c6fb17e9cd44a75)\n- Accept a thisArg forEach parameter. [`bd2fe03`](https://github.com/JakeChampion/fetch/commit/bd2fe03140cfdaf4bd38ca5b4798c775a58b6fd5)\n\n## [v0.8.2](https://github.com/JakeChampion/fetch/compare/v0.8.1...v0.8.2)\n\n> 19 May 2015\n\n- Set xhr.withCredentials after xhr.open called. [`a847967`](https://github.com/JakeChampion/fetch/commit/a847967a0314a574dada2c31e1825f75ed6dc24a)\n- Only support standard options. [`cc9f4b0`](https://github.com/JakeChampion/fetch/commit/cc9f4b0e3e2aaa8cf751dfc2098e58a94fc71e59)\n- Fetch 0.8.2 [`0b3e1d7`](https://github.com/JakeChampion/fetch/commit/0b3e1d7c41c75359a3e0b771741ebc2a8823da38)\n\n## [v0.8.1](https://github.com/JakeChampion/fetch/compare/v0.8.0...v0.8.1)\n\n> 4 May 2015\n\n- Fetch 0.8.1 [`09c316d`](https://github.com/JakeChampion/fetch/commit/09c316d2450c08fde129336438b3a44de4e8177c)\n- Ignore script/ dir [`2e39db1`](https://github.com/JakeChampion/fetch/commit/2e39db1b02c5453ed9c3e156f5d68240f0e76907)\n\n## [v0.8.0](https://github.com/JakeChampion/fetch/compare/v0.7.0...v0.8.0)\n\n> 4 May 2015\n\n- only define _initBody once [`#136`](https://github.com/JakeChampion/fetch/pull/136)\n- remove un-needed promise allocations in example [`#120`](https://github.com/JakeChampion/fetch/pull/120)\n- Headers constructor in Response constructor [`#107`](https://github.com/JakeChampion/fetch/pull/107)\n- Sauce: IE9 [`#102`](https://github.com/JakeChampion/fetch/pull/102)\n- Sauce Labs: IE 11 [`#101`](https://github.com/JakeChampion/fetch/pull/101)\n- Sauce Labs [`#99`](https://github.com/JakeChampion/fetch/pull/99)\n- Add a convenience `ok` getter on `Response` [`#82`](https://github.com/JakeChampion/fetch/pull/82)\n- Follow spec on Headers to throw TypeError, add tests for Headers [`#85`](https://github.com/JakeChampion/fetch/pull/85)\n- adds .npmignore [`#84`](https://github.com/JakeChampion/fetch/pull/84)\n- node.js module link [`#81`](https://github.com/JakeChampion/fetch/pull/81)\n- Add script runner for saucelabs [`47fc7d5`](https://github.com/JakeChampion/fetch/commit/47fc7d5a8431505af8dec8326e5d081219ad7d6a)\n- Split app and server [`29cc5dc`](https://github.com/JakeChampion/fetch/commit/29cc5dc74441679c63e99145ba841f8abd29da17)\n- More scripty [`ba1214a`](https://github.com/JakeChampion/fetch/commit/ba1214acaf766eba9e0a268de495d8b9c9e295c1)\n\n## [v0.7.0](https://github.com/JakeChampion/fetch/compare/v0.6.1...v0.7.0)\n\n> 24 January 2015\n\n- Centralise the checks for blob and form data support [`#78`](https://github.com/JakeChampion/fetch/pull/78)\n- If cors, with credentials [`#77`](https://github.com/JakeChampion/fetch/pull/77)\n- Add metadata for repository, bugs and license [`#67`](https://github.com/JakeChampion/fetch/pull/67)\n- Declare deliberate \"async=true\" on XMLHttpRequest open [`#74`](https://github.com/JakeChampion/fetch/pull/74)\n- Fix typo in npm install instructions [`#71`](https://github.com/JakeChampion/fetch/pull/71)\n- Improve Request/Response BodyInit consuming [`#70`](https://github.com/JakeChampion/fetch/pull/70)\n- Fix up body consuming on request [`fbfa9e3`](https://github.com/JakeChampion/fetch/commit/fbfa9e332039d3d4e4e91da6038729d061455ef1)\n- Throw TypeError if body is given for GET or HEAD [`5ce5677`](https://github.com/JakeChampion/fetch/commit/5ce56771da78d341561887df2bb65f78425333c4)\n- A few more tests and typo fix. [`614b2aa`](https://github.com/JakeChampion/fetch/commit/614b2aab10525f8e2a55124fdb33b374b61a0c87)\n\n## [v0.6.1](https://github.com/JakeChampion/fetch/compare/v0.6.0...v0.6.1)\n\n> 15 January 2015\n\n- Add charset content-type tests [`7474e42`](https://github.com/JakeChampion/fetch/commit/7474e42af467bcd843f97a3def92b0c7d63e4f48)\n- Add additional body init and consume test coverage [`9d58648`](https://github.com/JakeChampion/fetch/commit/9d586486e50a79551b1d12178b3408d1fd57cb35)\n- Fix X-Request-URL on CORS requests [`4525329`](https://github.com/JakeChampion/fetch/commit/4525329eb075da74fd7585d4ea8ddeabc97b17a4)\n\n## [v0.6.0](https://github.com/JakeChampion/fetch/compare/v0.5.0...v0.6.0)\n\n> 12 January 2015\n\n- Suspect this api key was wrong [`#63`](https://github.com/JakeChampion/fetch/pull/63)\n- Use responseText on IE9 which lacks XHR2 support [`eeb53d3`](https://github.com/JakeChampion/fetch/commit/eeb53d391dcb12a2d77765bf602fc45427112687)\n- Tidy up binary file reader [`7436589`](https://github.com/JakeChampion/fetch/commit/74365897619b533fe7b9080568ad43e852130974)\n- Use `xhr.responseType = 'blob'` to preserve binary data. [`080358d`](https://github.com/JakeChampion/fetch/commit/080358ddb26ff37cfd27caf730af9cd3c184bc42)\n\n## [v0.5.0](https://github.com/JakeChampion/fetch/compare/v0.4.0...v0.5.0)\n\n> 12 January 2015\n\n- Enable travis to publish to npm. [`#57`](https://github.com/JakeChampion/fetch/pull/57)\n- Make Headers case insensitive though lowercasing. [`#62`](https://github.com/JakeChampion/fetch/pull/62)\n- Support credentials [`#56`](https://github.com/JakeChampion/fetch/pull/56)\n- Switch to Mocha [`#59`](https://github.com/JakeChampion/fetch/pull/59)\n- Test Atomic HTTP redirect handling [`#55`](https://github.com/JakeChampion/fetch/pull/55)\n- Mark FormData support as optional [`#54`](https://github.com/JakeChampion/fetch/pull/54)\n- Add promise test helper [`#53`](https://github.com/JakeChampion/fetch/pull/53)\n- Test in web worker [`#51`](https://github.com/JakeChampion/fetch/issues/51)\n- Group tests [`ecd8600`](https://github.com/JakeChampion/fetch/commit/ecd8600932b0d8495d646df0d6fa74874cd57713)\n- Switch to mocha [`cbd6c66`](https://github.com/JakeChampion/fetch/commit/cbd6c66fe4bbda1b63cef54c299c2081c4b50955)\n- Skip tests in phantomjs [`8a4b620`](https://github.com/JakeChampion/fetch/commit/8a4b62027ea7c590861364e853eccb5f52a8991b)\n\n## [v0.4.0](https://github.com/JakeChampion/fetch/compare/v0.3.2...v0.4.0)\n\n> 29 December 2014\n\n- Assign to self [`#52`](https://github.com/JakeChampion/fetch/pull/52)\n- Web Workers support [`#48`](https://github.com/JakeChampion/fetch/pull/48)\n- Align used flag error message to Chrome's implementation [`#44`](https://github.com/JakeChampion/fetch/pull/44)\n- Add missing quote. [`#40`](https://github.com/JakeChampion/fetch/issues/40)\n- Align bodyUsed error message to Chrome's implementation [`e414284`](https://github.com/JakeChampion/fetch/commit/e4142843fab42705cc65d526bf86b1662da7f338)\n- Avoid testing implementation specific error messages [`cc42153`](https://github.com/JakeChampion/fetch/commit/cc4215367d2298f779ee9a5ab3f8c9cb6207c8c5)\n- Set esnext option [`3ebc441`](https://github.com/JakeChampion/fetch/commit/3ebc44129997dbc2e331450b6e876b8f6e36437b)\n\n## [v0.3.2](https://github.com/JakeChampion/fetch/compare/v0.3.1...v0.3.2)\n\n> 24 November 2014\n\n- FormData should only able to consume once [`#38`](https://github.com/JakeChampion/fetch/pull/38)\n- Test formData body consumption. [`4a7e655`](https://github.com/JakeChampion/fetch/commit/4a7e655b4f0361524d16adb16148c1fe0f2f1f0f)\n- Fetch 0.3.2 [`830231e`](https://github.com/JakeChampion/fetch/commit/830231e5682175fe04088b291192f72c59aed998)\n\n## [v0.3.1](https://github.com/JakeChampion/fetch/compare/v0.3.0...v0.3.1)\n\n> 21 November 2014\n\n- Reject promise with TypeError for network failures. [`#36`](https://github.com/JakeChampion/fetch/pull/36)\n- Reject example promise with an Error. [`#35`](https://github.com/JakeChampion/fetch/issues/35)\n- Fetch 0.3.1 [`eb3f9b2`](https://github.com/JakeChampion/fetch/commit/eb3f9b2b1fa7804883cbf853102944847d65e204)\n\n## [v0.3.0](https://github.com/JakeChampion/fetch/compare/v0.2.1...v0.3.0)\n\n> 13 November 2014\n\n- IE 9+ fixes [`#28`](https://github.com/JakeChampion/fetch/pull/28)\n- Move body to _body to prevent direct access [`#32`](https://github.com/JakeChampion/fetch/pull/32)\n- Remove form encoded object body. [`#30`](https://github.com/JakeChampion/fetch/pull/30)\n- Document how to use in Browserify… [`#29`](https://github.com/JakeChampion/fetch/pull/29)\n- Auto-detect available port when running headless tests [`#27`](https://github.com/JakeChampion/fetch/pull/27)\n- Shell highlight [`#24`](https://github.com/JakeChampion/fetch/pull/24)\n- use shorthand npm installation [`#23`](https://github.com/JakeChampion/fetch/pull/23)\n- Add name/version/main so it can be installed from npm. [`#22`](https://github.com/JakeChampion/fetch/pull/22)\n- Add example of success and error handlers [`#18`](https://github.com/JakeChampion/fetch/pull/18)\n- Test Server [`#13`](https://github.com/JakeChampion/fetch/pull/13)\n- Travis [`#12`](https://github.com/JakeChampion/fetch/pull/12)\n- Add test server [`3316bda`](https://github.com/JakeChampion/fetch/commit/3316bdaf03e4ef2eef35161913efca9a8bd31457)\n- Uppercase the HTTP method name [`c71f1dd`](https://github.com/JakeChampion/fetch/commit/c71f1dd9bb0a84453ad2e14cb4a638cc735e1344)\n- Skip blob tests on phantom [`c02cad2`](https://github.com/JakeChampion/fetch/commit/c02cad221e0d239dd79e42f2d91c9bb48501776c)\n\n## [v0.2.1](https://github.com/JakeChampion/fetch/compare/v0.2.0...v0.2.1)\n\n> 15 October 2014\n\n- Use of `Promise.reject` as a constructor [`#10`](https://github.com/JakeChampion/fetch/pull/10)\n- Fixed uncaught error when a body was consumed more than once. [`e428559`](https://github.com/JakeChampion/fetch/commit/e428559a68f5c9d445bf2fb5a91fb3f7e35b2f5d)\n- Fetch 0.2.1 [`8160180`](https://github.com/JakeChampion/fetch/commit/81601803ec9fd1ffa29f4d527b12e586dd9840c1)\n\n## [v0.2.0](https://github.com/JakeChampion/fetch/compare/v0.1.0...v0.2.0)\n\n> 15 October 2014\n\n- Parse form encoded response body [`#8`](https://github.com/JakeChampion/fetch/pull/8)\n- Allow body to be consumed only once [`#7`](https://github.com/JakeChampion/fetch/pull/7)\n- throw proper errors [`#5`](https://github.com/JakeChampion/fetch/pull/5)\n- Allow body to be consumed a single time. [`c7a27dc`](https://github.com/JakeChampion/fetch/commit/c7a27dc12f43f398f8159db98f3745d8c3320515)\n- Parse form encoded response body. [`60271ce`](https://github.com/JakeChampion/fetch/commit/60271cef8aa13641ba99c197f974fbb4a5f77c57)\n- Extract consumed function. [`a709976`](https://github.com/JakeChampion/fetch/commit/a7099768059b9befbb656c6b1e3944bad8a97327)\n\n## v0.1.0\n\n> 13 October 2014\n\n- 🐶 [`c1af6de`](https://github.com/JakeChampion/fetch/commit/c1af6de1e87d2753203f2e750e48b625fac2e24a)\n- Start tests. [`44e796a`](https://github.com/JakeChampion/fetch/commit/44e796a874dd88bfd365cc6dcddfe973daeec08a)\n- Add readme. [`7eee89d`](https://github.com/JakeChampion/fetch/commit/7eee89d15ee21e762a04b4c773fcc3d7d50a13f7)\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 contributors and maintainers pledge to making participation in our project and our community a harassment-free experience for everyone, regardless of age, body size, disability, ethnicity, gender identity and expression, level of experience, nationality, personal appearance, race, religion, or sexual identity and orientation.\n\n## Our Standards\n\nExamples of behavior that contributes to creating a positive environment include:\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 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 address, without explicit permission\n* Other conduct which could reasonably be considered inappropriate in a professional setting\n\n## Our Responsibilities\n\nProject maintainers are responsible for clarifying the standards of acceptable behavior and are expected to take appropriate and fair corrective action in response to any instances of unacceptable behavior.\n\nProject maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct, or to ban temporarily or permanently any contributor for other behaviors that they deem inappropriate, threatening, offensive, or harmful.\n\n## Scope\n\nThis Code of Conduct applies both within project spaces and in public spaces when an individual is representing the project or its community. Examples of representing a project or community include using an official project e-mail address, posting via an official social media account, or acting as an appointed representative at an online or offline event. Representation of a project may be further defined and clarified by project maintainers.\n\n## Enforcement\n\nInstances of abusive, harassing, or otherwise unacceptable behavior may be reported by contacting the project team at opensource+fetch@github.com. The project team will review and investigate all complaints, and will respond in a way that it deems appropriate to the circumstances. The project team is obligated to maintain confidentiality with regard to the reporter of an incident. Further details of specific enforcement policies may be posted separately.\n\nProject maintainers who do not follow or enforce the Code of Conduct in good faith may face temporary or permanent repercussions as determined by other members of the project's leadership.\n\n## Attribution\n\nThis Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, available at [http://contributor-covenant.org/version/1/4][version]\n\n[homepage]: http://contributor-covenant.org\n[version]: http://contributor-covenant.org/version/1/4/\n"
  },
  {
    "path": "CONTRIBUTING.md",
    "content": "# Contributing\n\nThank you for your interest in contributing to our `fetch` polyfill!\n\nNote that we only accept features that are also described in the official [fetch\nspecification][]. However, the aim of this project is not to implement the\ncomplete specification; just the parts that are feasible to emulate using\nXMLHttpRequest. See [Caveats][] for some examples of features that we are\nunlikely to implement.\n\nContributions to this project are [released][tos] to the public under the\n[project's open source license](LICENSE).\n\n## Running tests\n\nRunning `npm test` will:\n\n1. Build the `dist/` files;\n1. Run the test suite in headless Chrome & Firefox;\n1. Run the same test suite in Web Worker mode.\n\nWhen editing tests or implementation, keep `npm run karma` running:\n\n- You can connect additional browsers by navigating to `http://localhost:9876/`;\n- Changes to [test.js](test/test.js) will automatically re-run the tests in all\n  connected browsers;\n- When changing [fetch.js](fetch.js), re-run tests by executing `make`;\n- Re-run specific tests with `./node_modules/.bin/karma run -- --grep=<PATTERN>`.\n\n## Submitting a pull request\n\n1. [Fork][fork] and clone the repository;\n1. Create a new branch: `git checkout -b my-branch-name`;\n1. Make your change, push to your fork and [submit a pull request][pr];\n1. Pat your self on the back and wait for your pull request to be reviewed.\n\nHere are a few things you can do that will increase the likelihood of your pull\nrequest being accepted:\n\n- Keep your change as focused as possible. If there are multiple changes you\n  would like to make that are not dependent upon each other, consider submitting\n  them as separate pull requests.\n- Write a [good commit message][].\n\n## Resources\n\n- [How to Contribute to Open Source](https://opensource.guide/how-to-contribute/)\n- [Using Pull Requests](https://help.github.com/articles/about-pull-requests/)\n- [GitHub Help](https://help.github.com)\n\n\n  [fetch specification]: https://fetch.spec.whatwg.org\n  [tos]: https://help.github.com/articles/github-terms-of-service/#6-contributions-under-repository-license\n  [fork]: https://github.com/github/fetch/fork\n  [pr]: https://github.com/github/fetch/compare\n  [good commit message]: http://tbaggery.com/2008/04/19/a-note-about-git-commit-messages.html\n  [caveats]: https://github.github.io/fetch/#caveats\n"
  },
  {
    "path": "LICENSE",
    "content": "Copyright (c) 2014-2023 GitHub, Inc.\n\nPermission is hereby granted, free of charge, to any person obtaining\na copy of this software and associated documentation files (the\n\"Software\"), to deal in the Software without restriction, including\nwithout limitation the rights to use, copy, modify, merge, publish,\ndistribute, sublicense, and/or sell copies of the Software, and to\npermit persons to whom the Software is furnished to do so, subject to\nthe following conditions:\n\nThe above copyright notice and this permission notice shall be\nincluded in all copies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND,\nEXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\nMERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND\nNONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE\nLIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION\nOF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION\nWITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n"
  },
  {
    "path": "Makefile",
    "content": "test: lint dist/fetch.umd.js\n\nlint: node_modules/\n\t./node_modules/.bin/eslint --report-unused-disable-directives *.js test/*.js\n\ndist/fetch.umd.js: fetch.js rollup.config.js node_modules/\n\t./node_modules/.bin/rollup -c\n\ndist/fetch.umd.js.flow: fetch.js.flow\n\tcp $< $@\n\nnode_modules/:\n\tnpm install\n\nclean:\n\trm -rf ./bower_components ./node_modules ./dist\n\n.PHONY: clean lint test make dist/fetch.umd.js dist/fetch.umd.js.flow\n"
  },
  {
    "path": "README.md",
    "content": "# window.fetch polyfill\n\n[![OpenSSF Scorecard](https://api.securityscorecards.dev/projects/github.com/JakeChampion/fetch/badge)](https://securityscorecards.dev/viewer/?uri=github.com/JakeChampion/fetch)\n\nThe `fetch()` function is a Promise-based mechanism for programmatically making\nweb requests in the browser. This project is a polyfill that implements a subset\nof the standard [Fetch specification][], enough to make `fetch` a viable\nreplacement for most uses of XMLHttpRequest in traditional web applications.\n\n## Table of Contents\n\n* [Read this first](#read-this-first)\n* [Installation](#installation)\n* [Usage](#usage)\n  * [Importing](#importing)\n  * [HTML](#html)\n  * [JSON](#json)\n  * [Response metadata](#response-metadata)\n  * [Post form](#post-form)\n  * [Post JSON](#post-json)\n  * [File upload](#file-upload)\n  * [Caveats](#caveats)\n    * [Handling HTTP error statuses](#handling-http-error-statuses)\n    * [Sending cookies](#sending-cookies)\n    * [Receiving cookies](#receiving-cookies)\n    * [Redirect modes](#redirect-modes)\n    * [Obtaining the Response URL](#obtaining-the-response-url)\n    * [Aborting requests](#aborting-requests)\n* [Browser Support](#browser-support)\n\n## Read this first\n\n* If you believe you found a bug with how `fetch` behaves in your browser,\n  please **don't open an issue in this repository** unless you are testing in\n  an old version of a browser that doesn't support `window.fetch` natively.\n  Make sure you read this _entire_ readme, especially the [Caveats](#caveats)\n  section, as there's probably a known work-around for an issue you've found.\n  This project is a _polyfill_, and since all modern browsers now implement the\n  `fetch` function natively, **no code from this project** actually takes any\n  effect there. See [Browser support](#browser-support) for detailed\n  information.\n\n* If you have trouble **making a request to another domain** (a different\n  subdomain or port number also constitutes another domain), please familiarize\n  yourself with all the intricacies and limitations of [CORS][] requests.\n  Because CORS requires participation of the server by implementing specific\n  HTTP response headers, it is often nontrivial to set up or debug. CORS is\n  exclusively handled by the browser's internal mechanisms which this polyfill\n  cannot influence.\n\n* This project **doesn't work under Node.js environments**. It's meant for web\n  browsers only. You should ensure that your application doesn't try to package\n  and run this on the server.\n\n* If you have an idea for a new feature of `fetch`, **submit your feature\n  requests** to the [specification's repository](https://github.com/whatwg/fetch/issues).\n  We only add features and APIs that are part of the [Fetch specification][].\n\n## Installation\n\n```\nnpm install whatwg-fetch --save\n```\n\nYou will also need a Promise polyfill for [older browsers](https://caniuse.com/promises).\nWe recommend [taylorhakes/promise-polyfill](https://github.com/taylorhakes/promise-polyfill)\nfor its small size and Promises/A+ compatibility.\n\n## Usage\n\n### Importing\n\nImporting will automatically polyfill `window.fetch` and related APIs:\n\n```javascript\nimport 'whatwg-fetch'\n\nwindow.fetch(...)\n```\n\nIf for some reason you need to access the polyfill implementation, it is\navailable via exports:\n\n```javascript\nimport {fetch as fetchPolyfill} from 'whatwg-fetch'\n\nwindow.fetch(...)   // use native browser version\nfetchPolyfill(...)  // use polyfill implementation\n```\n\nThis approach can be used to, for example, use [abort\nfunctionality](#aborting-requests) in browsers that implement a native but\noutdated version of fetch that doesn't support aborting.\n\nFor use with webpack, add this package in the `entry` configuration option\nbefore your application entry point:\n\n```javascript\nentry: ['whatwg-fetch', ...]\n```\n\n### HTML\n\n```javascript\nfetch('/users.html')\n  .then(function(response) {\n    return response.text()\n  }).then(function(body) {\n    document.body.innerHTML = body\n  })\n```\n\n### JSON\n\n```javascript\nfetch('/users.json')\n  .then(function(response) {\n    return response.json()\n  }).then(function(json) {\n    console.log('parsed json', json)\n  }).catch(function(ex) {\n    console.log('parsing failed', ex)\n  })\n```\n\n### Response metadata\n\n```javascript\nfetch('/users.json').then(function(response) {\n  console.log(response.headers.get('Content-Type'))\n  console.log(response.headers.get('Date'))\n  console.log(response.status)\n  console.log(response.statusText)\n})\n```\n\n### Post form\n\n```javascript\nvar form = document.querySelector('form')\n\nfetch('/users', {\n  method: 'POST',\n  body: new FormData(form)\n})\n```\n\n### Post JSON\n\n```javascript\nfetch('/users', {\n  method: 'POST',\n  headers: {\n    'Content-Type': 'application/json'\n  },\n  body: JSON.stringify({\n    name: 'Hubot',\n    login: 'hubot',\n  })\n})\n```\n\n### File upload\n\n```javascript\nvar input = document.querySelector('input[type=\"file\"]')\n\nvar data = new FormData()\ndata.append('file', input.files[0])\ndata.append('user', 'hubot')\n\nfetch('/avatars', {\n  method: 'POST',\n  body: data\n})\n```\n\n### Caveats\n\n* The Promise returned from `fetch()` **won't reject on HTTP error status**\n  even if the response is an HTTP 404 or 500. Instead, it will resolve normally,\n  and it will only reject on network failure or if anything prevented the\n  request from completing.\n\n* For maximum browser compatibility when it comes to sending & receiving\n  cookies, always supply the `credentials: 'same-origin'` option instead of\n  relying on the default. See [Sending cookies](#sending-cookies).\n\n* Not all Fetch standard options are supported in this polyfill. For instance,\n  [`redirect`](#redirect-modes) and\n  `cache` directives are ignored.\n  \n* `keepalive` is not supported because it would involve making a synchronous XHR, which is something this project is not willing to do. See [issue #700](https://github.com/github/fetch/issues/700#issuecomment-484188326) for more information.\n\n#### Handling HTTP error statuses\n\nTo have `fetch` Promise reject on HTTP error statuses, i.e. on any non-2xx\nstatus, define a custom response handler:\n\n```javascript\nfunction checkStatus(response) {\n  if (response.status >= 200 && response.status < 300) {\n    return response\n  } else {\n    var error = new Error(response.statusText)\n    error.response = response\n    throw error\n  }\n}\n\nfunction parseJSON(response) {\n  return response.json()\n}\n\nfetch('/users')\n  .then(checkStatus)\n  .then(parseJSON)\n  .then(function(data) {\n    console.log('request succeeded with JSON response', data)\n  }).catch(function(error) {\n    console.log('request failed', error)\n  })\n```\n\n#### Sending cookies\n\nFor [CORS][] requests, use `credentials: 'include'` to allow sending credentials\nto other domains:\n\n```javascript\nfetch('https://example.com:1234/users', {\n  credentials: 'include'\n})\n```\n\nThe default value for `credentials` is \"same-origin\".\n\nThe default for `credentials` wasn't always the same, though. The following\nversions of browsers implemented an older version of the fetch specification\nwhere the default was \"omit\":\n\n* Firefox 39-60\n* Chrome 42-67\n* Safari 10.1-11.1.2\n\nIf you target these browsers, it's advisable to always specify `credentials:\n'same-origin'` explicitly with all fetch requests instead of relying on the\ndefault:\n\n```javascript\nfetch('/users', {\n  credentials: 'same-origin'\n})\n```\n\nNote: due to [limitations of\nXMLHttpRequest](https://github.com/github/fetch/pull/56#issuecomment-68835992),\nusing `credentials: 'omit'` is not respected for same domains in browsers where\nthis polyfill is active. Cookies will always be sent to same domains in older\nbrowsers.\n\n#### Receiving cookies\n\nAs with XMLHttpRequest, the `Set-Cookie` response header returned from the\nserver is a [forbidden header name][] and therefore can't be programmatically\nread with `response.headers.get()`. Instead, it's the browser's responsibility\nto handle new cookies being set (if applicable to the current URL). Unless they\nare HTTP-only, new cookies will be available through `document.cookie`.\n\n#### Redirect modes\n\nThe Fetch specification defines these values for [the `redirect`\noption](https://fetch.spec.whatwg.org/#concept-request-redirect-mode): \"follow\"\n(the default), \"error\", and \"manual\".\n\nDue to limitations of XMLHttpRequest, only the \"follow\" mode is available in\nbrowsers where this polyfill is active.\n\n#### Obtaining the Response URL\n\nDue to limitations of XMLHttpRequest, the `response.url` value might not be\nreliable after HTTP redirects on older browsers.\n\nThe solution is to configure the server to set the response HTTP header\n`X-Request-URL` to the current URL after any redirect that might have happened.\nIt should be safe to set it unconditionally.\n\n``` ruby\n# Ruby on Rails controller example\nresponse.headers['X-Request-URL'] = request.url\n```\n\nThis server workaround is necessary if you need reliable `response.url` in\nFirefox < 32, Chrome < 37, Safari, or IE.\n\n#### Aborting requests\n\nThis polyfill supports\n[the abortable fetch API](https://developers.google.com/web/updates/2017/09/abortable-fetch).\nHowever, aborting a fetch requires use of two additional DOM APIs:\n[AbortController](https://developer.mozilla.org/en-US/docs/Web/API/AbortController) and\n[AbortSignal](https://developer.mozilla.org/en-US/docs/Web/API/AbortSignal).\nTypically, browsers that do not support fetch will also not support\nAbortController or AbortSignal. Consequently, you will need to include\n[an additional polyfill](https://www.npmjs.com/package/yet-another-abortcontroller-polyfill)\nfor these APIs to abort fetches:\n\n```js\nimport 'yet-another-abortcontroller-polyfill'\nimport {fetch} from 'whatwg-fetch'\n\n// use native browser implementation if it supports aborting\nconst abortableFetch = ('signal' in new Request('')) ? window.fetch : fetch\n\nconst controller = new AbortController()\n\nabortableFetch('/avatars', {\n  signal: controller.signal\n}).catch(function(ex) {\n  if (ex.name === 'AbortError') {\n    console.log('request aborted')\n  }\n})\n\n// some time later...\ncontroller.abort()\n```\n\n## Browser Support\n\n- Chrome\n- Firefox\n- Safari 6.1+\n- Internet Explorer 10+\n\nNote: modern browsers such as Chrome, Firefox, Microsoft Edge, and Safari contain native\nimplementations of `window.fetch`, therefore the code from this polyfill doesn't\nhave any effect on those browsers. If you believe you've encountered an error\nwith how `window.fetch` is implemented in any of these browsers, you should file\nan issue with that browser vendor instead of this project.\n\n\n  [fetch specification]: https://fetch.spec.whatwg.org\n  [cors]: https://developer.mozilla.org/en-US/docs/Web/HTTP/Access_control_CORS\n    \"Cross-origin resource sharing\"\n  [csrf]: https://www.owasp.org/index.php/Cross-Site_Request_Forgery_(CSRF)_Prevention_Cheat_Sheet\n    \"Cross-site request forgery\"\n  [forbidden header name]: https://developer.mozilla.org/en-US/docs/Glossary/Forbidden_header_name\n  [releases]: https://github.com/github/fetch/releases\n"
  },
  {
    "path": "SECURITY.md",
    "content": "# Security Policy\n\n## Supported Versions\n\nSecurity updates are applied only to the latest release.\n\n## Reporting a Vulnerability\n\nIf you have discovered a security vulnerability in this project, please report it privately. **Do not disclose it as a public issue.** This gives us time to work with you to fix the issue before public exposure, reducing the chance that the exploit will be used before a patch is released.\nPlease disclose it at [security advisory](https://github.com/JakeChampion/fetch/security/advisories/new).\nThis project is maintained by a team of volunteers on a reasonable-effort basis. As such, please give us at least 90 days to work on a fix before public exposure.\n"
  },
  {
    "path": "bower.json",
    "content": "{\n  \"name\": \"fetch\",\n  \"main\": \"fetch.js\",\n  \"ignore\": [\n    \".*\",\n    \"*.md\",\n    \"examples/\",\n    \"Makefile\",\n    \"package.json\",\n    \"script/\",\n    \"test/\"\n  ]\n}\n"
  },
  {
    "path": "fetch.js",
    "content": "/* eslint-disable no-prototype-builtins */\nvar g =\n  (typeof globalThis !== 'undefined' && globalThis) ||\n  (typeof self !== 'undefined' && self) ||\n  // eslint-disable-next-line no-undef\n  (typeof global !== 'undefined' && global) ||\n  {}\n\nvar support = {\n  searchParams: 'URLSearchParams' in g,\n  iterable: 'Symbol' in g && 'iterator' in Symbol,\n  blob:\n    'FileReader' in g &&\n    'Blob' in g &&\n    (function() {\n      try {\n        new Blob()\n        return true\n      } catch (e) {\n        return false\n      }\n    })(),\n  formData: 'FormData' in g,\n  arrayBuffer: 'ArrayBuffer' in g\n}\n\nfunction isDataView(obj) {\n  return obj && DataView.prototype.isPrototypeOf(obj)\n}\n\nif (support.arrayBuffer) {\n  var viewClasses = [\n    '[object Int8Array]',\n    '[object Uint8Array]',\n    '[object Uint8ClampedArray]',\n    '[object Int16Array]',\n    '[object Uint16Array]',\n    '[object Int32Array]',\n    '[object Uint32Array]',\n    '[object Float32Array]',\n    '[object Float64Array]'\n  ]\n\n  var isArrayBufferView =\n    ArrayBuffer.isView ||\n    function(obj) {\n      return obj && viewClasses.indexOf(Object.prototype.toString.call(obj)) > -1\n    }\n}\n\nfunction normalizeName(name) {\n  if (typeof name !== 'string') {\n    name = String(name)\n  }\n  if (/[^a-z0-9\\-#$%&'*+.^_`|~!]/i.test(name) || name === '') {\n    throw new TypeError('Invalid character in header field name: \"' + name + '\"')\n  }\n  return name.toLowerCase()\n}\n\nfunction normalizeValue(value) {\n  if (typeof value !== 'string') {\n    value = String(value)\n  }\n  return value\n}\n\n// Build a destructive iterator for the value list\nfunction iteratorFor(items) {\n  var iterator = {\n    next: function() {\n      var value = items.shift()\n      return {done: value === undefined, value: value}\n    }\n  }\n\n  if (support.iterable) {\n    iterator[Symbol.iterator] = function() {\n      return iterator\n    }\n  }\n\n  return iterator\n}\n\nexport function Headers(headers) {\n  this.map = {}\n\n  if (headers instanceof Headers) {\n    headers.forEach(function(value, name) {\n      this.append(name, value)\n    }, this)\n  } else if (Array.isArray(headers)) {\n    headers.forEach(function(header) {\n      if (header.length != 2) {\n        throw new TypeError('Headers constructor: expected name/value pair to be length 2, found' + header.length)\n      }\n      this.append(header[0], header[1])\n    }, this)\n  } else if (headers) {\n    Object.getOwnPropertyNames(headers).forEach(function(name) {\n      this.append(name, headers[name])\n    }, this)\n  }\n}\n\nHeaders.prototype.append = function(name, value) {\n  name = normalizeName(name)\n  value = normalizeValue(value)\n  var oldValue = this.map[name]\n  this.map[name] = oldValue ? oldValue + ', ' + value : value\n}\n\nHeaders.prototype['delete'] = function(name) {\n  delete this.map[normalizeName(name)]\n}\n\nHeaders.prototype.get = function(name) {\n  name = normalizeName(name)\n  return this.has(name) ? this.map[name] : null\n}\n\nHeaders.prototype.has = function(name) {\n  return this.map.hasOwnProperty(normalizeName(name))\n}\n\nHeaders.prototype.set = function(name, value) {\n  this.map[normalizeName(name)] = normalizeValue(value)\n}\n\nHeaders.prototype.forEach = function(callback, thisArg) {\n  for (var name in this.map) {\n    if (this.map.hasOwnProperty(name)) {\n      callback.call(thisArg, this.map[name], name, this)\n    }\n  }\n}\n\nHeaders.prototype.keys = function() {\n  var items = []\n  this.forEach(function(value, name) {\n    items.push(name)\n  })\n  return iteratorFor(items)\n}\n\nHeaders.prototype.values = function() {\n  var items = []\n  this.forEach(function(value) {\n    items.push(value)\n  })\n  return iteratorFor(items)\n}\n\nHeaders.prototype.entries = function() {\n  var items = []\n  this.forEach(function(value, name) {\n    items.push([name, value])\n  })\n  return iteratorFor(items)\n}\n\nif (support.iterable) {\n  Headers.prototype[Symbol.iterator] = Headers.prototype.entries\n}\n\nfunction consumed(body) {\n  if (body._noBody) return\n  if (body.bodyUsed) {\n    return Promise.reject(new TypeError('Already read'))\n  }\n  body.bodyUsed = true\n}\n\nfunction fileReaderReady(reader) {\n  return new Promise(function(resolve, reject) {\n    reader.onload = function() {\n      resolve(reader.result)\n    }\n    reader.onerror = function() {\n      reject(reader.error)\n    }\n  })\n}\n\nfunction readBlobAsArrayBuffer(blob) {\n  var reader = new FileReader()\n  var promise = fileReaderReady(reader)\n  reader.readAsArrayBuffer(blob)\n  return promise\n}\n\nfunction readBlobAsText(blob) {\n  var reader = new FileReader()\n  var promise = fileReaderReady(reader)\n  var match = /charset=([A-Za-z0-9_-]+)/.exec(blob.type)\n  var encoding = match ? match[1] : 'utf-8'\n  reader.readAsText(blob, encoding)\n  return promise\n}\n\nfunction readArrayBufferAsText(buf) {\n  var view = new Uint8Array(buf)\n  var chars = new Array(view.length)\n\n  for (var i = 0; i < view.length; i++) {\n    chars[i] = String.fromCharCode(view[i])\n  }\n  return chars.join('')\n}\n\nfunction bufferClone(buf) {\n  if (buf.slice) {\n    return buf.slice(0)\n  } else {\n    var view = new Uint8Array(buf.byteLength)\n    view.set(new Uint8Array(buf))\n    return view.buffer\n  }\n}\n\nfunction Body() {\n  this.bodyUsed = false\n\n  this._initBody = function(body) {\n    /*\n      fetch-mock wraps the Response object in an ES6 Proxy to\n      provide useful test harness features such as flush. However, on\n      ES5 browsers without fetch or Proxy support pollyfills must be used;\n      the proxy-pollyfill is unable to proxy an attribute unless it exists\n      on the object before the Proxy is created. This change ensures\n      Response.bodyUsed exists on the instance, while maintaining the\n      semantic of setting Request.bodyUsed in the constructor before\n      _initBody is called.\n    */\n    // eslint-disable-next-line no-self-assign\n    this.bodyUsed = this.bodyUsed\n    this._bodyInit = body\n    if (!body) {\n      this._noBody = true;\n      this._bodyText = ''\n    } else if (typeof body === 'string') {\n      this._bodyText = body\n    } else if (support.blob && Blob.prototype.isPrototypeOf(body)) {\n      this._bodyBlob = body\n    } else if (support.formData && FormData.prototype.isPrototypeOf(body)) {\n      this._bodyFormData = body\n    } else if (support.searchParams && URLSearchParams.prototype.isPrototypeOf(body)) {\n      this._bodyText = body.toString()\n    } else if (support.arrayBuffer && support.blob && isDataView(body)) {\n      this._bodyArrayBuffer = bufferClone(body.buffer)\n      // IE 10-11 can't handle a DataView body.\n      this._bodyInit = new Blob([this._bodyArrayBuffer])\n    } else if (support.arrayBuffer && (ArrayBuffer.prototype.isPrototypeOf(body) || isArrayBufferView(body))) {\n      this._bodyArrayBuffer = bufferClone(body)\n    } else {\n      this._bodyText = body = Object.prototype.toString.call(body)\n    }\n\n    if (!this.headers.get('content-type')) {\n      if (typeof body === 'string') {\n        this.headers.set('content-type', 'text/plain;charset=UTF-8')\n      } else if (this._bodyBlob && this._bodyBlob.type) {\n        this.headers.set('content-type', this._bodyBlob.type)\n      } else if (support.searchParams && URLSearchParams.prototype.isPrototypeOf(body)) {\n        this.headers.set('content-type', 'application/x-www-form-urlencoded;charset=UTF-8')\n      }\n    }\n  }\n\n  if (support.blob) {\n    this.blob = function() {\n      var rejected = consumed(this)\n      if (rejected) {\n        return rejected\n      }\n\n      if (this._bodyBlob) {\n        return Promise.resolve(this._bodyBlob)\n      } else if (this._bodyArrayBuffer) {\n        return Promise.resolve(new Blob([this._bodyArrayBuffer]))\n      } else if (this._bodyFormData) {\n        throw new Error('could not read FormData body as blob')\n      } else {\n        return Promise.resolve(new Blob([this._bodyText]))\n      }\n    }\n  }\n\n  this.arrayBuffer = function() {\n    if (this._bodyArrayBuffer) {\n      var isConsumed = consumed(this)\n      if (isConsumed) {\n        return isConsumed\n      } else if (ArrayBuffer.isView(this._bodyArrayBuffer)) {\n        return Promise.resolve(\n          this._bodyArrayBuffer.buffer.slice(\n            this._bodyArrayBuffer.byteOffset,\n            this._bodyArrayBuffer.byteOffset + this._bodyArrayBuffer.byteLength\n          )\n        )\n      } else {\n        return Promise.resolve(this._bodyArrayBuffer)\n      }\n    } else if (support.blob) {\n      return this.blob().then(readBlobAsArrayBuffer)\n    } else {\n      throw new Error('could not read as ArrayBuffer')\n    }\n  }\n\n  this.text = function() {\n    var rejected = consumed(this)\n    if (rejected) {\n      return rejected\n    }\n\n    if (this._bodyBlob) {\n      return readBlobAsText(this._bodyBlob)\n    } else if (this._bodyArrayBuffer) {\n      return Promise.resolve(readArrayBufferAsText(this._bodyArrayBuffer))\n    } else if (this._bodyFormData) {\n      throw new Error('could not read FormData body as text')\n    } else {\n      return Promise.resolve(this._bodyText)\n    }\n  }\n\n  if (support.formData) {\n    this.formData = function() {\n      return this.text().then(decode)\n    }\n  }\n\n  this.json = function() {\n    return this.text().then(JSON.parse)\n  }\n\n  return this\n}\n\n// HTTP methods whose capitalization should be normalized\nvar methods = ['CONNECT', 'DELETE', 'GET', 'HEAD', 'OPTIONS', 'PATCH', 'POST', 'PUT', 'TRACE']\n\nfunction normalizeMethod(method) {\n  var upcased = method.toUpperCase()\n  return methods.indexOf(upcased) > -1 ? upcased : method\n}\n\nexport function Request(input, options) {\n  if (!(this instanceof Request)) {\n    throw new TypeError('Please use the \"new\" operator, this DOM object constructor cannot be called as a function.')\n  }\n\n  options = options || {}\n  var body = options.body\n\n  if (input instanceof Request) {\n    if (input.bodyUsed) {\n      throw new TypeError('Already read')\n    }\n    this.url = input.url\n    this.credentials = input.credentials\n    if (!options.headers) {\n      this.headers = new Headers(input.headers)\n    }\n    this.method = input.method\n    this.mode = input.mode\n    this.signal = input.signal\n    if (!body && input._bodyInit != null) {\n      body = input._bodyInit\n      input.bodyUsed = true\n    }\n  } else {\n    this.url = String(input)\n  }\n\n  this.credentials = options.credentials || this.credentials || 'same-origin'\n  if (options.headers || !this.headers) {\n    this.headers = new Headers(options.headers)\n  }\n  this.method = normalizeMethod(options.method || this.method || 'GET')\n  this.mode = options.mode || this.mode || null\n  this.signal = options.signal || this.signal || (function () {\n    if ('AbortController' in g) {\n      var ctrl = new AbortController();\n      return ctrl.signal;\n    }\n  }());\n  this.referrer = null\n\n  if ((this.method === 'GET' || this.method === 'HEAD') && body) {\n    throw new TypeError('Body not allowed for GET or HEAD requests')\n  }\n  this._initBody(body)\n\n  if (this.method === 'GET' || this.method === 'HEAD') {\n    if (options.cache === 'no-store' || options.cache === 'no-cache') {\n      // Search for a '_' parameter in the query string\n      var reParamSearch = /([?&])_=[^&]*/\n      if (reParamSearch.test(this.url)) {\n        // If it already exists then set the value with the current time\n        this.url = this.url.replace(reParamSearch, '$1_=' + new Date().getTime())\n      } else {\n        // Otherwise add a new '_' parameter to the end with the current time\n        var reQueryString = /\\?/\n        this.url += (reQueryString.test(this.url) ? '&' : '?') + '_=' + new Date().getTime()\n      }\n    }\n  }\n}\n\nRequest.prototype.clone = function() {\n  return new Request(this, {body: this._bodyInit})\n}\n\nfunction decode(body) {\n  var form = new FormData()\n  body\n    .trim()\n    .split('&')\n    .forEach(function(bytes) {\n      if (bytes) {\n        var split = bytes.split('=')\n        var name = split.shift().replace(/\\+/g, ' ')\n        var value = split.join('=').replace(/\\+/g, ' ')\n        form.append(decodeURIComponent(name), decodeURIComponent(value))\n      }\n    })\n  return form\n}\n\nfunction parseHeaders(rawHeaders) {\n  var headers = new Headers()\n  // Replace instances of \\r\\n and \\n followed by at least one space or horizontal tab with a space\n  // https://tools.ietf.org/html/rfc7230#section-3.2\n  var preProcessedHeaders = rawHeaders.replace(/\\r?\\n[\\t ]+/g, ' ')\n  // Avoiding split via regex to work around a common IE11 bug with the core-js 3.6.0 regex polyfill\n  // https://github.com/github/fetch/issues/748\n  // https://github.com/zloirock/core-js/issues/751\n  preProcessedHeaders\n    .split('\\r')\n    .map(function(header) {\n      return header.indexOf('\\n') === 0 ? header.substr(1, header.length) : header\n    })\n    .forEach(function(line) {\n      var parts = line.split(':')\n      var key = parts.shift().trim()\n      if (key) {\n        var value = parts.join(':').trim()\n        try {\n          headers.append(key, value)\n        } catch (error) {\n          console.warn('Response ' + error.message)\n        }\n      }\n    })\n  return headers\n}\n\nBody.call(Request.prototype)\n\nexport function Response(bodyInit, options) {\n  if (!(this instanceof Response)) {\n    throw new TypeError('Please use the \"new\" operator, this DOM object constructor cannot be called as a function.')\n  }\n  if (!options) {\n    options = {}\n  }\n\n  this.type = 'default'\n  this.status = options.status === undefined ? 200 : options.status\n  if (this.status < 200 || this.status > 599) {\n    throw new RangeError(\"Failed to construct 'Response': The status provided (0) is outside the range [200, 599].\")\n  }\n  this.ok = this.status >= 200 && this.status < 300\n  this.statusText = options.statusText === undefined ? '' : '' + options.statusText\n  this.headers = new Headers(options.headers)\n  this.url = options.url || ''\n  this._initBody(bodyInit)\n}\n\nBody.call(Response.prototype)\n\nResponse.prototype.clone = function() {\n  return new Response(this._bodyInit, {\n    status: this.status,\n    statusText: this.statusText,\n    headers: new Headers(this.headers),\n    url: this.url\n  })\n}\n\nResponse.error = function() {\n  var response = new Response(null, {status: 200, statusText: ''})\n  response.ok = false\n  response.status = 0\n  response.type = 'error'\n  return response\n}\n\nvar redirectStatuses = [301, 302, 303, 307, 308]\n\nResponse.redirect = function(url, status) {\n  if (redirectStatuses.indexOf(status) === -1) {\n    throw new RangeError('Invalid status code')\n  }\n\n  return new Response(null, {status: status, headers: {location: url}})\n}\n\nexport var DOMException = g.DOMException\ntry {\n  new DOMException()\n} catch (err) {\n  DOMException = function(message, name) {\n    this.message = message\n    this.name = name\n    var error = Error(message)\n    this.stack = error.stack\n  }\n  DOMException.prototype = Object.create(Error.prototype)\n  DOMException.prototype.constructor = DOMException\n}\n\nexport function fetch(input, init) {\n  return new Promise(function(resolve, reject) {\n    var request = new Request(input, init)\n\n    if (request.signal && request.signal.aborted) {\n      return reject(new DOMException('Aborted', 'AbortError'))\n    }\n\n    var xhr = new XMLHttpRequest()\n\n    function abortXhr() {\n      xhr.abort()\n    }\n\n    xhr.onload = function() {\n      var options = {\n        statusText: xhr.statusText,\n        headers: parseHeaders(xhr.getAllResponseHeaders() || '')\n      }\n      // This check if specifically for when a user fetches a file locally from the file system\n      // Only if the status is out of a normal range\n      if (request.url.indexOf('file://') === 0 && (xhr.status < 200 || xhr.status > 599)) {\n        options.status = 200;\n      } else {\n        options.status = xhr.status;\n      }\n      options.url = 'responseURL' in xhr ? xhr.responseURL : options.headers.get('X-Request-URL')\n      var body = 'response' in xhr ? xhr.response : xhr.responseText\n      setTimeout(function() {\n        resolve(new Response(body, options))\n      }, 0)\n    }\n\n    xhr.onerror = function() {\n      setTimeout(function() {\n        reject(new TypeError('Network request failed'))\n      }, 0)\n    }\n\n    xhr.ontimeout = function() {\n      setTimeout(function() {\n        reject(new TypeError('Network request timed out'))\n      }, 0)\n    }\n\n    xhr.onabort = function() {\n      setTimeout(function() {\n        reject(new DOMException('Aborted', 'AbortError'))\n      }, 0)\n    }\n\n    function fixUrl(url) {\n      try {\n        return url === '' && g.location.href ? g.location.href : url\n      } catch (e) {\n        return url\n      }\n    }\n\n    xhr.open(request.method, fixUrl(request.url), true)\n\n    if (request.credentials === 'include') {\n      xhr.withCredentials = true\n    } else if (request.credentials === 'omit') {\n      xhr.withCredentials = false\n    }\n\n    if ('responseType' in xhr) {\n      if (support.blob) {\n        xhr.responseType = 'blob'\n      } else if (\n        support.arrayBuffer\n      ) {\n        xhr.responseType = 'arraybuffer'\n      }\n    }\n\n    if (init && typeof init.headers === 'object' && !(init.headers instanceof Headers || (g.Headers && init.headers instanceof g.Headers))) {\n      var names = [];\n      Object.getOwnPropertyNames(init.headers).forEach(function(name) {\n        names.push(normalizeName(name))\n        xhr.setRequestHeader(name, normalizeValue(init.headers[name]))\n      })\n      request.headers.forEach(function(value, name) {\n        if (names.indexOf(name) === -1) {\n          xhr.setRequestHeader(name, value)\n        }\n      })\n    } else {\n      request.headers.forEach(function(value, name) {\n        xhr.setRequestHeader(name, value)\n      })\n    }\n\n    if (request.signal) {\n      request.signal.addEventListener('abort', abortXhr)\n\n      xhr.onreadystatechange = function() {\n        // DONE (success or failure)\n        if (xhr.readyState === 4) {\n          request.signal.removeEventListener('abort', abortXhr)\n        }\n      }\n    }\n\n    xhr.send(typeof request._bodyInit === 'undefined' ? null : request._bodyInit)\n  })\n}\n\nfetch.polyfill = true\n\nif (!g.fetch) {\n  g.fetch = fetch\n  g.Headers = Headers\n  g.Request = Request\n  g.Response = Response\n}\n"
  },
  {
    "path": "fetch.js.flow",
    "content": "/* @flow strict */\n\ntype CredentialsType = 'omit' | 'same-origin' | 'include'\n\ntype ResponseType =  'default' | 'error'\n\ntype BodyInit = string | URLSearchParams | FormData | Blob | ArrayBuffer | $ArrayBufferView\n\ntype RequestInfo = Request | URL | string\n\ntype RequestOptions = {|\n  body?: ?BodyInit;\n\n  credentials?: CredentialsType;\n  headers?: HeadersInit;\n  method?: string;\n  mode?: string;\n  referrer?: string;\n  signal?: ?AbortSignal;\n|}\n\ntype ResponseOptions = {|\n  status?: number;\n  statusText?: string;\n  headers?: HeadersInit;\n|}\n\ntype HeadersInit = Headers | {[string]: string}\n\n// https://github.com/facebook/flow/blob/f68b89a5012bd995ab3509e7a41b7325045c4045/lib/bom.js#L902-L914\ndeclare class Headers {\n  @@iterator(): Iterator<[string, string]>;\n  constructor(init?: HeadersInit): void;\n  append(name: string, value: string): void;\n  delete(name: string): void;\n  entries(): Iterator<[string, string]>;\n  forEach((value: string, name: string, headers: Headers) => any, thisArg?: any): void;\n  get(name: string): null | string;\n  has(name: string): boolean;\n  keys(): Iterator<string>;\n  set(name: string, value: string): void;\n  values(): Iterator<string>;\n}\n\n// https://github.com/facebook/flow/pull/6548\ninterface AbortSignal {\n  aborted: boolean;\n  addEventListener(type: string, listener: (Event) => mixed, options?: EventListenerOptionsOrUseCapture): void;\n  removeEventListener(type: string, listener: (Event) => mixed, options?: EventListenerOptionsOrUseCapture): void;\n}\n\n// https://github.com/facebook/flow/blob/f68b89a5012bd995ab3509e7a41b7325045c4045/lib/bom.js#L994-L1018\n// unsupported in polyfill:\n// - cache\n// - integrity\n// - redirect\n// - referrerPolicy\ndeclare class Request {\n  constructor(input: RequestInfo, init?: RequestOptions): void;\n  clone(): Request;\n\n  url: string;\n\n  credentials: CredentialsType;\n  headers: Headers;\n  method: string;\n  mode: ModeType;\n  referrer: string;\n  signal: ?AbortSignal;\n\n  // Body methods and attributes\n  bodyUsed: boolean;\n\n  arrayBuffer(): Promise<ArrayBuffer>;\n  blob(): Promise<Blob>;\n  formData(): Promise<FormData>;\n  json(): Promise<any>;\n  text(): Promise<string>;\n}\n\n// https://github.com/facebook/flow/blob/f68b89a5012bd995ab3509e7a41b7325045c4045/lib/bom.js#L968-L992\n// unsupported in polyfill:\n// - body\n// - redirected\n// - trailer\ndeclare class Response {\n  constructor(input?: ?BodyInit, init?: ResponseOptions): void;\n  clone(): Response;\n  static error(): Response;\n  static redirect(url: string, status?: number): Response;\n\n  type: ResponseType;\n  url: string;\n  ok: boolean;\n  status: number;\n  statusText: string;\n  headers: Headers;\n\n  // Body methods and attributes\n  bodyUsed: boolean;\n\n  arrayBuffer(): Promise<ArrayBuffer>;\n  blob(): Promise<Blob>;\n  formData(): Promise<FormData>;\n  json(): Promise<any>;\n  text(): Promise<string>;\n}\n\ndeclare class DOMException extends Error {\n  constructor(message?: string, name?: string): void;\n}\n\ndeclare module.exports: {\n  fetch(input: RequestInfo, init?: RequestOptions): Promise<Response>;\n  Headers: typeof Headers;\n  Request: typeof Request;\n  Response: typeof Response;\n  DOMException: typeof DOMException;\n}\n"
  },
  {
    "path": "package.json",
    "content": "{\n  \"name\": \"whatwg-fetch\",\n  \"description\": \"A window.fetch polyfill.\",\n  \"version\": \"3.6.20\",\n  \"main\": \"./dist/fetch.umd.js\",\n  \"module\": \"./fetch.js\",\n  \"repository\": \"github/fetch\",\n  \"license\": \"MIT\",\n  \"devDependencies\": {\n    \"abortcontroller-polyfill\": \"^1.1.9\",\n    \"auto-changelog\": \"^2.4.0\",\n    \"chai\": \"^4.1.2\",\n    \"eslint\": \"^7.20.0\",\n    \"karma\": \"^3.0.0\",\n    \"karma-chai\": \"^0.1.0\",\n    \"karma-chrome-launcher\": \"^2.2.0\",\n    \"karma-detect-browsers\": \"^2.3.2\",\n    \"karma-firefox-launcher\": \"^1.1.0\",\n    \"karma-mocha\": \"^1.3.0\",\n    \"karma-safari-launcher\": \"^1.0.0\",\n    \"karma-safaritechpreview-launcher\": \"0.0.6\",\n    \"mocha\": \"^4.0.1\",\n    \"prettier\": \"^1.19.1\",\n    \"promise-polyfill\": \"6.0.2\",\n    \"rollup\": \"^0.59.1\",\n    \"url-search-params\": \"0.6.1\"\n  },\n  \"files\": [\n    \"LICENSE\",\n    \"dist/fetch.umd.js\",\n    \"dist/fetch.umd.js.flow\",\n    \"fetch.js\",\n    \"fetch.js.flow\"\n  ],\n  \"scripts\": {\n    \"karma\": \"karma start ./test/karma.config.js --no-single-run --auto-watch\",\n    \"prepare\": \"make dist/fetch.umd.js dist/fetch.umd.js.flow\",\n    \"pretest\": \"make\",\n    \"test\": \"karma start ./test/karma.config.js && karma start ./test/karma-worker.config.js\",\n    \"version\": \"auto-changelog -p && git add CHANGELOG.md\"\n  }\n}\n"
  },
  {
    "path": "prettier.config.js",
    "content": "/* eslint-env node */\nmodule.exports = require('eslint-plugin-github/prettier.config')\n"
  },
  {
    "path": "rollup.config.js",
    "content": "export default {\n  input: 'fetch.js',\n  output: {\n    file: 'dist/fetch.umd.js',\n    format: 'umd',\n    name: 'WHATWGFetch'\n  }\n}\n"
  },
  {
    "path": "test/karma-worker.config.js",
    "content": "/* eslint-env node */\nconst parentConfig = require('./karma.config')\n\nmodule.exports = function(config) {\n  parentConfig(config)\n  config.set({\n    frameworks: ['detectBrowsers', 'mocha'],\n    files: [\n      'test/worker-adapter.js',\n      {\n        pattern: '{test,dist}/*.js',\n        included: false\n      },\n      {\n        pattern: 'node_modules/{mocha,chai,abortcontroller-polyfill/dist}/*.js',\n        included: false,\n        watched: false\n      }\n    ]\n  })\n}\n"
  },
  {
    "path": "test/karma.config.js",
    "content": "/* eslint-env node */\nconst serverEndpoints = require('./server')\n\nmodule.exports = function(config) {\n  config.set({\n    basePath: '..',\n    frameworks: ['detectBrowsers', 'mocha', 'chai'],\n    detectBrowsers: {\n      preferHeadless: true,\n      usePhantomJS: false,\n      postDetection: availableBrowsers =>\n        availableBrowsers\n          .filter(\n            browser =>\n              !process.env.CI || !browser.startsWith('Chromium') || !availableBrowsers.some(b => b.startsWith('Chrome'))\n          )\n          .map(browser => (browser.startsWith('Chrom') ? `${browser}NoSandbox` : browser))\n    },\n    client: {\n      mocha: {\n        ui: 'tdd'\n      }\n    },\n    files: [\n      'node_modules/promise-polyfill/promise.js',\n      'node_modules/abortcontroller-polyfill/dist/abortcontroller-polyfill-only.js',\n      'node_modules/url-search-params/build/url-search-params.max.js',\n      'dist/fetch.umd.js',\n      'test/test.js'\n    ],\n    reporters: process.env.CI ? ['dots'] : ['progress'],\n    port: 9876,\n    colors: true,\n    logLevel: process.env.CI ? config.LOG_WARN : config.LOG_INFO,\n    autoWatch: false,\n    singleRun: true,\n    concurrency: Infinity,\n    customLaunchers: {\n      ChromeHeadlessNoSandbox: {\n        base: 'ChromeHeadless',\n        flags: ['--no-sandbox']\n      },\n      ChromiumHeadlessNoSandbox: {\n        base: 'ChromiumHeadless',\n        flags: ['--no-sandbox']\n      }\n    },\n    beforeMiddleware: ['custom'],\n    plugins: [\n      'karma-*',\n      {\n        'middleware:custom': ['value', serverEndpoints]\n      }\n    ]\n  })\n}\n"
  },
  {
    "path": "test/server.js",
    "content": "/* eslint-env node */\nconst url = require('url')\nconst querystring = require('querystring')\n\nconst routes = {\n  '/request': function(res, req) {\n    res.writeHead(200, {'Content-Type': 'application/json'})\n    var data = ''\n    req.on('data', function(c) {\n      data += c\n    })\n    req.on('end', function() {\n      res.end(\n        JSON.stringify({\n          method: req.method,\n          url: req.url,\n          headers: req.headers,\n          data: data\n        })\n      )\n    })\n  },\n  '/hello': function(res, req) {\n    res.writeHead(200, {\n      'Content-Type': 'text/plain',\n      'X-Request-URL': 'http://' + req.headers.host + req.url\n    })\n    res.end('hi')\n  },\n  '/hello/utf8': function(res) {\n    res.writeHead(200, {\n      'Content-Type': 'text/plain; charset=utf-8'\n    })\n    // \"hello\"\n    var buf = Buffer.from([104, 101, 108, 108, 111])\n    res.end(buf)\n  },\n  '/hello/utf16le': function(res) {\n    res.writeHead(200, {\n      'Content-Type': 'text/plain; charset=utf-16le'\n    })\n    // \"hello\"\n    var buf = Buffer.from([104, 0, 101, 0, 108, 0, 108, 0, 111, 0])\n    res.end(buf)\n  },\n  '/binary': function(res) {\n    res.writeHead(200, {'Content-Type': 'application/octet-stream'})\n    var buf = Buffer.alloc(256)\n    for (var i = 0; i < 256; i++) {\n      buf[i] = i\n    }\n    res.end(buf)\n  },\n  '/redirect/301': function(res) {\n    res.writeHead(301, {Location: '/hello'})\n    res.end()\n  },\n  '/redirect/302': function(res) {\n    res.writeHead(302, {Location: '/hello'})\n    res.end()\n  },\n  '/redirect/303': function(res) {\n    res.writeHead(303, {Location: '/hello'})\n    res.end()\n  },\n  '/redirect/307': function(res) {\n    res.writeHead(307, {Location: '/hello'})\n    res.end()\n  },\n  '/redirect/308': function(res) {\n    res.writeHead(308, {Location: '/hello'})\n    res.end()\n  },\n  '/boom': function(res) {\n    res.writeHead(500, {'Content-Type': 'text/plain'})\n    res.end('boom')\n  },\n  '/empty': function(res) {\n    res.writeHead(204)\n    res.end()\n  },\n  '/slow': function(res) {\n    setTimeout(function() {\n      res.writeHead(200, {'Cache-Control': 'no-cache, must-revalidate'})\n      res.end()\n    }, 100)\n  },\n  '/error': function(res) {\n    res.destroy()\n  },\n  '/form': function(res) {\n    res.writeHead(200, {'Content-Type': 'application/x-www-form-urlencoded'})\n    res.end('number=1&space=one+two&empty=&encoded=a%2Bb&')\n  },\n  '/json': function(res) {\n    res.writeHead(200, {'Content-Type': 'application/json'})\n    res.end(JSON.stringify({name: 'Hubot', login: 'hubot'}))\n  },\n  '/json-error': function(res) {\n    res.writeHead(200, {'Content-Type': 'application/json'})\n    res.end('not json {')\n  },\n  '/cookie': function(res, req) {\n    var setCookie, cookie\n    var params = querystring.parse(url.parse(req.url).query)\n    if (params.name && params.value) {\n      setCookie = [params.name, params.value].join('=')\n    }\n    if (params.name) {\n      cookie = querystring.parse(req.headers['cookie'], '; ')[params.name]\n    }\n    res.writeHead(200, {\n      'Content-Type': 'text/plain',\n      'Set-Cookie': setCookie || ''\n    })\n    res.end(cookie)\n  },\n  '/headers': function(res) {\n    res.writeHead(200, {\n      Date: 'Mon, 13 Oct 2014 21:02:27 GMT',\n      'Content-Type': 'text/html; charset=utf-8'\n    })\n    res.end()\n  }\n}\n\nmodule.exports = function(req, res, next) {\n  const path = url.parse(req.url).pathname\n  const route = routes[path]\n  if (route) {\n    route(res, req)\n  } else {\n    next()\n  }\n}\n"
  },
  {
    "path": "test/test.js",
    "content": "/* eslint-env mocha */\n/* globals chai assert FileReaderSync assert WHATWGFetch */\nvar IEorEdge = /Edge\\//.test(navigator.userAgent) || /MSIE/.test(navigator.userAgent)\nvar Chrome = /Chrome\\//.test(navigator.userAgent) && !IEorEdge\nvar Safari = /Safari\\//.test(navigator.userAgent) && !IEorEdge && !Chrome\n\nvar support = {\n  url: (function(url) {\n    try {\n      return new URL(url).toString() === url\n    } catch (e) {\n      return false\n    }\n  })('http://example.com/'),\n  blob:\n    'FileReader' in self &&\n    'Blob' in self &&\n    (function() {\n      try {\n        new Blob()\n        return true\n      } catch (e) {\n        return false\n      }\n    })(),\n  formData: 'FormData' in self,\n  arrayBuffer: 'ArrayBuffer' in self,\n  aborting: 'signal' in new Request(''),\n  permanentRedirect: !/Trident/.test(navigator.userAgent)\n}\n\nfunction readBlobAsText(blob) {\n  if ('FileReader' in self) {\n    return new Promise(function(resolve, reject) {\n      var reader = new FileReader()\n      reader.onload = function() {\n        resolve(reader.result)\n      }\n      reader.onerror = function() {\n        reject(reader.error)\n      }\n      reader.readAsText(blob)\n    })\n  } else if ('FileReaderSync' in self) {\n    return new FileReaderSync().readAsText(blob)\n  } else {\n    throw new ReferenceError('FileReader is not defined')\n  }\n}\n\nfunction readBlobAsBytes(blob) {\n  if ('FileReader' in self) {\n    return new Promise(function(resolve, reject) {\n      var reader = new FileReader()\n      reader.onload = function() {\n        var view = new Uint8Array(reader.result)\n        resolve(Array.prototype.slice.call(view))\n      }\n      reader.onerror = function() {\n        reject(reader.error)\n      }\n      reader.readAsArrayBuffer(blob)\n    })\n  } else if ('FileReaderSync' in self) {\n    return new FileReaderSync().readAsArrayBuffer(blob)\n  } else {\n    throw new ReferenceError('FileReader is not defined')\n  }\n}\n\nfunction arrayBufferFromText(text) {\n  var buf = new ArrayBuffer(text.length)\n  var view = new Uint8Array(buf)\n\n  for (var i = 0; i < text.length; i++) {\n    view[i] = text.charCodeAt(i)\n  }\n  return buf\n}\n\nfunction readArrayBufferAsText(buf) {\n  var view = new Uint8Array(buf)\n  var chars = new Array(view.length)\n\n  for (var i = 0; i < view.length; i++) {\n    chars[i] = String.fromCharCode(view[i])\n  }\n  return chars.join('')\n}\n\nvar preservedGlobals = {}\nvar keepGlobals = ['fetch', 'Headers', 'Request', 'Response']\nvar exercise = ['polyfill']\n\n// If native fetch implementation exists, replace it with the polyfilled\n// version at first. The native implementation will be restored before the\n// additional `native` pass of the test suite.\nif (!self.fetch.polyfill) {\n  keepGlobals.forEach(function(name) {\n    preservedGlobals[name] = self[name]\n    self[name] = WHATWGFetch[name]\n  })\n  exercise.push('native')\n}\n\nvar slice = Array.prototype.slice\n\nfunction featureDependent(testOrSuite, condition) {\n  (condition ? testOrSuite : testOrSuite.skip).apply(this, slice.call(arguments, 2))\n}\n\nexercise.forEach(function(exerciseMode) {\n  suite(exerciseMode, function() {\n    if (exerciseMode === 'native') {\n      suiteSetup(function() {\n        keepGlobals.forEach(function(name) {\n          self[name] = preservedGlobals[name]\n        })\n      })\n    }\n\n    var nativeChrome = Chrome && exerciseMode === 'native'\n    var nativeSafari = Safari && exerciseMode === 'native'\n    var nativeEdge = /Edge\\//.test(navigator.userAgent) && exerciseMode === 'native'\n    var firefox = navigator.userAgent.match(/Firefox\\/(\\d+)/)\n    var brokenFF = firefox && firefox[1] <= 56 && exerciseMode === 'native'\n    var emptyDefaultStatusText =\n      exerciseMode !== 'native' || (exerciseMode === 'native' && (Chrome || (firefox && firefox[1] >= 67)))\n    var polyfillFirefox = firefox && exerciseMode === 'polyfill'\n    var omitSafari =\n      Safari && exerciseMode === 'native' && navigator.userAgent.match(/Version\\/(\\d+\\.\\d+)/)[1] <= '11.1'\n\n    // https://fetch.spec.whatwg.org/#concept-bodyinit-extract\n    function testBodyExtract(factory) {\n      suite('body extract', function() {\n        var expected = 'Hello World!'\n        var inputs = [['type USVString', expected]]\n        if (support.blob) {\n          inputs.push(['type Blob', new Blob([expected])])\n        }\n        if (support.arrayBuffer) {\n          inputs = inputs.concat([\n            ['type ArrayBuffer', arrayBufferFromText(expected)],\n            ['type TypedArray', new Uint8Array(arrayBufferFromText(expected))],\n            ['type DataView', new DataView(arrayBufferFromText(expected))]\n          ])\n        }\n\n        inputs.forEach(function(input) {\n          var typeLabel = input[0],\n            body = input[1]\n\n          suite(typeLabel, function() {\n            featureDependent(test, support.blob, 'consume as blob', function() {\n              var r = factory(body)\n              return r\n                .blob()\n                .then(readBlobAsText)\n                .then(function(text) {\n                  assert.equal(text, expected)\n                })\n            })\n\n            test('consume as text', function() {\n              var r = factory(body)\n              return r.text().then(function(text) {\n                assert.equal(text, expected)\n              })\n            })\n\n            featureDependent(test, support.arrayBuffer, 'consume as array buffer', function() {\n              var r = factory(body)\n              return r\n                .arrayBuffer()\n                .then(readArrayBufferAsText)\n                .then(function(text) {\n                  assert.equal(text, expected)\n                })\n            })\n          })\n        })\n      })\n    }\n\n    // https://fetch.spec.whatwg.org/#headers-class\n    suite('Headers', function() {\n      test('constructor copies headers', function() {\n        var original = new Headers()\n        original.append('Accept', 'application/json')\n        original.append('Accept', 'text/plain')\n        original.append('Content-Type', 'text/html')\n\n        var headers = new Headers(original)\n        assert.equal(headers.get('Accept'), 'application/json, text/plain')\n        assert.equal(headers.get('Content-type'), 'text/html')\n      })\n      test('constructor works with arrays', function() {\n        var array = [\n          ['Content-Type', 'text/xml'],\n          ['Breaking-Bad', '<3']\n        ]\n        var headers = new Headers(array)\n\n        assert.equal(headers.get('Content-Type'), 'text/xml')\n        assert.equal(headers.get('Breaking-Bad'), '<3')\n        assert.throws(function() {\n          new Headers([\n            ['Content-Type'],\n          ])\n        }, TypeError)\n        assert.throws(function() {\n          new Headers([\n            ['Content-Type', 'a', 'b'],\n          ])\n        }, TypeError)\n      })\n      test('headers are case insensitive', function() {\n        var headers = new Headers({Accept: 'application/json'})\n        assert.equal(headers.get('ACCEPT'), 'application/json')\n        assert.equal(headers.get('Accept'), 'application/json')\n        assert.equal(headers.get('accept'), 'application/json')\n      })\n      test('appends to existing', function() {\n        var headers = new Headers({Accept: 'application/json'})\n        assert.isFalse(headers.has('Content-Type'))\n        headers.append('Content-Type', 'application/json')\n        assert.isTrue(headers.has('Content-Type'))\n        assert.equal(headers.get('Content-Type'), 'application/json')\n      })\n      test('appends values to existing header name', function() {\n        var headers = new Headers({Accept: 'application/json'})\n        headers.append('Accept', 'text/plain')\n        assert.equal(headers.get('Accept'), 'application/json, text/plain')\n      })\n      test('sets header name and value', function() {\n        var headers = new Headers()\n        headers.set('Content-Type', 'application/json')\n        assert.equal(headers.get('Content-Type'), 'application/json')\n      })\n      test('returns null on no header found', function() {\n        var headers = new Headers()\n        assert.isNull(headers.get('Content-Type'))\n      })\n      test('has headers that are set', function() {\n        var headers = new Headers()\n        headers.set('Content-Type', 'application/json')\n        assert.isTrue(headers.has('Content-Type'))\n      })\n      test('deletes headers', function() {\n        var headers = new Headers()\n        headers.set('Content-Type', 'application/json')\n        assert.isTrue(headers.has('Content-Type'))\n        headers.delete('Content-Type')\n        assert.isFalse(headers.has('Content-Type'))\n        assert.isNull(headers.get('Content-Type'))\n      })\n      test('converts field name to string on set and get', function() {\n        var headers = new Headers()\n        headers.set(1, 'application/json')\n        assert.isTrue(headers.has('1'))\n        assert.equal(headers.get(1), 'application/json')\n      })\n      test('converts field value to string on set and get', function() {\n        var headers = new Headers()\n        headers.set('Content-Type', 1)\n        headers.set('X-CSRF-Token', undefined)\n        assert.equal(headers.get('Content-Type'), '1')\n        assert.equal(headers.get('X-CSRF-Token'), 'undefined')\n      })\n      test('throws TypeError on invalid character in field name', function() {\n        assert.throws(function() {\n          new Headers({'[Accept]': 'application/json'})\n        }, TypeError)\n        assert.throws(function() {\n          new Headers({'Accept:': 'application/json'})\n        }, TypeError)\n        assert.throws(function() {\n          var headers = new Headers()\n          headers.set({field: 'value'}, 'application/json')\n        }, TypeError)\n        assert.throws(function() {\n          new Headers({'': 'application/json'})\n        }, TypeError)\n      })\n      featureDependent(test, !brokenFF, 'is iterable with forEach', function() {\n        var headers = new Headers()\n        headers.append('Accept', 'application/json')\n        headers.append('Accept', 'text/plain')\n        headers.append('Content-Type', 'text/html')\n\n        var results = []\n        headers.forEach(function(value, key, object) {\n          results.push({value: value, key: key, object: object})\n        })\n\n        assert.equal(results.length, 2)\n        assert.deepEqual({key: 'accept', value: 'application/json, text/plain', object: headers}, results[0])\n        assert.deepEqual({key: 'content-type', value: 'text/html', object: headers}, results[1])\n      })\n      test('forEach accepts second thisArg argument', function() {\n        var headers = new Headers({Accept: 'application/json'})\n        var thisArg = 42\n        headers.forEach(function() {\n          assert.equal(this, thisArg)\n        }, thisArg)\n      })\n      featureDependent(test, !brokenFF, 'is iterable with keys', function() {\n        var headers = new Headers()\n        headers.append('Accept', 'application/json')\n        headers.append('Accept', 'text/plain')\n        headers.append('Content-Type', 'text/html')\n\n        var iterator = headers.keys()\n        assert.deepEqual({done: false, value: 'accept'}, iterator.next())\n        assert.deepEqual({done: false, value: 'content-type'}, iterator.next())\n        assert.deepEqual({done: true, value: undefined}, iterator.next())\n      })\n      featureDependent(test, !brokenFF, 'is iterable with values', function() {\n        var headers = new Headers()\n        headers.append('Accept', 'application/json')\n        headers.append('Accept', 'text/plain')\n        headers.append('Content-Type', 'text/html')\n\n        var iterator = headers.values()\n        assert.deepEqual({done: false, value: 'application/json, text/plain'}, iterator.next())\n        assert.deepEqual({done: false, value: 'text/html'}, iterator.next())\n        assert.deepEqual({done: true, value: undefined}, iterator.next())\n      })\n      featureDependent(test, !brokenFF, 'is iterable with entries', function() {\n        var headers = new Headers()\n        headers.append('Accept', 'application/json')\n        headers.append('Accept', 'text/plain')\n        headers.append('Content-Type', 'text/html')\n\n        var iterator = headers.entries()\n        assert.deepEqual({done: false, value: ['accept', 'application/json, text/plain']}, iterator.next())\n        assert.deepEqual({done: false, value: ['content-type', 'text/html']}, iterator.next())\n        assert.deepEqual({done: true, value: undefined}, iterator.next())\n      })\n    })\n\n    // https://fetch.spec.whatwg.org/#request-class\n    suite('Request', function() {\n      test('called as normal function', function() {\n        assert.throws(function() {\n          Request('https://fetch.spec.whatwg.org/')\n        })\n      })\n      test('construct with string url', function() {\n        var request = new Request('https://fetch.spec.whatwg.org/')\n        assert.equal(request.url, 'https://fetch.spec.whatwg.org/')\n      })\n\n      featureDependent(test, support.url, 'construct with URL instance', function() {\n        var url = new URL('https://fetch.spec.whatwg.org/')\n        url.pathname = 'cors'\n        var request = new Request(url)\n        assert.equal(request.url, 'https://fetch.spec.whatwg.org/cors')\n      })\n\n      test('construct with non-Request object', function() {\n        var url = {\n          toString: function() {\n            return 'https://fetch.spec.whatwg.org/'\n          }\n        }\n        var request = new Request(url)\n        assert.equal(request.url, 'https://fetch.spec.whatwg.org/')\n      })\n\n      test('construct with Request', function() {\n        var request1 = new Request('https://fetch.spec.whatwg.org/', {\n          method: 'post',\n          body: 'I work out',\n          headers: {\n            accept: 'application/json',\n            'Content-Type': 'text/plain'\n          }\n        })\n        var request2 = new Request(request1)\n\n        return request2.text().then(function(body2) {\n          assert.equal(body2, 'I work out')\n          assert.equal(request2.method, 'POST')\n          assert.equal(request2.url, 'https://fetch.spec.whatwg.org/')\n          assert.equal(request2.headers.get('accept'), 'application/json')\n          assert.equal(request2.headers.get('content-type'), 'text/plain')\n\n          return request1.text().then(\n            function() {\n              assert(false, 'original request body should have been consumed')\n            },\n            function(error) {\n              assert(error instanceof TypeError, 'expected TypeError for already read body')\n            }\n          )\n        })\n      })\n\n      test('construct with Request and override headers', function() {\n        var request1 = new Request('https://fetch.spec.whatwg.org/', {\n          method: 'post',\n          body: 'I work out',\n          headers: {\n            accept: 'application/json',\n            'X-Request-ID': '123'\n          }\n        })\n        var request2 = new Request(request1, {\n          headers: {'x-test': '42'}\n        })\n\n        assert.equal(request2.headers.get('accept'), undefined)\n        assert.equal(request2.headers.get('x-request-id'), undefined)\n        assert.equal(request2.headers.get('x-test'), '42')\n      })\n\n      test('construct with Request and override body', function() {\n        var request1 = new Request('https://fetch.spec.whatwg.org/', {\n          method: 'post',\n          body: 'I work out',\n          headers: {\n            'Content-Type': 'text/plain'\n          }\n        })\n        var request2 = new Request(request1, {\n          body: '{\"wiggles\": 5}',\n          headers: {'Content-Type': 'application/json'}\n        })\n\n        return request2.json().then(function(data) {\n          assert.equal(data.wiggles, 5)\n          assert.equal(request2.headers.get('content-type'), 'application/json')\n        })\n      })\n\n      featureDependent(test, !nativeChrome, 'construct with used Request body', function() {\n        var request1 = new Request('https://fetch.spec.whatwg.org/', {\n          method: 'post',\n          body: 'I work out'\n        })\n\n        return request1.text().then(function() {\n          assert.throws(function() {\n            new Request(request1)\n          }, TypeError)\n        })\n      })\n\n      test('GET should not have implicit Content-Type', function() {\n        var req = new Request('https://fetch.spec.whatwg.org/')\n        assert.equal(req.headers.get('content-type'), undefined)\n      })\n\n      test('POST with blank body should not have implicit Content-Type', function() {\n        var req = new Request('https://fetch.spec.whatwg.org/', {\n          method: 'post'\n        })\n        assert.equal(req.headers.get('content-type'), undefined)\n      })\n\n      test('construct with string body sets Content-Type header', function() {\n        var req = new Request('https://fetch.spec.whatwg.org/', {\n          method: 'post',\n          body: 'I work out'\n        })\n\n        assert.equal(req.headers.get('content-type'), 'text/plain;charset=UTF-8')\n      })\n\n      featureDependent(test, support.blob, 'construct with Blob body and type sets Content-Type header', function() {\n        var req = new Request('https://fetch.spec.whatwg.org/', {\n          method: 'post',\n          body: new Blob(['test'], {type: 'image/png'})\n        })\n\n        assert.equal(req.headers.get('content-type'), 'image/png')\n      })\n\n      test('construct with body and explicit header uses header', function() {\n        var req = new Request('https://fetch.spec.whatwg.org/', {\n          method: 'post',\n          headers: {'Content-Type': 'image/png'},\n          body: 'I work out'\n        })\n\n        assert.equal(req.headers.get('content-type'), 'image/png')\n      })\n\n      featureDependent(test, support.blob, 'construct with Blob body and explicit Content-Type header', function() {\n        var req = new Request('https://fetch.spec.whatwg.org/', {\n          method: 'post',\n          headers: {'Content-Type': 'image/png'},\n          body: new Blob(['test'], {type: 'text/plain'})\n        })\n\n        assert.equal(req.headers.get('content-type'), 'image/png')\n      })\n\n      featureDependent(test, !IEorEdge, 'construct with URLSearchParams body sets Content-Type header', function() {\n        var req = new Request('https://fetch.spec.whatwg.org/', {\n          method: 'post',\n          body: new URLSearchParams('a=1&b=2')\n        })\n\n        assert.equal(req.headers.get('content-type'), 'application/x-www-form-urlencoded;charset=UTF-8')\n      })\n\n      featureDependent(\n        test,\n        !IEorEdge,\n        'construct with URLSearchParams body and explicit Content-Type header',\n        function() {\n          var req = new Request('https://fetch.spec.whatwg.org/', {\n            method: 'post',\n            headers: {'Content-Type': 'image/png'},\n            body: new URLSearchParams('a=1&b=2')\n          })\n\n          assert.equal(req.headers.get('content-type'), 'image/png')\n        }\n      )\n\n      test('construct with unsupported body type', function() {\n        var req = new Request('https://fetch.spec.whatwg.org/', {\n          method: 'post',\n          body: {}\n        })\n\n        assert.equal(req.headers.get('content-type'), 'text/plain;charset=UTF-8')\n        return req.text().then(function(bodyText) {\n          assert.equal(bodyText, '[object Object]')\n        })\n      })\n\n      test('construct with null body', function() {\n        var req = new Request('https://fetch.spec.whatwg.org/', {\n          method: 'post'\n        })\n\n        assert.isNull(req.headers.get('content-type'))\n        return req.text().then(function(bodyText) {\n          assert.equal(bodyText, '')\n        })\n      })\n\n      test('clone GET request', function() {\n        var req = new Request('https://fetch.spec.whatwg.org/', {\n          headers: {'content-type': 'text/plain'}\n        })\n        var clone = req.clone()\n\n        assert.equal(clone.url, req.url)\n        assert.equal(clone.method, 'GET')\n        assert.equal(clone.headers.get('content-type'), 'text/plain')\n        assert.notEqual(clone.headers, req.headers)\n        assert.isFalse(req.bodyUsed)\n      })\n\n      test('clone POST request', function() {\n        var req = new Request('https://fetch.spec.whatwg.org/', {\n          method: 'post',\n          headers: {'content-type': 'text/plain'},\n          body: 'I work out'\n        })\n        var clone = req.clone()\n\n        assert.equal(clone.method, 'POST')\n        assert.equal(clone.headers.get('content-type'), 'text/plain')\n        assert.notEqual(clone.headers, req.headers)\n        assert.equal(req.bodyUsed, false)\n\n        return Promise.all([clone.text(), req.clone().text()]).then(function(bodies) {\n          assert.deepEqual(bodies, ['I work out', 'I work out'])\n        })\n      })\n\n      featureDependent(test, !nativeChrome, 'clone with used Request body', function() {\n        var req = new Request('https://fetch.spec.whatwg.org/', {\n          method: 'post',\n          body: 'I work out'\n        })\n\n        return req.text().then(function() {\n          assert.throws(function() {\n            req.clone()\n          }, TypeError)\n        })\n      })\n\n      testBodyExtract(function(body) {\n        return new Request('', {method: 'POST', body: body})\n      })\n\n      featureDependent(test, !omitSafari, 'credentials defaults to same-origin', function() {\n        var request = new Request('')\n        assert.equal(request.credentials, 'same-origin')\n      })\n\n      test('credentials is overridable', function() {\n        var request = new Request('', {credentials: 'omit'})\n        assert.equal(request.credentials, 'omit')\n      })\n    })\n\n    // https://fetch.spec.whatwg.org/#response-class\n    suite('Response', function() {\n      featureDependent(test, emptyDefaultStatusText, 'default status is 200', function() {\n        var res = new Response()\n        assert.equal(res.status, 200)\n        assert.equal(res.statusText, '')\n        assert.isTrue(res.ok)\n      })\n\n      featureDependent(\n        test,\n        emptyDefaultStatusText,\n        'default status is 200 when an explicit undefined status code is passed',\n        function() {\n          var res = new Response('', {status: undefined})\n          assert.equal(res.status, 200)\n          assert.equal(res.statusText, '')\n          assert.isTrue(res.ok)\n        }\n      )\n\n      testBodyExtract(function(body) {\n        return new Response(body)\n      })\n\n      test('called as normal function', function() {\n        assert.throws(function() {\n          Response('{\"foo\":\"bar\"}', {headers: {'content-type': 'application/json'}})\n        })\n      })\n      test('status outside inclusive range 200-599 ', function() {\n        assert.throws(function() {\n          new Response('', {status: 199})\n        })\n        for (var i = 0; i < 200; i++) {\n          assert.throws(function() {\n            new Response('', {status: i})\n          })\n        }\n        for (i = 999; i > 599; i--) {\n          assert.throws(function() {\n            new Response('', {status: i})\n          })\n        }\n        // A fetch with the url of a `file://` scheme may have a status 0 or\n        // similar in some operating systems. In the event that a status is found outside \n        // the standard range of 200-599, and the url start with `file://`\n        // the status should return 200\n        assert.doesNotThrow(function() {\n          new Request('', {status: 0, request: {url: 'file://path/to/local/file'}})\n        })\n      })\n\n      test('creates Headers object from raw headers', function() {\n        var r = new Response('{\"foo\":\"bar\"}', {headers: {'content-type': 'application/json'}})\n        assert.equal(r.headers instanceof Headers, true)\n        return r.json().then(function(json) {\n          assert.equal(json.foo, 'bar')\n          return json\n        })\n      })\n\n      test('always creates a new Headers instance', function() {\n        var headers = new Headers({'x-hello': 'world'})\n        var res = new Response('', {headers: headers})\n\n        assert.equal(res.headers.get('x-hello'), 'world')\n        assert.notEqual(res.headers, headers)\n      })\n\n      test('clone text response', function() {\n        var res = new Response('{\"foo\":\"bar\"}', {\n          headers: {'content-type': 'application/json'}\n        })\n        var clone = res.clone()\n\n        assert.notEqual(clone.headers, res.headers, 'headers were cloned')\n        assert.equal(clone.headers.get('content-type'), 'application/json')\n\n        return Promise.all([clone.json(), res.json()]).then(function(jsons) {\n          assert.deepEqual(jsons[0], jsons[1], 'json of cloned object is the same as original')\n        })\n      })\n\n      featureDependent(test, support.blob, 'clone blob response', function() {\n        var req = new Request(new Blob(['test']))\n        req.clone()\n        assert.equal(req.bodyUsed, false)\n      })\n\n      test('error creates error Response', function() {\n        var r = Response.error()\n        assert(r instanceof Response)\n        assert.equal(r.ok, false)\n        assert.equal(r.status, 0)\n        assert.equal(r.statusText, '')\n        assert.equal(r.type, 'error')\n      })\n\n      test('redirect creates redirect Response', function() {\n        var r = Response.redirect('https://fetch.spec.whatwg.org/', 301)\n        assert(r instanceof Response)\n        assert.equal(r.status, 301)\n        assert.equal(r.headers.get('Location'), 'https://fetch.spec.whatwg.org/')\n      })\n\n      test('construct with string body sets Content-Type header', function() {\n        var r = new Response('I work out')\n        assert.equal(r.headers.get('content-type'), 'text/plain;charset=UTF-8')\n      })\n\n      featureDependent(test, support.blob, 'construct with Blob body and type sets Content-Type header', function() {\n        var r = new Response(new Blob(['test'], {type: 'text/plain'}))\n        assert.equal(r.headers.get('content-type'), 'text/plain')\n      })\n\n      test('construct with body and explicit header uses header', function() {\n        var r = new Response('I work out', {\n          headers: {\n            'Content-Type': 'text/plain'\n          }\n        })\n\n        assert.equal(r.headers.get('content-type'), 'text/plain')\n      })\n\n      test('construct with undefined statusText', function() {\n        var r = new Response('', {statusText: undefined})\n        assert.equal(r.statusText, '')\n      })\n\n      test('construct with null statusText', function() {\n        var r = new Response('', {statusText: null})\n        assert.equal(r.statusText, 'null')\n      })\n\n      test('init object as first argument', function() {\n        var r = new Response({\n          status: 201,\n          headers: {\n            'Content-Type': 'text/html'\n          }\n        })\n\n        assert.equal(r.status, 200)\n        assert.equal(r.headers.get('content-type'), 'text/plain;charset=UTF-8')\n        return r.text().then(function(bodyText) {\n          assert.equal(bodyText, '[object Object]')\n        })\n      })\n\n      test('null as first argument', function() {\n        var r = new Response(null)\n\n        assert.isNull(r.headers.get('content-type'))\n        return r.text().then(function(bodyText) {\n          assert.equal(bodyText, '')\n        })\n      })\n    })\n\n    // https://fetch.spec.whatwg.org/#body-mixin\n    suite('Body mixin', function() {\n      featureDependent(suite, support.blob, 'arrayBuffer', function() {\n        test('resolves arrayBuffer promise', function() {\n          return fetch('/hello')\n            .then(function(response) {\n              return response.arrayBuffer()\n            })\n            .then(function(buf) {\n              assert(buf instanceof ArrayBuffer, 'buf is an ArrayBuffer instance')\n              assert.equal(buf.byteLength, 2)\n            })\n        })\n\n        test('arrayBuffer handles binary data', function() {\n          return fetch('/binary')\n            .then(function(response) {\n              return response.arrayBuffer()\n            })\n            .then(function(buf) {\n              assert(buf instanceof ArrayBuffer, 'buf is an ArrayBuffer instance')\n              assert.equal(buf.byteLength, 256, 'buf.byteLength is correct')\n              var view = new Uint8Array(buf)\n              for (var i = 0; i < 256; i++) {\n                assert.equal(view[i], i)\n              }\n            })\n        })\n\n        test('arrayBuffer handles utf-8 data', function() {\n          return fetch('/hello/utf8')\n            .then(function(response) {\n              return response.arrayBuffer()\n            })\n            .then(function(buf) {\n              assert(buf instanceof ArrayBuffer, 'buf is an ArrayBuffer instance')\n              assert.equal(buf.byteLength, 5, 'buf.byteLength is correct')\n              var octets = Array.prototype.slice.call(new Uint8Array(buf))\n              assert.deepEqual(octets, [104, 101, 108, 108, 111])\n            })\n        })\n\n        test('arrayBuffer handles utf-16le data', function() {\n          return fetch('/hello/utf16le')\n            .then(function(response) {\n              return response.arrayBuffer()\n            })\n            .then(function(buf) {\n              assert(buf instanceof ArrayBuffer, 'buf is an ArrayBuffer instance')\n              assert.equal(buf.byteLength, 10, 'buf.byteLength is correct')\n              var octets = Array.prototype.slice.call(new Uint8Array(buf))\n              assert.deepEqual(octets, [104, 0, 101, 0, 108, 0, 108, 0, 111, 0])\n            })\n        })\n\n        test('rejects arrayBuffer promise after body is consumed', function() {\n          return fetch('/hello')\n            .then(function(response) {\n              assert.equal(response.bodyUsed, false)\n              response.blob()\n              assert.equal(response.bodyUsed, true)\n              return response.arrayBuffer()\n            })\n            .catch(function(error) {\n              assert(error instanceof TypeError, 'Promise rejected after body consumed')\n            })\n        })\n      })\n\n      featureDependent(suite, support.blob, 'blob', function() {\n        test('resolves blob promise', function() {\n          return fetch('/hello')\n            .then(function(response) {\n              return response.blob()\n            })\n            .then(function(blob) {\n              assert(blob instanceof Blob, 'blob is a Blob instance')\n              assert.equal(blob.size, 2)\n            })\n        })\n\n        test('blob handles binary data', function() {\n          return fetch('/binary')\n            .then(function(response) {\n              return response.blob()\n            })\n            .then(function(blob) {\n              assert(blob instanceof Blob, 'blob is a Blob instance')\n              assert.equal(blob.size, 256, 'blob.size is correct')\n            })\n        })\n\n        test('blob handles utf-8 data', function() {\n          return fetch('/hello/utf8')\n            .then(function(response) {\n              return response.blob()\n            })\n            .then(readBlobAsBytes)\n            .then(function(octets) {\n              assert.equal(octets.length, 5, 'blob.size is correct')\n              assert.deepEqual(octets, [104, 101, 108, 108, 111])\n            })\n        })\n\n        test('blob handles utf-16le data', function() {\n          return fetch('/hello/utf16le')\n            .then(function(response) {\n              return response.blob()\n            })\n            .then(readBlobAsBytes)\n            .then(function(octets) {\n              assert.equal(octets.length, 10, 'blob.size is correct')\n              assert.deepEqual(octets, [104, 0, 101, 0, 108, 0, 108, 0, 111, 0])\n            })\n        })\n\n        test('rejects blob promise after body is consumed', function() {\n          return fetch('/hello')\n            .then(function(response) {\n              assert(response.blob, 'Body does not implement blob')\n              assert.equal(response.bodyUsed, false)\n              response.text()\n              assert.equal(response.bodyUsed, true)\n              return response.blob()\n            })\n            .catch(function(error) {\n              assert(error instanceof TypeError, 'Promise rejected after body consumed')\n            })\n        })\n      })\n\n      featureDependent(suite, support.formData, 'formData', function() {\n        test('post sets content-type header', function() {\n          return fetch('/request', {\n            method: 'post',\n            body: new FormData()\n          })\n            .then(function(response) {\n              return response.json()\n            })\n            .then(function(json) {\n              assert.equal(json.method, 'POST')\n              assert(/^multipart\\/form-data;/.test(json.headers['content-type']))\n            })\n        })\n\n        featureDependent(test, !nativeChrome && !nativeEdge, 'formData rejects after body was consumed', function() {\n          return fetch('/json')\n            .then(function(response) {\n              assert(response.formData, 'Body does not implement formData')\n              response.formData()\n              return response.formData()\n            })\n            .catch(function(error) {\n              if (error instanceof chai.AssertionError) {\n                throw error\n              } else {\n                assert(error instanceof TypeError, 'Promise rejected after body consumed')\n              }\n            })\n        })\n\n        featureDependent(\n          test,\n          !nativeChrome && !nativeSafari && !nativeEdge,\n          'parses form encoded response',\n          function() {\n            return fetch('/form')\n              .then(function(response) {\n                return response.formData()\n              })\n              .then(function(form) {\n                assert(form instanceof FormData, 'Parsed a FormData object')\n              })\n          }\n        )\n      })\n\n      suite('json', function() {\n        test('parses json response', function() {\n          return fetch('/json')\n            .then(function(response) {\n              return response.json()\n            })\n            .then(function(json) {\n              assert.equal(json.name, 'Hubot')\n              assert.equal(json.login, 'hubot')\n            })\n        })\n\n        test('rejects json promise after body is consumed', function() {\n          return fetch('/json')\n            .then(function(response) {\n              assert(response.json, 'Body does not implement json')\n              assert.equal(response.bodyUsed, false)\n              response.text()\n              assert.equal(response.bodyUsed, true)\n              return response.json()\n            })\n            .catch(function(error) {\n              assert(error instanceof TypeError, 'Promise rejected after body consumed')\n            })\n        })\n\n        featureDependent(test, !polyfillFirefox, 'handles json parse error', function() {\n          return fetch('/json-error')\n            .then(function(response) {\n              return response.json()\n            })\n            .catch(function(error) {\n              if (!IEorEdge) assert(error instanceof Error, 'JSON exception is an Error instance')\n              assert(error.message, 'JSON exception has an error message')\n            })\n        })\n      })\n\n      suite('text', function() {\n        test('handles 204 No Content response', function() {\n          return fetch('/empty')\n            .then(function(response) {\n              assert.equal(response.status, 204)\n              return response.text()\n            })\n            .then(function(body) {\n              assert.equal(body, '')\n            })\n        })\n\n        test('resolves text promise', function() {\n          return fetch('/hello')\n            .then(function(response) {\n              return response.text()\n            })\n            .then(function(text) {\n              assert.equal(text, 'hi')\n            })\n        })\n\n        test('rejects text promise after body is consumed', function() {\n          return fetch('/hello')\n            .then(function(response) {\n              assert(response.text, 'Body does not implement text')\n              assert.equal(response.bodyUsed, false)\n              response.text()\n              assert.equal(response.bodyUsed, true)\n              return response.text()\n            })\n            .catch(function(error) {\n              assert(error instanceof TypeError, 'Promise rejected after body consumed')\n            })\n        })\n\n        test('does not set bodyUsed to true if no body supplied', function() {\n          var response = new Response();\n          assert(response.text, 'Body does not implement text')\n          assert.equal(response.bodyUsed, false)\n          response.text()\n          assert.equal(response.bodyUsed, false)\n          return response.text()\n        })\n      })\n    })\n\n    suite('fetch method', function() {\n      suite('promise resolution', function() {\n        test('resolves promise on 500 error', function() {\n          return fetch('/boom')\n            .then(function(response) {\n              assert.equal(response.status, 500)\n              assert.equal(response.ok, false)\n              return response.text()\n            })\n            .then(function(body) {\n              assert.equal(body, 'boom')\n            })\n        })\n\n        test.skip('rejects promise for network error', function() {\n          return fetch('/error')\n            .then(function(response) {\n              assert(false, 'HTTP status ' + response.status + ' was treated as success')\n            })\n            .catch(function(error) {\n              assert(error instanceof TypeError, 'Rejected with Error')\n            })\n        })\n\n        test('rejects when Request constructor throws', function() {\n          return fetch('/request', {method: 'GET', body: 'invalid'})\n            .then(function() {\n              assert(false, 'Invalid Request init was accepted')\n            })\n            .catch(function(error) {\n              assert(error instanceof TypeError, 'Rejected with Error')\n            })\n        })\n      })\n\n      suite('request', function() {\n        test('sends headers', function() {\n          return fetch('/request', {\n            headers: {\n              Accept: 'application/json',\n              'X-Test': '42'\n            }\n          })\n            .then(function(response) {\n              return response.json()\n            })\n            .then(function(json) {\n              assert.equal(json.headers['accept'], 'application/json')\n              assert.equal(json.headers['x-test'], '42')\n            })\n        })\n\n        test('with Request as argument', function() {\n          var request = new Request('/request', {\n            headers: {\n              Accept: 'application/json',\n              'X-Test': '42'\n            }\n          })\n\n          return fetch(request)\n            .then(function(response) {\n              return response.json()\n            })\n            .then(function(json) {\n              assert.equal(json.headers['accept'], 'application/json')\n              assert.equal(json.headers['x-test'], '42')\n            })\n        })\n\n        test('reusing same Request multiple times', function() {\n          var request = new Request('/request', {\n            headers: {\n              Accept: 'application/json',\n              'X-Test': '42'\n            }\n          })\n\n          var responses = []\n\n          return fetch(request)\n            .then(function(response) {\n              responses.push(response)\n              return fetch(request)\n            })\n            .then(function(response) {\n              responses.push(response)\n              return fetch(request)\n            })\n            .then(function(response) {\n              responses.push(response)\n              return Promise.all(\n                responses.map(function(r) {\n                  return r.json()\n                })\n              )\n            })\n            .then(function(jsons) {\n              jsons.forEach(function(json) {\n                assert.equal(json.headers['accept'], 'application/json')\n                assert.equal(json.headers['x-test'], '42')\n              })\n            })\n        })\n\n        featureDependent(suite, support.arrayBuffer, 'ArrayBuffer', function() {\n          test('ArrayBuffer body', function() {\n            return fetch('/request', {\n              method: 'post',\n              body: arrayBufferFromText('name=Hubot')\n            })\n              .then(function(response) {\n                return response.json()\n              })\n              .then(function(request) {\n                assert.equal(request.method, 'POST')\n                assert.equal(request.data, 'name=Hubot')\n              })\n          })\n\n          test('DataView body', function() {\n            return fetch('/request', {\n              method: 'post',\n              body: new DataView(arrayBufferFromText('name=Hubot'))\n            })\n              .then(function(response) {\n                return response.json()\n              })\n              .then(function(request) {\n                assert.equal(request.method, 'POST')\n                assert.equal(request.data, 'name=Hubot')\n              })\n          })\n\n          test('TypedArray body', function() {\n            return fetch('/request', {\n              method: 'post',\n              body: new Uint8Array(arrayBufferFromText('name=Hubot'))\n            })\n              .then(function(response) {\n                return response.json()\n              })\n              .then(function(request) {\n                assert.equal(request.method, 'POST')\n                assert.equal(request.data, 'name=Hubot')\n              })\n          })\n        })\n\n        featureDependent(test, !IEorEdge, 'sends URLSearchParams body', function() {\n          return fetch('/request', {\n            method: 'post',\n            body: new URLSearchParams('a=1&b=2')\n          })\n            .then(function(response) {\n              return response.json()\n            })\n            .then(function(request) {\n              assert.equal(request.method, 'POST')\n              assert.equal(request.data, 'a=1&b=2')\n            })\n        })\n      })\n\n      featureDependent(suite, exerciseMode !== 'native' || support.aborting, 'aborting', function() {\n        test('Request init creates an AbortSignal without option', function() {\n          var request = new Request('/request')\n          assert.ok(request.signal);\n          assert.equal(request.signal.aborted, false);\n        })\n\n        test('Request init passes AbortSignal from option', function () {\n          var controller = new AbortController()\n          var request = new Request('/request', {signal: controller.signal})\n          assert.ok(request.signal);\n          assert.deepEqual(controller.signal, request.signal);\n        })\n\n        test('initially aborted signal', function () {\n          var controller = new AbortController()\n          controller.abort()\n\n          return fetch('/request', {\n            signal: controller.signal\n          }).then(\n            function() {\n              assert.ok(false)\n            },\n            function(error) {\n              if (!IEorEdge) assert.instanceOf(error, WHATWGFetch.DOMException)\n              assert.equal(error.name, 'AbortError')\n            }\n          )\n        })\n\n        test('initially aborted signal within Request', function() {\n          var controller = new AbortController()\n          controller.abort()\n\n          var request = new Request('/request', {signal: controller.signal})\n\n          return fetch(request).then(\n            function() {\n              assert.ok(false)\n            },\n            function(error) {\n              assert.equal(error.name, 'AbortError')\n            }\n          )\n        })\n\n        test('mid-request', function() {\n          var controller = new AbortController()\n\n          setTimeout(function() {\n            controller.abort()\n          }, 30)\n\n          return fetch('/slow?_=' + new Date().getTime(), {\n            signal: controller.signal\n          }).then(\n            function() {\n              assert.ok(false)\n            },\n            function(error) {\n              assert.equal(error.name, 'AbortError')\n            }\n          )\n        })\n\n        test('mid-request within Request', function() {\n          var controller = new AbortController()\n          var request = new Request('/slow?_=' + new Date().getTime(), {signal: controller.signal})\n\n          setTimeout(function() {\n            controller.abort()\n          }, 30)\n\n          return fetch(request).then(\n            function() {\n              assert.ok(false)\n            },\n            function(error) {\n              assert.equal(error.name, 'AbortError')\n            }\n          )\n        })\n\n        test('abort multiple with same signal', function() {\n          var controller = new AbortController()\n\n          setTimeout(function() {\n            controller.abort()\n          }, 30)\n\n          return Promise.all([\n            fetch('/slow?_=' + new Date().getTime(), {\n              signal: controller.signal\n            }).then(\n              function() {\n                assert.ok(false)\n              },\n              function(error) {\n                assert.equal(error.name, 'AbortError')\n              }\n            ),\n            fetch('/slow?_=' + new Date().getTime(), {\n              signal: controller.signal\n            }).then(\n              function() {\n                assert.ok(false)\n              },\n              function(error) {\n                assert.equal(error.name, 'AbortError')\n              }\n            )\n          ])\n        })\n      })\n\n      suite('response', function() {\n        test('populates body', function() {\n          return fetch('/hello')\n            .then(function(response) {\n              assert.equal(response.status, 200)\n              assert.equal(response.ok, true)\n              return response.text()\n            })\n            .then(function(body) {\n              assert.equal(body, 'hi')\n            })\n        })\n\n        test('parses headers', function() {\n          return fetch('/headers?' + new Date().getTime()).then(function(response) {\n            assert.equal(response.headers.get('Date'), 'Mon, 13 Oct 2014 21:02:27 GMT')\n            assert.equal(response.headers.get('Content-Type'), 'text/html; charset=utf-8')\n          })\n        })\n      })\n\n      // https://fetch.spec.whatwg.org/#methods\n      suite('HTTP methods', function() {\n        test('supports HTTP GET', function() {\n          return fetch('/request', {\n            method: 'get'\n          })\n            .then(function(response) {\n              return response.json()\n            })\n            .then(function(request) {\n              assert.equal(request.method, 'GET')\n              assert.equal(request.data, '')\n            })\n        })\n\n        test('GET with body throws TypeError', function() {\n          assert.throw(function() {\n            new Request('', {\n              method: 'get',\n              body: 'invalid'\n            })\n          }, TypeError)\n        })\n\n        test('HEAD with body throws TypeError', function() {\n          assert.throw(function() {\n            new Request('', {\n              method: 'head',\n              body: 'invalid'\n            })\n          }, TypeError)\n        })\n\n        test('supports HTTP POST', function() {\n          return fetch('/request', {\n            method: 'post',\n            body: 'name=Hubot'\n          })\n            .then(function(response) {\n              return response.json()\n            })\n            .then(function(request) {\n              assert.equal(request.method, 'POST')\n              assert.equal(request.data, 'name=Hubot')\n            })\n        })\n\n        test('supports HTTP PUT', function() {\n          return fetch('/request', {\n            method: 'put',\n            body: 'name=Hubot'\n          })\n            .then(function(response) {\n              return response.json()\n            })\n            .then(function(request) {\n              assert.equal(request.method, 'PUT')\n              assert.equal(request.data, 'name=Hubot')\n            })\n        })\n\n        test('supports HTTP PATCH', function() {\n          return fetch('/request', {\n            method: 'PATCH',\n            body: 'name=Hubot'\n          })\n            .then(function(response) {\n              return response.json()\n            })\n            .then(function(request) {\n              assert.equal(request.method, 'PATCH')\n              assert.equal(request.data, 'name=Hubot')\n            })\n        })\n\n        test('supports HTTP DELETE', function() {\n          return fetch('/request', {\n            method: 'delete'\n          })\n            .then(function(response) {\n              return response.json()\n            })\n            .then(function(request) {\n              assert.equal(request.method, 'DELETE')\n              assert.equal(request.data, '')\n            })\n        })\n      })\n\n      // https://fetch.spec.whatwg.org/#atomic-http-redirect-handling\n      suite('Atomic HTTP redirect handling', function() {\n        test('handles 301 redirect response', function() {\n          return fetch('/redirect/301')\n            .then(function(response) {\n              assert.equal(response.status, 200)\n              assert.equal(response.ok, true)\n              assert.match(response.url, /\\/hello/)\n              return response.text()\n            })\n            .then(function(body) {\n              assert.equal(body, 'hi')\n            })\n        })\n\n        test('handles 302 redirect response', function() {\n          return fetch('/redirect/302')\n            .then(function(response) {\n              assert.equal(response.status, 200)\n              assert.equal(response.ok, true)\n              assert.match(response.url, /\\/hello/)\n              return response.text()\n            })\n            .then(function(body) {\n              assert.equal(body, 'hi')\n            })\n        })\n\n        test('handles 303 redirect response', function() {\n          return fetch('/redirect/303')\n            .then(function(response) {\n              assert.equal(response.status, 200)\n              assert.equal(response.ok, true)\n              assert.match(response.url, /\\/hello/)\n              return response.text()\n            })\n            .then(function(body) {\n              assert.equal(body, 'hi')\n            })\n        })\n\n        test('handles 307 redirect response', function() {\n          return fetch('/redirect/307')\n            .then(function(response) {\n              assert.equal(response.status, 200)\n              assert.equal(response.ok, true)\n              assert.match(response.url, /\\/hello/)\n              return response.text()\n            })\n            .then(function(body) {\n              assert.equal(body, 'hi')\n            })\n        })\n\n        featureDependent(test, support.permanentRedirect, 'handles 308 redirect response', function() {\n          return fetch('/redirect/308')\n            .then(function(response) {\n              assert.equal(response.status, 200)\n              assert.equal(response.ok, true)\n              assert.match(response.url, /\\/hello/)\n              return response.text()\n            })\n            .then(function(body) {\n              assert.equal(body, 'hi')\n            })\n        })\n      })\n\n      // https://fetch.spec.whatwg.org/#concept-request-credentials-mode\n      suite('credentials mode', function() {\n        setup(function() {\n          return fetch('/cookie?name=foo&value=reset', {credentials: 'same-origin'})\n        })\n\n        featureDependent(suite, exerciseMode === 'native', 'omit', function() {\n          test('does not accept cookies with omit credentials', function() {\n            return fetch('/cookie?name=foo&value=bar', {credentials: 'omit'})\n              .then(function() {\n                return fetch('/cookie?name=foo', {credentials: 'same-origin'})\n              })\n              .then(function(response) {\n                return response.text()\n              })\n              .then(function(data) {\n                assert.equal(data, 'reset')\n              })\n          })\n\n          test('does not send cookies with omit credentials', function() {\n            return fetch('/cookie?name=foo&value=bar')\n              .then(function() {\n                return fetch('/cookie?name=foo', {credentials: 'omit'})\n              })\n              .then(function(response) {\n                return response.text()\n              })\n              .then(function(data) {\n                assert.equal(data, '')\n              })\n          })\n        })\n\n        suite('same-origin', function() {\n          test('send cookies with same-origin credentials', function() {\n            return fetch('/cookie?name=foo&value=bar', {credentials: 'same-origin'})\n              .then(function() {\n                return fetch('/cookie?name=foo', {credentials: 'same-origin'})\n              })\n              .then(function(response) {\n                return response.text()\n              })\n              .then(function(data) {\n                assert.equal(data, 'bar')\n              })\n          })\n        })\n\n        suite('include', function() {\n          test('send cookies with include credentials', function() {\n            return fetch('/cookie?name=foo&value=bar', {credentials: 'include'})\n              .then(function() {\n                return fetch('/cookie?name=foo', {credentials: 'include'})\n              })\n              .then(function(response) {\n                return response.text()\n              })\n              .then(function(data) {\n                assert.equal(data, 'bar')\n              })\n          })\n        })\n      })\n    })\n  })\n})\n"
  },
  {
    "path": "test/worker-adapter.js",
    "content": "/* eslint-env mocha */\n/* globals Mocha */\nvar mochaRun = mocha.run\nmocha.run = function() {}\n\nmocha.suite.suites.unshift(Mocha.Suite.create(mocha.suite, 'worker'))\n\nvar worker = new Worker('/base/test/worker.js')\n\nworker.addEventListener('message', function(e) {\n  switch (e.data.name) {\n    case 'pass':\n      test(e.data.title, function() {})\n      break\n    case 'pending':\n      test(e.data.title)\n      break\n    case 'fail':\n      test(e.data.title, function() {\n        var err = new Error(e.data.message)\n        err.stack = e.data.stack\n        throw err\n      })\n      break\n    case 'end':\n      mochaRun()\n      break\n  }\n})\n"
  },
  {
    "path": "test/worker.js",
    "content": "/* eslint-env worker */\n/* globals mocha chai */\nimportScripts('/base/node_modules/mocha/mocha.js')\nimportScripts('/base/node_modules/chai/chai.js')\n\nmocha.setup('tdd')\nself.assert = chai.assert\n\nimportScripts('/base/node_modules/abortcontroller-polyfill/dist/abortcontroller-polyfill-only.js')\nimportScripts('/base/dist/fetch.umd.js')\nimportScripts('/base/test/test.js')\n\nfunction title(test) {\n  return test.fullTitle().replace(/#/g, '')\n}\n\nfunction reporter(runner) {\n  runner.on('pending', function(test) {\n    self.postMessage({name: 'pending', title: title(test)})\n  })\n\n  runner.on('pass', function(test) {\n    self.postMessage({name: 'pass', title: title(test)})\n  })\n\n  runner.on('fail', function(test, err) {\n    self.postMessage({\n      name: 'fail',\n      title: title(test),\n      message: err.message,\n      stack: err.stack\n    })\n  })\n\n  runner.on('end', function() {\n    self.postMessage({name: 'end'})\n  })\n}\n\nmocha.reporter(reporter).run()\n"
  }
]