graphql-hooks
Version:
1,030 lines (1,010 loc) • 36.5 kB
JavaScript
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 };