Repository: urql-graphql/urql
Pull request #3119 (2023-03-31 20:26:52)

chore(multipart): Delete multipart-fetch exchange folder
## Summary

Removing the deprecated `multipart-fetch` exchange folder.

## Set of changes

- n/a



Patch:
diff --git a/examples/with-apq/package.json b/examples/with-apq/package.json
index ff7dc0c3..8b7023fb 100644
--- a/examples/with-apq/package.json
+++ b/examples/with-apq/package.json
@@ -6,7 +6,7 @@
     "start": "vite"
   },
   "dependencies": {
-    "@urql/core": "^4.0.0",
+    "@urql/core": "^4.0.1",
     "@urql/exchange-persisted-fetch": "^1.3.0",
     "graphql": "^16.6.0",
     "react": "^18.2.0",
diff --git a/examples/with-defer-stream-directives/package.json b/examples/with-defer-stream-directives/package.json
index 84f1cada..14665d69 100644
--- a/examples/with-defer-stream-directives/package.json
+++ b/examples/with-defer-stream-directives/package.json
@@ -17,7 +17,7 @@
   },
   "dependencies": {
     "@graphql-yoga/plugin-defer-stream": "^1.7.1",
-    "@urql/core": "^4.0.0",
+    "@urql/core": "^4.0.1",
     "@urql/exchange-graphcache": "^6.0.1",
     "graphql": "17.0.0-alpha.2",
     "react": "^18.2.0",
diff --git a/examples/with-graphcache-pagination/package.json b/examples/with-graphcache-pagination/package.json
index 142ebb4d..555e4b8f 100644
--- a/examples/with-graphcache-pagination/package.json
+++ b/examples/with-graphcache-pagination/package.json
@@ -6,7 +6,7 @@
     "start": "vite"
   },
   "dependencies": {
-    "@urql/core": "^4.0.0",
+    "@urql/core": "^4.0.1",
     "@urql/exchange-graphcache": "^6.0.1",
     "graphql": "^16.6.0",
     "react": "^18.2.0",
diff --git a/examples/with-graphcache-updates/package.json b/examples/with-graphcache-updates/package.json
index 8ce4fb28..762941c0 100644
--- a/examples/with-graphcache-updates/package.json
+++ b/examples/with-graphcache-updates/package.json
@@ -6,7 +6,7 @@
     "start": "vite"
   },
   "dependencies": {
-    "@urql/core": "^4.0.0",
+    "@urql/core": "^4.0.1",
     "@urql/exchange-auth": "^2.1.0",
     "@urql/exchange-graphcache": "^6.0.1",
     "graphql": "^16.6.0",
diff --git a/examples/with-multipart/package.json b/examples/with-multipart/package.json
index 75920124..63609813 100644
--- a/examples/with-multipart/package.json
+++ b/examples/with-multipart/package.json
@@ -6,7 +6,7 @@
     "start": "vite"
   },
   "dependencies": {
-    "@urql/core": "^4.0.0",
+    "@urql/core": "^4.0.1",
     "graphql": "^16.6.0",
     "react": "^18.2.0",
     "react-dom": "^18.2.0",
diff --git a/examples/with-next/package.json b/examples/with-next/package.json
index 2e9d582e..d35b5b93 100644
--- a/examples/with-next/package.json
+++ b/examples/with-next/package.json
@@ -3,7 +3,7 @@
   "version": "0.0.0",
   "private": true,
   "dependencies": {
-    "@urql/core": "^4.0.0",
+    "@urql/core": "^4.0.1",
     "graphql": "^16.6.0",
     "next": "13.2.4",
     "next-urql": "^5.0.0",
diff --git a/examples/with-pagination/package.json b/examples/with-pagination/package.json
index 29afd3ce..32e70891 100644
--- a/examples/with-pagination/package.json
+++ b/examples/with-pagination/package.json
@@ -6,7 +6,7 @@
     "start": "vite"
   },
   "dependencies": {
-    "@urql/core": "^4.0.0",
+    "@urql/core": "^4.0.1",
     "graphql": "^16.6.0",
     "react": "^18.2.0",
     "react-dom": "^18.2.0",
diff --git a/examples/with-react-native/package.json b/examples/with-react-native/package.json
index 382bd058..6a95b982 100644
--- a/examples/with-react-native/package.json
+++ b/examples/with-react-native/package.json
@@ -8,7 +8,7 @@
     "start": "react-native start"
   },
   "dependencies": {
-    "@urql/core": "^4.0.0",
+    "@urql/core": "^4.0.1",
     "graphql": "^16.6.0",
     "react": "18.2.0",
     "react-native": "0.71.4",
diff --git a/examples/with-react/package.json b/examples/with-react/package.json
index 2c7df868..df2344b6 100644
--- a/examples/with-react/package.json
+++ b/examples/with-react/package.json
@@ -6,7 +6,7 @@
     "start": "vite"
   },
   "dependencies": {
-    "@urql/core": "^4.0.0",
+    "@urql/core": "^4.0.1",
     "graphql": "^16.6.0",
     "react": "^18.2.0",
     "react-dom": "^18.2.0",
diff --git a/examples/with-refresh-auth/package.json b/examples/with-refresh-auth/package.json
index 7a174355..c07def5b 100644
--- a/examples/with-refresh-auth/package.json
+++ b/examples/with-refresh-auth/package.json
@@ -6,7 +6,7 @@
     "start": "vite"
   },
   "dependencies": {
-    "@urql/core": "^4.0.0",
+    "@urql/core": "^4.0.1",
     "@urql/exchange-auth": "^2.1.0",
     "graphql": "^16.6.0",
     "react": "^18.2.0",
diff --git a/examples/with-retry/package.json b/examples/with-retry/package.json
index 9d8cc239..389ade57 100644
--- a/examples/with-retry/package.json
+++ b/examples/with-retry/package.json
@@ -6,7 +6,7 @@
     "start": "vite"
   },
   "dependencies": {
-    "@urql/core": "^4.0.0",
+    "@urql/core": "^4.0.1",
     "@urql/exchange-retry": "^1.1.0",
     "graphql": "^16.6.0",
     "react": "^18.2.0",
diff --git a/examples/with-svelte/package.json b/examples/with-svelte/package.json
index 20633da8..5457dffa 100644
--- a/examples/with-svelte/package.json
+++ b/examples/with-svelte/package.json
@@ -8,7 +8,7 @@
     "serve": "vite preview"
   },
   "dependencies": {
-    "@urql/core": "^4.0.0",
+    "@urql/core": "^4.0.1",
     "@urql/svelte": "^4.0.0",
     "graphql": "^16.6.0",
     "svelte": "^3.57.0"
diff --git a/examples/with-vue3/package.json b/examples/with-vue3/package.json
index 54f029a0..ddc16292 100644
--- a/examples/with-vue3/package.json
+++ b/examples/with-vue3/package.json
@@ -8,7 +8,7 @@
     "serve": "vite preview"
   },
   "dependencies": {
-    "@urql/core": "^4.0.0",
+    "@urql/core": "^4.0.1",
     "@urql/vue": "^1.1.0",
     "graphql": "^16.6.0",
     "vue": "^3.2.47"
diff --git a/exchanges/multipart-fetch/CHANGELOG.md b/exchanges/multipart-fetch/CHANGELOG.md
deleted file mode 100644
index d4251491..00000000
--- a/exchanges/multipart-fetch/CHANGELOG.md
+++ /dev/null
@@ -1,166 +0,0 @@
-# @urql/exchange-multipart-fetch
-
-## 1.1.0
-
-### Minor Changes
-
-- Update exchanges to drop redundant `share` calls, since `@urql/core`’s `composeExchanges` utility now automatically does so for us
-  Submitted by [@kitten](https://github.com/kitten) (See [#3082](https://github.com/urql-graphql/urql/pull/3082))
-
-### Patch Changes
-
-- Upgrade to `wonka@^6.3.0`
-  Submitted by [@kitten](https://github.com/kitten) (See [#3104](https://github.com/urql-graphql/urql/pull/3104))
-- Deprecate `@urql/exchange-multipart-fetch` as behaviour has been absorbed into `@urql/core`. If you're using the `multipartFetchExchange`, you should now be able to simply remove it
-  Submitted by [@kitten](https://github.com/kitten) (See [#3051](https://github.com/urql-graphql/urql/pull/3051))
-- Updated dependencies (See [#3101](https://github.com/urql-graphql/urql/pull/3101), [#3033](https://github.com/urql-graphql/urql/pull/3033), [#3054](https://github.com/urql-graphql/urql/pull/3054), [#3053](https://github.com/urql-graphql/urql/pull/3053), [#3060](https://github.com/urql-graphql/urql/pull/3060), [#3081](https://github.com/urql-graphql/urql/pull/3081), [#3039](https://github.com/urql-graphql/urql/pull/3039), [#3104](https://github.com/urql-graphql/urql/pull/3104), [#3082](https://github.com/urql-graphql/urql/pull/3082), [#3097](https://github.com/urql-graphql/urql/pull/3097), [#3061](https://github.com/urql-graphql/urql/pull/3061), [#3055](https://github.com/urql-graphql/urql/pull/3055), [#3085](https://github.com/urql-graphql/urql/pull/3085), [#3079](https://github.com/urql-graphql/urql/pull/3079), [#3087](https://github.com/urql-graphql/urql/pull/3087), [#3059](https://github.com/urql-graphql/urql/pull/3059), [#3055](https://github.com/urql-graphql/urql/pull/3055), [#3057](https://github.com/urql-graphql/urql/pull/3057), [#3050](https://github.com/urql-graphql/urql/pull/3050), [#3062](https://github.com/urql-graphql/urql/pull/3062), [#3051](https://github.com/urql-graphql/urql/pull/3051), [#3043](https://github.com/urql-graphql/urql/pull/3043), [#3063](https://github.com/urql-graphql/urql/pull/3063), [#3054](https://github.com/urql-graphql/urql/pull/3054), [#3102](https://github.com/urql-graphql/urql/pull/3102), [#3097](https://github.com/urql-graphql/urql/pull/3097), [#3106](https://github.com/urql-graphql/urql/pull/3106), [#3058](https://github.com/urql-graphql/urql/pull/3058), and [#3062](https://github.com/urql-graphql/urql/pull/3062))
-  - @urql/core@4.0.0
-
-## 1.0.1
-
-### Patch Changes
-
-- ⚠️ Fix issue where we construct the fetchOptions before constructing the url resulting in our overflow fix not working, by [@JoviDeCroock](https://github.com/JoviDeCroock) (See [#2653](https://github.com/FormidableLabs/urql/pull/2653))
-
-## 1.0.0
-
-### Major Changes
-
-- **Goodbye IE11!** 👋 This major release removes support for IE11. All code that is shipped will be transpiled much less and will _not_ be ES5-compatible anymore, by [@kitten](https://github.com/kitten) (See [#2504](https://github.com/FormidableLabs/urql/pull/2504))
-- Upgrade to [Wonka v6](https://github.com/0no-co/wonka) (`wonka@^6.0.0`), which has no breaking changes but is built to target ES2015 and comes with other minor improvements.
-  The library has fully been migrated to TypeScript which will hopefully help with making contributions easier!, by [@kitten](https://github.com/kitten) (See [#2504](https://github.com/FormidableLabs/urql/pull/2504))
-
-### Patch Changes
-
-- Updated dependencies (See [#2551](https://github.com/FormidableLabs/urql/pull/2551), [#2504](https://github.com/FormidableLabs/urql/pull/2504), [#2619](https://github.com/FormidableLabs/urql/pull/2619), [#2607](https://github.com/FormidableLabs/urql/pull/2607), and [#2504](https://github.com/FormidableLabs/urql/pull/2504))
-  - @urql/core@3.0.0
-
-## 0.1.14
-
-### Patch Changes
-
-- Extend peer dependency range of `graphql` to include `^16.0.0`.
-  As always when upgrading across many packages of `urql`, especially including `@urql/core` we recommend you to deduplicate dependencies after upgrading, using `npm dedupe` or `npx yarn-deduplicate`, by [@kitten](https://github.com/kitten) (See [#2133](https://github.com/FormidableLabs/urql/pull/2133))
-- Updated dependencies (See [#2133](https://github.com/FormidableLabs/urql/pull/2133))
-  - @urql/core@2.3.6
-
-## 0.1.13
-
-### Patch Changes
-
-- Bump extract-files package to 11.0.0, by [@haswalt](https://github.com/haswalt) (See [#1795](https://github.com/FormidableLabs/urql/pull/1795))
-
-## 0.1.12
-
-### Patch Changes
-
-- Remove closure-compiler from the build step (See [#1570](https://github.com/FormidableLabs/urql/pull/1570))
-- Updated dependencies (See [#1570](https://github.com/FormidableLabs/urql/pull/1570), [#1509](https://github.com/FormidableLabs/urql/pull/1509), [#1600](https://github.com/FormidableLabs/urql/pull/1600), and [#1515](https://github.com/FormidableLabs/urql/pull/1515))
-  - @urql/core@2.1.0
-
-## 0.1.11
-
-### Patch Changes
-
-- ⚠️ Fix the production build overwriting the development build. Specifically in the previous release we mistakenly replaced all development bundles with production bundles. This doesn't have any direct influence on how these packages work, but prevented development warnings from being logged or full errors from being thrown, by [@kitten](https://github.com/kitten) (See [#1097](https://github.com/FormidableLabs/urql/pull/1097))
-- Updated dependencies (See [#1097](https://github.com/FormidableLabs/urql/pull/1097))
-  - @urql/core@1.14.1
-
-## 0.1.10
-
-### Patch Changes
-
-- Deprecate the `Operation.operationName` property in favor of `Operation.kind`. This name was
-  previously confusing as `operationName` was effectively referring to two different things. You can
-  safely upgrade to this new version, however to mute all deprecation warnings you will have to
-  **upgrade** all `urql` packages you use. If you have custom exchanges that spread operations, please
-  use [the new `makeOperation` helper
-  function](https://formidable.com/open-source/urql/docs/api/core/#makeoperation) instead, by [@bkonkle](https://github.com/bkonkle) (See [#1045](https://github.com/FormidableLabs/urql/pull/1045))
-- Updated dependencies (See [#1094](https://github.com/FormidableLabs/urql/pull/1094) and [#1045](https://github.com/FormidableLabs/urql/pull/1045))
-  - @urql/core@1.14.0
-
-## 0.1.9
-
-### Patch Changes
-
-- Omit the `Content-Type: application/json` HTTP header when using GET in the `fetchExchange`, `persistedFetchExchange`, or `multipartFetchExchange`, by [@JoviDeCroock](https://github.com/JoviDeCroock) (See [#957](https://github.com/FormidableLabs/urql/pull/957))
-- Updated dependencies (See [#947](https://github.com/FormidableLabs/urql/pull/947), [#962](https://github.com/FormidableLabs/urql/pull/962), and [#957](https://github.com/FormidableLabs/urql/pull/957))
-  - @urql/core@1.13.0
-
-## 0.1.8
-
-### Patch Changes
-
-- Upgrade to a minimum version of wonka@^4.0.14 to work around issues with React Native's minification builds, which use uglify-es and could lead to broken bundles, by [@kitten](https://github.com/kitten) (See [#842](https://github.com/FormidableLabs/urql/pull/842))
-- Updated dependencies (See [#838](https://github.com/FormidableLabs/urql/pull/838) and [#842](https://github.com/FormidableLabs/urql/pull/842))
-  - @urql/core@1.12.0
-
-## 0.1.7
-
-### Patch Changes
-
-- Add `source` debug name to all `dispatchDebug` calls during build time to identify events by which exchange dispatched them, by [@JoviDeCroock](https://github.com/JoviDeCroock) (See [#780](https://github.com/FormidableLabs/urql/pull/780))
-- Updated dependencies (See [#780](https://github.com/FormidableLabs/urql/pull/780))
-  - @urql/core@1.11.7
-
-## 0.1.6
-
-### Patch Changes
-
-- Add a `"./package.json"` entry to the `package.json`'s `"exports"` field for Node 14. This seems to be required by packages like `rollup-plugin-svelte` to function properly, by [@JoviDeCroock](https://github.com/JoviDeCroock) (See [#771](https://github.com/FormidableLabs/urql/pull/771))
-- Updated dependencies (See [#771](https://github.com/FormidableLabs/urql/pull/771))
-  - @urql/core@1.11.6
-
-## 0.1.5
-
-### Patch Changes
-
-- Add debugging events to exchanges that add more detailed information on what is happening
-  internally, which will be displayed by devtools like the urql [Chrome / Firefox extension](https://github.com/FormidableLabs/urql-devtools), by [@andyrichardson](https://github.com/andyrichardson) (See [#608](https://github.com/FormidableLabs/urql/pull/608))
-- Add @urql/core/internal entrypoint for internally shared utilities and start sharing fetchExchange-related code, by [@kitten](https://github.com/kitten) (See [#722](https://github.com/FormidableLabs/urql/pull/722))
-- Updated dependencies (See [#608](https://github.com/FormidableLabs/urql/pull/608), [#718](https://github.com/FormidableLabs/urql/pull/718), and [#722](https://github.com/FormidableLabs/urql/pull/722))
-  - @urql/core@1.11.0
-
-## 0.1.4
-
-### Patch Changes
-
-- Add graphql@^15.0.0 to peer dependency range, by [@kitten](https://github.com/kitten) (See [#688](https://github.com/FormidableLabs/urql/pull/688))
-- Bump extract-files to ^8.1.0, by [@kitten](https://github.com/kitten) (See [#688](https://github.com/FormidableLabs/urql/pull/688))
-- ⚠️ Fix non-2xx results never being parsed as GraphQL results. This can result in valid GraphQLErrors being hidden, which should take precedence over generic HTTP NetworkErrors, by [@kitten](https://github.com/kitten) (See [#678](https://github.com/FormidableLabs/urql/pull/678))
-- Updated dependencies (See [#688](https://github.com/FormidableLabs/urql/pull/688) and [#678](https://github.com/FormidableLabs/urql/pull/678))
-  - @urql/core@1.10.8
-
-## 0.1.3
-
-### Patch Changes
-
-- ⚠️ Fix node resolution when using Webpack, which experiences a bug where it only resolves
-  `package.json:main` instead of `module` when an `.mjs` file imports a package, by [@JoviDeCroock](https://github.com/JoviDeCroock) (See [#642](https://github.com/FormidableLabs/urql/pull/642))
-- Updated dependencies (See [#642](https://github.com/FormidableLabs/urql/pull/642))
-  - @urql/core@1.10.4
-
-## 0.1.2
-
-### Patch Changes
-
-- ⚠️ Fix multipart conversion, in the `extract-files` dependency (used by multipart-fetch) there is an explicit check for the constructor property of an object. This made the files unretrievable, by [@JoviDeCroock](https://github.com/JoviDeCroock) (See [#639](https://github.com/FormidableLabs/urql/pull/639))
-- ⚠️ Fix Node.js Module support for v13 (experimental-modules) and v14. If your bundler doesn't support
-  `.mjs` files and fails to resolve the new version, please double check your configuration for
-  Webpack, or similar tools, by [@JoviDeCroock](https://github.com/JoviDeCroock) (See [#637](https://github.com/FormidableLabs/urql/pull/637))
-- Updated dependencies (See [#637](https://github.com/FormidableLabs/urql/pull/637))
-  - @urql/core@1.10.3
-
-## 0.1.1
-
-### Patch Changes
-
-- ⚠️ Fix Rollup bundle output being written to .es.js instead of .esm.js, by [@kitten](https://github.com/kitten) (See [#609](https://github.com/FormidableLabs/urql/pull/609))
-- Updated dependencies (See [#609](https://github.com/FormidableLabs/urql/pull/609))
-  - @urql/core@1.10.1
-
-## 0.1.0
-
-### Initial release
-
-- Release the `multipartFetchExchange`
diff --git a/exchanges/multipart-fetch/README.md b/exchanges/multipart-fetch/README.md
deleted file mode 100644
index b3ae75cb..00000000
--- a/exchanges/multipart-fetch/README.md
+++ /dev/null
@@ -1,34 +0,0 @@
-# @urql/exchange-multipart-fetch
-
-> **DEPRECATION NOTICE**: The `multipartFetchExchange` has been deprecated, and
-> `@urql/core` now supports GraphQL Multipart Requests natively. This won't
-> break the behaviour of your existing apps, however, it's recommended to remove
-> the `multipartFetchExchange` from your apps.
-
-The `multipartFetchExchange` is an exchange that builds on the regular `fetchExchange`
-but adds the multipart file upload capability.
-
-## Quick Start Guide
-
-First install `@urql/exchange-multipart-fetch` alongside `urql`:
-
-```sh
-yarn add @urql/exchange-multipart-fetch
-# or
-npm install --save @urql/exchange-multipart-fetch
-```
-
-You'll then need to add the `multipartFetchExchange` method, that this package exposes,
-to your `exchanges`.
-
-```js
-import { createClient, dedupExchange, cacheExchange } from 'urql';
-import { multipartFetchExchange } from '@urql/exchange-multipart-fetch';
-
-const client = createClient({
-  url: 'http://localhost:1234/graphql',
-  exchanges: [dedupExchange, cacheExchange, multipartFetchExchange],
-});
-```
-
-Now we can start uploading files to our server!
diff --git a/exchanges/multipart-fetch/package.json b/exchanges/multipart-fetch/package.json
deleted file mode 100644
index 07b3d807..00000000
--- a/exchanges/multipart-fetch/package.json
+++ /dev/null
@@ -1,60 +0,0 @@
-{
-  "name": "@urql/exchange-multipart-fetch",
-  "version": "1.1.0",
-  "description": "An exchange that allows regular fetch and will transition to multipart when files are included",
-  "sideEffects": false,
-  "homepage": "https://formidable.com/open-source/urql/docs/",
-  "bugs": "https://github.com/urql-graphql/urql/issues",
-  "license": "MIT",
-  "repository": {
-    "type": "git",
-    "url": "https://github.com/urql-graphql/urql.git",
-    "directory": "exchanges/multipart-fetch"
-  },
-  "keywords": [
-    "urql",
-    "graphql",
-    "exchanges"
-  ],
-  "main": "dist/urql-exchange-multipart-fetch",
-  "module": "dist/urql-exchange-multipart-fetch.mjs",
-  "types": "dist/urql-exchange-multipart-fetch.d.ts",
-  "source": "src/index.ts",
-  "exports": {
-    ".": {
-      "import": "./dist/urql-exchange-multipart-fetch.mjs",
-      "require": "./dist/urql-exchange-multipart-fetch.js",
-      "types": "./dist/urql-exchange-multipart-fetch.d.ts",
-      "source": "./src/index.ts"
-    },
-    "./package.json": "./package.json"
-  },
-  "files": [
-    "LICENSE",
-    "CHANGELOG.md",
-    "README.md",
-    "dist/",
-    "extras/"
-  ],
-  "scripts": {
-    "test": "vitest --config ../../vitest.config.ts",
-    "clean": "rimraf dist extras",
-    "check": "tsc --noEmit",
-    "lint": "eslint --ext=js,jsx,ts,tsx .",
-    "build": "rollup -c ../../scripts/rollup/config.mjs",
-    "prepare": "node ../../scripts/prepare/index.js",
-    "prepublishOnly": "run-s clean build"
-  },
-  "dependencies": {
-    "@urql/core": ">=4.0.0",
-    "extract-files": "^11.0.0",
-    "wonka": "^6.3.0"
-  },
-  "devDependencies": {
-    "@urql/core": "workspace:*",
-    "graphql": "^16.0.0"
-  },
-  "publishConfig": {
-    "access": "public"
-  }
-}
diff --git a/exchanges/multipart-fetch/src/index.ts b/exchanges/multipart-fetch/src/index.ts
deleted file mode 100644
index 7c3765d2..00000000
--- a/exchanges/multipart-fetch/src/index.ts
+++ /dev/null
@@ -1,1 +0,0 @@
-export * from './multipartFetchExchange';
diff --git a/exchanges/multipart-fetch/src/multipartFetchExchange.ts b/exchanges/multipart-fetch/src/multipartFetchExchange.ts
deleted file mode 100644
index ee8ba272..00000000
--- a/exchanges/multipart-fetch/src/multipartFetchExchange.ts
+++ /dev/null
@@ -1,110 +0,0 @@
-import { filter, merge, mergeMap, pipe, takeUntil, onPush } from 'wonka';
-import { extractFiles } from 'extract-files';
-import { Exchange } from '@urql/core';
-
-import {
-  makeFetchBody,
-  makeFetchURL,
-  makeFetchOptions,
-  makeFetchSource,
-} from '@urql/core/internal';
-
-/** An Exchange which creates a multipart request when File/Blobs are found in variables.
- * @deprecated
- * `@urql/core` now supports the GraphQL Multipart Request spec out-of-the-box.
- */
-export const multipartFetchExchange: Exchange =
-  ({ forward, dispatchDebug }) =>
-  operations$ => {
-    const fetchResults$ = pipe(
-      operations$,
-      filter(operation => {
-        return operation.kind === 'query' || operation.kind === 'mutation';
-      }),
-      mergeMap(operation => {
-        const teardown$ = pipe(
-          operations$,
-          filter(op => op.kind === 'teardown' && op.key === operation.key)
-        );
-
-        // Spreading operation.variables here in case someone made a variables with Object.create(null).
-        const { files, clone: variables } = extractFiles({
-          ...operation.variables,
-        });
-        const body = makeFetchBody({ query: operation.query, variables });
-
-        let url: string;
-        let fetchOptions: RequestInit;
-        if (files.size) {
-          url = makeFetchURL(operation);
-          fetchOptions = makeFetchOptions(operation);
-          if (!(fetchOptions.body instanceof FormData)) {
-            if (fetchOptions.headers!['content-type'] === 'application/json') {
-              delete fetchOptions.headers!['content-type'];
-            }
-
-            fetchOptions.method = 'POST';
-            fetchOptions.body = new FormData();
-            fetchOptions.body.append('operations', JSON.stringify(body));
-
-            const map = {};
-            let i = 0;
-            files.forEach(paths => {
-              map[++i] = paths.map(path => `variables.${path}`);
-            });
-
-            fetchOptions.body.append('map', JSON.stringify(map));
-
-            i = 0;
-            files.forEach((_, file) => {
-              (fetchOptions.body as FormData).append(`${++i}`, file, file.name);
-            });
-          }
-        } else {
-          url = makeFetchURL(operation, body);
-          fetchOptions = makeFetchOptions(operation, body);
-        }
-
-        dispatchDebug({
-          type: 'fetchRequest',
-          message: 'A fetch request is being executed.',
-          operation,
-          data: {
-            url,
-            fetchOptions,
-          },
-        });
-
-        return pipe(
-          makeFetchSource(operation, url, fetchOptions),
-          takeUntil(teardown$),
-          onPush(result => {
-            const error = !result.data ? result.error : undefined;
-
-            dispatchDebug({
-              type: error ? 'fetchError' : 'fetchSuccess',
-              message: `A ${
-                error ? 'failed' : 'successful'
-              } fetch response has been returned.`,
-              operation,
-              data: {
-                url,
-                fetchOptions,
-                value: error || result,
-              },
-            });
-          })
-        );
-      })
-    );
-
-    const forward$ = pipe(
-      operations$,
-      filter(operation => {
-        return operation.kind !== 'query' && operation.kind !== 'mutation';
-      }),
-      forward
-    );
-
-    return merge([fetchResults$, forward$]);
-  };
diff --git a/exchanges/multipart-fetch/tsconfig.json b/exchanges/multipart-fetch/tsconfig.json
deleted file mode 100644
index 596e2cf7..00000000
--- a/exchanges/multipart-fetch/tsconfig.json
+++ /dev/null
@@ -1,4 +0,0 @@
-{
-  "extends": "../../tsconfig.json",
-  "include": ["src"]
-}
diff --git a/packages/core/CHANGELOG.md b/packages/core/CHANGELOG.md
index d7200193..7db89f90 100644
--- a/packages/core/CHANGELOG.md
+++ b/packages/core/CHANGELOG.md
@@ -1,5 +1,12 @@
 # @urql/core
 
+## 4.0.1
+
+### Patch Changes
+
+- ⚠️ Fix format of `map` form data field on multipart upload requests. This was erroneously set to a string rather than a string tuple
+  Submitted by [@kitten](https://github.com/kitten) (See [#3118](https://github.com/urql-graphql/urql/pull/3118))
+
 ## 4.0.0
 
 ### Major Changes
@@ -8,6 +15,7 @@
   In doing so we make the `urql` package more tree-shakeable as the three default exchanges are in no code paths
   meaning they can be removed if not used.
   A migration would look as follows if you are currently creating a client without exchanges
+
   ```js
   import { createClient, cacheExchange, fetchExchange } from '@urql/core';
 
@@ -16,7 +24,9 @@
     exchanges: [cacheExchange, fetchExchange],
   });
   ```
+
   Submitted by [@JoviDeCroock](https://github.com/JoviDeCroock) (See [#3033](https://github.com/urql-graphql/urql/pull/3033))
+
 - Update `subscriptionExchange` to receive `FetchBody` instead. In the usual usage of `subscriptionExchange` (for instance with `graphql-ws`) you can expect no breaking changes. However, the `key` and `extensions` field has been removed and instead the `forwardSubscription` function receives the full `Operation` as a second argument
   Submitted by [@kitten](https://github.com/kitten) (See [#3054](https://github.com/urql-graphql/urql/pull/3054))
 - Remove dependence on `graphql` package and replace it with `@0no-co/graphql.web`, which reduces the default bundlesize impact of `urql` packages to a minimum. All types should remain compatible, even if you use `graphql` elsewhere in your app, and if other dependencies are using `graphql` you may alias it to `graphql-web-lite`
diff --git a/packages/core/package.json b/packages/core/package.json
index 46a4af1e..0d8e0937 100644
--- a/packages/core/package.json
+++ b/packages/core/package.json
@@ -1,6 +1,6 @@
 {
   "name": "@urql/core",
-  "version": "4.0.0",
+  "version": "4.0.1",
   "description": "The shared core for the highly customizable and versatile GraphQL client",
   "sideEffects": false,
   "homepage": "https://formidable.com/open-source/urql/docs/",
diff --git a/packages/core/src/internal/fetchOptions.ts b/packages/core/src/internal/fetchOptions.ts
index 7aa6513f..f08ed0e7 100644
--- a/packages/core/src/internal/fetchOptions.ts
+++ b/packages/core/src/internal/fetchOptions.ts
@@ -87,15 +87,15 @@ const serializeBody = (
     const files = extractFiles(body.variables);
     if (files.size) {
       const form = new FormData();
-
       form.append('operations', json);
-      form.append('map', stringifyVariables({ ...[...files.keys()] }));
-
+      form.append(
+        'map',
+        stringifyVariables({
+          ...[...files.keys()].map(value => [value]),
+        })
+      );
       let index = 0;
-      for (const file of files.values()) {
-        form.append(`${index++}`, file);
-      }
-
+      for (const file of files.values()) form.append(`${index++}`, file);
       return form;
     }
     return json;


Test patch:
diff --git a/exchanges/multipart-fetch/src/__snapshots__/multipartFetchExchange.test.ts.snap b/exchanges/multipart-fetch/src/__snapshots__/multipartFetchExchange.test.ts.snap
deleted file mode 100644
index 10bd223b..00000000
--- a/exchanges/multipart-fetch/src/__snapshots__/multipartFetchExchange.test.ts.snap
+++ /dev/null
@@ -1,741 +0,0 @@
-// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
-
-exports[`on error > returns error data 1`] = `
-{
-  "data": undefined,
-  "error": [CombinedError: [Network] No Content],
-  "extensions": undefined,
-  "hasNext": false,
-  "operation": {
-    "context": {
-      "fetchOptions": {
-        "method": "POST",
-      },
-      "requestPolicy": "cache-first",
-      "url": "http://localhost:3000/graphql",
-    },
-    "key": 2,
-    "kind": "query",
-    "query": {
-      "__key": -2395444236,
-      "definitions": [
-        {
-          "directives": [],
-          "kind": "OperationDefinition",
-          "name": {
-            "kind": "Name",
-            "value": "getUser",
-          },
-          "operation": "query",
-          "selectionSet": {
-            "kind": "SelectionSet",
-            "selections": [
-              {
-                "alias": undefined,
-                "arguments": [
-                  {
-                    "kind": "Argument",
-                    "name": {
-                      "kind": "Name",
-                      "value": "name",
-                    },
-                    "value": {
-                      "kind": "Variable",
-                      "name": {
-                        "kind": "Name",
-                        "value": "name",
-                      },
-                    },
-                  },
-                ],
-                "directives": [],
-                "kind": "Field",
-                "name": {
-                  "kind": "Name",
-                  "value": "user",
-                },
-                "selectionSet": {
-                  "kind": "SelectionSet",
-                  "selections": [
-                    {
-                      "alias": undefined,
-                      "arguments": [],
-                      "directives": [],
-                      "kind": "Field",
-                      "name": {
-                        "kind": "Name",
-                        "value": "id",
-                      },
-                      "selectionSet": undefined,
-                    },
-                    {
-                      "alias": undefined,
-                      "arguments": [],
-                      "directives": [],
-                      "kind": "Field",
-                      "name": {
-                        "kind": "Name",
-                        "value": "firstName",
-                      },
-                      "selectionSet": undefined,
-                    },
-                    {
-                      "alias": undefined,
-                      "arguments": [],
-                      "directives": [],
-                      "kind": "Field",
-                      "name": {
-                        "kind": "Name",
-                        "value": "lastName",
-                      },
-                      "selectionSet": undefined,
-                    },
-                  ],
-                },
-              },
-            ],
-          },
-          "variableDefinitions": [
-            {
-              "defaultValue": undefined,
-              "directives": [],
-              "kind": "VariableDefinition",
-              "type": {
-                "kind": "NamedType",
-                "name": {
-                  "kind": "Name",
-                  "value": "String",
-                },
-              },
-              "variable": {
-                "kind": "Variable",
-                "name": {
-                  "kind": "Name",
-                  "value": "name",
-                },
-              },
-            },
-          ],
-        },
-      ],
-      "kind": "Document",
-      "loc": {
-        "end": 92,
-        "source": {
-          "body": "query getUser($name: String) {
-  user(name: $name) {
-    id
-    firstName
-    lastName
-  }
-}",
-          "locationOffset": {
-            "column": 1,
-            "line": 1,
-          },
-          "name": "gql",
-        },
-        "start": 0,
-      },
-    },
-    "variables": {
-      "name": "Clara",
-    },
-  },
-  "stale": false,
-}
-`;
-
-exports[`on error > returns error data with status 400 and manual redirect mode 1`] = `
-{
-  "data": undefined,
-  "error": [CombinedError: [Network] No Content],
-  "extensions": undefined,
-  "hasNext": false,
-  "operation": {
-    "context": {
-      "fetchOptions": [MockFunction spy] {
-        "calls": [
-          [],
-        ],
-        "results": [
-          {
-            "type": "return",
-            "value": {
-              "redirect": "manual",
-            },
-          },
-        ],
-      },
-      "requestPolicy": "cache-first",
-      "url": "http://localhost:3000/graphql",
-    },
-    "key": 2,
-    "kind": "query",
-    "query": {
-      "__key": -2395444236,
-      "definitions": [
-        {
-          "directives": [],
-          "kind": "OperationDefinition",
-          "name": {
-            "kind": "Name",
-            "value": "getUser",
-          },
-          "operation": "query",
-          "selectionSet": {
-            "kind": "SelectionSet",
-            "selections": [
-              {
-                "alias": undefined,
-                "arguments": [
-                  {
-                    "kind": "Argument",
-                    "name": {
-                      "kind": "Name",
-                      "value": "name",
-                    },
-                    "value": {
-                      "kind": "Variable",
-                      "name": {
-                        "kind": "Name",
-                        "value": "name",
-                      },
-                    },
-                  },
-                ],
-                "directives": [],
-                "kind": "Field",
-                "name": {
-                  "kind": "Name",
-                  "value": "user",
-                },
-                "selectionSet": {
-                  "kind": "SelectionSet",
-                  "selections": [
-                    {
-                      "alias": undefined,
-                      "arguments": [],
-                      "directives": [],
-                      "kind": "Field",
-                      "name": {
-                        "kind": "Name",
-                        "value": "id",
-                      },
-                      "selectionSet": undefined,
-                    },
-                    {
-                      "alias": undefined,
-                      "arguments": [],
-                      "directives": [],
-                      "kind": "Field",
-                      "name": {
-                        "kind": "Name",
-                        "value": "firstName",
-                      },
-                      "selectionSet": undefined,
-                    },
-                    {
-                      "alias": undefined,
-                      "arguments": [],
-                      "directives": [],
-                      "kind": "Field",
-                      "name": {
-                        "kind": "Name",
-                        "value": "lastName",
-                      },
-                      "selectionSet": undefined,
-                    },
-                  ],
-                },
-              },
-            ],
-          },
-          "variableDefinitions": [
-            {
-              "defaultValue": undefined,
-              "directives": [],
-              "kind": "VariableDefinition",
-              "type": {
-                "kind": "NamedType",
-                "name": {
-                  "kind": "Name",
-                  "value": "String",
-                },
-              },
-              "variable": {
-                "kind": "Variable",
-                "name": {
-                  "kind": "Name",
-                  "value": "name",
-                },
-              },
-            },
-          ],
-        },
-      ],
-      "kind": "Document",
-      "loc": {
-        "end": 92,
-        "source": {
-          "body": "query getUser($name: String) {
-  user(name: $name) {
-    id
-    firstName
-    lastName
-  }
-}",
-          "locationOffset": {
-            "column": 1,
-            "line": 1,
-          },
-          "name": "gql",
-        },
-        "start": 0,
-      },
-    },
-    "variables": {
-      "name": "Clara",
-    },
-  },
-  "stale": false,
-}
-`;
-
-exports[`on success > returns response data 1`] = `
-{
-  "data": {
-    "data": {
-      "user": 1200,
-    },
-  },
-  "error": undefined,
-  "extensions": undefined,
-  "hasNext": false,
-  "operation": {
-    "context": {
-      "fetchOptions": [MockFunction spy] {
-        "calls": [
-          [],
-        ],
-        "results": [
-          {
-            "type": "return",
-            "value": {},
-          },
-        ],
-      },
-      "requestPolicy": "cache-first",
-      "url": "http://localhost:3000/graphql",
-    },
-    "key": 2,
-    "kind": "query",
-    "query": {
-      "__key": -2395444236,
-      "definitions": [
-        {
-          "directives": [],
-          "kind": "OperationDefinition",
-          "name": {
-            "kind": "Name",
-            "value": "getUser",
-          },
-          "operation": "query",
-          "selectionSet": {
-            "kind": "SelectionSet",
-            "selections": [
-              {
-                "alias": undefined,
-                "arguments": [
-                  {
-                    "kind": "Argument",
-                    "name": {
-                      "kind": "Name",
-                      "value": "name",
-                    },
-                    "value": {
-                      "kind": "Variable",
-                      "name": {
-                        "kind": "Name",
-                        "value": "name",
-                      },
-                    },
-                  },
-                ],
-                "directives": [],
-                "kind": "Field",
-                "name": {
-                  "kind": "Name",
-                  "value": "user",
-                },
-                "selectionSet": {
-                  "kind": "SelectionSet",
-                  "selections": [
-                    {
-                      "alias": undefined,
-                      "arguments": [],
-                      "directives": [],
-                      "kind": "Field",
-                      "name": {
-                        "kind": "Name",
-                        "value": "id",
-                      },
-                      "selectionSet": undefined,
-                    },
-                    {
-                      "alias": undefined,
-                      "arguments": [],
-                      "directives": [],
-                      "kind": "Field",
-                      "name": {
-                        "kind": "Name",
-                        "value": "firstName",
-                      },
-                      "selectionSet": undefined,
-                    },
-                    {
-                      "alias": undefined,
-                      "arguments": [],
-                      "directives": [],
-                      "kind": "Field",
-                      "name": {
-                        "kind": "Name",
-                        "value": "lastName",
-                      },
-                      "selectionSet": undefined,
-                    },
-                  ],
-                },
-              },
-            ],
-          },
-          "variableDefinitions": [
-            {
-              "defaultValue": undefined,
-              "directives": [],
-              "kind": "VariableDefinition",
-              "type": {
-                "kind": "NamedType",
-                "name": {
-                  "kind": "Name",
-                  "value": "String",
-                },
-              },
-              "variable": {
-                "kind": "Variable",
-                "name": {
-                  "kind": "Name",
-                  "value": "name",
-                },
-              },
-            },
-          ],
-        },
-      ],
-      "kind": "Document",
-      "loc": {
-        "end": 92,
-        "source": {
-          "body": "query getUser($name: String) {
-  user(name: $name) {
-    id
-    firstName
-    lastName
-  }
-}",
-          "locationOffset": {
-            "column": 1,
-            "line": 1,
-          },
-          "name": "gql",
-        },
-        "start": 0,
-      },
-    },
-    "variables": {
-      "name": "Clara",
-    },
-  },
-  "stale": false,
-}
-`;
-
-exports[`on success > returns response data 2`] = `"{\\"operationName\\":\\"getUser\\",\\"query\\":\\"query getUser($name: String) {\\\\n  user(name: $name) {\\\\n    id\\\\n    firstName\\\\n    lastName\\\\n  }\\\\n}\\",\\"variables\\":{\\"name\\":\\"Clara\\"}}"`;
-
-exports[`on success > uses a file when given 1`] = `
-{
-  "data": {
-    "data": {
-      "user": 1200,
-    },
-  },
-  "error": undefined,
-  "extensions": undefined,
-  "hasNext": false,
-  "operation": {
-    "context": {
-      "fetchOptions": [MockFunction spy] {
-        "calls": [
-          [],
-        ],
-        "results": [
-          {
-            "type": "return",
-            "value": {},
-          },
-        ],
-      },
-      "requestPolicy": "cache-first",
-      "url": "http://localhost:3000/graphql",
-    },
-    "key": 3,
-    "kind": "mutation",
-    "query": {
-      "__key": 8029062428,
-      "definitions": [
-        {
-          "directives": [],
-          "kind": "OperationDefinition",
-          "name": {
-            "kind": "Name",
-            "value": "uploadProfilePicture",
-          },
-          "operation": "mutation",
-          "selectionSet": {
-            "kind": "SelectionSet",
-            "selections": [
-              {
-                "alias": undefined,
-                "arguments": [
-                  {
-                    "kind": "Argument",
-                    "name": {
-                      "kind": "Name",
-                      "value": "picture",
-                    },
-                    "value": {
-                      "kind": "Variable",
-                      "name": {
-                        "kind": "Name",
-                        "value": "picture",
-                      },
-                    },
-                  },
-                ],
-                "directives": [],
-                "kind": "Field",
-                "name": {
-                  "kind": "Name",
-                  "value": "uploadProfilePicture",
-                },
-                "selectionSet": {
-                  "kind": "SelectionSet",
-                  "selections": [
-                    {
-                      "alias": undefined,
-                      "arguments": [],
-                      "directives": [],
-                      "kind": "Field",
-                      "name": {
-                        "kind": "Name",
-                        "value": "location",
-                      },
-                      "selectionSet": undefined,
-                    },
-                  ],
-                },
-              },
-            ],
-          },
-          "variableDefinitions": [
-            {
-              "defaultValue": undefined,
-              "directives": [],
-              "kind": "VariableDefinition",
-              "type": {
-                "kind": "NamedType",
-                "name": {
-                  "kind": "Name",
-                  "value": "File",
-                },
-              },
-              "variable": {
-                "kind": "Variable",
-                "name": {
-                  "kind": "Name",
-                  "value": "picture",
-                },
-              },
-            },
-          ],
-        },
-      ],
-      "kind": "Document",
-      "loc": {
-        "end": 110,
-        "source": {
-          "body": "mutation uploadProfilePicture($picture: File) {
-  uploadProfilePicture(picture: $picture) {
-    location
-  }
-}",
-          "locationOffset": {
-            "column": 1,
-            "line": 1,
-          },
-          "name": "gql",
-        },
-        "start": 0,
-      },
-    },
-    "variables": {
-      "picture": File {},
-    },
-  },
-  "stale": false,
-}
-`;
-
-exports[`on success > uses a file when given 2`] = `FormData {}`;
-
-exports[`on success > uses multiple files when given 1`] = `
-{
-  "data": {
-    "data": {
-      "user": 1200,
-    },
-  },
-  "error": undefined,
-  "extensions": undefined,
-  "hasNext": false,
-  "operation": {
-    "context": {
-      "fetchOptions": [MockFunction spy] {
-        "calls": [
-          [],
-        ],
-        "results": [
-          {
-            "type": "return",
-            "value": {},
-          },
-        ],
-      },
-      "requestPolicy": "cache-first",
-      "url": "http://localhost:3000/graphql",
-    },
-    "key": 3,
-    "kind": "mutation",
-    "query": {
-      "__key": -6039055341,
-      "definitions": [
-        {
-          "directives": [],
-          "kind": "OperationDefinition",
-          "name": {
-            "kind": "Name",
-            "value": "uploadProfilePictures",
-          },
-          "operation": "mutation",
-          "selectionSet": {
-            "kind": "SelectionSet",
-            "selections": [
-              {
-                "alias": undefined,
-                "arguments": [
-                  {
-                    "kind": "Argument",
-                    "name": {
-                      "kind": "Name",
-                      "value": "pictures",
-                    },
-                    "value": {
-                      "kind": "Variable",
-                      "name": {
-                        "kind": "Name",
-                        "value": "pictures",
-                      },
-                    },
-                  },
-                ],
-                "directives": [],
-                "kind": "Field",
-                "name": {
-                  "kind": "Name",
-                  "value": "uploadProfilePicture",
-                },
-                "selectionSet": {
-                  "kind": "SelectionSet",
-                  "selections": [
-                    {
-                      "alias": undefined,
-                      "arguments": [],
-                      "directives": [],
-                      "kind": "Field",
-                      "name": {
-                        "kind": "Name",
-                        "value": "location",
-                      },
-                      "selectionSet": undefined,
-                    },
-                  ],
-                },
-              },
-            ],
-          },
-          "variableDefinitions": [
-            {
-              "defaultValue": undefined,
-              "directives": [],
-              "kind": "VariableDefinition",
-              "type": {
-                "kind": "ListType",
-                "type": {
-                  "kind": "NamedType",
-                  "name": {
-                    "kind": "Name",
-                    "value": "File",
-                  },
-                },
-              },
-              "variable": {
-                "kind": "Variable",
-                "name": {
-                  "kind": "Name",
-                  "value": "pictures",
-                },
-              },
-            },
-          ],
-        },
-      ],
-      "kind": "Document",
-      "loc": {
-        "end": 116,
-        "source": {
-          "body": "mutation uploadProfilePictures($pictures: [File]) {
-  uploadProfilePicture(pictures: $pictures) {
-    location
-  }
-}",
-          "locationOffset": {
-            "column": 1,
-            "line": 1,
-          },
-          "name": "gql",
-        },
-        "start": 0,
-      },
-    },
-    "variables": {
-      "picture": [
-        File {},
-        File {},
-      ],
-    },
-  },
-  "stale": false,
-}
-`;
-
-exports[`on success > uses multiple files when given 2`] = `FormData {}`;
diff --git a/exchanges/multipart-fetch/src/multipartFetchExchange.test.ts b/exchanges/multipart-fetch/src/multipartFetchExchange.test.ts
deleted file mode 100644
index f336ce68..00000000
--- a/exchanges/multipart-fetch/src/multipartFetchExchange.test.ts
+++ /dev/null
@@ -1,180 +0,0 @@
-import { Client, OperationResult } from '@urql/core';
-import { empty, fromValue, pipe, Source, toPromise } from 'wonka';
-
-import {
-  vi,
-  expect,
-  it,
-  beforeEach,
-  describe,
-  beforeAll,
-  Mock,
-  afterEach,
-  afterAll,
-} from 'vitest';
-
-import { multipartFetchExchange } from './multipartFetchExchange';
-
-import {
-  uploadOperation,
-  queryOperation,
-  multipleUploadOperation,
-} from './test-utils';
-
-const fetch = (global as any).fetch as Mock;
-const abort = vi.fn();
-
-beforeAll(() => {
-  (global as any).AbortController = function AbortController() {
-    this.signal = undefined;
-    this.abort = abort;
-  };
-});
-
-afterEach(() => {
-  fetch.mockClear();
-  abort.mockClear();
-});
-
-afterAll(() => {
-  (global as any).AbortController = undefined;
-});
-
-const response = JSON.stringify({
-  status: 200,
-  data: {
-    data: {
-      user: 1200,
-    },
-  },
-});
-
-const exchangeArgs = {
-  forward: () => empty as Source<OperationResult>,
-  client: {} as Client,
-  dispatchDebug: vi.fn(),
-};
-
-describe('on success', () => {
-  beforeEach(() => {
-    fetch.mockResolvedValue({
-      status: 200,
-      headers: { get: () => 'application/json' },
-      text: vi.fn().mockResolvedValue(response),
-    });
-  });
-
-  it('uses a file when given', async () => {
-    const fetchOptions = vi.fn().mockReturnValue({});
-
-    const data = await pipe(
-      fromValue({
-        ...uploadOperation,
-        context: {
-          ...uploadOperation.context,
-          fetchOptions,
-        },
-      }),
-      multipartFetchExchange(exchangeArgs),
-      toPromise
-    );
-
-    expect(data).toMatchSnapshot();
-    expect(fetchOptions).toHaveBeenCalled();
-    expect(fetch.mock.calls[0][1].body).toMatchSnapshot();
-  });
-
-  it('uses multiple files when given', async () => {
-    const fetchOptions = vi.fn().mockReturnValue({});
-
-    const data = await pipe(
-      fromValue({
-        ...multipleUploadOperation,
-        context: {
-          ...multipleUploadOperation.context,
-          fetchOptions,
-        },
-      }),
-      multipartFetchExchange(exchangeArgs),
-      toPromise
-    );
-
-    expect(data).toMatchSnapshot();
-    expect(fetchOptions).toHaveBeenCalled();
-    expect(fetch.mock.calls[0][1].body).toMatchSnapshot();
-  });
-
-  it('returns response data', async () => {
-    const fetchOptions = vi.fn().mockReturnValue({});
-
-    const data = await pipe(
-      fromValue({
-        ...queryOperation,
-        context: {
-          ...queryOperation.context,
-          fetchOptions,
-        },
-      }),
-      multipartFetchExchange(exchangeArgs),
-      toPromise
-    );
-
-    expect(data).toMatchSnapshot();
-    expect(fetchOptions).toHaveBeenCalled();
-    expect(fetch.mock.calls[0][1].body).toMatchSnapshot();
-  });
-});
-
-describe('on error', () => {
-  beforeEach(() => {
-    fetch.mockResolvedValue({
-      status: 400,
-      headers: { get: () => 'application/json' },
-      text: vi.fn().mockResolvedValue('{}'),
-    });
-  });
-
-  it('returns error data', async () => {
-    const data = await pipe(
-      fromValue(queryOperation),
-      multipartFetchExchange(exchangeArgs),
-      toPromise
-    );
-
-    expect(data).toMatchSnapshot();
-  });
-
-  it('returns error data with status 400 and manual redirect mode', async () => {
-    const fetchOptions = vi.fn().mockReturnValue({ redirect: 'manual' });
-
-    const data = await pipe(
-      fromValue({
-        ...queryOperation,
-        context: {
-          ...queryOperation.context,
-          fetchOptions,
-        },
-      }),
-      multipartFetchExchange(exchangeArgs),
-      toPromise
-    );
-
-    expect(data).toMatchSnapshot();
-  });
-
-  it('ignores the error when a result is available', async () => {
-    fetch.mockResolvedValue({
-      status: 400,
-      headers: { get: () => 'application/json' },
-      text: vi.fn().mockResolvedValue(response),
-    });
-
-    const data = await pipe(
-      fromValue(queryOperation),
-      multipartFetchExchange(exchangeArgs),
-      toPromise
-    );
-
-    expect(data.data).toEqual(JSON.parse(response).data);
-  });
-});
diff --git a/exchanges/multipart-fetch/src/test-utils.ts b/exchanges/multipart-fetch/src/test-utils.ts
deleted file mode 100644
index 492fb402..00000000
--- a/exchanges/multipart-fetch/src/test-utils.ts
+++ /dev/null
@@ -1,84 +0,0 @@
-import {
-  gql,
-  GraphQLRequest,
-  OperationContext,
-  Operation,
-  makeOperation,
-} from '@urql/core';
-
-const context: OperationContext = {
-  fetchOptions: {
-    method: 'POST',
-  },
-  requestPolicy: 'cache-first',
-  url: 'http://localhost:3000/graphql',
-};
-
-const queryGql: GraphQLRequest = {
-  key: 2,
-  query: gql`
-    query getUser($name: String) {
-      user(name: $name) {
-        id
-        firstName
-        lastName
-      }
-    }
-  `,
-  variables: {
-    name: 'Clara',
-  },
-};
-
-const obj = { hello: 'world' };
-const file = new File(
-  [new Blob([JSON.stringify(obj, null, 2)], { type: 'application/json' })],
-  'index.ts'
-);
-const files = [file, file];
-
-const upload: GraphQLRequest = {
-  key: 3,
-  query: gql`
-    mutation uploadProfilePicture($picture: File) {
-      uploadProfilePicture(picture: $picture) {
-        location
-      }
-    }
-  `,
-  variables: {
-    picture: file,
-  },
-};
-
-const uploads: GraphQLRequest = {
-  key: 3,
-  query: gql`
-    mutation uploadProfilePictures($pictures: [File]) {
-      uploadProfilePicture(pictures: $pictures) {
-        location
-      }
-    }
-  `,
-  variables: {
-    picture: files,
-  },
-};
-
-export const uploadOperation: Operation = makeOperation(
-  'mutation',
-  upload,
-  context
-);
-
-export const multipleUploadOperation: Operation = makeOperation(
-  'mutation',
-  uploads,
-  context
-);
-
-export const queryOperation: Operation = makeOperation(
-  'query',
-  queryGql,
-  context
-);
diff --git a/packages/core/src/internal/fetchOptions.test.ts b/packages/core/src/internal/fetchOptions.test.ts
index 245efdbc..bade73cf 100644
--- a/packages/core/src/internal/fetchOptions.test.ts
+++ b/packages/core/src/internal/fetchOptions.test.ts
@@ -154,7 +154,7 @@ describe('makeFetchOptions', () => {
     });
 
     expect(form.get('map')).toMatchInlineSnapshot(
-      '"{\\"0\\":\\"variables.file\\"}"'
+      '"{\\"0\\":[\\"variables.file\\"]}"'
     );
     expect(form.get('0')).toBeInstanceOf(Blob);
   });