···11+---
22+'@urql/core': major
33+---
44+55+Remove deprecated `dedupExchange`
+5
.changeset/strange-steaks-grow.md
···11+---
22+'@urql/exchange-graphcache': major
33+---
44+55+Remove deprecated `resolveFieldByKey`, use `cache.resolve` instead
+5
.changeset/stupid-mice-judge.md
···11+---
22+'@urql/core': major
33+---
44+55+Remove deprecated `maskTypename`
+1-2
docs/advanced/authentication.md
···346346The order is very important here:
347347348348```js
349349-import { createClient, dedupExchange, cacheExchange, fetchExchange, errorExchange, mapExchange } from 'urql';
349349+import { createClient, cacheExchange, fetchExchange, mapExchange } from 'urql';
350350import { authExchange } from '@urql/exchange-auth';
351351352352const client = createClient({
353353 url: 'http://localhost:3000/graphql',
354354 exchanges: [
355355- dedupExchange,
356355 cacheExchange,
357356 mapExchange({
358357 onError(error, _operation) {
+8-10
docs/advanced/server-side-rendering.md
···385385you'll need to instead provide them in the `exchanges` property of the returned client object.
386386387387```js
388388-import { dedupExchange, cacheExchange, fetchExchange } from '@urql/core';
388388+import { cacheExchange, fetchExchange } from '@urql/core';
389389390390import { withUrqlClient } from 'next-urql';
391391392392export default withUrqlClient(ssrExchange => ({
393393 url: 'http://localhost:3000/graphql',
394394- exchanges: [dedupExchange, cacheExchange, ssrExchange, fetchExchange],
394394+ exchanges: [cacheExchange, ssrExchange, fetchExchange],
395395}))(Index);
396396```
397397···409409argument to `withUrqlClient`:
410410411411```js
412412-import { dedupExchange, cacheExchange, fetchExchange } from '@urql/core';
412412+import { cacheExchange, fetchExchange } from '@urql/core';
413413414414import { withUrqlClient } from 'next-urql';
415415416416export default withUrqlClient(
417417 ssrExchange => ({
418418 url: 'http://localhost:3000/graphql',
419419- exchanges: [dedupExchange, cacheExchange, ssrExchange, fetchExchange],
419419+ exchanges: [cacheExchange, ssrExchange, fetchExchange],
420420 }),
421421 { ssr: true } // Enables server-side rendering using `getInitialProps`
422422)(Index);
···440440441441```js
442442import { withUrqlClient, initUrqlClient } from 'next-urql';
443443-import { ssrExchange, dedupExchange, cacheExchange, fetchExchange, useQuery } from 'urql';
443443+import { ssrExchange, cacheExchange, fetchExchange, useQuery } from 'urql';
444444445445const TODOS_QUERY = `
446446 query { todos { id text } }
···464464 const client = initUrqlClient(
465465 {
466466 url: 'your-url',
467467- exchanges: [dedupExchange, cacheExchange, ssrCache, fetchExchange],
467467+ exchanges: [cacheExchange, ssrCache, fetchExchange],
468468 },
469469 false
470470 );
···501501502502```js
503503import { withUrqlClient, initUrqlClient } from 'next-urql';
504504-import { ssrExchange, dedupExchange, cacheExchange, fetchExchange, useQuery } from 'urql';
504504+import { ssrExchange, cacheExchange, fetchExchange, useQuery } from 'urql';
505505import { executeExchange } from '@urql/exchange-execute';
506506507507import { schema } from '@/server/graphql'; // our GraphQL server's executable schema
···529529 {
530530 url: '', // not needed without `fetchExchange`
531531 exchanges: [
532532- dedupExchange,
533532 cacheExchange,
534533 ssrCache,
535534 executeExchange({ schema }), // replaces `fetchExchange`
···603602604603import urql, {
605604 createClient,
606606- dedupExchange,
607605 cacheExchange,
608606 fetchExchange,
609607 ssrExchange
···616614 // NOTE: All we care about here is that the SSR Exchange is included
617615 const ssr = ssrExchange({ isClient: false });
618616 app.use(urql, {
619619- exchanges: [dedupExchange, cacheExchange, ssr, fetchExchange]
617617+ exchanges: [cacheExchange, ssr, fetchExchange]
620618 });
621619622620 const markup = await renderToString(app);
+1-2
docs/api/auth-exchange.md
···2929but after all other synchronous exchanges, like the `cacheExchange`.
30303131```js
3232-import { createClient, dedupExchange, cacheExchange, fetchExchange } from 'urql';
3232+import { createClient, cacheExchange, fetchExchange } from 'urql';
3333import { authExchange } from '@urql/exchange-auth';
34343535const client = createClient({
3636 url: 'http://localhost:3000/graphql',
3737 exchanges: [
3838- dedupExchange,
3938 cacheExchange,
4039 authExchange(async utils => {
4140 return {
+1-21
docs/api/core.md
···3434| `suspense` | `?boolean` | Activates the experimental React suspense mode, which can be used during server-side rendering to prefetch data |
3535| `requestPolicy` | `?RequestPolicy` | Changes the default request policy that will be used. By default, this will be `cache-first`. |
3636| `preferGetMethod` | `?boolean \| 'force' \| 'within-url-limit'` | This is picked up by the `fetchExchange` and will force all queries (not mutations) to be sent using the HTTP GET method instead of POST if the length of the resulting URL doesn't exceed 2048 characters. When `'force'` is passed a GET request is always sent regardless of how long the resulting URL is. |
3737-| `maskTypename` | `?boolean` | Enables the `Client` to automatically apply the `maskTypename` utility to all `data` on [`OperationResult`s](#operationresult). This makes the `__typename` properties non-enumerable. |
38373938### client.executeQuery
4039···251250An exchange is defined to be a function that receives [`ExchangeInput`](#exchangeinput) and returns
252251an `ExchangeIO` function. The `ExchangeIO` function in turn will receive a stream of operations, and
253252must return a stream of results. If the exchange is purely transforming data, like the
254254-`dedupExchange` for instance, it'll call `forward`, which is the next Exchange's `ExchangeIO`
253253+`mapExchange` for instance, it'll call `forward`, which is the next Exchange's `ExchangeIO`
255254function to get a stream of results.
256255257256```js
···330329This exchange is disabled in production and is based on the `mapExchange`.
331330If you'd like to customise it, you can replace it with a custom `mapExchange`.
332331333333-### dedupExchange
334334-335335-An exchange that keeps track of ongoing `Operation`s that haven't returned had
336336-a corresponding `OperationResult` yet. Any duplicate `Operation` that it
337337-receives is filtered out if the same `Operation` has already been received
338338-and is still waiting for a result.
339339-340332### fetchExchange
341333342334The `fetchExchange` of type `Exchange` is responsible for sending operations of type `'query'` and
···515507516508This utility is used by the [`cacheExchange`](#cacheexchange) and by
517509[Graphcache](../graphcache/README.md) to add `__typename` fields to GraphQL `DocumentNode`s.
518518-519519-### maskTypename
520520-521521-This utility accepts a GraphQL `data` object, like `data` on [`OperationResult`s](#operationresult)
522522-and marks every `__typename` property as non-enumerable.
523523-524524-The [`formatDocument`](#formatdocument) is often used by `urql` automatically and adds `__typename`
525525-fields to all results. However, this means that data often cannot be passed back into variables or
526526-inputs on mutations, which is a common use-case. This utility hides these fields, which can solve
527527-this problem.
528528-529529-It's used by the [`Client`](#client) when the `maskTypename` option is enabled.
530510531511### composeExchanges
532512
···273273```
274274275275This specialized case is likely only going to be useful in combination with
276276-[`cache.inspectFields`](#inspectfields). Previously a specialised method existed for this
277277-case specifically and was called `cache.resolveFieldByKey`, which is now deprecated, since
278278-`cache.resolve` may be called with a field key and no extra arguments.
276276+[`cache.inspectFields`](#inspectfields).
279277280278### inspectFields
281279
+3-4
docs/api/refocus-exchange.md
···2323npm install --save @urql/exchange-refocus
2424```
25252626-Then add it to your `Client`, preferably after the `dedupExchange` but in front of any asynchronous
2727-exchanges, like the `fetchExchange`:
2626+Then add it to your `Client`, preferably in front of your `cacheExchange`
28272928```js
3030-import { createClient, dedupExchange, cacheExchange, fetchExchange } from 'urql';
2929+import { createClient, cacheExchange, fetchExchange } from 'urql';
3130import { refocusExchange } from '@urql/exchange-refocus';
32313332const client = createClient({
3433 url: 'http://localhost:3000/graphql',
3535- exchanges: [dedupExchange, refocusExchange(), cacheExchange, fetchExchange],
3434+ exchanges: [refocusExchange(), cacheExchange, fetchExchange],
3635});
3736```
+2-3
docs/api/request-policy-exchange.md
···3232npm install --save @urql/exchange-request-policy
3333```
34343535-Then add it to your `Client`, preferably after the `dedupExchange` but in front of any asynchronous
3535+Then add it to your `Client`, preferably in front of the `cacheExchange` and in front of any asynchronous
3636exchanges, like the `fetchExchange`:
37373838```js
3939-import { createClient, dedupExchange, cacheExchange, fetchExchange } from 'urql';
3939+import { createClient, cacheExchange, fetchExchange } from 'urql';
4040import { requestPolicyExchange } from '@urql/exchange-request-policy';
41414242const client = createClient({
4343 url: 'http://localhost:3000/graphql',
4444 exchanges: [
4545- dedupExchange,
4645 requestPolicyExchange({
4746 /* config */
4847 }),
+1-2
exchanges/auth/README.md
···1717You'll then need to add the `authExchange`, that this package exposes to your `urql` Client
18181919```js
2020-import { createClient, dedupExchange, cacheExchange, fetchExchange } from 'urql';
2020+import { createClient, cacheExchange, fetchExchange } from 'urql';
2121import { makeOperation } from '@urql/core';
2222import { authExchange } from '@urql/exchange-auth';
23232424const client = createClient({
2525 url: 'http://localhost:1234/graphql',
2626 exchanges: [
2727- dedupExchange,
2827 cacheExchange,
2928 authExchange(async utils => {
3029 // called on initial launch,
+1-2
exchanges/context/README.md
···1717You'll then need to add the `contextExchange`, that this package exposes, to your `urql` Client, the positioning of this exchange depends on whether you set an async setter or not. If you set an async context-setter it's best placed after all the synchronous exchanges (in front of the fetchExchange).
18181919```js
2020-import { createClient, dedupExchange, cacheExchange, fetchExchange } from 'urql';
2020+import { createClient, cacheExchange, fetchExchange } from 'urql';
2121import { contextExchange } from '@urql/exchange-context';
22222323const client = createClient({
2424 url: 'http://localhost:1234/graphql',
2525 exchanges: [
2626- dedupExchange,
2726 cacheExchange,
2827 contextExchange({
2928 getContext: async operation => {
+1-2
exchanges/execute/README.md
···1919by replacing the default fetch exchange with it:
20202121```js
2222-import { createClient, dedupExchange, cacheExchange } from 'urql';
2222+import { createClient, cacheExchange } from 'urql';
2323import { executeExchange } from '@urql/exchange-execute';
24242525const client = createClient({
2626 url: 'http://localhost:1234/graphql',
2727 exchanges: [
2828- dedupExchange,
2928 cacheExchange,
3029 // Replace the default fetchExchange with the new one.
3130 executeExchange({
+1-2
exchanges/graphcache/README.md
···2929by replacing the default cache exchange with it:
30303131```js
3232-import { createClient, dedupExchange, fetchExchange } from 'urql';
3232+import { createClient, fetchExchange } from 'urql';
3333import { cacheExchange } from '@urql/exchange-graphcache';
34343535const client = createClient({
3636 url: 'http://localhost:1234/graphql',
3737 exchanges: [
3838- dedupExchange,
3938 // Replace the default cacheExchange with the new one
4039 cacheExchange({
4140 /* optional config */
···333333 args?: FieldArgs
334334 ): DataField | undefined;
335335336336- /** Returns a cached value on a given entity’s field by its field key.
337337- *
338338- * @deprecated
339339- * Use {@link cache.resolve} instead.
340340- */
341341- resolveFieldByKey(
342342- entity: Entity | undefined,
343343- fieldKey: string
344344- ): DataField | undefined;
345345-346336 /** Returns a list of cached fields for a given GraphQL object (“entity”).
347337 *
348338 * @param entity - a GraphQL object (“entity”) or an entity key.
+2-4
exchanges/persisted/README.md
···1717to your `exchanges`.
18181919```js
2020-import { createClient, dedupExchange, fetchExchange, cacheExchange } from 'urql';
2020+import { createClient, fetchExchange, cacheExchange } from 'urql';
2121import { persistedExchange } from '@urql/exchange-persisted';
22222323const client = createClient({
2424 url: 'http://localhost:1234/graphql',
2525 exchanges: [
2626- dedupExchange,
2726 cacheExchange,
2827 persistedExchange({
2928 /* optional config */
···4645when using this all you need to do in this exchange is the following:
47464847```js
4949-import { createClient, dedupExchange, fetchExchange, cacheExchange } from 'urql';
4848+import { createClient, fetchExchange, cacheExchange } from 'urql';
5049import { persistedExchange } from '@urql/exchange-persisted';
51505251const client = createClient({
5352 url: 'http://localhost:1234/graphql',
5453 exchanges: [
5555- dedupExchange,
5654 cacheExchange,
5755 persistedExchange({
5856 generateHash: (_, document) => document.documentId,
+2-2
exchanges/populate/README.md
···1717You'll then need to add the `populateExchange`, that this package exposes.
18181919```js
2020-import { createClient, dedupExchange, cacheExchange, fetchExchange } from 'urql';
2020+import { createClient, cacheExchange, fetchExchange } from 'urql';
2121import { populateExchange } from '@urql/exchange-populate';
22222323const client = createClient({
2424 url: 'http://localhost:1234/graphql',
2525- exchanges: [dedupExchange, populateExchange({ schema }), cacheExchange, fetchExchange],
2525+ exchanges: [populateExchange({ schema }), cacheExchange, fetchExchange],
2626});
2727```
2828
+3-3
exchanges/refocus/README.md
···1313npm install --save @urql/exchange-refocus
1414```
15151616-Then add it to your `Client`, preferably after the `dedupExchange` but in front of any asynchronous
1616+Then add it to your `Client`, preferably before the `cacheExchange` and in front of any asynchronous
1717exchanges, like the `fetchExchange`:
18181919```js
2020-import { createClient, dedupExchange, cacheExchange, fetchExchange } from 'urql';
2020+import { createClient, cacheExchange, fetchExchange } from 'urql';
2121import { refocusExchange } from '@urql/exchange-refocus';
22222323const client = createClient({
2424 url: 'http://localhost:3000/graphql',
2525- exchanges: [dedupExchange, refocusExchange(), cacheExchange, fetchExchange],
2525+ exchanges: [refocusExchange(), cacheExchange, fetchExchange],
2626});
2727```
+1-2
exchanges/request-policy/README.md
···1616Then add it to your client.
17171818```js
1919-import { createClient, dedupExchange, cacheExchange, fetchExchange } from 'urql';
1919+import { createClient, cacheExchange, fetchExchange } from 'urql';
2020import { requestPolicyExchange } from '@urql/exchange-request-policy';
21212222const client = createClient({
2323 url: 'http://localhost:1234/graphql',
2424 exchanges: [
2525- dedupExchange,
2625 requestPolicyExchange({
2726 // The amount of time in ms that has to go by before upgrading, default is 5 minutes.
2827 ttl: 60 * 1000, // 1 minute.
+1-32
packages/core/src/client.ts
···4343import {
4444 createRequest,
4545 withPromise,
4646- maskTypename,
4746 noop,
4847 makeOperation,
4948 getOperationType,
···119118 * This is the basis for how `urql` handles GraphQL operations, and exchanges handle the creation, execution,
120119 * and control flow of exchanges for the `Client`.
121120 *
122122- * To easily get started you should consider using the {@link dedupExchange}, {@link cacheExchange} and {@link fetchExchange}
121121+ * To easily get started you should consider using the {@link cacheExchange} and {@link fetchExchange}
123122 * these are all exported from the core package.
124123 *
125124 * @see {@link https://urql.dev/goto/docs/architecture/#the-client-and-exchanges} for more information
···168167 * requests for queries.
169168 */
170169 preferGetMethod?: boolean | 'force' | 'within-url-limit';
171171- /** Instructs the `Client` to remove `__typename` properties on all results.
172172- *
173173- * @deprecated Not recommended over modelling inputs manually (See #3299)
174174- *
175175- * @remarks
176176- * By default, cache exchanges will alter your GraphQL documents to request `__typename` fields
177177- * for all selections. However, this means that your GraphQL data will now contain `__typename` fields you
178178- * didn't ask for. This is why the {@link Client} supports “masking” this field by marking it
179179- * as non-enumerable via this option.
180180- *
181181- * Only use this option if you absolutely have to. It's popular to model mutation inputs in
182182- * GraphQL schemas after the object types they modify, and if you're using this option to make
183183- * it possible to directly pass objects from results as inputs to your mutation variables, it's
184184- * more performant and idomatic to instead create a new input object.
185185- *
186186- * Hint: With `@urql/exchange-graphcache` you will never need this option, as it selects fields on
187187- * the client-side according to which fields you specified, rather than the fields it modified.
188188- *
189189- * @see {@link https://spec.graphql.org/October2021/#sec-Type-Name-Introspection} for more information
190190- * on typename introspection via the `__typename` field.
191191- */
192192- maskTypename?: boolean;
193170}
194171195172/** The `Client` is the central hub for your GraphQL operations and holds `urql`'s state.
···629606 )
630607 )
631608 );
632632-633633- // Mask typename properties if the option for it is turned on
634634- if (opts.maskTypename) {
635635- result$ = pipe(
636636- result$,
637637- map(res => ({ ...res, data: maskTypename(res.data, true) }))
638638- );
639639- }
640609641610 if (operation.kind !== 'query') {
642611 // Interrupt subscriptions and mutations when they have no more results
-10
packages/core/src/exchanges/dedup.ts
···11-import type { Exchange } from '../types';
22-33-/** Default deduplication exchange.
44- * @deprecated
55- * This exchange's functionality is now built into the {@link Client}.
66- */
77-export const dedupExchange: Exchange =
88- ({ forward }) =>
99- ops$ =>
1010- forward(ops$);
-1
packages/core/src/exchanges/index.ts
···22export { cacheExchange } from './cache';
33export { subscriptionExchange } from './subscription';
44export { debugExchange } from './debug';
55-export { dedupExchange } from './dedup';
65export { fetchExchange } from './fetch';
76export { composeExchanges } from './compose';
87
···44export * from './variables';
55export * from './collectTypenames';
66export * from './formatDocument';
77-export * from './maskTypename';
87export * from './streamUtils';
98export * from './operation';
109
···11-/** Used to recursively mark `__typename` fields in data as non-enumerable.
22- *
33- * @deprecated Not recommended over modelling inputs manually (See #3299)
44- *
55- * @remarks
66- * This utility can be used to recursively copy GraphQl response data and hide
77- * all `__typename` fields present on it.
88- *
99- * Hint: It’s not recommended to do this, unless it's absolutely necessary as
1010- * cloning and modifying all data of a response can be unnecessarily slow, when
1111- * a manual and more specific copy/mask is more efficient.
1212- *
1313- * @see {@link ClientOptions.maskTypename} for a description of how the `Client` uses this utility.
1414- */
1515-export const maskTypename = (data: any, isRoot?: boolean): any => {
1616- if (!data || typeof data !== 'object') {
1717- return data;
1818- } else if (Array.isArray(data)) {
1919- return data.map(d => maskTypename(d));
2020- } else if (
2121- data &&
2222- typeof data === 'object' &&
2323- (isRoot || '__typename' in data)
2424- ) {
2525- const acc = {};
2626- for (const key in data) {
2727- if (key === '__typename') {
2828- Object.defineProperty(acc, '__typename', {
2929- enumerable: false,
3030- value: data.__typename,
3131- });
3232- } else {
3333- acc[key] = maskTypename(data[key]);
3434- }
3535- }
3636- return acc;
3737- } else {
3838- return data;
3939- }
4040-};