+5
.changeset/pretty-cows-dance.md
+5
.changeset/pretty-cows-dance.md
+5
.changeset/strange-apples-trade.md
+5
.changeset/strange-apples-trade.md
···+Remove `persistedFetchExchange` and instead implement `persistedExchange`. This exchange must be placed in front of a terminating exchange (such as the default `fetchExchange` or a `subscriptionExchange` that supports persisted queries), and only modifies incoming operations to contain `extensions.persistedQuery`, which is sent on via the API. If the API expects Automatic Persisted Queries, requests are retried by this exchange internally.
+5
.changeset/three-poets-think.md
+5
.changeset/three-poets-think.md
+37
-69
docs/advanced/persistence-and-uploads.md
+37
-69
docs/advanced/persistence-and-uploads.md
···+Queries](https://www.apollographql.com/docs/apollo-server/performance/apq/), Persisted Queries, and+While File Uploads should work without any modifications, an additional exchange must be installed···requests. If we only send the persisted queries with hashes as GET requests then they become a loteasier for a CDN to cache, as by default most caches would not cache POST requests automatically.-In `urql`, we may use the `@urql/exchange-persisted-fetch` package's `persistedFetchExchange` to-implement Automatic Persisted Queries. This exchange works alongside other fetch exchanges and only+implement Automatic Persisted Queries. This exchange works alongside the default `fetchExchange`···As we can see, typically it's recommended to set `preferGetForPersistedQueries` to `true` to force-We also added the `persistedFetchExchange` in front of the usual `fetchExchange`, since it only`preferGetMethod`](../api/core.md#client) but only switches persisted queries to use GET requestsinstead. This is preferable since sometimes the GraphQL query can grow too large for a simple GET-query to handle, while the `persistedFetchExchange`'s SHA256 hashes will remain predictably small.-The `persistedFetchExchange` also accepts a `generateHash` option. This may be used to swap out the-built-in [Web Crypto API](https://developer.mozilla.org/en-US/docs/Web/API/Web_Crypto_API) on the+built-in [Web Crypto API](https://developer.mozilla.org/en-US/docs/Web/API/Web_Crypto_API) when it's+available, and in Node.js it'll use the [Node Crypto Module](https://nodejs.org/api/crypto.html)-Webpack](https://github.com/leoasis/graphql-persisted-document-loader) for instance, then you will+Webpack](https://github.com/leoasis/graphql-persisted-document-loader), for instance, then you willalready have a loader generating SHA256 hashes for you at compile time. In that case we could swapout the `generateHash` function with a much simpler one that uses the `generateHash` function's···If you're using **React Native** then you may not have access to the Web Crypto API, which means-that you have to provide your own SHA256 function to the `persistedFetchExchange`. Luckily we can do+that you have to provide your own SHA256 function to the `persistedExchange`. Luckily, we can do···Additionally, if the API only expects persisted queries and not arbitrary ones and all queries are-pre-registered against the API then the `persistedFetchExchange` may be put into a **non-automatic**+pre-registered against the API then the `persistedExchange` may be put into a **non-automatic**persisted queries mode by giving it the `enforcePersistedQueries: true` option. This disables anyretry logic and assumes that persisted queries will be handled like regular GraphQL requests.-uploads.](https://www.apollographql.com/docs/apollo-server/data/file-uploads/) This allows us to-define mutations on our API that accept an `Upload` input, which on the client would be a variable-that we can set to a [File](https://developer.mozilla.org/en-US/docs/Web/API/File), which we'd-instance](https://developer.mozilla.org/en-US/docs/Web/API/File/Using_files_from_web_applications).+Spec](https://github.com/jaydenseric/graphql-multipart-request-spec) to allow files to be uploaded.+This allows us to pass a `File` or `Blob` directly to our GraphQL requests as variables, and the-In `urql`, we may use the `@urql/exchange-multipart-fetch` package's `multipartFetchExchange` to+Files are often handled in the browser via the [File API](https://developer.mozilla.org/en-US/docs/Web/API/File),+which we may typically get to via a [file input](https://developer.mozilla.org/en-US/docs/Web/API/File/Using_files_from_web_applications)-It works by using the [`extract-files` package](https://www.npmjs.com/package/extract-files). When-the `multipartFetchExchange` sees at least one `File` in the variables it receives for a mutation,-then it will send a `multipart/form-data` POST request instead of a standard `application/json`-one. This is basically the same kind of request that we'd expect to send for regular HTML forms.+In `urql`, these are supported natively, so as long as your JS environment supports either `File` or-The `multipartFetchExchange` is a drop-in replacement for the `fetchExchange`, which should be-If you're using the `persistedFetchExchange` then put the `persistedFetchExchange` in front of the-`multipartFetchExchange`, since only the latter is a full replacement for the `fetchExchange`, and+Previously, this worked by installing the [`@urql/multipart-fetch-exchange` package](../api/multipart-fetch-exchange.md),
-1
docs/api/README.md
-1
docs/api/README.md
···
+1
-2
docs/api/multipart-fetch-exchange.md
+1
-2
docs/api/multipart-fetch-exchange.md
···Spec](https://github.com/jaydenseric/graphql-multipart-request-spec) which is supported by the-This exchange uses the same fetch logic as the [`fetchExchange`](./core.md#fetchexchange) and the-[`persistedFetchExchange`](./persisted-fetch-exchange.md) by reusing logic from `@urql/core/internal`.+This exchange uses the same fetch logic as the [`fetchExchange`](./core.md#fetchexchange) and by reusing logic from `@urql/core/internal`.[`fetchExchange`](./core.md#fetchexchange) and will act exactly like the `fetchExchange` unless the
-68
docs/api/persisted-fetch-exchange.md
-68
docs/api/persisted-fetch-exchange.md
···-The `@urql/exchange-persisted-fetch` package contains an addon `persistedFetchExchange` for `urql`-This exchange uses the same fetch logic as the [`fetchExchange`](./core.md#fetchexchange) and the-[`multipartFetchExchange`](./multipart-fetch-exchange.md) by reusing logic from `@urql/core/internal`.-The `persistedFetchExchange` will attempt to send queries with an additional SHA256 hash to the-GraphQL API and will otherwise, when Automatic Persisted Queries are unsupported or when a mutation-or subscription is sent, forward the operation to the next exchange. Hence it should always be added-API](https://developer.mozilla.org/en-US/docs/Web/API/Web_Crypto_API) for SHA256 hashing in the-[`multipartFetchExchange`](./multipart-fetch-exchange.md) then it must be added in front of that-| ------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |-| `preferGetForPersistedQueries` | This is similar to [the `Client`'s `preferGetMethod` option](./core.md#client) and will cause all persisted queries to be sent using a GET request. |-| `enforcePersistedQueries` | This option enforced persisted queries. Instead of allowing automatic persisted queries or triggering any retry logic when the API responds, it instead assumes that persisted queries will succeed and run like normal GraphQL API requests. |-| `generateHash` | This option accepts a function that receives the `query` as a string and the raw `DocumentNode` as a second argument and must return a `Promise<string>` resolving to a SHA256 hash. This can be used to swap out the SHA256 API, e.g. for React Native, or to use pre-generated SHA256 strings from the `DocumentNode`. |-| `enableForMutation` | This option allows mutations to be persisted in addition to queries. It's false by default. When a persisted mutation is requested, `preferGetForPersistedQueries` will be ignored and a POST method will always be used. |
+22
-22
docs/comparison.md
+22
-22
docs/comparison.md
···-| ------------------------------------------ | ----------------------------------- | -------------------------------------------------------------------------- | ------------------------------ |-| Base Bundle Size | **5.9kB** (7.1kB with bindings) | 32.9kB | 27.7kB (34.1kB with bindings) |-| Persisted Queries | ✅ `@urql/exchange-persisted-fetch` | ✅ `apollo-link-persisted-queries` | ✅ |-| Defer & Stream Directives | ✅ | ✅ / 🛑 (`@defer` is supported in >=3.7.0, `@stream` is not yet supported) | 🟡 (unreleased) |-| Retrying Failed Queries | ✅ `@urql/exchange-retry` | ✅ `apollo-link-retry` | ✅ `DefaultNetworkLayer` |-| Easy Authentication Flows | ✅ `@urql/exchange-auth` | 🛑 (no docs for refresh-based authentication) | 🟡 `react-relay-network-layer` |+| ------------------------------------------ | ---------------------------------- | -------------------------------------------------------------------------- | ------------------------------ |+| Base Bundle Size | **5.9kB** (7.1kB with bindings) | 32.9kB | 27.7kB (34.1kB with bindings) |+| Defer & Stream Directives | ✅ | ✅ / 🛑 (`@defer` is supported in >=3.7.0, `@stream` is not yet supported) | 🟡 (unreleased) |+| Retrying Failed Queries | ✅ `@urql/exchange-retry` | ✅ `apollo-link-retry` | ✅ `DefaultNetworkLayer` |+| Easy Authentication Flows | ✅ `@urql/exchange-auth` | 🛑 (no docs for refresh-based authentication) | 🟡 `react-relay-network-layer` |Typically these are all additional addon features that you may expect from a GraphQL client, no
exchanges/persisted-fetch/CHANGELOG.md
exchanges/persisted/CHANGELOG.md
exchanges/persisted-fetch/CHANGELOG.md
exchanges/persisted/CHANGELOG.md
-67
exchanges/persisted-fetch/README.md
-67
exchanges/persisted-fetch/README.md
···-- `enforcePersistedQueries`: This disables _automatic persisted queries_ and disables any retry-- `generateHash`: A function that takes a GraphQL query and returns the hashed result. This defaults to the `window.crypto` API in the browser and the `crypto` module in node.-If you want to generate hashes at build-time you can use a [webpack-loader](https://github.com/leoasis/graphql-persisted-document-loader) to achieve this,
+8
-8
exchanges/persisted-fetch/package.json
exchanges/persisted/package.json
+8
-8
exchanges/persisted-fetch/package.json
exchanges/persisted/package.json
·········
-9
exchanges/persisted-fetch/src/__snapshots__/persistedFetchExchange.test.ts.snap
-9
exchanges/persisted-fetch/src/__snapshots__/persistedFetchExchange.test.ts.snap
···-exports[`accepts successful persisted query responses 1`] = `"{\\"extensions\\":{\\"persistedQuery\\":{\\"sha256Hash\\":\\"b4228e10e04c59def248546d305b710309c1b297423b38eb64f989a89a398cd8\\",\\"version\\":1}},\\"operationName\\":\\"getUser\\",\\"variables\\":{\\"name\\":\\"Clara\\"}}"`;-exports[`supports cache-miss persisted query errors 1`] = `"{\\"extensions\\":{\\"persistedQuery\\":{\\"sha256Hash\\":\\"b4228e10e04c59def248546d305b710309c1b297423b38eb64f989a89a398cd8\\",\\"version\\":1}},\\"operationName\\":\\"getUser\\",\\"variables\\":{\\"name\\":\\"Clara\\"}}"`;-exports[`supports cache-miss persisted query errors 2`] = `"{\\"extensions\\":{\\"persistedQuery\\":{\\"sha256Hash\\":\\"b4228e10e04c59def248546d305b710309c1b297423b38eb64f989a89a398cd8\\",\\"version\\":1}},\\"operationName\\":\\"getUser\\",\\"query\\":\\"query getUser($name: String) {\\\\n user(name: $name) {\\\\n id\\\\n firstName\\\\n lastName\\\\n }\\\\n}\\",\\"variables\\":{\\"name\\":\\"Clara\\"}}"`;-exports[`supports unsupported persisted query errors 1`] = `"{\\"extensions\\":{\\"persistedQuery\\":{\\"sha256Hash\\":\\"b4228e10e04c59def248546d305b710309c1b297423b38eb64f989a89a398cd8\\",\\"version\\":1}},\\"operationName\\":\\"getUser\\",\\"variables\\":{\\"name\\":\\"Clara\\"}}"`;
-1
exchanges/persisted-fetch/src/index.ts
-1
exchanges/persisted-fetch/src/index.ts
···
-282
exchanges/persisted-fetch/src/persistedFetchExchange.test.ts
-282
exchanges/persisted-fetch/src/persistedFetchExchange.test.ts
···
-215
exchanges/persisted-fetch/src/persistedFetchExchange.ts
-215
exchanges/persisted-fetch/src/persistedFetchExchange.ts
···
+1
-1
exchanges/persisted-fetch/src/sha256.ts
exchanges/persisted/src/sha256.ts
+1
-1
exchanges/persisted-fetch/src/sha256.ts
exchanges/persisted/src/sha256.ts
exchanges/persisted-fetch/src/test-utils.ts
exchanges/persisted/src/test-utils.ts
exchanges/persisted-fetch/src/test-utils.ts
exchanges/persisted/src/test-utils.ts
exchanges/persisted-fetch/tsconfig.json
exchanges/persisted/tsconfig.json
exchanges/persisted-fetch/tsconfig.json
exchanges/persisted/tsconfig.json
+63
exchanges/persisted/README.md
+63
exchanges/persisted/README.md
···+The `persistedExchange` is an exchange that allows other terminating exchanges to support Persisted Queries, and is as such placed in front of either the default `fetchExchange` or+- `preferGetForPersistedQueries`: Enforce `GET` method to be used by the default `fetchExchange` for persisted queries+- `enforcePersistedQueries`: This disables _automatic persisted queries_ and disables any retry logic for how the API responds to persisted queries. Instead it's assumed that they'll always succeed.+- `generateHash`: A function that takes a GraphQL query and returns the hashed result. This defaults to the `window.crypto` API in the browser and the `crypto` module in Node.+- `enableForMutation`: By default, the exchange only handles `query` operations, but enabling this allows it to handle mutations as well.+If you want to generate hashes at build-time you can use a [webpack-loader](https://github.com/leoasis/graphql-persisted-document-loader) to achieve this,
+1
exchanges/persisted/src/index.ts
+1
exchanges/persisted/src/index.ts
···
+120
exchanges/persisted/src/persistedExchange.test.ts
+120
exchanges/persisted/src/persistedExchange.test.ts
···
+143
exchanges/persisted/src/persistedExchange.ts
+143
exchanges/persisted/src/persistedExchange.ts
···
+1
packages/core/src/index.ts
+1
packages/core/src/index.ts
+39
packages/core/src/internal/fetchOptions.test.ts
+39
packages/core/src/internal/fetchOptions.test.ts
···
+5
-1
packages/core/src/internal/fetchOptions.ts
+5
-1
packages/core/src/internal/fetchOptions.ts
···
+22
-1
packages/core/src/types.ts
+22
-1
packages/core/src/types.ts
···+/** Set when a `sha256Hash` previously experienced a miss which will force `query` to be sent. */+* @see {@link https://github.com/graphql/graphql-over-http/blob/1928447/spec/GraphQLOverHTTP.md#request-parameters} for the GraphQL over HTTP spec···* @see {@link https://github.com/graphql/graphql-over-http/blob/1928447/spec/GraphQLOverHTTP.md#request-parameters} for the GraphQL over HTTP spec
+8
-2
packages/core/src/utils/request.ts
+8
-2
packages/core/src/utils/request.ts
······