UNPKG

graphql-hooks

Version:
1,466 lines (1,433 loc) 53.1 kB
(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