Mirror: The highly customizable and versatile GraphQL client with which you add on features like normalized caching as you grow.
at main 37 kB view raw
1import type { 2 AnyVariables, 3 DocumentInput, 4 RequestExtensions, 5 TypedDocumentNode, 6 FormattedNode, 7 ErrorLike, 8} from '@urql/core'; 9 10import type { DocumentNode, FragmentDefinitionNode } from '@0no-co/graphql.web'; 11import type { IntrospectionData } from './ast'; 12 13/** Nullable GraphQL list types of `T`. 14 * 15 * @remarks 16 * Any GraphQL list of a given type `T` that is nullable is 17 * expected to contain nullable values. Nested lists are 18 * also taken into account in Graphcache. 19 */ 20export type NullArray<T> = Array<null | T | NullArray<T>>; 21 22/** Dictionary of GraphQL Fragment definitions by their names. 23 * 24 * @remarks 25 * A map of {@link FragmentDefinitionNode | FragmentDefinitionNodes} by their 26 * fragment names from the original GraphQL document that Graphcache is 27 * executing. 28 */ 29export interface Fragments { 30 [fragmentName: string]: void | FormattedNode<FragmentDefinitionNode>; 31} 32 33/** Non-object JSON values as serialized by a GraphQL API 34 * @see {@link https://spec.graphql.org/October2021/#sel-DAPJDHAAEJHAKmzP} for the 35 * GraphQL spec’s serialization format. 36 */ 37export type Primitive = null | number | boolean | string; 38 39/** Any GraphQL scalar object 40 * 41 * @remarks 42 * A GraphQL schema may define custom scalars that are resolved 43 * and serialized as objects. These objects could also be turned 44 * on the client-side into a non-JSON object, e.g. a `Date`. 45 * 46 * @see {@link https://spec.graphql.org/October2021/#sec-Scalars} for the 47 * GraphQL spec’s information on custom scalars. 48 */ 49export interface ScalarObject { 50 constructor?: Function; 51 [key: string]: any; 52} 53 54/** GraphQL scalar value 55 * @see {@link https://spec.graphql.org/October2021/#sec-Scalars} for the GraphQL 56 * spec’s definition of scalars 57 */ 58export type Scalar = Primitive | ScalarObject; 59 60/** Fields that Graphcache expects on GraphQL object (“entity”) results. 61 * 62 * @remarks 63 * Any object that comes back from a GraphQL API will have 64 * a `__typename` field from GraphQL Object types. 65 * 66 * The `__typename` field must be present as Graphcache updates 67 * GraphQL queries with type name introspection. 68 * Furthermore, Graphcache always checks for its default key 69 * fields, `id` and `_id` to be present. 70 */ 71export interface SystemFields { 72 /** GraphQL Object type name as returned by Type Name Introspection. 73 * @see {@link https://spec.graphql.org/October2021/#sec-Type-Name-Introspection} for 74 * more information on GraphQL’s Type Name introspection. 75 */ 76 __typename: string; 77 _id?: string | number | null; 78 id?: string | number | null; 79} 80 81/** Scalar values are stored separately from relations between entities. 82 * @internal 83 */ 84export type EntityField = undefined | Scalar | NullArray<Scalar>; 85 86/** Values on GraphQL object (“entity”) results. 87 * 88 * @remarks 89 * Any field that comes back from a GraphQL API will have 90 * values that are scalars, other objects, or arrays 91 * of scalars or objects. 92 */ 93export type DataField = Scalar | Data | NullArray<Scalar> | NullArray<Data>; 94 95/** Definition of GraphQL object (“entity”) fields. 96 * 97 * @remarks 98 * Any object that comes back from a GraphQL API will have 99 * values that are scalars, other objects, or arrays 100 * of scalars or objects, i.e. the {@link DataField} type. 101 */ 102export interface DataFields { 103 [fieldName: string]: DataField; 104} 105 106/** Definition of GraphQL variables objects. 107 * @remarks 108 * Variables, as passed to GraphQL queries, can only contain scalar values. 109 * 110 * @see {@link https://spec.graphql.org/October2021/#sec-Coercing-Variable-Values} for the 111 * GraphQL spec’s coercion of GraphQL variables. 112 */ 113export interface Variables { 114 [name: string]: Scalar | Scalar[] | Variables | NullArray<Variables>; 115} 116 117/** Definition of GraphQL objects (“entities”). 118 * 119 * @remarks 120 * An entity is expected to consist of a `__typename` 121 * fields, optionally the default `id` or `_id` key 122 * fields, and scalar values or other entities 123 * otherwise. 124 */ 125export type Data = SystemFields & DataFields; 126 127/** An entity, a key of an entity, or `null` 128 * 129 * @remarks 130 * When Graphcache accepts a reference to an entity, you may pass it a key of an entity, 131 * as retrieved for instance by {@link Cache.keyOfEntity} or a partial GraphQL object 132 * (i.e. an object with a `__typename` and key field). 133 */ 134export type Entity = undefined | null | Data | string; 135 136/** A key of an entity, or `null`; or a list of keys. 137 * 138 * @remarks 139 * When Graphcache accepts a reference to one or more entities, you may pass it a 140 * key, an entity, or a list of entities or keys. This is often passed to {@link Cache.link} 141 * to update a field pointing to other GraphQL objects. 142 */ 143export type Link<Key = string> = null | Key | NullArray<Key>; 144 145/** Arguments passed to a Graphcache field resolver. 146 * 147 * @remarks 148 * Arguments a field receives are similar to variables and can 149 * only contain scalars or other arguments objects. This 150 * is equivalent to the {@link Variables} type. 151 * 152 * @see {@link https://spec.graphql.org/October2021/#sec-Coercing-Field-Arguments} for the 153 * GraphQL spec’s coercion of field arguments. 154 */ 155export type FieldArgs = Variables | null | undefined; 156 157/** Metadata about an entity’s cached field. 158 * 159 * @remarks 160 * As returned by {@link Cache.inspectFields}, `FieldInfo` specifies an entity’s cached field, 161 * split into the field’s key itself and the field’s original name and arguments. 162 */ 163export interface FieldInfo { 164 /** The field’s key which combines `fieldName` and `arguments`. */ 165 fieldKey: string; 166 /** The field’s name, as defined on a GraphQL Object type. */ 167 fieldName: string; 168 /** The arguments passed to the field as found on the cache. */ 169 arguments: Variables | null; 170} 171 172/** A key to an entity field split back into the entity’s key and the field’s key part. 173 * @internal 174 */ 175export interface KeyInfo { 176 entityKey: string; 177 fieldKey: string; 178} 179 180/** Abstract type for GraphQL requests. 181 * 182 * @remarks 183 * Similarly to `@urql/core`’s `GraphQLRequest` type, `OperationRequest` 184 * requires the minimum fields that Grapcache requires to execute a 185 * GraphQL operation: its query document and variables. 186 */ 187export interface OperationRequest { 188 query: FormattedNode<DocumentNode> | DocumentNode; 189 variables?: any; 190} 191 192/** Metadata object passed to all resolver functions. 193 * 194 * @remarks 195 * `ResolveInfo`, similar to GraphQL.js’ `GraphQLResolveInfo` object, 196 * gives your resolvers a global state of the current GraphQL 197 * document traversal. 198 * 199 * `parent`, `parenTypeName`, `parentKey`, and `parentFieldKey` 200 * are particularly useful to make reusable resolver functions that 201 * must know on which field and type they’re being called on. 202 */ 203export interface ResolveInfo { 204 /** The parent GraphQL object. 205 * 206 * @remarks 207 * The GraphQL object that the resolver has been called on. Because this is 208 * a reference to raw GraphQL data, this may be incomplete or contain 209 * aliased fields! 210 */ 211 parent: Data; 212 /** The parent object’s typename that the resolver has been called on. */ 213 parentTypeName: string; 214 /** The parent object’s entity key that the resolver has been called on. */ 215 parentKey: string; 216 /** Current field’s key that the resolver has been called on. */ 217 parentFieldKey: string; 218 /** Current field that the resolver has been called on. */ 219 fieldName: string; 220 /** Map of fragment definitions from the query document. */ 221 fragments: Fragments; 222 /** Full original {@link Variables} object on the {@link OperationRequest}. */ 223 variables: Variables; 224 /** Error that occurred for the current field, if any. 225 * 226 * @remarks 227 * If a {@link GraphQLError.path} points at the current field, the error 228 * will be set and provided here. This can be useful to recover from an 229 * error on a specific field. 230 */ 231 error: ErrorLike | undefined; 232 /** Flag used to indicate whether the current GraphQL query is only partially cached. 233 * 234 * @remarks 235 * When Graphcache has {@link CacheExchangeOpts.schema} introspection information, 236 * it can automatically generate partial results and trigger a full API request 237 * in the background. 238 * Hence, this field indicates whether any data so far has only been partially 239 * resolved from the cache, and is only in use on {@link Resolver | Resolvers}. 240 * 241 * However, you can also flip this flag to `true` manually to indicate to 242 * the {@link cacheExchange} that it should still make a network request. 243 */ 244 partial?: boolean; 245 /** Flag used to indicate whether the current GraphQL mutation is optimistically executed. 246 * 247 * @remarks 248 * An {@link UpdateResolver} is called for both API mutation responses and 249 * optimistic mutation reuslts, as generated by {@link OptimisticMutationResolver}. 250 * 251 * Since an update sometimes needs to perform different actions if it’s run 252 * optimistically, this flag is set to `true` during optimisti cupdates. 253 */ 254 optimistic?: boolean; 255 /** Internal state used by Graphcache. 256 * @internal 257 */ 258 __internal?: unknown; 259} 260 261/** GraphQL document and variables that should be queried against the cache. 262 * 263 * @remarks 264 * `QueryInput` is a generic GraphQL request that should be executed against 265 * cached data, as accepted by {@link cache.readQuery}. 266 */ 267export interface QueryInput<T = Data, V = Variables> { 268 query: DocumentInput<T, V>; 269 variables?: V; 270} 271 272/** Interface to interact with cached data, which resolvers receive. */ 273export interface Cache { 274 /** Returns the cache key for a given entity or `null` if it’s unkeyable. 275 * 276 * @param entity - the {@link Entity} to generate a key for. 277 * @returns the entity’s key or `null`. 278 * 279 * @remarks 280 * `cache.keyOfEntity` may be called with a partial GraphQL object (“entity”) 281 * and generates a key for it. It uses your {@link KeyingConfig} and otherwise 282 * defaults to `id` and `_id` fields. 283 * 284 * If it’s passed a `string` or `null`, it will simply return what it’s been passed. 285 * Objects that lack a `__typename` field will return `null`. 286 */ 287 keyOfEntity(entity: Entity | undefined): string | null; 288 289 /** Returns the cache key for a field. 290 * 291 * @param fieldName - the field’s name. 292 * @param args - the field’s arguments, if any. 293 * @returns the field key 294 * 295 * @remarks 296 * `cache.keyOfField` is used to create a field’s cache key from a given 297 * field name and its arguments. This is used internally by {@link cache.resolve} 298 * to combine an entity key and a field key into a path that normalized data is 299 * accessed on in Graphcache’s internal data structure. 300 */ 301 keyOfField(fieldName: string, args?: FieldArgs): string | null; 302 303 /** Returns a cached value on a given entity’s field. 304 * 305 * @param entity - a GraphQL object (“entity”) or an entity key. 306 * @param fieldName - the field’s name. 307 * @param args - the field’s arguments, if any. 308 * @returns the field’s value or the entity key(s) this field is pointing at. 309 * 310 * @remarks 311 * `cache.resolve` is used to retrieve either the cached value of a field, or 312 * to get the relation of the field (“link”). When a cached field points at 313 * another normalized entity, this method will return the related entity key 314 * (or a list, if it’s pointing at a list of entities). 315 * 316 * As such, if you’re accessing a nested field, you may have to call 317 * `cache.resolve` again and chain its calls. 318 * 319 * Hint: If you have a field key from {@link FieldInfo} or {@link cache.keyOfField}, 320 * you may pass it as a second argument. 321 * 322 * @example 323 * ```ts 324 * const authorName = cache.resolve( 325 * cache.resolve({ __typename: 'Book', id }, 'author'), 326 * 'name' 327 * ); 328 * ``` 329 */ 330 resolve( 331 entity: Entity | undefined, 332 fieldName: string, 333 args?: FieldArgs 334 ): DataField | undefined; 335 336 /** Returns a list of cached fields for a given GraphQL object (“entity”). 337 * 338 * @param entity - a GraphQL object (“entity”) or an entity key. 339 * @returns a list of {@link FieldInfo} objects. 340 * 341 * @remarks 342 * `cache.inspectFields` can be used to list out all known fields 343 * of a given entity. This can be useful in an {@link UpdateResolver} 344 * if you have a `Query` field that accepts many different arguments, 345 * for instance a paginated field. 346 * 347 * The returned list of fields are all fields that the cache knows about, 348 * and you may have to filter them by name or arguments to find only which 349 * ones you need. 350 * 351 * Hint: This method is theoretically a slower operation than simple 352 * cache lookups, as it has to decode field keys. It’s only recommended 353 * to be used in updaters. 354 */ 355 inspectFields(entity: Entity): FieldInfo[]; 356 357 /** Deletes a cached entity or an entity’s field. 358 * 359 * @param entity - a GraphQL object (“entity”) or an entity key. 360 * @param fieldName - optionally, a field name. 361 * @param args - optionally, the field’s arguments, if any. 362 * 363 * @remarks 364 * `cache.invalidate` can be used in updaters to delete data from 365 * the cache. This will cause the {@link cacheExchange} to reexecute 366 * queries that contain the deleted data. 367 * 368 * If you only pass its first argument, the entire entity is deleted. 369 * However, if a field name (and optionally, its arguments) are passed, 370 * only a single field is erased. 371 */ 372 invalidate( 373 entity: Entity | undefined, 374 fieldName?: string, 375 args?: FieldArgs 376 ): void; 377 378 /** Updates a GraphQL query‘s cached data. 379 * 380 * @param input - a {@link QueryInput}, which is a GraphQL query request. 381 * @param updater - a function called with the query’s result or `null` in case of a cache miss, which 382 * may return updated data, which is written to the cache using the query. 383 * 384 * @remarks 385 * `cache.updateQuery` can be used to update data for an entire GraphQL query document. 386 * When it's passed a GraphQL query request, it calls the passed `updater` function 387 * with the cached result for this query. You may then modify and update the data and 388 * return it, after which it’s written back to the cache. 389 * 390 * Hint: While this allows for large updates at once, {@link cache.link}, 391 * {@link cache.resolve}, and {@link cache.writeFragment} are often better 392 * choices for more granular and compact updater code. 393 * 394 * @example 395 * ```ts 396 * cache.updateQuery({ query: TodoList }, data => { 397 * data.todos.push(newTodo); 398 * return data; 399 * }); 400 * ``` 401 */ 402 updateQuery<T = Data, V = Variables>( 403 input: QueryInput<T, V>, 404 updater: (data: T | null) => T | null 405 ): void; 406 407 /** Returns a GraphQL query‘s cached result. 408 * 409 * @param input - a {@link QueryInput}, which is a GraphQL query request. 410 * @returns the cached data result of the query or `null`, in case of a cache miss. 411 * 412 * @remarks 413 * `cache.readQuery` can be used to read an entire query’s data all at once 414 * from the cache. 415 * 416 * This can be useful when typing out many {@link cache.resolve} 417 * calls is too tedious. 418 * 419 * @example 420 * ```ts 421 * const data = cache.readQuery({ 422 * query: TodosQuery, 423 * variables: { from: 0, limit: 10 } 424 * }); 425 * ``` 426 */ 427 readQuery<T = Data, V = Variables>(input: QueryInput<T, V>): T | null; 428 429 /** Returns a GraphQL fragment‘s cached result. 430 * 431 * @param fragment - a {@link DocumentNode} containing a fragment definition. 432 * @param entity - a GraphQL object (“entity”) or an entity key to read the fragment on. 433 * @param variables - optionally, GraphQL variables, if the fragments use any. 434 * @returns the cached data result of the fragment or `null`, in case of a cache miss. 435 * 436 * @remarks 437 * `cache.readFragment` can be used to read an entire query’s data all at once 438 * from the cache. 439 * 440 * It attempts to read the fragment starting from the `entity` that’s passed to it. 441 * If the entity can’t be resolved or has mismatching types, `null` is returned. 442 * 443 * This can be useful when typing out many {@link cache.resolve} 444 * calls is too tedious. 445 * 446 * @example 447 * ```ts 448 * const data = cache.readFragment( 449 * gql`fragment _ on Todo { id, text }`, 450 * { id: '123' } 451 * ); 452 * ``` 453 */ 454 readFragment<T = Data, V = Variables>( 455 fragment: TypedDocumentNode<any, any> | TypedDocumentNode<T, V>, 456 entity: string | Data | T, 457 variables?: V 458 ): T | null; 459 460 /** Writes a GraphQL fragment to the cache. 461 * 462 * @param fragment - a {@link DocumentNode} containing a fragment definition. 463 * @param data - a GraphQL object to be written with the given fragment. 464 * @param variables - optionally, GraphQL variables, if the fragments use any. 465 * 466 * @remarks 467 * `cache.writeFragment` can be used to write an entity to the cache. 468 * The method will generate a key for the `data` it’s passed, and start writing 469 * it using the fragment. 470 * 471 * This method is used when writing scalar values to the cache. 472 * Since it's rare for an updater to write values to the cache, {@link cache.link} 473 * only allows relations (“links”) to be updated, and `cache.writeFragment` is 474 * instead used when writing multiple scalars. 475 * 476 * @example 477 * ```ts 478 * const data = cache.writeFragment( 479 * gql`fragment _ on Todo { id, text }`, 480 * { id: '123', text: 'New Text' } 481 * ); 482 * ``` 483 */ 484 writeFragment<T = Data, V = Variables>( 485 fragment: TypedDocumentNode<any, any> | TypedDocumentNode<T, V>, 486 data: T, 487 variables?: V 488 ): void; 489 490 /** Updates the relation (“link”) from an entity’s field to another entity. 491 * 492 * @param entity - a GraphQL object (“entity”) or an entity key. 493 * @param fieldName - the field’s name. 494 * @param args - optionally, the field’s arguments, if any. 495 * @param link - the GraphQL object(s) that should be set on this field. 496 * 497 * @remarks 498 * The normalized cache stores relations between GraphQL objects separately. 499 * As such, a field can be updated using `cache.link` to point to a new entity, 500 * or a list of entities. 501 * 502 * In other words, `cache.link` is used to set a field to point to another 503 * entity or a list of entities. 504 * 505 * @example 506 * ```ts 507 * const todos = cache.resolve('Query', 'todos'); 508 * cache.link('Query', 'todos', [...todos, newTodo]); 509 * ``` 510 */ 511 link( 512 entity: Entity, 513 field: string, 514 args: FieldArgs, 515 link: Link<Entity> 516 ): void; 517 link(entity: Entity, field: string, value: Link<Entity>): void; 518} 519 520/** Values a {@link Resolver} may return. 521 * 522 * @remarks 523 * A resolver may return any value that a GraphQL object may contain. 524 * 525 * Additionally however, a resolver may return `undefined` to indicate that data 526 * isn’t available from the cache, i.e. to trigger a cache miss. 527 */ 528export type ResolverResult = 529 | DataField 530 | (DataFields & { __typename?: string }) 531 | null 532 | undefined; 533 534export type Logger = ( 535 severity: 'debug' | 'error' | 'warn', 536 message: string 537) => void; 538 539/** Input parameters for the {@link cacheExchange}. */ 540export type CacheExchangeOpts = { 541 /** Configure a custom-logger for graphcache, this function wll be called with a severity and a message. 542 * 543 * @remarks 544 * By default we will invoke `console.warn` for warnings during development, however you might want to opt 545 * out of this because you are re-using urql for a different library. This setting allows you to stub the logger 546 * function or filter to only logs you want. 547 */ 548 logger?: Logger; 549 /** Configures update functions which are called when the mapped fields are written to the cache. 550 * 551 * @remarks 552 * `updates` are commonly used to define additional changes to the cache for 553 * mutation or subscription fields. It may commonly be used to invalidate 554 * cached data or to modify lists after mutations. 555 * This is a map of types to fields to {@link UpdateResolver} functions. 556 * 557 * @see {@link https://urql.dev/goto/docs/graphcache/cache-updates} for the full updates docs. 558 */ 559 updates?: UpdatesConfig; 560 /** Configures resolvers which replace cached reuslts with custom values. 561 * 562 * @remarks 563 * `resolvers` is a map of types to fields to {@link Resolver} functions. 564 * These functions allow us to replace cached field values with a custom 565 * result, either to replace values on GraphQL results, or to resolve 566 * entities from the cache for queries that haven't been sent to the API 567 * yet. 568 * 569 * @see {@link https://urql.dev/goto/docs/graphcache/local-resolvers} for the full resolvers docs. 570 */ 571 resolvers?: ResolverConfig; 572 /** Configures directives which can perform custom logic on fields. 573 * 574 * @remarks 575 * A {@link DirectivesConfig} may be passed to allow local directives to be used. For example, when `@_custom` is placed on a field and the configuration contains `custom` then this directive is executed by Graphcache. 576 * 577 * @see {@link https://urql.dev/goto/docs/graphcache/local-directives} for the full directives docs. 578 */ 579 directives?: DirectivesConfig; 580 /** Configures optimistic updates to react to mutations instantly before an API response. 581 * 582 * @remarks 583 * `optimistic` is a map of mutation fields to {@link OptimisticMutationResolver} functions. 584 * These functions allow us to return result data for mutations to optimistically apply them. 585 * Optimistic updates are temporary updates to the cache’s data which allow an app to 586 * instantly reflect changes that a mutation will make. 587 * 588 * @see {@link https://urql.dev/goto/docs/graphcache/cache-updates/#optimistic-updates} for the 589 * full optimistic updates docs. 590 */ 591 optimistic?: OptimisticMutationConfig; 592 /** Configures keying functions for GraphQL types. 593 * 594 * @remarks 595 * `keys` is a map of GraphQL object type names to {@link KeyGenerator} functions. 596 * If a type in your API has no key field or a key field that isn't the default 597 * `id` or `_id` fields, you may define a custom key generator for the type. 598 * 599 * Hint: Graphcache will log warnings when it finds objects that have no keyable 600 * fields, which will remind you to define these functions gradually for every 601 * type that needs them. 602 * 603 * @see {@link https://urql.dev/goto/docs/graphcache/normalized-caching/#custom-keys-and-non-keyable-entities} for 604 * the full keys docs. 605 */ 606 keys?: KeyingConfig; 607 /** Enables global IDs for keying GraphQL types. 608 * 609 * @remarks 610 * When `globalIDs` are enabled, GraphQL object type names will not contribute 611 * to the keys of entities and instead only their ID fields (or `keys` return 612 * values will be used. 613 * 614 * This is useful to overlap types of differing typenames. While this isn’t recommended 615 * it can be necessary to represent more complex interface relationships. 616 * 617 * If this should only be applied to a limited set of type names, a list of 618 * type names may be passed instead. 619 */ 620 globalIDs?: string[] | boolean; 621 /** Configures abstract to concrete types mapping for GraphQL types. 622 * 623 * @remarks 624 * This will disable heuristic fragment matching, allowing Graphcache to match 625 * fragment deterministically. 626 * 627 * When both `possibleTypes` and `schema` is set, `possibleTypes` value will be 628 * ignored. 629 */ 630 possibleTypes?: PossibleTypesConfig; 631 /** Configures Graphcache with Schema Introspection data. 632 * 633 * @remarks 634 * Passing a `schema` to Graphcache enables it to do non-heuristic fragment 635 * matching, and be certain when a fragment matches against a union or interface 636 * on your schema. 637 * 638 * It also enables a mode called “Schema Awareness”, which allows Graphcache to 639 * return partial GraphQL results, `null`-ing out fields that aren’t in the cache 640 * that are nullable on your schema, while requesting the full API response in 641 * the background. 642 * 643 * @see {@link https://urql.dev/goto/urql/docs/graphcache/schema-awareness} for 644 * the full keys docs on Schema Awareness. 645 */ 646 schema?: IntrospectionData; 647 /** Configures an offline storage adapter for Graphcache. 648 * 649 * @remarks 650 * A {@link StorageAdapter} allows Graphcache to write data to an external, 651 * asynchronous storage, and hydrate data from it when it first loads. 652 * This allows you to preserve normalized data between restarts/reloads. 653 * 654 * Hint: If you’re trying to use Graphcache’s Offline Support, you may 655 * want to swap out the `cacheExchange` with the {@link offlineExchange}. 656 * 657 * @see {@link https://urql.dev/goto/docs/graphcache/offline} for the full Offline Support docs. 658 */ 659 storage?: StorageAdapter; 660}; 661 662/** Cache Resolver, which may resolve or replace data during cache reads. 663 * 664 * @param parent - The GraphQL object that is currently being constructed from cache data. 665 * @param args - This field’s arguments. 666 * @param cache - {@link Cache} interface. 667 * @param info - {@link ResolveInfo} interface. 668 * @returns a {@link ResolverResult}, which is an updated value, partial entity, or entity key 669 * 670 * @remarks 671 * A `Resolver`, as defined on the {@link ResolverConfig}, is called for 672 * a field’s type during cache reads, and can be used to deserialize or replace 673 * scalar values, or to resolve an entity from cached data, even if the 674 * current field hasn’t been cached from an API response yet. 675 * 676 * For instance, if you have a `Query.picture(id: ID!)` field, you may define 677 * a resolver that returns `{ __typename: 'Picture', id: args.id }`, since you 678 * know the key fields of the GraphQL object. 679 * 680 * @example 681 * ```ts 682 * cacheExchange({ 683 * resolvers: { 684 * Query: { 685 * // resolvers can be used to resolve cached entities without API requests 686 * todo: (_parent, args) => ({ __typename: 'Todo', id: args.id }), 687 * }, 688 * Todo: { 689 * // resolvers can also be used to replace/deserialize scalars 690 * updatedAt: parent => new Date(parent.updatedAt), 691 * }, 692 * }, 693 * }); 694 * ``` 695 * 696 * @see {@link https://urql.dev/goto/docs/graphcache/local-resolvers} for the full resolvers docs. 697 */ 698export type Resolver< 699 ParentData = DataFields, 700 Args = Variables, 701 Result = ResolverResult, 702> = { 703 bivarianceHack( 704 parent: ParentData, 705 args: Args, 706 cache: Cache, 707 info: ResolveInfo 708 ): Result; 709}['bivarianceHack']; 710 711/** Configures resolvers which replace cached reuslts with custom values. 712 * 713 * @remarks 714 * A `ResolverConfig` is a map of types to fields to {@link Resolver} functions. 715 * These functions allow us to replace cached field values with a custom 716 * result, either to replace values on GraphQL results, or to resolve 717 * entities from the cache for queries that haven't been sent to the API 718 * yet. 719 * 720 * @see {@link https://urql.dev/goto/docs/graphcache/local-resolvers} for the full resolvers docs. 721 */ 722export type ResolverConfig = { 723 [typeName: string]: { 724 [fieldName: string]: Resolver | void; 725 } | void; 726}; 727 728export type Directive = ( 729 directiveArguments: Record<string, unknown> | null 730) => Resolver; 731 732export type DirectivesConfig = { 733 [directiveName: string]: Directive; 734}; 735 736/** Cache Updater, which defines additional cache updates after cache writes. 737 * 738 * @param parent - The GraphQL object that is currently being written to the cache. 739 * @param args - This field’s arguments. 740 * @param cache - {@link Cache} interface. 741 * @param info - {@link ResolveInfo} interface. 742 * 743 * @remarks 744 * An `UpdateResolver` (“updater”), as defined on the {@link UpdatesConfig}, is 745 * called for a field’s type during cache writes, and can be used to instruct 746 * the {@link Cache} to perform other cache updates at the same time. 747 * 748 * This is often used, for instance, to update lists or invalidate entities 749 * after a mutation response has come back from the API. 750 * 751 * @example 752 * ```ts 753 * cacheExchange({ 754 * updates: { 755 * Mutation: { 756 * // updaters can invalidate data from the cache 757 * deleteAuthor: (_parent, args, cache) => { 758 * cache.invalidate({ __typename: 'Author', id: args.id }); 759 * }, 760 * }, 761 * }, 762 * }); 763 * ``` 764 * 765 * @see {@link https://urql.dev/goto/docs/graphcache/cache-updates} for the 766 * full cache updates docs. 767 */ 768export type UpdateResolver<ParentData = DataFields, Args = Variables> = { 769 bivarianceHack( 770 parent: ParentData, 771 args: Args, 772 cache: Cache, 773 info: ResolveInfo 774 ): void; 775}['bivarianceHack']; 776 777/** A key functon, which is called to create a cache key for a GraphQL object (“entity”). 778 * 779 * @param data - The GraphQL object that a key is generated for. 780 * @returns a key `string` or `null` or unkeyable objects. 781 * 782 * @remarks 783 * By default, Graphcache will use an object’s `__typename`, and `id` or `_id` fields 784 * to generate a key for an object. However, not all GraphQL objects will have a unique 785 * field, and some objects don’t have a key at all. 786 * 787 * When one of your GraphQL object types has a different key field, you may define a 788 * function on the {@link KeyingConfig} to return its key field. 789 * You may also have objects that don’t have keys, like “Edge” objects, or scalar-like 790 * objects. For these, you can define a function that returns `null`, which tells 791 * Graphcache that it’s an embedded object, which only occurs on its parent and is 792 * globally unique. 793 * 794 * @see {@link https://urql.dev/goto/docs/graphcache/normalized-caching/#custom-keys-and-non-keyable-entities} for 795 * the full keys docs. 796 * 797 * @example 798 * ```ts 799 * cacheExchange({ 800 * keys: { 801 * Image: data => data.url, 802 * LatLng: () => null, 803 * }, 804 * }); 805 * ``` 806 */ 807export type KeyGenerator = { 808 bivarianceHack(data: Data): string | null; 809}['bivarianceHack']; 810 811/** Configures update functions which are called when the mapped fields are written to the cache. 812 * 813 * @remarks 814 * `UpdatesConfig` is a map of types to fields to {@link UpdateResolver} functions. 815 * These update functions are defined to instruct the cache to make additional changes 816 * when a field is written to the cache. 817 * 818 * As changes are often made after a mutation or subscription, the `typeName` is 819 * often set to `'Mutation'` or `'Subscription'`. 820 * 821 * @see {@link https://urql.dev/goto/docs/graphcache/cache-updates} for the full updates docs. 822 * 823 * @example 824 * ```ts 825 * const updates = { 826 * Mutation: { 827 * deleteAuthor(_parent, args, cache) { 828 * // Delete the Author from the cache when Mutation.deleteAuthor is sent 829 * cache.invalidate({ __typename: 'Author', id: args.id }); 830 * }, 831 * }, 832 * }; 833 */ 834export type UpdatesConfig = { 835 [typeName: string | 'Query' | 'Mutation' | 'Subscription']: { 836 [fieldName: string]: UpdateResolver | void; 837 } | void; 838}; 839 840/** Remaps result type to allow for nested optimistic mutation resolvers. 841 * 842 * @remarks 843 * An {@link OptimisticMutationResolver} can not only return partial, nested 844 * mutation result data, but may also contain more optimistic mutation resolvers 845 * for nested fields, which allows fields with arguments to optimistically be 846 * resolved to dynamic values. 847 * 848 * @see {@link OptimisticMutationConfig} for more information. 849 */ 850export type MakeFunctional<T> = T extends { __typename: string } 851 ? WithTypename<{ 852 [P in keyof T]?: MakeFunctional<T[P]>; 853 }> 854 : OptimisticMutationResolver<Variables, T> | T; 855 856/** Optimistic mutation resolver, which may return data that a mutation response will return. 857 * 858 * @param args - This field’s arguments. 859 * @param cache - {@link Cache} interface. 860 * @param info - {@link ResolveInfo} interface. 861 * @returns the field’s optimistic data 862 * 863 * @remarks 864 * Graphcache can update its cache optimistically via the {@link OptimisticMutationConfig}. 865 * An `OptimisticMutationResolver` should return partial data that a mutation will return 866 * once it completes and we receive its result. 867 * 868 * For instance, it could return the data that a deletion mutation may return 869 * optimistically, which might allow an updater to run early and your UI to update 870 * instantly. 871 * 872 * The result that this function returns may miss some fields that your mutation may return, 873 * especially if it contains GraphQL object that are already cached. It may also contain 874 * other, nested resolvers, which allows you to handle fields that accept arguments. 875 */ 876export type OptimisticMutationResolver< 877 Args = Variables, 878 Result = Link<Data> | Scalar, 879> = { 880 bivarianceHack( 881 args: Args, 882 cache: Cache, 883 info: ResolveInfo 884 ): MakeFunctional<Result>; 885}['bivarianceHack']; 886 887/** Configures optimistic result functions which are called to get a mutation’s optimistic result. 888 * 889 * @remarks 890 * `OptimisticMutationConfig` is a map of mutation fields to {@link OptimisticMutationResolver} 891 * functions, which return result data for mutations to optimistically apply them. 892 * Optimistic updates are temporary updates to the cache’s data which allow an app to 893 * instantly reflect changes that a mutation will make. 894 * 895 * Hint: Results returned from optimistic functions may be partial, and may contain functions. 896 * If the returned optimistic object contains functions on fields, these are executed as nested 897 * optimistic resolver functions. 898 * 899 * @see {@link https://urql.dev/goto/docs/graphcache/cache-updates/#optimistic-updates} for the 900 * full optimistic updates docs. 901 * 902 * @example 903 * ```ts 904 * const optimistic = { 905 * updateProfile: (args) => ({ 906 * __typename: 'UserProfile', 907 * id: args.id, 908 * name: args.newName, 909 * }), 910 * }; 911 */ 912export type OptimisticMutationConfig = { 913 [mutationFieldName: string]: OptimisticMutationResolver; 914}; 915 916/** Configures keying functions for GraphQL types. 917 * 918 * @remarks 919 * `KeyingConfig` is a map of GraphQL object type names to {@link KeyGenerator} functions. 920 * If a type in your API has no key field or a key field that isn't the default 921 * `id` or `_id` fields, you may define a custom key generator for the type. 922 * 923 * Keys are important to a normalized cache, because they’re the identity of the object 924 * that is shared across the cache, and helps the cache recognize shared/normalized data. 925 * 926 * Hint: Graphcache will log warnings when it finds objects that have no keyable 927 * fields, which will remind you to define these functions gradually for every 928 * type that needs them. 929 * 930 * @see {@link https://urql.dev/goto/docs/graphcache/normalized-caching/#custom-keys-and-non-keyable-entities} for 931 * the full keys docs. 932 * 933 * @example 934 * ```ts 935 * const keys = { 936 * Image: data => data.url, 937 * LatLng: () => null, 938 * }; 939 * ``` 940 */ 941export type KeyingConfig = { 942 [typename: string]: KeyGenerator; 943}; 944 945export type PossibleTypesConfig = { 946 [abstractType: string]: string[]; 947}; 948 949/** Serialized normalized caching data. */ 950export interface SerializedEntries { 951 [key: string]: string | undefined; 952} 953 954/** A serialized GraphQL request for offline storage. */ 955export interface SerializedRequest { 956 query: string; 957 variables: AnyVariables | undefined; 958 extensions?: RequestExtensions | undefined; 959} 960 961/** Interface for a storage adapter, used by the {@link offlineExchange} for Offline Support. 962 * @see {@link https://urql.dev/goto/docs/graphcache/offline} for the full Offline Support docs. 963 * @see `@urql/exchange-graphcache/default-storage` for an example implementation using IndexedDB. 964 */ 965export interface StorageAdapter { 966 /** Called to rehydrate data when the {@link cacheExchange} first loads. 967 * @remarks 968 * `readData` is called when Graphcache first starts up, and loads cache entries 969 * using which it'll repopulate its normalized cache data. 970 */ 971 readData(): Promise<SerializedEntries>; 972 /** Called by the {@link cacheExchange} to write new data to the offline storage. 973 * @remarks 974 * `writeData` is called when Graphcache updated its cached data and wishes to 975 * persist this data to the offline storage. The data is a partial object and 976 * Graphcache does not write all its data at once. 977 */ 978 writeData(delta: SerializedEntries): Promise<any>; 979 /** Called to rehydrate metadata when the {@link offlineExchange} first loads. 980 * @remarks 981 * `readMetadata` is called when Graphcache first starts up, and loads 982 * metadata informing it of pending mutations that failed while the device 983 * was offline. 984 */ 985 readMetadata?(): Promise<null | SerializedRequest[]>; 986 /** Called by the {@link offlineExchange} to persist failed mutations. 987 * @remarks 988 * `writeMetadata` is called when a mutation failed to persist a queue 989 * of failed mutations to the offline storage that must be retried when 990 * the application is reloaded. 991 */ 992 writeMetadata?(json: SerializedRequest[]): void; 993 /** Called to register a callback called when the device is back online. 994 * @remarks 995 * `onOnline` is called by the {@link offlineExchange} with a callback. 996 * This callback must be called when the device comes back online and 997 * will cause all failed mutations in the queue to be retried. 998 */ 999 onOnline?(cb: () => void): any; 1000 /** Called when the cache has been hydrated with the data from `readData` */ 1001 onCacheHydrated?(): any; 1002} 1003 1004/** Set of keys that have been modified or accessed. 1005 * @internal 1006 */ 1007export type Dependencies = Set<string>; 1008 1009/** The type of cache operation being executed. 1010 * @internal 1011 */ 1012export type OperationType = 'read' | 'write'; 1013 1014/** Casts a given object type to have a required typename field. 1015 * @internal 1016 */ 1017export type WithTypename<T extends { __typename?: any }> = T & { 1018 __typename: NonNullable<T['__typename']>; 1019};