UNPKG

graphql-hooks

Version:
1,030 lines (1,010 loc) 36.5 kB
import React, { useContext, useRef } from 'react'; import EventEmitter from 'events'; import { isExtractableFile, extractFiles } from 'extract-files'; import { Kind, print } from '@0no-co/graphql.web'; import useDeepCompareEffect, { useDeepCompareMemoize } from 'use-deep-compare-effect'; const ClientContext = React.createContext(null); ClientContext.displayName = "ClientContext"; var canUseDOM = (function () { return typeof window !== "undefined" && typeof window.document !== "undefined" && typeof window.document.createElement !== "undefined"; }); const isExtractableFileEnhanced = (value) => isExtractableFile(value) || // Check if stream // https://github.com/sindresorhus/is-stream/blob/3750505b0727f6df54324784fe369365ef78841e/index.js#L3 value !== null && typeof value === "object" && typeof value.pipe === "function" || // Check if formdata-node File // https://github.com/octet-stream/form-data/blob/14a6708f0ae28a5ffded8b6f8156394ba1d1244e/lib/File.ts#L29 value !== null && typeof value === "object" && typeof value.stream === "function"; function _arrayLikeToArray(r, a) { (null == a || a > r.length) && (a = r.length); for (var e = 0, n = Array(a); e < a; e++) n[e] = r[e]; return n; } function _createForOfIteratorHelperLoose(r, e) { var t = "undefined" != typeof Symbol && r[Symbol.iterator] || r["@@iterator"]; if (t) return (t = t.call(r)).next.bind(t); if (Array.isArray(r) || (t = _unsupportedIterableToArray(r)) || e && r && "number" == typeof r.length) { t && (r = t); var o = 0; return function () { return o >= r.length ? { done: !0 } : { done: !1, value: r[o++] }; }; } throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); } function _unsupportedIterableToArray(r, a) { if (r) { if ("string" == typeof r) return _arrayLikeToArray(r, a); var t = {}.toString.call(r).slice(8, -1); return "Object" === t && r.constructor && (t = r.constructor.name), "Map" === t || "Set" === t ? Array.from(r) : "Arguments" === t || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(t) ? _arrayLikeToArray(r, a) : void 0; } } var Middleware = /*#__PURE__*/function () { function Middleware(fns) { var _this = this; if (fns.length === 0) { fns.push(function (_, next) { return next(); }); } var _loop = function _loop() { var fn = _step.value; if (typeof fn !== "function") { throw new Error("GraphQLClient Middleware: middleware has to be of type `function`"); } _this.run = /* @__PURE__ */function (stack) { return function (opts, next) { stack(opts, function () { fn.apply(_this, [opts, next.bind.apply(next, [null, opts])]); }); }; }(_this.run); }; for (var _iterator = _createForOfIteratorHelperLoose(fns), _step; !(_step = _iterator()).done;) { _loop(); } } /** * Run middleware * @param {opts.client} GraphQLClient instance * @param {opts.operation} Operation object with properties such as query and variables * @param {opts.resolve} Used to early resolve the request * @param {opts.addResponseHook} Hook that accepts a function that will be run after response is fetched * @param {opts.reject} User to early reject the request * @param {function} next */ var _proto = Middleware.prototype; _proto.run = function run(opts, next) { next.apply(this, opts); }; return Middleware; }(); const pipeP = (fns) => (arg) => fns.reduce((p, f) => p.then(f), Promise.resolve(arg)); function extractOperationName(document) { var _a, _b; let operationName = void 0; if (typeof document !== "string") { const operationDefinitions = document.definitions.filter( (definition) => definition.kind === Kind.OPERATION_DEFINITION ); if (operationDefinitions.length === 1) { operationName = (_b = (_a = operationDefinitions[0]) == null ? void 0 : _a.name) == null ? void 0 : _b.value; } } return operationName; } function stringifyDocumentNode(document) { if (typeof document === "string") { return document; } return print(document); } var Events = /* @__PURE__ */ ((Events2) => { Events2["DATA_INVALIDATED"] = "DATA_INVALIDATED"; Events2["DATA_UPDATED"] = "DATA_UPDATED"; return Events2; })(Events || {}); var __defProp$6 = Object.defineProperty; var __defProps$2 = Object.defineProperties; var __getOwnPropDescs$2 = Object.getOwnPropertyDescriptors; var __getOwnPropSymbols$5 = Object.getOwnPropertySymbols; var __hasOwnProp$5 = Object.prototype.hasOwnProperty; var __propIsEnum$5 = Object.prototype.propertyIsEnumerable; var __defNormalProp$6 = (obj, key, value) => key in obj ? __defProp$6(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value; var __spreadValues$5 = (a, b) => { for (var prop in b || (b = {})) if (__hasOwnProp$5.call(b, prop)) __defNormalProp$6(a, prop, b[prop]); if (__getOwnPropSymbols$5) for (var prop of __getOwnPropSymbols$5(b)) { if (__propIsEnum$5.call(b, prop)) __defNormalProp$6(a, prop, b[prop]); } return a; }; var __spreadProps$2 = (a, b) => __defProps$2(a, __getOwnPropDescs$2(b)); var __publicField$2 = (obj, key, value) => __defNormalProp$6(obj, typeof key !== "symbol" ? key + "" : key, value); class GraphQLClient { constructor(config) { __publicField$2(this, "url"); __publicField$2(this, "ssrPromises"); __publicField$2(this, "FormData"); __publicField$2(this, "fetch"); __publicField$2(this, "fetchOptions"); __publicField$2(this, "logErrors"); __publicField$2(this, "useGETForQueries"); __publicField$2(this, "middleware"); __publicField$2(this, "mutationsEmitter"); __publicField$2(this, "cache"); __publicField$2(this, "headers"); __publicField$2(this, "ssrMode"); __publicField$2(this, "subscriptionClient"); __publicField$2(this, "fullWsTransport"); __publicField$2(this, "onError"); if (!config) { throw new Error(`GraphQLClient: config is required as first parameter`); } this.fullWsTransport = config.fullWsTransport; if (typeof config.subscriptionClient === "function") { this.subscriptionClient = config.subscriptionClient(); } else { this.subscriptionClient = config.subscriptionClient; } this.verifyConfig(config); this.cache = config.cache; this.headers = config.headers || {}; this.ssrMode = config.ssrMode; this.ssrPromises = []; this.url = config.url; this.fetch = config.fetch || (typeof fetch !== "undefined" && fetch ? fetch.bind(void 0) : void 0); this.fetchOptions = config.fetchOptions || {}; this.FormData = config.FormData || (typeof FormData !== "undefined" ? FormData : void 0); this.logErrors = config.logErrors !== void 0 ? config.logErrors : true; this.onError = config.onError; this.useGETForQueries = config.useGETForQueries === true; this.middleware = new Middleware(config.middleware || []); this.mutationsEmitter = new EventEmitter(); } /** Checks that the given config has the correct required options */ verifyConfig(config) { if (!config.url) { if (this.fullWsTransport) { if (!this.subscriptionClient) { throw new Error("GraphQLClient: subscriptionClient is required"); } } else { throw new Error("GraphQLClient: config.url is required"); } } if (config.fetch && typeof config.fetch !== "function") { throw new Error("GraphQLClient: config.fetch must be a function"); } if ((canUseDOM() || config.ssrMode) && !config.fetch && typeof fetch !== "function") { throw new Error( "GraphQLClient: fetch must be polyfilled or passed in new GraphQLClient({ fetch })" ); } if (config.ssrMode && !config.cache) { throw new Error("GraphQLClient: config.cache is required when in ssrMode"); } } setHeader(key, value) { this.headers[key] = value; return this; } setHeaders(headers) { this.headers = headers; return this; } removeHeader(key) { delete this.headers[key]; return this; } /* eslint-disable no-console */ logErrorResult({ result, operation }) { console.error("GraphQL Hooks Error"); console.groupCollapsed("---> Full Error Details"); console.groupCollapsed("Operation:"); console.log(operation); console.groupEnd(); const error = result.error; if (error) { if (error.fetchError) { console.groupCollapsed("FETCH ERROR:"); console.log(error.fetchError); console.groupEnd(); } if (error.httpError) { console.groupCollapsed("HTTP ERROR:"); console.log(error.httpError); console.groupEnd(); } if (error.graphQLErrors && error.graphQLErrors.length > 0) { console.groupCollapsed("GRAPHQL ERROR:"); error.graphQLErrors.forEach((err) => console.log(err)); console.groupEnd(); } } console.groupEnd(); } /* eslint-enable no-console */ generateResult({ fetchError, httpError, graphQLErrors, data, headers }) { const errorFound = !!(graphQLErrors && graphQLErrors.length > 0 || fetchError || httpError); return !errorFound ? { data, headers } : { data, error: { fetchError, httpError, graphQLErrors }, headers }; } getCacheKey(operation, options = {}) { const fetchOptions = __spreadValues$5(__spreadValues$5({}, this.fetchOptions), options.fetchOptionsOverrides); return { operation, fetchOptions }; } getCache(cacheKey) { const cacheHit = this.cache ? this.cache.get(cacheKey) : null; if (cacheHit) { return cacheHit; } } saveCache(cacheKey, value) { if (this.cache) { this.cache.set(cacheKey, value); } } removeCache(cacheKey) { var _a; (_a = this.cache) == null ? void 0 : _a.delete(cacheKey); } // Kudos to Jayden Seric (@jaydenseric) for this piece of code. // See original source: https://github.com/jaydenseric/graphql-react/blob/82d576b5fe6664c4a01cd928d79f33ddc3f7bbfd/src/universal/graphqlFetchOptions.mjs. getFetchOptions(operation, fetchOptionsOverrides = {}) { const fetchOptions = __spreadValues$5(__spreadValues$5({ method: "POST", headers: __spreadValues$5({}, this.headers) }, this.fetchOptions), fetchOptionsOverrides); if (fetchOptions.method === "GET") { return fetchOptions; } const { clone, files } = extractFiles( operation, "", isExtractableFileEnhanced ); const operationJSON = JSON.stringify(clone); if (files.size) { if (!this.FormData) { throw new Error( "GraphQLClient: FormData must be polyfilled or passed in new GraphQLClient({ FormData })" ); } const form = new this.FormData(); form.append("operations", operationJSON); const map = {}; let i = 0; files.forEach((paths) => { map[++i] = paths; }); form.append("map", JSON.stringify(map)); i = 0; files.forEach((paths, file) => { form.append(`${++i}`, file, file.name); }); fetchOptions.body = form; } else { fetchOptions.headers["Content-Type"] = "application/json"; fetchOptions.body = operationJSON; } return fetchOptions; } request(operation, options) { const responseHandlers = []; const addResponseHook = (handler) => responseHandlers.push(handler); return new Promise( (resolve, reject) => this.middleware.run( { operation, client: this, addResponseHook, resolve, reject }, ({ operation: updatedOperation }) => { const transformResponse = (res) => { if (responseHandlers.length > 0) { return pipeP(responseHandlers)(res); } return res; }; if (this.fullWsTransport) { return this.requestViaWS(updatedOperation).then(transformResponse).then(resolve).catch(reject); } if (this.url) { return this.requestViaHttp( updatedOperation, options ).then(transformResponse).then(resolve).catch(reject); } reject(new Error("GraphQLClient: config.url is required")); } ) ); } requestViaHttp(operation, options = {}) { let url = this.url; const fetchOptions = this.getFetchOptions( operation, options.fetchOptionsOverrides ); if (fetchOptions.method === "GET") { const paramsQueryString = Object.entries(operation).filter(([, v]) => !!v).map(([k, v]) => { if (k === "variables" || k === "extensions") { v = JSON.stringify(v); } return `${k}=${encodeURIComponent(v)}`; }).join("&"); url = url + "?" + paramsQueryString; } return this.fetch(url, fetchOptions).then((response) => { if (!response.ok) { return response.text().then((body) => { const { status, statusText } = response; return this.generateResult({ httpError: { status, statusText, body }, headers: response.headers }); }); } else { return response.json().then(({ errors, data }) => { return this.generateResult({ graphQLErrors: errors, data: applyResponseReducer( options.responseReducer, data, response ), headers: response.headers }); }); } }).catch((error) => { return this.generateResult({ fetchError: error }); }).then((result) => { if (result.error) { if (this.logErrors) { this.logErrorResult({ result, operation }); } if (this.onError) { this.onError({ result, operation }); } } return result; }); } requestViaWS(operationPayload) { return new Promise((resolve, reject) => { let data; try { const observable = this.createSubscription(operationPayload); const subscription = observable.subscribe({ next: (result) => { data = result; }, error: reject, complete: () => { subscription.unsubscribe(); resolve(data); } }); } catch (e) { reject(e); } }); } createSubscription(operationPayload) { if (!this.subscriptionClient) { throw new Error("No SubscriptionClient! Please set in the constructor."); } if (isGraphQLWsClient(this.subscriptionClient)) { return { subscribe: (sink) => ({ unsubscribe: this.subscriptionClient.subscribe( operationPayload, sink ) }) }; } else { return this.subscriptionClient.request(operationPayload); } } invalidateQuery(query) { const cacheKeyProp = typeof query === "string" ? { query } : query; const cacheKey = this.getCacheKey(cacheKeyProp); if (this.cache && cacheKey) { this.removeCache(cacheKey); this.request(cacheKeyProp).then((result) => { this.mutationsEmitter.emit(Events.DATA_INVALIDATED, result); }).catch((err) => console.error(err)); } } setQueryData(query, updater) { const cacheKeyProp = typeof query === "string" ? { query } : query; const cacheKey = this.getCacheKey(cacheKeyProp); if (this.cache && cacheKey) { const oldState = this.cache.get(cacheKey); const newState = __spreadProps$2(__spreadValues$5({}, oldState), { data: updater(oldState.data || null) }); this.saveCache(cacheKey, newState); this.mutationsEmitter.emit(Events.DATA_UPDATED, newState); } } } function isGraphQLWsClient(value) { return typeof value.subscribe === "function"; } function applyResponseReducer(responseReducer, data, response) { return typeof responseReducer === "function" ? responseReducer(data, response) : data; } var __defProp$5 = Object.defineProperty; var __defNormalProp$5 = (obj, key, value) => key in obj ? __defProp$5(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value; var __publicField$1 = (obj, key, value) => __defNormalProp$5(obj, typeof key !== "symbol" ? key + "" : key, value); class LocalGraphQLError { constructor(error) { __publicField$1(this, "fetchError"); __publicField$1(this, "httpError"); __publicField$1(this, "graphQLErrors"); this.fetchError = error.fetchError; this.httpError = error.httpError; this.graphQLErrors = error.graphQLErrors; } } var __defProp$4 = Object.defineProperty; var __getOwnPropSymbols$4 = Object.getOwnPropertySymbols; var __hasOwnProp$4 = Object.prototype.hasOwnProperty; var __propIsEnum$4 = Object.prototype.propertyIsEnumerable; var __defNormalProp$4 = (obj, key, value) => key in obj ? __defProp$4(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value; var __spreadValues$4 = (a, b) => { for (var prop in b || (b = {})) if (__hasOwnProp$4.call(b, prop)) __defNormalProp$4(a, prop, b[prop]); if (__getOwnPropSymbols$4) for (var prop of __getOwnPropSymbols$4(b)) { if (__propIsEnum$4.call(b, prop)) __defNormalProp$4(a, prop, b[prop]); } return a; }; var __publicField = (obj, key, value) => __defNormalProp$4(obj, typeof key !== "symbol" ? key + "" : key, value); class LocalGraphQLClient extends GraphQLClient { constructor(config) { super(__spreadValues$4({ url: "http://localhost" }, config)); __publicField(this, "localQueries"); // Delay before sending responses in miliseconds for simulating latency __publicField(this, "requestDelayMs"); this.localQueries = config.localQueries; this.requestDelayMs = config.requestDelayMs || 0; if (!this.localQueries) { throw new Error( "LocalGraphQLClient: `localQueries` object required in the constructor options" ); } } verifyConfig() { } requestViaHttp(operation, options = {}) { return timeoutPromise(this.requestDelayMs).then(() => { if (!operation.query || !this.localQueries[operation.query]) { throw new Error( `LocalGraphQLClient: no query match for: ${operation.query}` ); } const data = this.localQueries[operation.query]( operation.variables, operation.operationName ); return applyResponseReducer(options.responseReducer, data, new Response()); }); } request(operation, options) { return super.request(operation, options).then((result) => { if (result instanceof LocalGraphQLError) { return { error: result }; } const { data, errors } = collectErrors(result); if (errors && errors.length > 0) { return { data, error: new LocalGraphQLError({ graphQLErrors: errors }) }; } else { return { data }; } }); } } function timeoutPromise(delayInMs) { return new Promise((resolve) => { setTimeout(resolve, delayInMs); }); } function isObject(o) { return o === Object(o); } function collectErrorsFromObject(objectIn) { const data = {}; const errors = []; for (const [key, value] of Object.entries(objectIn)) { const child = collectErrors(value); data[key] = child.data; if (child.errors != null) { errors.push(...child.errors); } } return { data, errors }; } function collectErrorsFromArray(arrayIn) { const data = Array(arrayIn.length); const errors = []; for (const [idx, entry] of arrayIn.entries()) { const child = collectErrors(entry); data[idx] = child.data; if (child.errors != null) { errors.push(...child.errors); } } return { data, errors }; } function collectErrors(entry) { if (entry instanceof Error) { return { data: null, errors: [entry] }; } else if (Array.isArray(entry)) { return collectErrorsFromArray(entry); } else if (isObject(entry)) { return collectErrorsFromObject(entry); } else { return { data: entry, errors: null }; } } function useDeepCompareCallback(callback, deps) { return React.useCallback(callback, useDeepCompareMemoize(deps)); } var __defProp$3 = Object.defineProperty; var __defProps$1 = Object.defineProperties; var __getOwnPropDescs$1 = Object.getOwnPropertyDescriptors; var __getOwnPropSymbols$3 = Object.getOwnPropertySymbols; var __hasOwnProp$3 = Object.prototype.hasOwnProperty; var __propIsEnum$3 = Object.prototype.propertyIsEnumerable; var __defNormalProp$3 = (obj, key, value) => key in obj ? __defProp$3(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value; var __spreadValues$3 = (a, b) => { for (var prop in b || (b = {})) if (__hasOwnProp$3.call(b, prop)) __defNormalProp$3(a, prop, b[prop]); if (__getOwnPropSymbols$3) for (var prop of __getOwnPropSymbols$3(b)) { if (__propIsEnum$3.call(b, prop)) __defNormalProp$3(a, prop, b[prop]); } return a; }; var __spreadProps$1 = (a, b) => __defProps$1(a, __getOwnPropDescs$1(b)); const actionTypes = { RESET_STATE: "RESET_STATE", LOADING: "LOADING", CACHE_HIT: "CACHE_HIT", REQUEST_RESULT: "REQUEST_RESULT", DATA_UPDATED: "DATA_UPDATED" }; function reducer(state, action) { switch (action.type) { case actionTypes.RESET_STATE: if (state.loading) { return state; } return action.initialState; case actionTypes.LOADING: if (state.error) { return __spreadProps$1(__spreadValues$3({}, action.initialState), { data: state.data, loading: true }); } if (state.loading) { return state; } return __spreadProps$1(__spreadValues$3({}, state), { loading: true }); case actionTypes.DATA_UPDATED: return __spreadProps$1(__spreadValues$3({}, state), { data: action.result.data }); case actionTypes.CACHE_HIT: if (state.cacheHit && !action.resetState) { return state; } return __spreadProps$1(__spreadValues$3({}, action.result), { cacheHit: true, loading: false }); case actionTypes.REQUEST_RESULT: return __spreadProps$1(__spreadValues$3({}, action.result), { data: state.data && action.result.data && action.updateData ? action.updateData(state.data, action.result.data) : action.result.data, cacheHit: false, loading: false }); default: return state; } } function useClientRequest(query, initialOpts = {}) { var _a; const queryString = stringifyDocumentNode(query); const operationName = (_a = initialOpts.operationName) != null ? _a : extractOperationName(query); const contextClient = React.useContext(ClientContext); const client = initialOpts.client || contextClient; if (client === null || client === void 0) { throw new Error( "A client must be provided in order to use the useClientRequest hook." ); } const isMounted = React.useRef(true); const activeCacheKey = React.useRef(null); const operation = { query: queryString, variables: initialOpts.variables, operationName, persisted: initialOpts.persisted }; if (initialOpts.persisted || client.useGETForQueries && !initialOpts.isMutation) { initialOpts.fetchOptionsOverrides = __spreadProps$1(__spreadValues$3({}, initialOpts.fetchOptionsOverrides), { method: "GET" }); } const cacheKey = client.getCacheKey(operation, initialOpts); const isDeferred = initialOpts.isMutation || initialOpts.isManual || initialOpts.skip; const initialCacheHit = initialOpts.skipCache || !client.cache || !cacheKey ? null : client.cache.get(cacheKey); const initialState = __spreadProps$1(__spreadValues$3({}, initialCacheHit), { cacheHit: !!initialCacheHit, loading: isDeferred ? false : !initialCacheHit }); const [state, dispatch] = React.useReducer(reducer, initialState); const stringifiedCacheKey = JSON.stringify(cacheKey); React.useEffect(() => { if (!initialOpts.updateData) { dispatch({ type: actionTypes.RESET_STATE, initialState }); } }, [stringifiedCacheKey]); React.useEffect(() => { isMounted.current = true; return () => { isMounted.current = false; }; }, []); const fetchData = useDeepCompareCallback( (newOpts) => { const revisedOpts = __spreadValues$3(__spreadValues$3({}, initialOpts), newOpts); const revisedOperation = __spreadProps$1(__spreadValues$3({}, operation), { variables: revisedOpts.variables, operationName: revisedOpts.operationName }); if (!isMounted.current) { return Promise.resolve({ error: { fetchError: new Error( "fetchData should not be called after hook unmounted" ) }, loading: false, cacheHit: false }); } const revisedCacheKey = client.getCacheKey( revisedOperation, revisedOpts ); activeCacheKey.current = revisedCacheKey; const cacheHit = revisedOpts.skipCache ? null : client.getCache(revisedCacheKey); if (cacheHit) { dispatch({ type: actionTypes.CACHE_HIT, result: cacheHit, resetState: stringifiedCacheKey !== JSON.stringify(state.cacheKey) }); return Promise.resolve(cacheHit); } dispatch({ type: actionTypes.LOADING, initialState }); return client.request(revisedOperation, revisedOpts).then((result) => { if (revisedOpts.updateData && typeof revisedOpts.updateData !== "function") { throw new Error("options.updateData must be a function"); } const actionResult = __spreadValues$3({}, result); if (revisedOpts.useCache) { actionResult.useCache = true; actionResult.cacheKey = revisedCacheKey; if (client.ssrMode) { const cacheValue = { error: actionResult.error, data: revisedOpts.updateData ? revisedOpts.updateData(state.data, actionResult.data) : actionResult.data }; client.saveCache(revisedCacheKey, cacheValue); } } if (isMounted.current && revisedCacheKey === activeCacheKey.current) { dispatch({ type: actionTypes.REQUEST_RESULT, updateData: revisedOpts.updateData, result: actionResult }); } if (initialOpts.isMutation) { client.mutationsEmitter.emit(queryString, __spreadProps$1(__spreadValues$3({}, revisedOperation), { mutation: queryString, result: actionResult })); } if (!(result == null ? void 0 : result.error) && revisedOpts.onSuccess) { if (typeof revisedOpts.onSuccess !== "function") { throw new Error("options.onSuccess must be a function"); } revisedOpts.onSuccess(result, revisedOperation.variables); } return result; }); }, [client, initialOpts, operation] ); React.useEffect(() => { if (state.useCache && !client.ssrMode) { client.saveCache(state.cacheKey, state); } }, [client, state]); const reset = (desiredState = {}) => dispatch({ type: actionTypes.RESET_STATE, initialState: __spreadValues$3(__spreadValues$3({}, initialState), desiredState) }); React.useEffect(() => { const handleEvents = (payload, actionType) => { dispatch({ type: actionType, result: payload }); }; const dataInvalidatedCallback = (payload) => handleEvents(payload, actionTypes.REQUEST_RESULT); const dataUpdatedCallback = (payload) => handleEvents(payload, actionTypes.DATA_UPDATED); const mutationsEmitter = client.mutationsEmitter; mutationsEmitter.on(Events.DATA_INVALIDATED, dataInvalidatedCallback); mutationsEmitter.on(Events.DATA_UPDATED, dataUpdatedCallback); return () => { if (mutationsEmitter) { mutationsEmitter.removeListener( Events.DATA_INVALIDATED, dataInvalidatedCallback ); mutationsEmitter.removeListener( Events.DATA_UPDATED, dataUpdatedCallback ); } }; }, []); return [fetchData, state, reset]; } function isRefetchAfterMutationItem(item) { return typeof item === "object" && item != null && "mutation" in item; } function isTypedDocumentNode(item) { return typeof item === "object" && item != null && "kind" in item; } function createRefetchMutationsMap(refetchAfterMutations) { if (!refetchAfterMutations) return {}; const mutations = Array.isArray(refetchAfterMutations) ? refetchAfterMutations : [refetchAfterMutations]; const result = {}; mutations.forEach((mutationInfo) => { if (mutationInfo == null) return; if (typeof mutationInfo === "string") { result[mutationInfo] = {}; } else if (isRefetchAfterMutationItem(mutationInfo)) { const { filter, mutation, refetchOnMutationError = true } = mutationInfo; result[mutation] = { filter, refetchOnMutationError }; } else if (isTypedDocumentNode(mutationInfo)) { result[stringifyDocumentNode(mutationInfo)] = {}; } }); return result; } var __defProp$2 = Object.defineProperty; var __defProps = Object.defineProperties; var __getOwnPropDescs = Object.getOwnPropertyDescriptors; var __getOwnPropSymbols$2 = Object.getOwnPropertySymbols; var __hasOwnProp$2 = Object.prototype.hasOwnProperty; var __propIsEnum$2 = Object.prototype.propertyIsEnumerable; var __defNormalProp$2 = (obj, key, value) => key in obj ? __defProp$2(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value; var __spreadValues$2 = (a, b) => { for (var prop in b || (b = {})) if (__hasOwnProp$2.call(b, prop)) __defNormalProp$2(a, prop, b[prop]); if (__getOwnPropSymbols$2) for (var prop of __getOwnPropSymbols$2(b)) { if (__propIsEnum$2.call(b, prop)) __defNormalProp$2(a, prop, b[prop]); } return a; }; var __spreadProps = (a, b) => __defProps(a, __getOwnPropDescs(b)); var __objRest = (source, exclude) => { var target = {}; for (var prop in source) if (__hasOwnProp$2.call(source, prop) && exclude.indexOf(prop) < 0) target[prop] = source[prop]; if (source != null && __getOwnPropSymbols$2) for (var prop of __getOwnPropSymbols$2(source)) { if (exclude.indexOf(prop) < 0 && __propIsEnum$2.call(source, prop)) target[prop] = source[prop]; } return target; }; const defaultOpts = { useCache: true, skip: false, throwErrors: false }; function useQuery(query, opts = {}) { const allOpts = __spreadValues$2(__spreadValues$2({}, defaultOpts), opts); const contextClient = React.useContext(ClientContext); const client = opts.client || contextClient; const [calledDuringSSR, setCalledDuringSSR] = React.useState(false); const [queryReq, state] = useClientRequest(query, allOpts); if (!client) { throw new Error( "useQuery() requires a client to be passed in the options or as a context value" ); } if (client.ssrMode && opts.ssr !== false && !calledDuringSSR && !opts.skipCache && !opts.skip) { if (!state.data && !state.error) { const p = queryReq(); client.ssrPromises.push(p); } setCalledDuringSSR(true); } const _a = allOpts, allOptsToStringify = __objRest(_a, ["client"]); const stringifiedAllOpts = JSON.stringify(allOptsToStringify); React.useEffect(() => { if (allOpts.skip) { return; } queryReq(); }, [query, stringifiedAllOpts]); React.useEffect(() => { if (state.error && allOpts.throwErrors) { throw state.error; } }, [state.error, allOpts.throwErrors]); const refetch = React.useCallback( (options = {}) => queryReq(__spreadValues$2({ skipCache: true, // don't call the updateData that has been passed into useQuery here // reset to the default behaviour of returning the raw query result // this can be overridden in refetch options updateData: (_, data) => data }, options)), [queryReq] ); React.useEffect( function subscribeToMutationsAndRefetch() { const mutationsMap = createRefetchMutationsMap(opts.refetchAfterMutations); const mutations = Object.keys(mutationsMap); const afterConditionsCheckRefetch = ({ mutation, variables, result }) => { const { filter, refetchOnMutationError } = mutationsMap[mutation]; const hasValidFilterOrNoFilter = !filter || variables && filter(variables); const shouldRefetch = refetchOnMutationError || !result.error; if (hasValidFilterOrNoFilter && shouldRefetch) { refetch(); } }; mutations.forEach((mutation) => { client.mutationsEmitter.on(mutation, afterConditionsCheckRefetch); }); return () => { mutations.forEach((mutation) => { client.mutationsEmitter.removeListener( mutation, afterConditionsCheckRefetch ); }); }; }, [opts.refetchAfterMutations, refetch, client.mutationsEmitter] ); return __spreadProps(__spreadValues$2({}, state), { refetch }); } function useQueryClient() { return useContext(ClientContext); } function useSubscription(options, callback) { const callbackRef = useRef(callback); callbackRef.current = callback; const contextClient = useContext(ClientContext); const client = options.client || contextClient; if (!client) { throw new Error( "useSubscription() requires a client to be passed in the options or as a context value" ); } useDeepCompareEffect(() => { if (options.skip) { return; } const request = { query: options.query, variables: options.variables }; const observable = client.createSubscription(request); const subscription = observable.subscribe({ next: (result) => { callbackRef.current(result); }, error: (errors) => { callbackRef.current({ errors }); }, complete: () => { subscription.unsubscribe(); } }); return () => { subscription.unsubscribe(); }; }, [options.query, options.variables, options.skip]); } var __defProp$1 = Object.defineProperty; var __getOwnPropSymbols$1 = Object.getOwnPropertySymbols; var __hasOwnProp$1 = Object.prototype.hasOwnProperty; var __propIsEnum$1 = Object.prototype.propertyIsEnumerable; var __defNormalProp$1 = (obj, key, value) => key in obj ? __defProp$1(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value; var __spreadValues$1 = (a, b) => { for (var prop in b || (b = {})) if (__hasOwnProp$1.call(b, prop)) __defNormalProp$1(a, prop, b[prop]); if (__getOwnPropSymbols$1) for (var prop of __getOwnPropSymbols$1(b)) { if (__propIsEnum$1.call(b, prop)) __defNormalProp$1(a, prop, b[prop]); } return a; }; const useMutation = (query, options = {}) => useClientRequest(query, __spreadValues$1({ isMutation: true }, options)); var __defProp = Object.defineProperty; var __getOwnPropSymbols = Object.getOwnPropertySymbols; var __hasOwnProp = Object.prototype.hasOwnProperty; var __propIsEnum = Object.prototype.propertyIsEnumerable; var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value; var __spreadValues = (a, b) => { for (var prop in b || (b = {})) if (__hasOwnProp.call(b, prop)) __defNormalProp(a, prop, b[prop]); if (__getOwnPropSymbols) for (var prop of __getOwnPropSymbols(b)) { if (__propIsEnum.call(b, prop)) __defNormalProp(a, prop, b[prop]); } return a; }; const useManualQuery = (query, options = {}) => useClientRequest(query, __spreadValues({ useCache: true, isManual: true }, options)); export { ClientContext, GraphQLClient, LocalGraphQLClient, LocalGraphQLError, useClientRequest, useManualQuery, useMutation, useQuery, useQueryClient, useSubscription };