+1
-1
docs/README.md
+1
-1
docs/README.md
···`urql` is a highly customizable and versatile GraphQL client with which you add on features like
+2
-2
docs/advanced/README.md
+2
-2
docs/advanced/README.md
···- [**Authentication**](./authentication.md) describes how to implement authentication using the `authExchange`- [**Testing**](./testing.md) covers how to test components that use `urql` particularly in React.- [**Authoring Exchanges**](./authoring-exchanges.md) describes how to implement exchanges from-- [**Auto-populate Mutations**](./auto-populate-mutations.md) presents the `populateExchange` addon which can make it easier to+- [**Auto-populate Mutations**](./auto-populate-mutations.md) presents the `populateExchange` addon, which can make it easier to
+35
-24
docs/advanced/authentication.md
+35
-24
docs/advanced/authentication.md
···-**Initial login** - the user opens the application and authenticates for the first time. They enter their credentials and receive an auth token.+**Initial login** — the user opens the application and authenticates for the first time. They enter their credentials and receive an auth token.The token is saved to storage that is persisted though sessions, e.g. `localStorage` on the web or `AsyncStorage` in React Native. The token is-**Resume** - the user opens the application after having authenticated in the past. In this case, we should already have the token in persisted+**Resume** — the user opens the application after having authenticated in the past. In this case, we should already have the token in persisted-**Forced log out due to invalid token** - the user's session could become invalid for a variety reasons: their token expired, they requested to be-signed out of all devices, or their session was invalidated remotely. In this case, we would want to also log them out in the application so they+**Forced log out due to invalid token** — the user's session could become invalid for a variety reasons: their token expired, they requested to be+signed out of all devices, or their session was invalidated remotely. In this case, we would want tocould have the opportunity to log in again. To do this, we want to clear any persisted storage, and redirect them to the application home or login page.-**User initiated log out** - when the user chooses to log out of the application, we usually send a logout request to the API, then clear any tokens+**User initiated log out** — when the user chooses to log out of the application, we usually send a logout request to the API, then clear any tokens-**Refresh (optional)** - this is not always implemented, but given that your API supports it, the user will receive both an auth token and a refresh token,-where the auth token is valid for a shorter duration of time (e.g. 1 week) than the refresh token (e.g. 6 months) and the latter can be used to request a new+The auth token is usually valid for a shorter duration of time (e.g. 1 week) than the refresh tokenauth token if the auth token has expired. The refresh logic is triggered either when the JWT is known to be invalid (e.g. by decoding it and inspecting the expiry date),or when an API request returns with an unauthorized response. For graphQL APIs, it is usually an error code, instead of a 401 HTTP response, but both can be supported.When the token as been successfully refreshed (this can be done as a mutation to the graphQL API or a request to a different API endpoint, depending on implementation),···We check that the `authState` doesn't already exist (this indicates that it is the first time this exchange is executed and not an auth failure) and fetch the auth state from-storage. The structure of this particular`authState` is an object with keys for `token` and `refreshToken`, but this format is not required. You can-use different keys or store any additional auth related information here. For example you could decode and store the token expiry date, which would save you from decoding+`refreshToken`, but this format is not required. We can use different keys or store any additional+auth related information here. For example, we could decode and store the token expiry date, whichIn React Native, this is very similar, but because persisted storage in React Native is always asynchronous, so is this function:···-The purpose of `addAuthToOperation` is to take apply your auth state to each request. Note that the format of the `authState` will be whatever+The purpose of `addAuthToOperation` is to apply an auth state to each request. Note that the format+of the `authState` will be whatever we've returned from `getAuth` and not constrained by the exchange:···-First we check that we have an `authState` and a `token`. Then we apply it to the request `fetchOptions` as an `Authorization` header.-The header format can vary based on the API (e.g using `Bearer ${token}` instead of just `token`) which is why it'll be up to you to add the header+`fetchOptions` as an `Authorization` header. The header format can vary based on the API (e.g. usingThis function lets the exchange know what is defined to be an API error for your API. `didAuthError` receives an `error` which is of type-[`CombinedError`](../api/core.md#combinederror) and we can use the `graphQLErrors` array in `CombinedError` to determine if an auth error has occurred.+[`CombinedError`](../api/core.md#combinederror), and we can use the `graphQLErrors` array in `CombinedError` to determine if an auth error has occurred.···-Most GraphQL APIs will communicate auth errors via the [error code extension](https://www.apollographql.com/docs/apollo-server/data/errors/#codes) which-is the recommended approach. We'll be able to determine whether any of the GraphQL errors were due to an unauthorized error code, which would indicate an auth failure:+is the recommended approach. We'll be able to determine whether any of the GraphQL errors were due···-If your API doesn't support any sort of token refresh, this is where you should simply log the user out.+If the API doesn't support any sort of token refresh, this is where we could simply log the user out.···-Here, `logout()` is a placeholder that is called when we got an error, so that we can redirect to a login page again and clear our tokens from local storage or otherwise.+Here, `logout()` is a placeholder that is called when we got an error, so that we can redirect to a-If we had a way to refresh our token using a refresh token, we can attempt to get a new token for the user first:+If we had a way to refresh our token using a refresh token, we can attempt to get a new token for the···When the application launches, the first thing we do is check whether the user has any auth tokens in persisted storage. This will tell us-The `isLoggedIn` prop should always be updated based on authentication state change e.g. set to `true` after the use has authenticated and their tokens have been-added to storage, and set to `false` if the user has been logged out and their tokens have been cleared. It's important clear or add tokens to storage _before_+The `isLoggedIn` prop should always be updated based on authentication state change. For instance, we may set it to+`true` after the user has authenticated and their tokens have been added to storage, and set it to+`false` once the user has been logged out and their tokens have been cleared. It's important to clear
+5
-5
docs/advanced/auto-populate-mutations.md
+5
-5
docs/advanced/auto-populate-mutations.md
···`@populate` directive. In combination with [Graphcache](../graphcache/README.md) this is a useful-tool to update the data in your application automatically following a mutation, when your app grows+tool to update the data in your application automatically following a mutation, when your app grows,-> **NOTE:** The `populateExchange` is currently _experimental_! Certain patterns and usage paths> like GraphQL field arguments aren't covered yet, and the exchange hasn't been extensively used······-You may not want to populate your whole mutation response. In order to reduce your payload, pass populate lower in your query.+You may not want to populate your whole mutation response. To reduce your payload, pass populate lower in your query.···-[use aliases](https://graphql.org/learn/queries/#aliases) in order to allow merging of queries.
+3
-3
docs/advanced/debugging.md
+3
-3
docs/advanced/debugging.md
···-The quickest way to debug `urql` is to use the [`urql` devtools.](https://github.com/FormidableLabs/urql-devtools/)+It's easiest to debug `urql` with the [`urql` devtools.](https://github.com/FormidableLabs/urql-devtools/)It offers tools to inspect internal ["Debug Events"](#debug-events) as they happen, to explore data···-Lastly, in summary, here are a few tips, dos, and don'ts that are important when we're adding new+Lastly, in summary, here are a few tips, that are important when we're adding new Debug Events to- ✅ **Share internal details**: Frequent debug messages on key events inside your exchange are very
+3
-3
docs/advanced/persistence-and-uploads.md
+3
-3
docs/advanced/persistence-and-uploads.md
···hash and sends this hash instead of the full query. If the server has seen this GraphQL query beforeit will recognise it by its hash and process the GraphQL API request as usual, otherwise it mayrespond using a `PersistedQueryNotFound` error. In that case the client is supposed to instead send-the full GraphQL query and the hash together, which will cause the query to be "registered" with the+the full GraphQL query, and the hash together, which will cause the query to be "registered" with theAdditionally we could also decide to send these hashed queries as GET requests instead of POST···The `persistedFetchExchange` also accepts a `generateHash` option. This may be used to swap out thebuilt-in [Web Crypto API](https://developer.mozilla.org/en-US/docs/Web/API/Web_Crypto_API) on the···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+`multipartFetchExchange`, since only the latter is a full replacement for the `fetchExchange`, and
+2
-2
docs/advanced/retry-operations.md
+2
-2
docs/advanced/retry-operations.md
······We have the `initialDelayMs` to specify at what interval the `retrying` should start, this means that if we specify `1000` that when our `operation` fails we'll wait 1 second and then retry it.-Next up is the `maxDelayMs`, our `retryExchange` will keep increasing the time between retries so we don't spam our server with requests it can't complete, this option ensures we don't exceed a certain threshold. This time between requests will increase with a random `back-off` factor multiplied by the `initialDelayMs`, read more about the [thundering herd problem](https://en.wikipedia.org/wiki/Thundering_herd_problem).+Next up is the `maxDelayMs`, our `retryExchange` will keep increasing the time between retries, so we don't spam our server with requests it can't complete, this option ensures we don't exceed a certain threshold. This time between requests will increase with a random `back-off` factor multiplied by the `initialDelayMs`, read more about the [thundering herd problem](https://en.wikipedia.org/wiki/Thundering_herd_problem).Talking about increasing the `delay` randomly, `randomDelay` allows us to disable this. When this option is set to `false` we'll only increase the time between attempts with the `initialDelayMs`. This means if we fail the first time we'll have 1 second wait, next fail we'll have 2 seconds and so on.
+8
-8
docs/advanced/server-side-rendering.md
+8
-8
docs/advanced/server-side-rendering.md
···-This will provide `__URQL_DATA__` globally which we've used in our first example to inject data into+This will provide `__URQL_DATA__` globally, which we've used in our first example to inject data intoAlternatively you can also call `restoreData` as long as this call happens synchronously before the···-rendering](https://reactjs.org/docs/concurrent-mode-suspense.html). However, suspense is currentlyUsing [the `react-ssr-prepass` package](https://github.com/FormidableLabs/react-ssr-prepass) however,···-`react-ssr-prepass`, which is called `preact-ssr-prepass`. It only has a peer dependency on Preact+`react-ssr-prepass`, which is called `preact-ssr-prepass`. It only has a peer dependency on Preact,···-All above examples for `react-ssr-prepass` will still be the exact same, except that instead ofusing the `urql` package we'll have to import from `@urql/preact`, and instead of `react-ssr-prepass`······This will automatically set up server-side rendering on the page. The `withUrqlClient` higher-ordercomponent function accepts the usual `Client` options as an argument. This may either just be anOne added caveat is that these options may not include the `exchanges` option because `next-urql`injects the `ssrExchange` automatically at the right location. If you're setting up custom exchanges···-In rare scenario's you possibly will have to reset the client instance (reset all cache, ...), this is an uncommon scenario+In rare scenario's you possibly will have to reset the client instance (reset all cache, ...), thisWhen this does seem like the appropriate solution any component wrapped with `withUrqlClient` will receive the `resetUrqlClient`
+5
-2
docs/advanced/subscriptions.md
+5
-2
docs/advanced/subscriptions.md
···In the above example, we add the `subscriptionExchange` to the `Client` with the default exchangesadd before it. The `subscriptionExchange` is a factory that accepts additional options and returnsthe actual `Exchange` function. It does not make any assumption over the transport protocol and-scheme that is used. Instead, we need to pass a `forwardSubscription` function which is called with+scheme that is used. Instead, we need to pass a `forwardSubscription` function, which is called withWhen we define this function it must return an "Observable-like" object, which needs to follow the···`Client`'s `subscription` method for one-off subscriptions. This method is similar to the ones formutations and subscriptions [that we've seen before on the "Core Package" page.](../basics/core.md)-This method will always [returns a Wonka stream](../architecture.md#the-wonka-library) and doesn't have a `.toPromise()` shortcut method, since promises won't return the multiple values that a subscription may deliver. Let's convert the above example to one without framework code, as we may use subscriptions in a Node.js environment.+This method will always [returns a Wonka stream](../architecture.md#the-wonka-library) and doesn't+subscription may deliver. Let's convert the above example to one without framework code, as we may
+7
-7
docs/advanced/testing.md
+7
-7
docs/advanced/testing.md
···In the section ["Stream Patterns" on the "Architecture" page](../architecture.md) we've seen, thatourselves to mock the different states of our operations, e.g. fetching, errors, or success with data.···-Fetching states can be simulated by returning a stream which never returns. Wonka provides a utility for this, aptly called `never`.+Fetching states can be simulated by returning a stream, which never returns. Wonka provides a utility for this, aptly called `never`.···-Response states are simulated by providing a stream which contains a network response. For single responses, Wonka's `fromValue` function can do this for us.+Response states are simulated by providing a stream, which contains a network response. For single responses, Wonka's `fromValue` function can do this for us.···-The above client we've created mocks all three operations — queries, mutations, and subscriptions — to always remain in the `fetching: true` state.+The above client we've created mocks all three operations — queries, mutations and subscriptions — to always remain in the `fetching: true` state.Generally when we're _hoisting_ our mocked client and reuse it across multiple tests we have to bemindful not to instantiate the mocks outside of Jest's lifecycle functions (like `it`, `beforeEach`,···If you prefer to have more control on when the new data is arriving you can use the `makeSubject` utility from Wonka. You can see more details in the next section.···Simulating multiple responses can be useful, particularly testing `useEffect` calls dependent on changing query responses.-For this, a _subject_ is the way to go. In short, it's a stream which you can push responses to. The `makeSubject` function from Wonka is what you'll want to use for this purpose.+For this, a _subject_ is the way to go. In short, it's a stream that you can push responses to. The `makeSubject` function from Wonka is what you'll want to use for this purpose.Below is an example of simulating subsequent responses (such as a cache update/refetch) in a test.
+9
-9
docs/api/core.md
+9
-9
docs/api/core.md
···-like [`urql` for React](./urql.md) or [`@urql/preact`](./preact.md) will reuse the core logic and+like [`urql` for React](./urql.md) or [`@urql/preact`](./preact.md), will reuse the core logic andTherefore if you're not accessing utilities directly, aren't in a Node.js environment, and are usingframework bindings, you'll likely want to import from your framework bindings package directly.···| `fetchOptions` | `RequestInit \| () => RequestInit` | Additional `fetchOptions` that `fetch` in `fetchExchange` should use to make a request || `fetch` | `typeof fetch` | An alternative implementation of `fetch` that will be used by the `fetchExchange` instead of `window.fetch` || `suspense` | `?boolean` | Activates the experimental React suspense mode, which can be used during server-side rendering to prefetch data |-| `requestPolicy` | `?RequestPolicy` | Changes the default request policy that will be used. By default this will be `cache-first`. |+| `requestPolicy` | `?RequestPolicy` | Changes the default request policy that will be used. By default, this will be `cache-first`. || `preferGetMethod` | `?boolean` | 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. || `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. |···This is a shorthand method for [`client.executeQuery`](#clientexecutequery), which accepts a query(`DocumentNode | string`) and variables separately and creates a [`GraphQLRequest`](#graphqlrequest) [`createRequest`](#createrequest) automatically.-The returned `Source<OperationResult>` will also have an added `toPromise` method so the stream can+The returned `Source<OperationResult>` will also have an added `toPromise` method, so the stream can·········-[`Operation` object](#operation) or to copy an `Operation`. It adds the `kind` property and the+[`Operation` object](#operation) or to copy an `Operation`. It adds the `kind` property, and the···The [`formatDocument`](#formatdocument) is often used by `urql` automatically and adds `__typename`-fields to all results. However, this means that data can often not be passed back into variables or-inputs on mutations, which is a common use-case. This utility hides these fields which can solves+fields to all results. However, this means that data often cannot be passed back into variables or+inputs on mutations, which is a common use-case. This utility hides these fields, which can solve
+6
-6
docs/api/urql.md
+6
-6
docs/api/urql.md
···- The `result` is an object with the shape of an [`OperationResult`](./core.md#operationresult) with-an added `fetching: boolean` property, indicating whether the query is currently being fetched.[`Partial<OperationContext>`](./core.md#operationcontext) and reexecutes the current query when···- The `result` is an object with the shape of an [`OperationResult`](./core.md#operationresult) with-an added `fetching: boolean` property, indicating whether the mutation is currently being executed.[`Partial<OperationContext>`](./core.md#operationcontext) and may be used to start executing amutation. It returns a `Promise` resolving to an [`OperationResult`](./core.md#operationresult).···it's called. When `pause` is set to `true` this starts the subscription, overriding the otherwise-By default `urql` is not able to start subscriptions, since this requires some additional setup.+The `fetching: boolean` property on the `result` may change to `false` when the server proactively+ends the subscription. By default, `urql` is unable able to start subscriptions, since this requires···-The `Mutation` component accepts a `query` prop and a function callback must be passed to `children`+The `Mutation` component accepts a `query` prop, and a function callback must be passed to `children``useMutation`'s returned tuple, `executeMutation` is passed as an added property on the mutation
+10
-10
docs/architecture.md
+10
-10
docs/architecture.md
···If `urql` was a train it would take several stops to arrive at its terminus, our API. It starts with usdefining queries or mutations. Any GraphQL request can be abstracted into their query documents and-their variables. In `urql`, these GraphQL requests are treated as unique objects which are uniquely+their variables. In `urql`, these GraphQL requests are treated as unique objects, which are uniquelyidentified by the query document and variables (which is why a `key` is generated from the two). This···It's the `Client`s responsibility to accept an `Operation` and execute it. The bindings interally-call the `client.executeQuery`, `client.executeMutation`, or `client.executeSubscription` methods+call the `client.executeQuery`, `client.executeMutation`, or `client.executeSubscription` methods,and we'll get a "stream" of results. This "stream" allows us to register a callback with it toIn the diagram we can see that each operation is a signal for our request to start at which pointwe can expect to receive our results eventually on a callback. Once we're not interested in resultsanymore a special "teardown" signal is issued on the `Client`. While we don't see operations outsideTo reiterate, when we use `urql`'s bindings for our framework of choice, methods are called on the-`Client` but we never see the operations that are created in the background from our bindings. We+`Client`, but we never see the operations that are created in the background from our bindings. Wecall a method like `client.executeQuery` (or it's called for us in the bindings), an operation isissued internally when we subscribe with a callback, and later our callback is called with results.···-- The `Client` issues the operation and we'll receive some results back eventually as either the-- We eventually unsubscribe and the `Client` issues a "teardown" operation with the same `key` as+- The `Client` issues the operation, and we'll receive some results back eventually as either the+- We eventually unsubscribe, and the `Client` issues a "teardown" operation with the same `key` asThe `Client` itself doesn't actually know what to do with operations. Instead, it sends them through···- This operation is sent into the **exchanges** and eventually ends up at the `fetchExchange`-- The operation is sent to the API and a **result** comes back which is wrapped in an `OperationResult`+- The operation is sent to the API and a **result** comes back, which is wrapped in an `OperationResult`- The `Client` filters the `OperationResult` by the `operation.key` and — via a callback — gives us···Generally we refer to _streams_ as abstractions that allow us to program with asynchronous eventsand [Reactive Programming with Observables.](http://reactivex.io/documentation/observable.html)These concepts may sound initimidating, but from a high-level view what we're talking about can bethought of as a combination of promises and iterables (e.g. arrays). We're dealing with multiple-events but our callback is called over time. It's like calling `forEach` on an array but expecting+events, but our callback is called over time. It's like calling `forEach` on an array but expecting
+17
-16
docs/basics/core.md
+17
-16
docs/basics/core.md
···As we said above, if we are using bindings then those will already have installed `@urql/core` as-they depend on it. They also all re-export all exports from `@urql/core`, so we can use those no+regardless of which bindings we've installed. However, it's also possible to explicitly install···-identical and the output is approximately the same. The two packages are also intercompatible.-However, one small change that `@urql/core`'s implementation makes is that your fragment names don't-have to be globally unique, since it's possible to create some one-off fragments every now and then.+identical, and its output is approximately the same. The two packages are also intercompatible.+have to be globally unique, since it's possible to create some one-off fragments occasionally,It also pre-generates a "hash key" for the `DocumentNode` which is what `urql` does anyway, thus···At the bare minimum we'll need to pass an API's `url` when we create a `Client` to get started.Another common option is `fetchOptions`. This option allows us to customize the options that will be-passed to `fetch` when a request is sent to the given API `url`. We may pass in an options object or+passed to `fetch` when a request is sent to the given API `url`. We may pass in an options object, orIn the following example we'll add a token to each `fetch` request that our `Client` sends to our···This option passes a list of exchanges to the `Client`, which tell it how to execute our requests···supports by adding new exchanges to this list. On [the "Architecture" page](../architecture.md)exchanges in order. First, the `dedupExchange` deduplicates requests if we send the same queriestwice, the `cacheExchange` implements the default "document caching" behaviour (as we'll learn about···In the above example we're executing a query on the client, are passing some variables and arecalling the `toPromise()` method on the return value to execute the request immediately and get theSimilarly there's a way to read data from the cache synchronously, provided that the cache has···This code example is similar to the one before. However, instead of sending a one-off query, we'resubscription means that our callback may be called repeatedly. We may get future results as well as···immediately if our cache already has a result for the given query. The same principle applies here!-Once we're not interested in any results anymore we need to clean up after ourselves by calling+Once we're not interested in any results anymore, we need to clean up after ourselves by calling`unsubscribe`. This stops the subscription and makes sure that the `Client` doesn't actively updatethe query anymore or refetches it. We can think of this pattern as being very similar to events or-We're using [the Wonka library for our streams](https://wonka.kitten.sh/basics/background) which+We're using [the Wonka library for our streams](https://wonka.kitten.sh/basics/background), whichwe'll learn more about [on the "Architecture" page](./architecture.md). But we can think of this as···- [`CombinedError`](../api/core.md#combinederror) - our abstraction to combine one or more `GraphQLError`(s) and a `NetworkError`-- [`createRequest`](../api/core.md#createrequest) - a utility function to create a request from a query and some variables (which+- [`createRequest`](../api/core.md#createrequest) - a utility function to create a request from aThere are other utilities not mentioned here. Read more about the `@urql/core` API in the [API docs](../api/core.md).
+6
-7
docs/basics/document-caching.md
+6
-7
docs/basics/document-caching.md
···-By default `urql` uses a concept called _Document Caching_. It will avoid sending the same requests+By default, `urql` uses a concept called _Document Caching_. It will avoid sending the same requestsThis works like the cache in a browser. `urql` creates a key for each request that is sent based on···-The _request policy_ that is defined will alter what the default document cache does. By default the+The _request policy_ that is defined will alter what the default document cache does. By default, thecache will prefer cached results and will otherwise send a request, which is called `cache-first`.···-This cache has a small trade-off! If we request a list of data and the API returns an empty list,+This cache has a small trade-off! If we request a list of data, and the API returns an empty list,There are two ways to fix this issue, supplying `additionalTypenames` to the context of your query or [switch to "Normalized Caching"···+We may also use this feature for mutations, since occasionally mutations must invalidate data that
+1
-1
docs/basics/errors.md
+1
-1
docs/basics/errors.md
···- The `networkError` property will contain any error that stopped `urql` from making a network- The `graphQLErrors` property may be an array that contains [normalized `GraphQLError`s as they-were returned in the `errors` array from a GraphQL API.](https://graphql.org/graphql-js/error/)+were received in the `errors` array from a GraphQL API.](https://graphql.org/graphql-js/error/)
+16
-16
docs/basics/react-preact.md
+16
-16
docs/basics/react-preact.md
···-Installing `urql` is as quick as you'd expect and you won't need any other packages to get started+Installing `urql` is as quick as you'd expect, and you won't need any other packages to get started···At the bare minimum we'll need to pass an API's `url` when we create a `Client` to get started.Another common option is `fetchOptions`. This option allows us to customize the options that will be-passed to `fetch` when a request is sent to the given API `url`. We may pass in an options object or+passed to `fetch` when a request is sent to the given API `url`. We may pass in an options object, orIn the following example we'll add a token to each `fetch` request that our `Client` sends to our···-Now every component and element inside and under the `Provider` are able to use GraphQL queries that···Here we have implemented our first GraphQL query to fetch todos. We see that `useQuery` acceptsoptions and returns a tuple. In this case we've set the `query` option to our GraphQL query. The-tuple we then get in return is an array that contains a result object and a re-execute function.+tuple we then get in return is an array that contains a result object, and a re-execute function.-The result object contains several properties. The `fetching` field indicates whether we're currently+The result object contains several properties. The `fetching` field indicates whether the hook isloading data, `data` contains the actual `data` from the API's result, and `error` is set when eitherthe request to the API has failed or when our API result contained some `GraphQLError`s, which···Whenever the `variables` (or the `query`) option on the `useQuery` hook changes `fetching` will-switch to `true` and a new request will be sent to our API, unless a result has already been cached+switch to `true`, and a new request will be sent to our API, unless a result has already been cached···written to not execute when these variables are empty, to prevent `null` variables from being···The `requestPolicy` option determines how results are retrieved from our `Client`'s cache. By-default this is set to `cache-first`, which means that we prefer to get results from our cache, but+default, this is set to `cache-first`, which means that we prefer to get results from our cache, butRequest policies aren't specific to `urql`'s React API, but are a common feature in its core. [You···`variables` change, but in some cases we may find that we need to programmatically trigger a new-query. This is the purpose of the `reexecuteQuery` function which is the second item in the tuple+query. This is the purpose of the `reexecuteQuery` function, which is the second item in the tupleTriggering a query programmatically may be useful in a couple of cases. It can for instance be used+to refresh the hook's data. In these cases we may also override the `requestPolicy` of our query just···Both libraries offer a `useMutation` hook and a `Mutation` component. The latter accepts the same···When calling our `updateTodo` function we have two ways of getting to the result as it comes back-from our API. We can either use the first value of the returned tuple — our `updateTodoResult` — or+from our API. We can either use the first value of the returned tuple, our `updateTodoResult`, or···-promise is particularly useful when you're adding side-effects that run after the mutation has+promise is particularly useful when you're adding side effects that run after the mutation has···This concludes the introduction for using `urql` with React or Preact. The rest of the documentation-is mostly framework-agnostic and will apply to either `urql` in general or the `@urql/core` package,+is mostly framework-agnostic and will apply to either `urql` in general, or the `@urql/core` package,which is the same between all framework bindings. Hence, next we may want to learn more about one of
+8
-8
docs/basics/svelte.md
+8
-8
docs/basics/svelte.md
···The `operationStore` function creates a [Svelte Writable store](https://svelte.dev/docs#writable).You can use it to initialise a data container in `urql`. This store holds on to our query inputs,-like the GraphQL query and variables, which we can change to launch new queries, and also exposes+like the GraphQL query and variables, which we can change to launch new queries. It also exposes···-The `operationStore` provides getters too so it's also possible for us to pass `todos` around and+The `operationStore` provides getters as well, so it's also possible for us to pass `todos` around and`$todos.variables` in a component for instance, will cause `query` to pick up the update and execute···started at will. Instead, the `query`'s third argument, the `context`, may have an added `pause`-For instance we may start out with a paused store and then unpause it once a callback is invoked:+For instance, we may start out with a paused store and then unpause it once a callback is invoked:···The `requestPolicy` option determines how results are retrieved from our `Client`'s cache. By-default this is set to `cache-first`, which means that we prefer to get results from our cache, but+default, this is set to `cache-first`, which means that we prefer to get results from our cache, but···-As we can see, the `requestPolicy` is easily changed here and we can read our `context` option back+As we can see, the `requestPolicy` is easily changed, and we can read our `context` option back`operationStore.context` can be very useful to also refetch queries, as we'll see in the next···The default caching approach in `@urql/svelte` typically takes care of updating queries on the flyquite well and does so automatically. Sometimes it may be necessary though to refetch data and toexecute a query with a different `context`. Triggering a query programmatically may be useful in a-couple of cases. It can for instance be used to refresh data that is currently being displayed.···The `mutation` function isn't dissimilar from the `query` function but is triggered manually and-can accept a [`GraphQLRequest` object](../api/core.md#graphqlrequest) too while also supporting our+can accept a [`GraphQLRequest` object](../api/core.md#graphqlrequest), while also supporting our···-is mostly framework-agnostic and will apply to either `urql` in general or the `@urql/core` package,+is mostly framework-agnostic and will apply to either `urql` in general, or the `@urql/core` package,which is the same between all framework bindings. Hence, next we may want to learn more about one of
+8
-7
docs/comparison.md
+8
-7
docs/comparison.md
···-> This comparison page aims to be accurate, unbiased, and up-to-date. If you see any information that+> This comparison page aims to be detailed, unbiased, and up-to-date. If you see any information thatThe most common question that you may encounter with GraphQL is what client to choose when you are-getting started. We aim to provide an unbiased and accurate comparison of several options on this+getting started. We aim to provide an unbiased and detailed comparison of several options on thisAll options come with several drawbacks and advantages, and all of these clients have been aroundfor a while now. A little known fact is that `urql` in its current form and architecture has already···Typically these are all additional addon features that you may expect from a GraphQL client, nomatter which framework you use it with. It's worth mentioning that all three clients support some-kind of extensibility API which allows you to change when and how queries are sent to an API. These+kind of extensibility API, which allows you to change when and how queries are sent to an API. Theseare easy to use primitives particularly in Apollo, with links, and in `urql` with exchanges. Themajor difference in `urql` is that all caching logic is abstracted in exchanges too, which makes···`@urql/exchange-graphcache` we chose to include it as a feature since it also strengthened other-Relay does in fact have similar guarantees as [`urql`'s Commutativity Guarantees](./graphcache/under-the-hood.md)···- All packages in `urql` reuse parts of `@urql/core` and `wonka`, which means adding all their total- These sizes may change drastically given the code you write and add yourself, but can be managedvia precompilation (e.g. with `babel-plugin-graphql-tag` or GraphQL Code Generator for Apollo and
+5
-5
docs/graphcache/README.md
+5
-5
docs/graphcache/README.md
···complex it's likely that the data and state that `urql` manages, will also grow more complex and···-The following pages introduce different features in _Graphcache_ which together make it a compelling+The following pages introduce different features in _Graphcache_, which together make it a compellingalternative to the standard [document cache](../basics/document-caching.md) that `urql` uses by- 🔁 [**Fully reactive, normalized caching.**](./normalized-caching.md) _Graphcache_ stores data in-a normalized data structure. Query, mutation, and subscription results may update one another if+a normalized data structure. Query, mutation and subscription results may update one another ifthey share data, and the app will rerender or refetch data accordingly. This often allows your app
+32
-32
docs/graphcache/cache-updates.md
+32
-32
docs/graphcache/cache-updates.md
···-starting from the root `Query` entity which then connects to other entities via links, which are+starting from the root `Query` entity, which then connects to other entities via links, which arerelations stored as keys, where each entity has records that store scalar values, which are thetree's leafs. On the previous page, on ["Local Resolvers"](./local-resolvers.md), we've seen howresolvers can be attached to fields to manually resolve other entities (or transform record fields).···> Any mutation or subscription can also be written to this data structure. Once Graphcache finds a-> keyable entity in their results it's written to its relational table which may update other queriesThis means that mutations and subscriptions still write and update entities in the cache. These-limitations to this. While resolvers can be used to passively change data for queries, for mutations+updates are then reflected on all active queries that our app uses. However, there are limitations to this.This is often necessary when a given mutation or subscription deliver a result that is more granular···An "updater" may be attached to a `Mutation` or `Subscription` field and accepts four positional-- `result`: The full API result that's currently being written to the cache. Typically we'd want to- `args`: The arguments that the field has been called with, which will be replaced with an empty···- `cache`: The `cache` instance, which gives us access to methods allowing us to interact with the- local cache. Its full API can be found [in the API docs](../api/graphcache.md#cache). On this page-- `info`: This argument shouldn't be used frequently but it contains running information about the+- `info`: This argument shouldn't be used frequently, but it contains running information about theThe cache updaters return value is disregarded (and typed as `void` in TypeScript), which makes any-method that they call on the `cache` instance a side-effect, which may trigger additional cache+method that they call on the `cache` instance a side effect, which may trigger additional cache···-Cache updates are **not** possible outside of `updates`. If we attempt to store the `cache` in a-variable and call its methods outside of any `updates` functions (or functions, like `resolvers`)+variable and call its methods outside any `updates` functions (or functions, like `resolvers`)-Methods like these cannot be called outside of the `cacheExchange`'s `updates` functions, because+Methods like these cannot be called outside the `cacheExchange`'s `updates` functions, becauseall updates are isolated to be _reactive_ to mutations and subscription events. In Graphcache,out-of-band updates aren't permitted because the cache attempts to only represent the server'sstate. This limitation keeps the data of the cache true to the server data we receive from API-If we still manage to call any of the cache's methods outside of its callbacks in its configuration,+If we still manage to call any of the cache's methods outside its callbacks in its configuration,···Here we use the `cache.updateQuery` method, which is similar to the `cache.readQuery` method that-This method accepts a callback which will give us the `data` of the query, as read from the locally-cached data and we may return an updated version of this data. While we may want to instinctively+This method accepts a callback, which will give us the `data` of the query, as read from the locally+cached data, and we may return an updated version of this data. While we may want to instinctivelyopt for immutably copying and modifying this data, we're actually allowed to mutate it directly,This `data` may also be `null` if the cache doesn't actually have enough locally cached informationto fulfil the query. This is important because resolvers aren't actually applied to cache methods in-updaters. All resolvers are ignored so it becomes impossible to accidentally commit transformed data+updaters. All resolvers are ignored, so it becomes impossible to accidentally commit transformed datato our cache. We could safely add a resolver for `Todo.createdAt` and wouldn't have to worry about···the cache. However, we've used a rather simple example when we've looked at a single list on a known-In many schemas pagination is quite common and when we for instance delete a todo then knowing which-list to update becomes unknowable. We cannot know ahead of time how many pages (and using which-variables) we've already accessed. This knowledge in fact _shouldn't_ be available to Graphcache.-Querying the `Client` is an entirely separate concern that's often colocated with some part of our+In many schemas pagination is quite common, and when we for instance delete a todo then knowing the+lists to update becomes unknowable. We cannot know ahead of time how many pages (and its variables)+we've already accessed. This knowledge in fact _shouldn't_ be available to Graphcache. Querying the···-Suppose we have the above mutation which deletes a `Todo` entity by its ID. Our app may query a list+Suppose we have the above mutation, which deletes a `Todo` entity by its ID. Our app may query a listof these items over many pages with separate queries being sent to our API, which makes it hard to···-Instead, we can **introspect an entity's fields** to find out dynamically which fields we may want-method](../api/graphcache.md#inspectfields). This method accepts a key or a keyable entity like the+method](../api/graphcache.md#inspectfields). This method accepts a key, or a keyable entity like thepage](./local-resolvers.md#resolving-by-keys) or the `cache.resolve` method's first argument.···- `arguments`: The arguments for the given field, since each field that accepts arguments can be···We may use the cache's [`cache.invalidate` method](../api/graphcache.md#invalidate) to eitherinvalidate entire entities or individual fields. It has the same signature as [the `cache.resolve`-method](../api/graphcache.md#resolve) which we've already seen [on the "Local Resolvers" page as+method](../api/graphcache.md#resolve), which we've already seen [on the "Local Resolvers" page aswell](./local-resolvers.md#resolving-other-fields). We can simplify the previous update we've written···If we know what result a mutation may return, why wait for the GraphQL API to fulfill our mutations?-`cacheExchange` which is a factory function using which we can create a "virtual" result for a+`cacheExchange` which is a factory function using, which we can create a "virtual" result for amutation. This temporary result can be applied immediately to the cache to give our users theillusion that mutations were executed immediately, which is a great method to reduce waiting time···- `cache`: The `cache` instance, which gives us access to methods allowing us to interact with the- local cache. Its full API can be found [in the API docs](../api/graphcache.md#cache). On this page-- `info`: This argument shouldn't be used frequently but it contains running information about the+- `info`: This argument shouldn't be used frequently, but it contains running information about theThe usual `parent` argument isn't present since optimistic functions don't have any server data tohandle or deal with and instead create this data. When a mutation is run that contains one or more-optimistic mutation fields, Graphcache picks these up and generates immediate changes which it+optimistic mutation fields, Graphcache picks these up and generates immediate changes, which itapplies to the cache. The `resolvers` functions also trigger as if the results were real server···Sometimes it's not possible for us to retrieve all data that an optimistic update requires to create-This is why Graphcache allows for a small escape hatch for these scenarios which allows us to access-additional variables which we may want to pass from our UI code to the mutation. For instance, given+This is why Graphcache allows for a small escape hatch for these scenarios, which allows us to access+additional variables, which we may want to pass from our UI code to the mutation. For instance, given
+15
-15
docs/graphcache/errors.md
+15
-15
docs/graphcache/errors.md
······························-> Invalid mutation field `???` is not in the defined schema but the `updates` option is referencing it.+> Invalid mutation field `???` is not in the defined schema, but the `updates` option is referencing it.···-> Invalid subscription field: `???` is not in the defined schema but the `updates` option is referencing it.+> Invalid subscription field: `???` is not in the defined schema, but the `updates` option is referencing it.
+9
-9
docs/graphcache/local-resolvers.md
+9
-9
docs/graphcache/local-resolvers.md
···- `args`: The arguments that the field is being called with, which will be replaced with an emptyobject if the field hasn't been called with any arguments. For example, if the field is queried as-- `cache`: Unlike in GraphQL.js this will not be the context but a `cache` instance, which gives us+- `cache`: Unlike in GraphQL.js this will not be the context, but a `cache` instance, which gives usaccess to methods allowing us to interact with the local cache. Its full API can be found [in the-- `info`: This argument shouldn't be used frequently but it contains running information about the+- `info`: This argument shouldn't be used frequently, but it contains running information about the···We may also run into situations where we'd like to generalise the resolver and not make it dependentobject](../api/graphcache.md#info) can be very helpful as it provides us information about the-current query traversal and which part of the query document the cache is currently processing. The-`info.fieldName` property is one of these properties and lets us know which field the resolver is+`info.fieldName` property is one of these properties and lets us know the field that the resolver is···configuration to generate a key for this entity and will then be able to look this entity up in itslocal cache. As with regular queries, the resolver is known to return a link since the `todo(id:···-In the above two examples we've seen how a resolver can replace Graphcache's logic which usually+In the above two examples we've seen how a resolver can replace Graphcache's logic, which usuallyreads links and records only from its locally cached data. We've seen how a field on a record canuse `parent[fieldName]` to access its cached record value and transform it and how a resolver for a···- `entity`: This is the entity on which we'd like to access a field. We may either pass a keyable,partial entity, e.g. `{ __typename: 'Todo', id: 1 }` or a key. It takes the same inputs as [the+`cache.keyOfEntity` method](../api/graphcache.md#keyofentity), which we've seen earlier in the["Resolving by keys" section](#resolving-by-keys). It also accepts `null` which causes it toreturn `null`, which is useful for chaining multiple `resolve` calls for deeply accessing a field.- `fieldName`: This is the field's name we'd like to access. If we're looking for the record on···-At any point, the `cache` allows us to read entirely separate queries in our resolvers which starts+At any point, the `cache` allows us to read entirely separate queries in our resolvers, which startsa separate virtual operation in our resolvers. When we call `cache.readQuery` with a query and
+3
-3
docs/graphcache/offline.md
+3
-3
docs/graphcache/offline.md
···_Graphcache_ allows you to build an offline-first app with built-in offline and persistence support,···`offlineExchange`. The `storage` is an adapter that contains methods for storing cache data in a-By default we can use the default storage option that `@urql/exchange-graphcache` comes with. This+By default, we can use the default storage option that `@urql/exchange-graphcache` comes with. Thisdefault storage uses [IndexedDB](https://developer.mozilla.org/en-US/docs/Web/API/IndexedDB_API) topersist the cache's data. We can use this default storage by importing the `makeDefaultStorage`···[The API docs list the entire interface for the `storage` option.](../api/graphcache.md#storage-option)
+6
-6
docs/graphcache/schema-awareness.md
+6
-6
docs/graphcache/schema-awareness.md
···Previously, [on the "Normalized Caching" page](./normalized-caching.md) we've seen how Graphcachestores normalized data in its store and how it traverses GraphQL documents to do so. What we've seen+is that just using the GraphQL document for traversal, and the `__typename` introspection fieldGraphcache is able to build a normalized caching structure that keeps our application up-to-dateacross API results, allows it to store data by entities and keys, and provides us configuration···- Fragments will be matched deterministically: A fragment can be written to be on an interface typeor multiple fragments can be spread for separate union'ed types in a selection set. In many cases,if Graphcache doesn't have any schema information then it won't know what possible types a fieldwarning](./errors.md#16-heuristic-fragment-matching). If we pass Graphcache a `schema` then it'll- A schema may have non-default names for its root types; `Query`, `Mutation`, and `Subscription`.···start checking whether any of the configuration options actually don't exist, maybe because we've-Graphcache has a schema it knows which fields can be made optional and it'll be able to generate+Graphcache has a schema it knows optional fields that may be left out, and it'll be able to generateAs we navigate an app that uses Graphcache we may be in states where some of our data is already-cached and some isn't. Graphcache normalizes data and stores it in tables for links and records for+cached while some aren't. Graphcache normalizes data and stores it in tables for links and records foreach entity, which means that sometimes it can maybe even execute a query against its cache that it···Without a `schema` and information on which fields are optional, Graphcache will consider a "partial-result" as a cache miss. If we don't have all of the information for a query then we can't execute+result" as a cache miss. If we don't have all the information for a query then we can't executeit against the locally cached data after all. However, an API's schema contains information on which-fields are required and which fields are optional, and if our apps are typed with this schema andTypeScript, can't we then use and handle these partial results before a request is sent to the API?
+1
-1
docs/showcase.md
+1
-1
docs/showcase.md
···