+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
······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···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-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 swap···-that you have to provide your own SHA256 function to the `persistedFetchExchange`. 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**persisted queries mode by giving it the `enforcePersistedQueries: true` option. This disables any-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).-In `urql`, we may use the `@urql/exchange-multipart-fetch` package's `multipartFetchExchange` to-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.-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
···+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.+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`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+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 willalready have a loader generating SHA256 hashes for you at compile time. In that case we could swap···+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 `persistedExchange` may be put into a **non-automatic**persisted queries mode by giving it the `enforcePersistedQueries: true` option. This disables any+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+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)+In `urql`, these are supported natively, so as long as your JS environment supports either `File` or+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
···-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`.[`fetchExchange`](./core.md#fetchexchange) and will act exactly like the `fetchExchange` unless the`variables` that it receives for mutations contain any `File`s as detected by the `extract-files` package.
···+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`variables` that it receives for mutations contain any `File`s as detected by the `extract-files` package.
-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` |matter which framework you use it with. It's worth mentioning that all three clients support some
···+| ------------------------------------------ | ---------------------------------- | -------------------------------------------------------------------------- | ------------------------------ |+| 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` |matter which framework you use it with. It's worth mentioning that all three clients support some
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
······* @see {@link https://github.com/graphql/graphql-over-http/blob/1928447/spec/GraphQLOverHTTP.md#request-parameters} for the GraphQL over HTTP spec
···+/** 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
······
······
+1
-1
pnpm-lock.yaml
+1
-1
pnpm-lock.yaml