graphql-hooks
Version:
1,466 lines (1,433 loc) • 53.1 kB
JavaScript
(function (global, factory) {
typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports, require('react'), require('events')) :
typeof define === 'function' && define.amd ? define(['exports', 'react', 'events'], factory) :
(global = typeof globalThis !== 'undefined' ? globalThis : global || self, factory(global.GraphQLHooks = {}, global.React, global.EventEmitter));
})(this, (function (exports, React, EventEmitter) { 'use strict';
function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e : { 'default': e }; }
function _interopNamespace(e) {
if (e && e.__esModule) return e;
var n = Object.create(null);
if (e) {
Object.keys(e).forEach(function (k) {
if (k !== 'default') {
var d = Object.getOwnPropertyDescriptor(e, k);
Object.defineProperty(n, k, d.get ? d : {
enumerable: true,
get: function () { return e[k]; }
});
}
});
}
n["default"] = e;
return Object.freeze(n);
}
var React__default = /*#__PURE__*/_interopDefaultLegacy(React);
var React__namespace = /*#__PURE__*/_interopNamespace(React);
var EventEmitter__default = /*#__PURE__*/_interopDefaultLegacy(EventEmitter);
const ClientContext = React__default["default"].createContext(null);
ClientContext.displayName = "ClientContext";
function getDefaultExportFromCjs (x) {
return x && x.__esModule && Object.prototype.hasOwnProperty.call(x, 'default') ? x['default'] : x;
}
/**
* Used to mark a
* [React Native `File` substitute]{@link ReactNativeFileSubstitute}
* in an object tree for [`extractFiles`]{@link extractFiles}. It’s too risky to
* assume all objects with `uri`, `type` and `name` properties are files to
* extract.
* @kind class
* @name ReactNativeFile
* @param {ReactNativeFileSubstitute} file A [React Native](https://reactnative.dev) [`File`](https://developer.mozilla.org/en-US/docs/Web/API/File) substitute.
* @example <caption>Ways to `import`.</caption>
* ```js
* import { ReactNativeFile } from 'extract-files';
* ```
*
* ```js
* import ReactNativeFile from 'extract-files/public/ReactNativeFile.js';
* ```
* @example <caption>Ways to `require`.</caption>
* ```js
* const { ReactNativeFile } = require('extract-files');
* ```
*
* ```js
* const ReactNativeFile = require('extract-files/public/ReactNativeFile.js');
* ```
* @example <caption>An extractable file in [React Native](https://reactnative.dev).</caption>
* ```js
* const file = new ReactNativeFile({
* uri: uriFromCameraRoll,
* name: 'a.jpg',
* type: 'image/jpeg',
* });
* ```
*/
var ReactNativeFile_1 = class ReactNativeFile {
constructor({
uri,
name,
type
}) {
this.uri = uri;
this.name = name;
this.type = type;
}
};
const ReactNativeFile = ReactNativeFile_1;
/**
* Checks if a value is an [extractable file]{@link ExtractableFile}.
* @kind function
* @name isExtractableFile
* @type {ExtractableFileMatcher}
* @param {*} value Value to check.
* @returns {boolean} Is the value an [extractable file]{@link ExtractableFile}.
* @example <caption>Ways to `import`.</caption>
* ```js
* import { isExtractableFile } from 'extract-files';
* ```
*
* ```js
* import isExtractableFile from 'extract-files/public/isExtractableFile.js';
* ```
* @example <caption>Ways to `require`.</caption>
* ```js
* const { isExtractableFile } = require('extract-files');
* ```
*
* ```js
* const isExtractableFile = require('extract-files/public/isExtractableFile.js');
* ```
*/
var isExtractableFile = function isExtractableFile(value) {
return typeof File !== 'undefined' && value instanceof File || typeof Blob !== 'undefined' && value instanceof Blob || value instanceof ReactNativeFile;
};
var isExtractableFile$1 = /*@__PURE__*/getDefaultExportFromCjs(isExtractableFile);
const defaultIsExtractableFile = isExtractableFile;
/**
* Clones a value, recursively extracting
* [`File`](https://developer.mozilla.org/en-US/docs/Web/API/File),
* [`Blob`](https://developer.mozilla.org/en-US/docs/Web/API/Blob) and
* [`ReactNativeFile`]{@link ReactNativeFile} instances with their
* [object paths]{@link ObjectPath}, replacing them with `null`.
* [`FileList`](https://developer.mozilla.org/en-US/docs/Web/API/Filelist) instances
* are treated as [`File`](https://developer.mozilla.org/en-US/docs/Web/API/File)
* instance arrays.
* @kind function
* @name extractFiles
* @param {*} value Value (typically an object tree) to extract files from.
* @param {ObjectPath} [path=''] Prefix for object paths for extracted files.
* @param {ExtractableFileMatcher} [isExtractableFile=isExtractableFile] The function used to identify extractable files.
* @returns {ExtractFilesResult} Result.
* @example <caption>Ways to `import`.</caption>
* ```js
* import { extractFiles } from 'extract-files';
* ```
*
* ```js
* import extractFiles from 'extract-files/public/extractFiles.js';
* ```
* @example <caption>Ways to `require`.</caption>
* ```js
* const { extractFiles } = require('extract-files');
* ```
*
* ```js
* const extractFiles = require('extract-files/public/extractFiles.js');
* ```
* @example <caption>Extract files from an object.</caption>
* For the following:
*
* ```js
* const file1 = new File(['1'], '1.txt', { type: 'text/plain' });
* const file2 = new File(['2'], '2.txt', { type: 'text/plain' });
* const value = {
* a: file1,
* b: [file1, file2],
* };
*
* const { clone, files } = extractFiles(value, 'prefix');
* ```
*
* `value` remains the same.
*
* `clone` is:
*
* ```json
* {
* "a": null,
* "b": [null, null]
* }
* ```
*
* `files` is a [`Map`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map) instance containing:
*
* | Key | Value |
* | :------ | :--------------------------- |
* | `file1` | `['prefix.a', 'prefix.b.0']` |
* | `file2` | `['prefix.b.1']` |
*/
var extractFiles = function extractFiles(value, path = '', isExtractableFile = defaultIsExtractableFile) {
// Map of extracted files and their object paths within the input value.
const files = new Map();
// Map of arrays and objects recursed within the input value and their clones,
// for reusing clones of values that are referenced multiple times within the
// input value.
const clones = new Map();
/**
* Recursively clones the value, extracting files.
* @kind function
* @name extractFiles~recurse
* @param {*} value Value to extract files from.
* @param {ObjectPath} path Prefix for object paths for extracted files.
* @param {Set} recursed Recursed arrays and objects for avoiding infinite recursion of circular references within the input value.
* @returns {*} Clone of the value with files replaced with `null`.
* @ignore
*/
function recurse(value, path, recursed) {
let clone = value;
if (isExtractableFile(value)) {
clone = null;
const filePaths = files.get(value);
filePaths ? filePaths.push(path) : files.set(value, [path]);
} else {
const isList = Array.isArray(value) || typeof FileList !== 'undefined' && value instanceof FileList;
const isObject = value && value.constructor === Object;
if (isList || isObject) {
const hasClone = clones.has(value);
if (hasClone) clone = clones.get(value);else {
clone = isList ? [] : {};
clones.set(value, clone);
}
if (!recursed.has(value)) {
const pathPrefix = path ? `${path}.` : '';
const recursedDeeper = new Set(recursed).add(value);
if (isList) {
let index = 0;
for (const item of value) {
const itemClone = recurse(item, pathPrefix + index++, recursedDeeper);
if (!hasClone) clone.push(itemClone);
}
} else for (const key in value) {
const propertyClone = recurse(value[key], pathPrefix + key, recursedDeeper);
if (!hasClone) clone[key] = propertyClone;
}
}
}
}
return clone;
}
return {
clone: recurse(value, path, new Set()),
files
};
};
var extractFiles$1 = /*@__PURE__*/getDefaultExportFromCjs(extractFiles);
var canUseDOM = (function () {
return typeof window !== "undefined" && typeof window.document !== "undefined" && typeof window.document.createElement !== "undefined";
});
const isExtractableFileEnhanced = (value) => isExtractableFile$1(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;
}();
var e = {
NAME: "Name",
DOCUMENT: "Document",
OPERATION_DEFINITION: "OperationDefinition",
VARIABLE_DEFINITION: "VariableDefinition",
SELECTION_SET: "SelectionSet",
FIELD: "Field",
ARGUMENT: "Argument",
FRAGMENT_SPREAD: "FragmentSpread",
INLINE_FRAGMENT: "InlineFragment",
FRAGMENT_DEFINITION: "FragmentDefinition",
VARIABLE: "Variable",
INT: "IntValue",
FLOAT: "FloatValue",
STRING: "StringValue",
BOOLEAN: "BooleanValue",
NULL: "NullValue",
ENUM: "EnumValue",
LIST: "ListValue",
OBJECT: "ObjectValue",
OBJECT_FIELD: "ObjectField",
DIRECTIVE: "Directive",
NAMED_TYPE: "NamedType",
LIST_TYPE: "ListType",
NON_NULL_TYPE: "NonNullType"
};
var o = function (e) {
e[e.Const = 1] = "Const";
e[e.Var = 2] = "Var";
e[e.Int = 3] = "Int";
e[e.Float = 4] = "Float";
e[e.BlockString = 5] = "BlockString";
e[e.String = 6] = "String";
e[e.Enum = 7] = "Enum";
return e;
}(o || {});
var s = function (e) {
e[e.Spread = 1] = "Spread";
e[e.Name = 2] = "Name";
return e;
}(s || {});
function mapJoin(e, r, n) {
var i = "";
for (var t = 0; t < e.length; t++) {
if (t) {
i += r;
}
i += n(e[t]);
}
return i;
}
function printString(e) {
return JSON.stringify(e);
}
function printBlockString(e) {
return '"""\n' + e.replace(/"""/g, '\\"""') + '\n"""';
}
var f = "\n";
var g = {
OperationDefinition(e) {
var r = e.operation;
if (e.name) {
r += " " + e.name.value;
}
if (e.variableDefinitions && e.variableDefinitions.length) {
if (!e.name) {
r += " ";
}
r += "(" + mapJoin(e.variableDefinitions, ", ", g.VariableDefinition) + ")";
}
if (e.directives && e.directives.length) {
r += " " + mapJoin(e.directives, " ", g.Directive);
}
return "query" !== r ? r + " " + g.SelectionSet(e.selectionSet) : g.SelectionSet(e.selectionSet);
},
VariableDefinition(e) {
var r = g.Variable(e.variable) + ": " + _print(e.type);
if (e.defaultValue) {
r += " = " + _print(e.defaultValue);
}
if (e.directives && e.directives.length) {
r += " " + mapJoin(e.directives, " ", g.Directive);
}
return r;
},
Field(e) {
var r = e.alias ? e.alias.value + ": " + e.name.value : e.name.value;
if (e.arguments && e.arguments.length) {
var n = mapJoin(e.arguments, ", ", g.Argument);
if (r.length + n.length + 2 > 80) {
r += "(" + (f += " ") + mapJoin(e.arguments, f, g.Argument) + (f = f.slice(0, -2)) + ")";
} else {
r += "(" + n + ")";
}
}
if (e.directives && e.directives.length) {
r += " " + mapJoin(e.directives, " ", g.Directive);
}
if (e.selectionSet && e.selectionSet.selections.length) {
r += " " + g.SelectionSet(e.selectionSet);
}
return r;
},
StringValue(e) {
if (e.block) {
return printBlockString(e.value).replace(/\n/g, f);
} else {
return printString(e.value);
}
},
BooleanValue: e => "" + e.value,
NullValue: e => "null",
IntValue: e => e.value,
FloatValue: e => e.value,
EnumValue: e => e.value,
Name: e => e.value,
Variable: e => "$" + e.name.value,
ListValue: e => "[" + mapJoin(e.values, ", ", _print) + "]",
ObjectValue: e => "{" + mapJoin(e.fields, ", ", g.ObjectField) + "}",
ObjectField: e => e.name.value + ": " + _print(e.value),
Document(e) {
if (!e.definitions || !e.definitions.length) {
return "";
}
return mapJoin(e.definitions, "\n\n", _print);
},
SelectionSet: e => "{" + (f += " ") + mapJoin(e.selections, f, _print) + (f = f.slice(0, -2)) + "}",
Argument: e => e.name.value + ": " + _print(e.value),
FragmentSpread(e) {
var r = "..." + e.name.value;
if (e.directives && e.directives.length) {
r += " " + mapJoin(e.directives, " ", g.Directive);
}
return r;
},
InlineFragment(e) {
var r = "...";
if (e.typeCondition) {
r += " on " + e.typeCondition.name.value;
}
if (e.directives && e.directives.length) {
r += " " + mapJoin(e.directives, " ", g.Directive);
}
return r += " " + g.SelectionSet(e.selectionSet);
},
FragmentDefinition(e) {
var r = "fragment " + e.name.value;
r += " on " + e.typeCondition.name.value;
if (e.directives && e.directives.length) {
r += " " + mapJoin(e.directives, " ", g.Directive);
}
return r + " " + g.SelectionSet(e.selectionSet);
},
Directive(e) {
var r = "@" + e.name.value;
if (e.arguments && e.arguments.length) {
r += "(" + mapJoin(e.arguments, ", ", g.Argument) + ")";
}
return r;
},
NamedType: e => e.name.value,
ListType: e => "[" + _print(e.type) + "]",
NonNullType: e => _print(e.type) + "!"
};
var _print = e => g[e.kind](e);
function print(e) {
f = "\n";
return g[e.kind] ? g[e.kind](e) : "";
}
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 === e.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__default["default"]();
}
/** 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$1(
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 };
}
}
var has = Object.prototype.hasOwnProperty;
function find(iter, tar, key) {
for (key of iter.keys()) {
if (dequal(key, tar)) return key;
}
}
function dequal(foo, bar) {
var ctor, len, tmp;
if (foo === bar) return true;
if (foo && bar && (ctor = foo.constructor) === bar.constructor) {
if (ctor === Date) return foo.getTime() === bar.getTime();
if (ctor === RegExp) return foo.toString() === bar.toString();
if (ctor === Array) {
if ((len = foo.length) === bar.length) {
while (len-- && dequal(foo[len], bar[len]));
}
return len === -1;
}
if (ctor === Set) {
if (foo.size !== bar.size) {
return false;
}
for (len of foo) {
tmp = len;
if (tmp && typeof tmp === 'object') {
tmp = find(bar, tmp);
if (!tmp) return false;
}
if (!bar.has(tmp)) return false;
}
return true;
}
if (ctor === Map) {
if (foo.size !== bar.size) {
return false;
}
for (len of foo) {
tmp = len[0];
if (tmp && typeof tmp === 'object') {
tmp = find(bar, tmp);
if (!tmp) return false;
}
if (!dequal(len[1], bar.get(tmp))) {
return false;
}
}
return true;
}
if (ctor === ArrayBuffer) {
foo = new Uint8Array(foo);
bar = new Uint8Array(bar);
} else if (ctor === DataView) {
if ((len = foo.byteLength) === bar.byteLength) {
while (len-- && foo.getInt8(len) === bar.getInt8(len));
}
return len === -1;
}
if (ArrayBuffer.isView(foo)) {
if ((len = foo.byteLength) === bar.byteLength) {
while (len-- && foo[len] === bar[len]);
}
return len === -1;
}
if (!ctor || typeof foo === 'object') {
len = 0;
for (ctor in foo) {
if (has.call(foo, ctor) && ++len && !has.call(bar, ctor)) return false;
if (!(ctor in bar) || !dequal(foo[ctor], bar[ctor])) return false;
}
return Object.keys(bar).length === len;
}
}
return foo !== foo && bar !== bar;
}
function checkDeps(deps) {
if (!deps || !deps.length) {
throw new Error('useDeepCompareEffect should not be used with no dependencies. Use React.useEffect instead.');
}
if (deps.every(isPrimitive)) {
throw new Error('useDeepCompareEffect should not be used with dependencies that are all primitive values. Use React.useEffect instead.');
}
}
function isPrimitive(val) {
return val == null || /^[sbn]/.test(typeof val);
}
/**
* @param value the value to be memoized (usually a dependency list)
* @returns a momoized version of the value as long as it remains deeply equal
*/
function useDeepCompareMemoize(value) {
var ref = React__namespace.useRef(value);
var signalRef = React__namespace.useRef(0);
if (!dequal(value, ref.current)) {
ref.current = value;
signalRef.current += 1;
} // eslint-disable-next-line react-hooks/exhaustive-deps
return React__namespace.useMemo(function () {
return ref.current;
}, [signalRef.current]);
}
function useDeepCompareEffect(callback, dependencies) {
{
checkDeps(dependencies);
} // eslint-disable-next-line react-hooks/exhaustive-deps
return React__namespace.useEffect(callback, useDeepCompareMemoize(dependencies));
}
function useDeepCompareCallback(callback, deps) {
return React__default["default"].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__default["default"].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__default["default"].useRef(true);
const activeCacheKey = React__default["default"].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__default["default"].useReducer(reducer, initialState);
const stringifiedCacheKey = JSON.stringify(cacheKey);
React__default["default"].useEffect(() => {
if (!initialOpts.updateData) {
dispatch({ type: actionTypes.RESET_STATE, initialState });
}
}, [stringifiedCacheKey]);
React__default["default"].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__default["default"].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__default["default"].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__default["default"].useContext(ClientContext);
const client = opts.client || contextClient;
const [calledDuringSSR, setCalledDuringSSR] = React__default["default"].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__default["default"].useEffect(() => {
if (allOpts.skip) {
return;
}
queryReq();
}, [query, stringifiedAllOpts]);
React__default["default"].useEffect(() => {
if (state.error && allOpts.throwErrors) {
throw state.error;
}
}, [state.error, allOpts.throwErrors]);
const refetch = React__default["default"].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__default["default"].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 React.useContext(ClientContext);
}
function useSubscription(options, callback) {
cons