You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
219 lines
10 KiB
219 lines
10 KiB
import { __assign } from "tslib"; |
|
import { invariant } from "../../utilities/globals/index.js"; |
|
import { print } from "../../utilities/index.js"; |
|
import { ApolloLink } from "../core/index.js"; |
|
import { Observable, compact, isNonEmptyArray } from "../../utilities/index.js"; |
|
import { cacheSizes, AutoCleanedWeakCache, } from "../../utilities/index.js"; |
|
export var VERSION = 1; |
|
function processErrors(graphQLErrors) { |
|
var byMessage = Object.create(null), byCode = Object.create(null); |
|
if (isNonEmptyArray(graphQLErrors)) { |
|
graphQLErrors.forEach(function (error) { |
|
var _a; |
|
byMessage[error.message] = error; |
|
if (typeof ((_a = error.extensions) === null || _a === void 0 ? void 0 : _a.code) == "string") |
|
byCode[error.extensions.code] = error; |
|
}); |
|
} |
|
return { |
|
persistedQueryNotSupported: !!(byMessage.PersistedQueryNotSupported || |
|
byCode.PERSISTED_QUERY_NOT_SUPPORTED), |
|
persistedQueryNotFound: !!(byMessage.PersistedQueryNotFound || byCode.PERSISTED_QUERY_NOT_FOUND), |
|
}; |
|
} |
|
var defaultOptions = { |
|
disable: function (_a) { |
|
var meta = _a.meta; |
|
return meta.persistedQueryNotSupported; |
|
}, |
|
retry: function (_a) { |
|
var meta = _a.meta; |
|
return meta.persistedQueryNotSupported || meta.persistedQueryNotFound; |
|
}, |
|
useGETForHashedQueries: false, |
|
}; |
|
function operationDefinesMutation(operation) { |
|
return operation.query.definitions.some(function (d) { return d.kind === "OperationDefinition" && d.operation === "mutation"; }); |
|
} |
|
export var createPersistedQueryLink = function (options) { |
|
var hashesByQuery; |
|
function resetHashCache() { |
|
hashesByQuery = undefined; |
|
} |
|
// Ensure a SHA-256 hash function is provided, if a custom hash |
|
// generation function is not provided. We don't supply a SHA-256 hash |
|
// function by default, to avoid forcing one as a dependency. Developers |
|
// should pick the most appropriate SHA-256 function (sync or async) for |
|
// their needs/environment, or provide a fully custom hash generation |
|
// function (via the `generateHash` option) if they want to handle |
|
// hashing with something other than SHA-256. |
|
invariant(options && |
|
(typeof options.sha256 === "function" || |
|
typeof options.generateHash === "function"), 40); |
|
var _a = compact(defaultOptions, options), sha256 = _a.sha256, |
|
// If both a `sha256` and `generateHash` option are provided, the |
|
// `sha256` option will be ignored. Developers can configure and |
|
// use any hashing approach they want in a custom `generateHash` |
|
// function; they aren't limited to SHA-256. |
|
_b = _a.generateHash, |
|
// If both a `sha256` and `generateHash` option are provided, the |
|
// `sha256` option will be ignored. Developers can configure and |
|
// use any hashing approach they want in a custom `generateHash` |
|
// function; they aren't limited to SHA-256. |
|
generateHash = _b === void 0 ? function (query) { |
|
return Promise.resolve(sha256(print(query))); |
|
} : _b, disable = _a.disable, retry = _a.retry, useGETForHashedQueries = _a.useGETForHashedQueries; |
|
var supportsPersistedQueries = true; |
|
var getHashPromise = function (query) { |
|
return new Promise(function (resolve) { return resolve(generateHash(query)); }); |
|
}; |
|
function getQueryHash(query) { |
|
if (!query || typeof query !== "object") { |
|
// If the query is not an object, we won't be able to store its hash as |
|
// a property of query[hashesKey], so we let generateHash(query) decide |
|
// what to do with the bogus query. |
|
return getHashPromise(query); |
|
} |
|
if (!hashesByQuery) { |
|
hashesByQuery = new AutoCleanedWeakCache(cacheSizes["PersistedQueryLink.persistedQueryHashes"] || |
|
2000 /* defaultCacheSizes["PersistedQueryLink.persistedQueryHashes"] */); |
|
} |
|
var hash = hashesByQuery.get(query); |
|
if (!hash) |
|
hashesByQuery.set(query, (hash = getHashPromise(query))); |
|
return hash; |
|
} |
|
return Object.assign(new ApolloLink(function (operation, forward) { |
|
invariant(forward, 41); |
|
var query = operation.query; |
|
return new Observable(function (observer) { |
|
var subscription; |
|
var retried = false; |
|
var originalFetchOptions; |
|
var setFetchOptions = false; |
|
var maybeRetry = function (_a, cb) { |
|
var response = _a.response, networkError = _a.networkError; |
|
if (!retried && ((response && response.errors) || networkError)) { |
|
retried = true; |
|
var graphQLErrors = []; |
|
var responseErrors = response && response.errors; |
|
if (isNonEmptyArray(responseErrors)) { |
|
graphQLErrors.push.apply(graphQLErrors, responseErrors); |
|
} |
|
// Network errors can return GraphQL errors on for example a 403 |
|
var networkErrors = void 0; |
|
if (typeof (networkError === null || networkError === void 0 ? void 0 : networkError.result) !== "string") { |
|
networkErrors = |
|
networkError && |
|
networkError.result && |
|
networkError.result.errors; |
|
} |
|
if (isNonEmptyArray(networkErrors)) { |
|
graphQLErrors.push.apply(graphQLErrors, networkErrors); |
|
} |
|
var disablePayload = { |
|
response: response, |
|
networkError: networkError, |
|
operation: operation, |
|
graphQLErrors: isNonEmptyArray(graphQLErrors) ? graphQLErrors : void 0, |
|
meta: processErrors(graphQLErrors), |
|
}; |
|
// if the server doesn't support persisted queries, don't try anymore |
|
supportsPersistedQueries = !disable(disablePayload); |
|
if (!supportsPersistedQueries) { |
|
// clear hashes from cache, we don't need them anymore |
|
resetHashCache(); |
|
} |
|
// if its not found, we can try it again, otherwise just report the error |
|
if (retry(disablePayload)) { |
|
// need to recall the link chain |
|
if (subscription) |
|
subscription.unsubscribe(); |
|
// actually send the query this time |
|
operation.setContext({ |
|
http: { |
|
includeQuery: true, |
|
includeExtensions: supportsPersistedQueries, |
|
}, |
|
fetchOptions: { |
|
// Since we're including the full query, which may be |
|
// large, we should send it in the body of a POST request. |
|
// See issue #7456. |
|
method: "POST", |
|
}, |
|
}); |
|
if (setFetchOptions) { |
|
operation.setContext({ fetchOptions: originalFetchOptions }); |
|
} |
|
subscription = forward(operation).subscribe(handler); |
|
return; |
|
} |
|
} |
|
cb(); |
|
}; |
|
var handler = { |
|
next: function (response) { |
|
maybeRetry({ response: response }, function () { return observer.next(response); }); |
|
}, |
|
error: function (networkError) { |
|
maybeRetry({ networkError: networkError }, function () { return observer.error(networkError); }); |
|
}, |
|
complete: observer.complete.bind(observer), |
|
}; |
|
// don't send the query the first time |
|
operation.setContext({ |
|
http: { |
|
includeQuery: !supportsPersistedQueries, |
|
includeExtensions: supportsPersistedQueries, |
|
}, |
|
}); |
|
// If requested, set method to GET if there are no mutations. Remember the |
|
// original fetchOptions so we can restore them if we fall back to a |
|
// non-hashed request. |
|
if (useGETForHashedQueries && |
|
supportsPersistedQueries && |
|
!operationDefinesMutation(operation)) { |
|
operation.setContext(function (_a) { |
|
var _b = _a.fetchOptions, fetchOptions = _b === void 0 ? {} : _b; |
|
originalFetchOptions = fetchOptions; |
|
return { |
|
fetchOptions: __assign(__assign({}, fetchOptions), { method: "GET" }), |
|
}; |
|
}); |
|
setFetchOptions = true; |
|
} |
|
if (supportsPersistedQueries) { |
|
getQueryHash(query) |
|
.then(function (sha256Hash) { |
|
operation.extensions.persistedQuery = { |
|
version: VERSION, |
|
sha256Hash: sha256Hash, |
|
}; |
|
subscription = forward(operation).subscribe(handler); |
|
}) |
|
.catch(observer.error.bind(observer)); |
|
} |
|
else { |
|
subscription = forward(operation).subscribe(handler); |
|
} |
|
return function () { |
|
if (subscription) |
|
subscription.unsubscribe(); |
|
}; |
|
}); |
|
}), { |
|
resetHashCache: resetHashCache, |
|
}, globalThis.__DEV__ !== false ? |
|
{ |
|
getMemoryInternals: function () { |
|
var _a; |
|
return { |
|
PersistedQueryLink: { |
|
persistedQueryHashes: (_a = hashesByQuery === null || hashesByQuery === void 0 ? void 0 : hashesByQuery.size) !== null && _a !== void 0 ? _a : 0, |
|
}, |
|
}; |
|
}, |
|
} |
|
: {}); |
|
}; |
|
//# sourceMappingURL=index.js.map
|