@graphql-hive/core
Version:
102 lines (101 loc) • 3.96 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.createPersistedDocuments = createPersistedDocuments;
const tslib_1 = require("tslib");
const tiny_lru_1 = tslib_1.__importDefault(require("tiny-lru"));
const circuit_js_1 = tslib_1.__importDefault(require("../circuit-breaker/circuit.js"));
const circuit_breaker_js_1 = require("./circuit-breaker.js");
const http_client_js_1 = require("./http-client.js");
function isRequestOk(response) {
return response.status === 200 || response.status === 404;
}
function createPersistedDocuments(config) {
var _a;
const persistedDocumentsCache = (0, tiny_lru_1.default)((_a = config.cache) !== null && _a !== void 0 ? _a : 10000);
let allowArbitraryDocuments;
if (typeof config.allowArbitraryDocuments === 'boolean') {
let value = config.allowArbitraryDocuments;
allowArbitraryDocuments = () => value;
}
else if (typeof config.allowArbitraryDocuments === 'function') {
allowArbitraryDocuments = config.allowArbitraryDocuments;
}
else {
allowArbitraryDocuments = () => false;
}
/** if there is already a in-flight request for a document, we re-use it. */
const fetchCache = new Map();
const endpoints = Array.isArray(config.cdn.endpoint)
? config.cdn.endpoint
: [config.cdn.endpoint];
const circuitBreakers = endpoints.map(endpoint => {
var _a;
const circuitBreaker = new circuit_js_1.default(async function doFetch(cdnDocumentId) {
const signal = circuitBreaker.getSignal();
return await http_client_js_1.http
.get(endpoint + '/apps/' + cdnDocumentId, {
headers: {
'X-Hive-CDN-Key': config.cdn.accessToken,
},
logger: config.logger,
isRequestOk,
fetchImplementation: config.fetch,
signal,
retry: config.retry,
})
.then(async (response) => {
if (response.status !== 200) {
return null;
}
const text = await response.text();
return text;
});
}, Object.assign(Object.assign({}, ((_a = config.circuitBreaker) !== null && _a !== void 0 ? _a : circuit_breaker_js_1.defaultCircuitBreakerConfiguration)), { timeout: false, autoRenewAbortController: true }));
return circuitBreaker;
});
/** Batch load a persisted documents */
function loadPersistedDocument(documentId) {
const document = persistedDocumentsCache.get(documentId);
if (document) {
return document;
}
let promise = fetchCache.get(documentId);
if (promise) {
return promise;
}
promise = Promise.resolve()
.then(async () => {
const cdnDocumentId = documentId.replaceAll('~', '/');
let lastError = null;
for (const breaker of circuitBreakers) {
try {
return await breaker.fire(cdnDocumentId);
}
catch (error) {
config.logger.debug({ error });
lastError = error;
}
}
if (lastError) {
config.logger.error({ error: lastError });
}
throw new Error('Failed to look up persisted operation.');
})
.then(result => {
persistedDocumentsCache.set(documentId, result);
return result;
})
.finally(() => {
fetchCache.delete(documentId);
});
fetchCache.set(documentId, promise);
return promise;
}
return {
allowArbitraryDocuments,
resolve: loadPersistedDocument,
dispose() {
circuitBreakers.map(breaker => breaker.shutdown());
},
};
}