UNPKG

40.1 kBSource Map (JSON)View Raw
1{"version":3,"file":"urql-core.js","sources":["../src/utils/typenames.ts","../src/exchanges/ssr.ts","../src/exchanges/cache.ts","../src/exchanges/subscription.ts","../src/client.ts","../src/utils/maskTypename.ts","../src/utils/withPromise.ts","../src/utils/operation.ts","../src/exchanges/debug.ts","../src/exchanges/dedup.ts","../src/exchanges/fetch.ts","../src/exchanges/fallback.ts","../src/exchanges/compose.ts","../src/exchanges/error.ts","../src/exchanges/index.ts"],"sourcesContent":["import {\n DocumentNode,\n FieldNode,\n InlineFragmentNode,\n SelectionNode,\n Kind,\n visit,\n} from 'graphql';\n\ninterface EntityLike {\n [key: string]: EntityLike | EntityLike[] | any;\n __typename: string | null | void;\n}\n\nconst collectTypes = (obj: EntityLike | EntityLike[], types: string[] = []) => {\n if (Array.isArray(obj)) {\n obj.forEach(inner => {\n collectTypes(inner, types);\n });\n } else if (typeof obj === 'object' && obj !== null) {\n for (const key in obj) {\n if (key === '__typename' && typeof obj[key] === 'string') {\n types.push(obj[key] as string);\n } else {\n collectTypes(obj[key], types);\n }\n }\n }\n\n return types;\n};\n\nexport const collectTypesFromResponse = (response: object) =>\n collectTypes(response as EntityLike).filter((v, i, a) => a.indexOf(v) === i);\n\nconst formatNode = (node: FieldNode | InlineFragmentNode) => {\n if (\n node.selectionSet &&\n !node.selectionSet.selections.some(\n node => node.kind === Kind.FIELD && node.name.value === '__typename'\n )\n ) {\n return {\n ...node,\n selectionSet: {\n ...node.selectionSet,\n selections: [\n ...(node.selectionSet.selections as SelectionNode[]),\n {\n kind: Kind.FIELD,\n name: {\n kind: Kind.NAME,\n value: '__typename',\n },\n },\n ],\n },\n };\n }\n};\n\nexport const formatDocument = <T extends DocumentNode>(node: T): T => {\n const result = visit(node, {\n Field: formatNode,\n InlineFragment: formatNode,\n });\n\n // Ensure that the hash of the resulting document won't suddenly change\n result.__key = (node as any).__key;\n return result;\n};\n","import { GraphQLError } from 'graphql';\nimport { pipe, share, filter, merge, map, tap } from 'wonka';\nimport { Exchange, OperationResult, Operation } from '../types';\nimport { CombinedError } from '../utils';\n\nexport interface SerializedResult {\n data?: string | undefined; // JSON string of data\n error?: {\n graphQLErrors: Array<Partial<GraphQLError> | string>;\n networkError?: string;\n };\n}\n\nexport interface SSRData {\n [key: string]: SerializedResult;\n}\n\nexport interface SSRExchangeParams {\n isClient?: boolean;\n initialState?: SSRData;\n}\n\nexport interface SSRExchange extends Exchange {\n /** Rehydrates cached data */\n restoreData(data: SSRData): void;\n /** Extracts cached data */\n extractData(): SSRData;\n}\n\nconst shouldSkip = ({ kind }: Operation) =>\n kind !== 'subscription' && kind !== 'query';\n\n/** Serialize an OperationResult to plain JSON */\nconst serializeResult = ({\n data,\n error,\n}: OperationResult): SerializedResult => {\n const result: SerializedResult = {\n data: JSON.stringify(data),\n error: undefined,\n };\n\n if (error) {\n result.error = {\n graphQLErrors: error.graphQLErrors.map(error => {\n if (!error.path && !error.extensions) return error.message;\n\n return {\n message: error.message,\n path: error.path,\n extensions: error.extensions,\n };\n }),\n networkError: error.networkError ? '' + error.networkError : undefined,\n };\n }\n\n return result;\n};\n\n/** Deserialize plain JSON to an OperationResult */\nconst deserializeResult = (\n operation: Operation,\n result: SerializedResult\n): OperationResult => {\n const { error, data: dataJson } = result;\n\n const deserialized: OperationResult = {\n operation,\n data: dataJson ? JSON.parse(dataJson) : undefined,\n extensions: undefined,\n error: error\n ? new CombinedError({\n networkError: error.networkError\n ? new Error(error.networkError)\n : undefined,\n graphQLErrors:\n error.graphQLErrors && error.graphQLErrors.length\n ? error.graphQLErrors\n : undefined,\n })\n : undefined,\n };\n\n return deserialized;\n};\n\n/** The ssrExchange can be created to capture data during SSR and also to rehydrate it on the client */\nexport const ssrExchange = (params?: SSRExchangeParams): SSRExchange => {\n const data: SSRData = {};\n\n // On the client-side, we delete results from the cache as they're resolved\n // this is delayed so that concurrent queries don't delete each other's data\n const invalidateQueue: number[] = [];\n const invalidate = (result: OperationResult) => {\n invalidateQueue.push(result.operation.key);\n if (invalidateQueue.length === 1) {\n Promise.resolve().then(() => {\n let key: number | void;\n while ((key = invalidateQueue.shift())) delete data[key];\n });\n }\n };\n\n const isCached = (operation: Operation) => {\n return !shouldSkip(operation) && data[operation.key] !== undefined;\n };\n\n // The SSR Exchange is a temporary cache that can populate results into data for suspense\n // On the client it can be used to retrieve these temporary results from a rehydrated cache\n const ssr: SSRExchange = ({ client, forward }) => ops$ => {\n // params.isClient tells us whether we're on the client-side\n // By default we assume that we're on the client if suspense-mode is disabled\n const isClient =\n params && typeof params.isClient === 'boolean'\n ? !!params.isClient\n : !client.suspense;\n\n const sharedOps$ = share(ops$);\n\n let forwardedOps$ = pipe(\n sharedOps$,\n filter(op => !isCached(op)),\n forward\n );\n\n // NOTE: Since below we might delete the cached entry after accessing\n // it once, cachedOps$ needs to be merged after forwardedOps$\n let cachedOps$ = pipe(\n sharedOps$,\n filter(op => isCached(op)),\n map(op => {\n const serialized = data[op.key];\n return deserializeResult(op, serialized);\n })\n );\n\n if (!isClient) {\n // On the server we cache results in the cache as they're resolved\n forwardedOps$ = pipe(\n forwardedOps$,\n tap((result: OperationResult) => {\n const { operation } = result;\n if (!shouldSkip(operation)) {\n const serialized = serializeResult(result);\n data[operation.key] = serialized;\n }\n })\n );\n } else {\n // On the client we delete results from the cache as they're resolved\n cachedOps$ = pipe(cachedOps$, tap(invalidate));\n }\n\n return merge([forwardedOps$, cachedOps$]);\n };\n\n ssr.restoreData = (restore: SSRData) => Object.assign(data, restore);\n ssr.extractData = () => Object.assign({}, data);\n\n if (params && params.initialState) {\n ssr.restoreData(params.initialState);\n }\n\n return ssr;\n};\n","/* eslint-disable @typescript-eslint/no-use-before-define */\nimport { filter, map, merge, pipe, share, tap } from 'wonka';\n\nimport { Client } from '../client';\nimport { Exchange, Operation, OperationResult, ExchangeInput } from '../types';\n\nimport {\n makeOperation,\n addMetadata,\n collectTypesFromResponse,\n formatDocument,\n} from '../utils';\n\ntype ResultCache = Map<number, OperationResult>;\n\ninterface OperationCache {\n [key: string]: Set<number>;\n}\n\nconst shouldSkip = ({ kind }: Operation) =>\n kind !== 'mutation' && kind !== 'query';\n\nexport const cacheExchange: Exchange = ({ forward, client, dispatchDebug }) => {\n const resultCache = new Map() as ResultCache;\n const operationCache = Object.create(null) as OperationCache;\n\n // Adds unique typenames to query (for invalidating cache entries)\n const mapTypeNames = (operation: Operation): Operation => {\n const formattedOperation = makeOperation(operation.kind, operation);\n formattedOperation.query = formatDocument(operation.query);\n return formattedOperation;\n };\n\n const handleAfterMutation = afterMutation(\n resultCache,\n operationCache,\n client,\n dispatchDebug\n );\n\n const handleAfterQuery = afterQuery(resultCache, operationCache);\n\n const isOperationCached = (operation: Operation) => {\n const {\n key,\n kind,\n context: { requestPolicy },\n } = operation;\n return (\n kind === 'query' &&\n requestPolicy !== 'network-only' &&\n (requestPolicy === 'cache-only' || resultCache.has(key))\n );\n };\n\n return ops$ => {\n const sharedOps$ = share(ops$);\n\n const cachedOps$ = pipe(\n sharedOps$,\n filter(op => !shouldSkip(op) && isOperationCached(op)),\n map(operation => {\n const cachedResult = resultCache.get(operation.key);\n\n dispatchDebug({\n operation,\n ...(cachedResult\n ? {\n type: 'cacheHit',\n message: 'The result was successfully retried from the cache',\n }\n : {\n type: 'cacheMiss',\n message: 'The result could not be retrieved from the cache',\n }),\n });\n\n const result: OperationResult = {\n ...cachedResult,\n operation: addMetadata(operation, {\n cacheOutcome: cachedResult ? 'hit' : 'miss',\n }),\n };\n\n if (operation.context.requestPolicy === 'cache-and-network') {\n result.stale = true;\n reexecuteOperation(client, operation);\n }\n\n return result;\n })\n );\n\n const forwardedOps$ = pipe(\n merge([\n pipe(\n sharedOps$,\n filter(op => !shouldSkip(op) && !isOperationCached(op)),\n map(mapTypeNames)\n ),\n pipe(\n sharedOps$,\n filter(op => shouldSkip(op))\n ),\n ]),\n map(op => addMetadata(op, { cacheOutcome: 'miss' })),\n filter(\n op => op.kind !== 'query' || op.context.requestPolicy !== 'cache-only'\n ),\n forward,\n tap(response => {\n if (response.operation && response.operation.kind === 'mutation') {\n handleAfterMutation(response);\n } else if (response.operation && response.operation.kind === 'query') {\n handleAfterQuery(response);\n }\n })\n );\n\n return merge([cachedOps$, forwardedOps$]);\n };\n};\n\n// Reexecutes a given operation with the default requestPolicy\nconst reexecuteOperation = (client: Client, operation: Operation) => {\n return client.reexecuteOperation(\n makeOperation(operation.kind, operation, {\n ...operation.context,\n requestPolicy: 'network-only',\n })\n );\n};\n\n// Invalidates the cache given a mutation's response\nexport const afterMutation = (\n resultCache: ResultCache,\n operationCache: OperationCache,\n client: Client,\n dispatchDebug: ExchangeInput['dispatchDebug']\n) => (response: OperationResult) => {\n const pendingOperations = new Set<number>();\n const { additionalTypenames } = response.operation.context;\n\n const typenames = [\n ...collectTypesFromResponse(response.data),\n ...(additionalTypenames || []),\n ];\n\n dispatchDebug({\n type: 'cacheInvalidation',\n message: `The following typenames have been invalidated: ${typenames}`,\n operation: response.operation,\n data: { typenames, response },\n });\n\n typenames.forEach(typeName => {\n const operations =\n operationCache[typeName] || (operationCache[typeName] = new Set());\n operations.forEach(key => {\n pendingOperations.add(key);\n });\n operations.clear();\n });\n\n pendingOperations.forEach(key => {\n if (resultCache.has(key)) {\n const operation = (resultCache.get(key) as OperationResult).operation;\n resultCache.delete(key);\n reexecuteOperation(client, operation);\n }\n });\n};\n\n// Mark typenames on typenameInvalidate for early invalidation\nconst afterQuery = (\n resultCache: ResultCache,\n operationCache: OperationCache\n) => (response: OperationResult) => {\n const { operation, data, error } = response;\n const { additionalTypenames } = operation.context;\n\n if (data === undefined || data === null) {\n return;\n }\n\n resultCache.set(operation.key, { operation, data, error });\n\n [\n ...collectTypesFromResponse(response.data),\n ...(additionalTypenames || []),\n ].forEach(typeName => {\n const operations =\n operationCache[typeName] || (operationCache[typeName] = new Set());\n operations.add(operation.key);\n });\n};\n","import { print } from 'graphql';\n\nimport {\n filter,\n make,\n merge,\n mergeMap,\n pipe,\n share,\n Source,\n takeUntil,\n} from 'wonka';\n\nimport { makeResult, makeErrorResult, makeOperation } from '../utils';\n\nimport {\n Exchange,\n ExecutionResult,\n Operation,\n OperationContext,\n OperationResult,\n} from '../types';\n\nexport interface ObserverLike<T> {\n next: (value: T) => void;\n error: (err: any) => void;\n complete: () => void;\n}\n\n/** An abstract observable interface conforming to: https://github.com/tc39/proposal-observable */\nexport interface ObservableLike<T> {\n subscribe(\n observer: ObserverLike<T>\n ): {\n unsubscribe: () => void;\n };\n}\n\nexport interface SubscriptionOperation {\n query: string;\n variables?: Record<string, unknown>;\n key: string;\n context: OperationContext;\n}\n\nexport type SubscriptionForwarder = (\n operation: SubscriptionOperation\n) => ObservableLike<ExecutionResult & { extensions?: Record<string, any> }>;\n\n/** This is called to create a subscription and needs to be hooked up to a transport client. */\nexport interface SubscriptionExchangeOpts {\n // This has been modelled to work with subscription-transport-ws\n // See: https://github.com/apollographql/subscriptions-transport-ws#requestoptions--observableexecutionresult-returns-observable-to-execute-the-operation\n forwardSubscription: SubscriptionForwarder;\n\n /** This flag may be turned on to allow your subscriptions-transport to handle all operation types */\n enableAllOperations?: boolean;\n}\n\nexport const subscriptionExchange = ({\n forwardSubscription,\n enableAllOperations,\n}: SubscriptionExchangeOpts): Exchange => ({ client, forward }) => {\n const createSubscriptionSource = (\n operation: Operation\n ): Source<OperationResult> => {\n // This excludes the query's name as a field although subscription-transport-ws does accept it since it's optional\n const observableish = forwardSubscription({\n key: operation.key.toString(36),\n query: print(operation.query),\n variables: operation.variables,\n context: { ...operation.context },\n });\n\n return make<OperationResult>(({ next, complete }) => {\n let isComplete = false;\n let sub;\n\n Promise.resolve().then(() => {\n if (isComplete) return;\n\n sub = observableish.subscribe({\n next: result => next(makeResult(operation, result)),\n error: err => next(makeErrorResult(operation, err)),\n complete: () => {\n if (!isComplete) {\n isComplete = true;\n if (operation.kind === 'subscription') {\n client.reexecuteOperation(\n makeOperation('teardown', operation, operation.context)\n );\n }\n\n complete();\n }\n },\n });\n });\n\n return () => {\n isComplete = true;\n if (sub) sub.unsubscribe();\n };\n });\n };\n\n const isSubscriptionOperation = (operation: Operation): boolean => {\n const { kind } = operation;\n return (\n kind === 'subscription' ||\n (!!enableAllOperations && (kind === 'query' || kind === 'mutation'))\n );\n };\n\n return ops$ => {\n const sharedOps$ = share(ops$);\n const subscriptionResults$ = pipe(\n sharedOps$,\n filter(isSubscriptionOperation),\n mergeMap(operation => {\n const { key } = operation;\n const teardown$ = pipe(\n sharedOps$,\n filter(op => op.kind === 'teardown' && op.key === key)\n );\n\n return pipe(createSubscriptionSource(operation), takeUntil(teardown$));\n })\n );\n\n const forward$ = pipe(\n sharedOps$,\n filter(op => !isSubscriptionOperation(op)),\n forward\n );\n\n return merge([subscriptionResults$, forward$]);\n };\n};\n","/* eslint-disable @typescript-eslint/no-use-before-define */\n\nimport {\n filter,\n makeSubject,\n onEnd,\n onStart,\n pipe,\n share,\n Source,\n take,\n takeUntil,\n merge,\n interval,\n fromValue,\n switchMap,\n publish,\n subscribe,\n map,\n Subscription,\n} from 'wonka';\n\nimport { TypedDocumentNode } from '@graphql-typed-document-node/core';\nimport { DocumentNode } from 'graphql';\n\nimport { composeExchanges, defaultExchanges } from './exchanges';\nimport { fallbackExchange } from './exchanges/fallback';\n\nimport {\n Exchange,\n ExchangeInput,\n GraphQLRequest,\n Operation,\n OperationContext,\n OperationResult,\n OperationType,\n RequestPolicy,\n PromisifiedSource,\n DebugEvent,\n} from './types';\n\nimport {\n createRequest,\n withPromise,\n maskTypename,\n noop,\n makeOperation,\n} from './utils';\n\n/** Options for configuring the URQL [client]{@link Client}. */\nexport interface ClientOptions {\n /** Target endpoint URL such as `https://my-target:8080/graphql`. */\n url: string;\n /** Any additional options to pass to fetch. */\n fetchOptions?: RequestInit | (() => RequestInit);\n /** An alternative fetch implementation. */\n fetch?: typeof fetch;\n /** An ordered array of Exchanges. */\n exchanges?: Exchange[];\n /** Activates support for Suspense. */\n suspense?: boolean;\n /** The default request policy for requests. */\n requestPolicy?: RequestPolicy;\n /** Use HTTP GET for queries. */\n preferGetMethod?: boolean;\n /** Mask __typename from results. */\n maskTypename?: boolean;\n}\n\ninterface ActiveOperations {\n [operationKey: string]: number;\n}\n\nexport const createClient = (opts: ClientOptions) => new Client(opts);\n\n/** The URQL application-wide client library. Each execute method starts a GraphQL request and returns a stream of results. */\nexport class Client {\n /** Start an operation from an exchange */\n reexecuteOperation: (operation: Operation) => void;\n\n // Event target for monitoring\n subscribeToDebugTarget?: (onEvent: (e: DebugEvent) => void) => Subscription;\n\n // These are variables derived from ClientOptions\n url: string;\n fetch?: typeof fetch;\n fetchOptions?: RequestInit | (() => RequestInit);\n suspense: boolean;\n preferGetMethod: boolean;\n requestPolicy: RequestPolicy;\n maskTypename: boolean;\n\n // These are internals to be used to keep track of operations\n dispatchOperation: (operation?: Operation | void) => void;\n operations$: Source<Operation>;\n results$: Source<OperationResult>;\n activeOperations = Object.create(null) as ActiveOperations;\n queue: Operation[] = [];\n\n constructor(opts: ClientOptions) {\n if (process.env.NODE_ENV !== 'production' && !opts.url) {\n throw new Error('You are creating an urql-client without a url.');\n }\n\n let dispatchDebug: ExchangeInput['dispatchDebug'] = noop;\n if (process.env.NODE_ENV !== 'production') {\n const { next, source } = makeSubject<DebugEvent>();\n this.subscribeToDebugTarget = (onEvent: (e: DebugEvent) => void) =>\n pipe(source, subscribe(onEvent));\n dispatchDebug = next as ExchangeInput['dispatchDebug'];\n }\n\n this.url = opts.url;\n this.fetchOptions = opts.fetchOptions;\n this.fetch = opts.fetch;\n this.suspense = !!opts.suspense;\n this.requestPolicy = opts.requestPolicy || 'cache-first';\n this.preferGetMethod = !!opts.preferGetMethod;\n this.maskTypename = !!opts.maskTypename;\n\n // This subject forms the input of operations; executeOperation may be\n // called to dispatch a new operation on the subject\n const { source: operations$, next: nextOperation } = makeSubject<\n Operation\n >();\n this.operations$ = operations$;\n\n let isOperationBatchActive = false;\n this.dispatchOperation = (operation?: Operation | void) => {\n isOperationBatchActive = true;\n if (operation) nextOperation(operation);\n while ((operation = this.queue.shift())) nextOperation(operation);\n isOperationBatchActive = false;\n };\n\n this.reexecuteOperation = (operation: Operation) => {\n // Reexecute operation only if any subscribers are still subscribed to the\n // operation's exchange results\n if (\n operation.kind === 'mutation' ||\n (this.activeOperations[operation.key] || 0) > 0\n ) {\n this.queue.push(operation);\n if (!isOperationBatchActive) {\n Promise.resolve().then(this.dispatchOperation);\n }\n }\n };\n\n const exchanges =\n opts.exchanges !== undefined ? opts.exchanges : defaultExchanges;\n\n // All exchange are composed into a single one and are called using the constructed client\n // and the fallback exchange stream\n const composedExchange = composeExchanges(exchanges);\n\n // All exchanges receive inputs using which they can forward operations to the next exchange\n // and receive a stream of results in return, access the client, or dispatch debugging events\n // All operations then run through the Exchange IOs in a pipeline-like fashion\n this.results$ = share(\n composedExchange({\n client: this,\n dispatchDebug,\n forward: fallbackExchange({ dispatchDebug }),\n })(this.operations$)\n );\n\n // Prevent the `results$` exchange pipeline from being closed by active\n // cancellations cascading up from components\n pipe(this.results$, publish);\n }\n\n createOperationContext = (\n opts?: Partial<OperationContext>\n ): OperationContext => {\n if (!opts) opts = {};\n\n return {\n url: this.url,\n fetchOptions: this.fetchOptions,\n fetch: this.fetch,\n preferGetMethod: this.preferGetMethod,\n ...opts,\n suspense: opts.suspense || (opts.suspense !== false && this.suspense),\n requestPolicy: opts.requestPolicy || this.requestPolicy,\n };\n };\n\n createRequestOperation = <Data = any, Variables = object>(\n kind: OperationType,\n request: GraphQLRequest<Data, Variables>,\n opts?: Partial<OperationContext>\n ): Operation<Data, Variables> =>\n makeOperation<Data, Variables>(\n kind,\n request,\n this.createOperationContext(opts)\n );\n\n /** Counts up the active operation key and dispatches the operation */\n private onOperationStart(operation: Operation) {\n const { key } = operation;\n this.activeOperations[key] = (this.activeOperations[key] || 0) + 1;\n this.dispatchOperation(operation);\n }\n\n /** Deletes an active operation's result observable and sends a teardown signal through the exchange pipeline */\n private onOperationEnd(operation: Operation) {\n const { key } = operation;\n const prevActive = this.activeOperations[key] || 0;\n const newActive = (this.activeOperations[key] =\n prevActive <= 0 ? 0 : prevActive - 1);\n // Check whether this operation has now become inactive\n if (newActive <= 0) {\n // Delete all related queued up operations for the inactive one\n for (let i = this.queue.length - 1; i >= 0; i--)\n if (this.queue[i].key === operation.key) this.queue.splice(i, 1);\n // Issue the cancellation teardown operation\n this.dispatchOperation(\n makeOperation('teardown', operation, operation.context)\n );\n }\n }\n\n /** Executes an Operation by sending it through the exchange pipeline It returns an observable that emits all related exchange results and keeps track of this observable's subscribers. A teardown signal will be emitted when no subscribers are listening anymore. */\n executeRequestOperation<Data = any, Variables = object>(\n operation: Operation<Data, Variables>\n ): Source<OperationResult<Data, Variables>> {\n let operationResults$ = pipe(\n this.results$,\n filter((res: OperationResult) => res.operation.key === operation.key)\n ) as Source<OperationResult<Data, Variables>>;\n\n if (this.maskTypename) {\n operationResults$ = pipe(\n operationResults$,\n map(res => {\n res.data = maskTypename(res.data);\n return res;\n })\n );\n }\n\n if (operation.kind === 'mutation') {\n // A mutation is always limited to just a single result and is never shared\n return pipe(\n operationResults$,\n onStart<OperationResult>(() => this.dispatchOperation(operation)),\n take(1)\n );\n }\n\n const teardown$ = pipe(\n this.operations$,\n filter(\n (op: Operation) => op.kind === 'teardown' && op.key === operation.key\n )\n );\n\n const result$ = pipe(\n operationResults$,\n takeUntil(teardown$),\n onStart<OperationResult>(() => {\n this.onOperationStart(operation);\n }),\n onEnd<OperationResult>(() => {\n this.onOperationEnd(operation);\n })\n );\n\n if (operation.kind === 'query' && operation.context.pollInterval) {\n return pipe(\n merge([fromValue(0), interval(operation.context.pollInterval)]),\n switchMap(() => result$)\n );\n }\n\n return result$;\n }\n\n query<Data = any, Variables extends object = {}>(\n query: DocumentNode | TypedDocumentNode<Data, Variables> | string,\n variables?: Variables,\n context?: Partial<OperationContext>\n ): PromisifiedSource<OperationResult<Data, Variables>> {\n if (!context || typeof context.suspense !== 'boolean') {\n context = { ...context, suspense: false };\n }\n\n return withPromise<OperationResult<Data, Variables>>(\n this.executeQuery<Data, Variables>(\n createRequest(query, variables),\n context\n )\n );\n }\n\n readQuery<Data = any, Variables extends object = {}>(\n query: DocumentNode | TypedDocumentNode<Data, Variables> | string,\n variables?: Variables,\n context?: Partial<OperationContext>\n ): OperationResult<Data, Variables> | null {\n let result: OperationResult<Data, Variables> | null = null;\n\n pipe(\n this.executeQuery(createRequest(query, variables), context),\n subscribe(res => {\n result = res;\n })\n ).unsubscribe();\n\n return result;\n }\n\n executeQuery = <Data = any, Variables = object>(\n query: GraphQLRequest<Data, Variables>,\n opts?: Partial<OperationContext>\n ): Source<OperationResult<Data, Variables>> => {\n const operation = this.createRequestOperation('query', query, opts);\n return this.executeRequestOperation<Data, Variables>(operation);\n };\n\n subscription<Data = any, Variables extends object = {}>(\n query: DocumentNode | TypedDocumentNode<Data, Variables> | string,\n variables?: Variables,\n context?: Partial<OperationContext>\n ): Source<OperationResult<Data, Variables>> {\n return this.executeSubscription<Data, Variables>(\n createRequest(query, variables),\n context\n );\n }\n\n executeSubscription = <Data = any, Variables = object>(\n query: GraphQLRequest<Data, Variables>,\n opts?: Partial<OperationContext>\n ): Source<OperationResult<Data, Variables>> => {\n const operation = this.createRequestOperation('subscription', query, opts);\n return this.executeRequestOperation<Data, Variables>(operation);\n };\n\n mutation<Data = any, Variables extends object = {}>(\n query: DocumentNode | TypedDocumentNode<Data, Variables> | string,\n variables?: Variables,\n context?: Partial<OperationContext>\n ): PromisifiedSource<OperationResult<Data, Variables>> {\n return withPromise<OperationResult<Data, Variables>>(\n this.executeMutation<Data, Variables>(\n createRequest(query, variables),\n context\n )\n );\n }\n\n executeMutation = <Data = any, Variables = object>(\n query: GraphQLRequest<Data, Variables>,\n opts?: Partial<OperationContext>\n ): Source<OperationResult<Data, Variables>> => {\n const operation = this.createRequestOperation('mutation', query, opts);\n return this.executeRequestOperation<Data, Variables>(operation);\n };\n}\n","export const maskTypename = (data: any): any => {\n if (!data || typeof data !== 'object') return data;\n\n return Object.keys(data).reduce((acc, key: string) => {\n const value = data[key];\n if (key === '__typename') {\n Object.defineProperty(acc, '__typename', {\n enumerable: false,\n value,\n });\n } else if (Array.isArray(value)) {\n acc[key] = value.map(maskTypename);\n } else if (value && typeof value === 'object' && '__typename' in value) {\n acc[key] = maskTypename(value);\n } else {\n acc[key] = value;\n }\n\n return acc;\n }, {});\n};\n","import { Source, pipe, toPromise, take } from 'wonka';\nimport { PromisifiedSource } from '../types';\n\nexport function withPromise<T>(source$: Source<T>): PromisifiedSource<T> {\n (source$ as PromisifiedSource<T>).toPromise = () =>\n pipe(source$, take(1), toPromise);\n return source$ as PromisifiedSource<T>;\n}\n","import {\n GraphQLRequest,\n Operation,\n OperationContext,\n OperationType,\n} from '../types';\nimport { Warning, deprecationWarning } from './deprecation';\n\n// TODO: Remove when the deprecated `operationName` property is removed\nconst DEPRECATED: Record<string, Warning> = {\n operationName: {\n key: 'Operation.operationName',\n message:\n 'The \"Operation.operationName\" property has been deprecated and will be removed in a future release of urql. Use \"Operation.kind\" instead.',\n },\n};\n\nfunction makeOperation<Data = any, Variables = object>(\n kind: OperationType,\n request: GraphQLRequest<Data, Variables>,\n context: OperationContext\n): Operation<Data, Variables>;\n\nfunction makeOperation<Data = any, Variables = object>(\n kind: OperationType,\n request: Operation<Data, Variables>,\n context?: OperationContext\n): Operation<Data, Variables>;\n\nfunction makeOperation(kind, request, context) {\n if (!context) context = request.context;\n\n return {\n key: request.key,\n query: request.query,\n variables: request.variables,\n kind,\n context,\n\n get operationName(): OperationType {\n deprecationWarning(DEPRECATED.operationName);\n\n return this.kind;\n },\n };\n}\n\nexport { makeOperation };\n\n/** Spreads the provided metadata to the source operation's meta property in context. */\nexport const addMetadata = (\n operation: Operation,\n meta: OperationContext['meta']\n) => {\n return makeOperation(operation.kind, operation, {\n ...operation.context,\n meta: {\n ...operation.context.meta,\n ...meta,\n },\n });\n};\n","import { pipe, tap } from 'wonka';\nimport { Exchange } from '../types';\n\nexport const debugExchange: Exchange = ({ forward }) => {\n if (process.env.NODE_ENV === 'production') {\n return ops$ => forward(ops$);\n } else {\n return ops$ =>\n pipe(\n ops$,\n // eslint-disable-next-line no-console\n tap(op => console.log('[Exchange debug]: Incoming operation: ', op)),\n forward,\n tap(result =>\n // eslint-disable-next-line no-console\n console.log('[Exchange debug]: Completed operation: ', result)\n )\n );\n }\n};\n","import { filter, pipe, tap } from 'wonka';\nimport { Exchange, Operation, OperationResult } from '../types';\n\n/** A default exchange for debouncing GraphQL requests. */\nexport const dedupExchange: Exchange = ({ forward, dispatchDebug }) => {\n const inFlightKeys = new Set<number>();\n\n const filterIncomingOperation = (operation: Operation) => {\n const { key, kind } = operation;\n if (kind === 'teardown') {\n inFlightKeys.delete(key);\n return true;\n }\n\n if (kind !== 'query' && kind !== 'subscription') {\n return true;\n }\n\n const isInFlight = inFlightKeys.has(key);\n inFlightKeys.add(key);\n\n if (isInFlight) {\n dispatchDebug({\n type: 'dedup',\n message: 'An operation has been deduped.',\n operation,\n });\n }\n\n return !isInFlight;\n };\n\n const afterOperationResult = ({ operation }: OperationResult) => {\n inFlightKeys.delete(operation.key);\n };\n\n return ops$ => {\n const forward$ = pipe(ops$, filter(filterIncomingOperation));\n return pipe(forward(forward$), tap(afterOperationResult));\n };\n};\n","/* eslint-disable @typescript-eslint/no-use-before-define */\nimport { filter, merge, mergeMap, pipe, share, takeUntil, onPush } from 'wonka';\n\nimport { Exchange } from '../types';\nimport {\n makeFetchBody,\n makeFetchURL,\n makeFetchOptions,\n makeFetchSource,\n} from '../internal';\n\n/** A default exchange for fetching GraphQL requests. */\nexport const fetchExchange: Exchange = ({ forward, dispatchDebug }) => {\n return ops$ => {\n const sharedOps$ = share(ops$);\n const fetchResults$ = pipe(\n sharedOps$,\n filter(operation => {\n return operation.kind === 'query' || operation.kind === 'mutation';\n }),\n mergeMap(operation => {\n const { key } = operation;\n const teardown$ = pipe(\n sharedOps$,\n filter(op => op.kind === 'teardown' && op.key === key)\n );\n\n const body = makeFetchBody(operation);\n const url = makeFetchURL(operation, body);\n const fetchOptions = makeFetchOptions(operation, body);\n\n dispatchDebug({\n type: 'fetchRequest',\n message: 'A fetch request is being executed.',\n operation,\n data: {\n url,\n fetchOptions,\n },\n });\n\n return pipe(\n makeFetchSource(operation, url, fetchOptions),\n takeUntil(teardown$),\n onPush(result => {\n const error = !result.data ? result.error : undefined;\n\n dispatchDebug({\n type: error ? 'fetchError' : 'fetchSuccess',\n message: `A ${\n error ? 'failed' : 'successful'\n } fetch response has been returned.`,\n operation,\n data: {\n url,\n fetchOptions,\n value: error || result,\n },\n });\n })\n );\n })\n );\n\n const forward$ = pipe(\n sharedOps$,\n filter(operation => {\n return operation.kind !== 'query' && operation.kind !== 'mutation';\n }),\n forward\n );\n\n return merge([fetchResults$, forward$]);\n };\n};\n","import { filter, pipe, tap } from 'wonka';\nimport { Operation, ExchangeIO, ExchangeInput } from '../types';\nimport { noop } from '../utils';\n\n/** This is always the last exchange in the chain; No operation should ever reach it */\nexport const fallbackExchange: ({\n dispatchDebug,\n}: Pick<ExchangeInput, 'dispatchDebug'>) => ExchangeIO = ({\n dispatchDebug,\n}) => ops$ =>\n pipe(\n ops$,\n tap<Operation>(operation => {\n if (\n operation.kind !== 'teardown' &&\n process.env.NODE_ENV !== 'production'\n ) {\n const message = `No exchange has handled operations of kind \"${operation.kind}\". Check whether you've added an exchange responsible for these operations.`;\n\n dispatchDebug({\n type: 'fallbackCatch',\n message,\n operation,\n });\n console.warn(message);\n }\n }),\n /* All operations that skipped through the entire exchange chain should be filtered from the output */\n filter<any>(() => false)\n );\n\nexport const fallbackExchangeIO: ExchangeIO = fallbackExchange({\n dispatchDebug: noop,\n});\n","import { Exchange, ExchangeInput } from '../types';\n\n/** This composes an array of Exchanges into a single ExchangeIO function */\nexport const composeExchanges = (exchanges: Exchange[]) => ({\n client,\n forward,\n dispatchDebug,\n}: ExchangeInput) =>\n exchanges.reduceRight(\n (forward, exchange) =>\n exchange({\n client,\n forward,\n dispatchDebug(event) {\n dispatchDebug({\n timestamp: Date.now(),\n source: exchange.name,\n ...event,\n });\n },\n }),\n forward\n );\n","import { pipe, tap } from 'wonka';\nimport { Exchange, Operation } from '../types';\nimport { CombinedError } from '../utils';\n\nexport const errorExchange = ({\n onError,\n}: {\n onError: (error: CombinedError, operation: Operation) => void;\n}): Exchange => ({ forward }) => ops$ => {\n return pipe(\n forward(ops$),\n tap(({ error, operation }) => {\n if (error) {\n onError(error, operation);\n }\n })\n );\n};\n","export { ssrExchange } from './ssr';\nexport { cacheExchange } from './cache';\nexport { subscriptionExchange } from './subscription';\nexport { debugExchange } from './debug';\nexport { dedupExchange } from './dedup';\nexport { fetchExchange } from './fetch';\nexport { fallbackExchangeIO } from './fallback';\nexport { composeExchanges } from './compose';\nexport { errorExchange } from './error';\n\nimport { cacheExchange } from './cache';\nimport { dedupExchange } from './dedup';\nimport { fetchExchange } from './fetch';\n\nexport const defaultExchanges = [dedupExchange, cacheExchange, fetchExchange];\n"],"names":["node","result","invalidateQueue","operation","formattedOperation","Promise","observableish","a","complete","isComplete","i","queue","types","obj","Array","data","withPromise","toPromise","makeOperation","merge","_extends","c","isOperationCached","tap","resultCache","reexecuteOperation","length","typeName","response","operationCache","makeResult","mergeMap","filter","console","process","key","inFlightKeys","isInFlight","ops$","afterOperationResult","forward","fetchExchange","op","onPush","takeUntil","forward$","d","exchange","onError","dedupExchange","onEvent","opts","this","then","subscribe","nextOperation","share","b","teardown$","onEnd"],"mappings":";;;0BAmCoBA;;;SAkCXC;;;;AChCDA;;;;;;;;;;;;;UA0DJC;;;;;;;;;;;;;gBCpEoBC;MACdC;;;;;;;;;ACkDJC,eAAAA;qBAGQC,UAAAA,iBAAwBC,EAG5BC;;;AAgBFC,eAAaF;;;;;;;;;;SCmHNG,QAAIC;iBACID;;;AAHC;;;;;;;;;;;;;;;;;;;;;4DJpMEE;mBAGJC;;wBALhBC;;;;;;;;;;;;;WKd0CC;;QCEhCC;;gBAEWC;;;;;;;;;;;;;;;2BCiDlBC;;;;;;;;;;;;;;;;iBNoGEC,YAAAA;;;;;;;;;;;;;;;;;;;;;iBC7E6BC;;WAjBrBC,oBAAmBC;;;;;;;;;;;;;;aAkDhCC;WASKJ,kBAAAA;;;;;;cAgDLK;0BACAC;;;;YA5BsBC;;uBAeRC;;;;;kBAsBdC;;oBAI+BL,gBAInCC,MAAgBrB,IAAhBqB,EAAAA;mBAOiCK;;;;;;;;;;;;oDC9GJC;;;QAqCzBC,MADAC;qBAcAA,YAAAA;;;;;;;;;oBKzHYC;;;;;;;;;iCAPZC;;;;;;;;sBCeeC,EAAjBC,6BAUQC;;gCAQcC,4BACaC,GAAvBC;;;;SC6BkB;;IAvDrBC;;;;wBAYHT;8BAAaU;;;;;QAoBbC,MADAC;MAvBJb;QA4CIc;yBAQOxB,GAAAyB;;;SC5CK;;;;;;;;;;;;;;;;eClBhBC,SAASxC;qCAATwC;;;;;;SCGEC;;;;;;;uBCCyBC;;;0BV8FFC;;;;UAmEhBC;;;;;QA+IOC,kBACXA;;QAkBWA;;;;;;;;;;;;;;;;+BA/NLD;0BAGWE;sBACJC;;;;;;QAWO;eACVC;UAC0BA;;;;;;;yCA4B3BC;;;;;;yBA4COrD;;;;;;;;;;;MAwCAsD,iDASjBC,IAEJ1B;;IAWA2B;sBAFEP;;;;;;;SAuCkD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"}
\No newline at end of file