UNPKG

@graphql-hive/gateway-plugin-console-sdk

Version:
222 lines (221 loc) • 12.2 kB
import { __asyncGenerator, __asyncValues, __await } from "tslib"; import { OperationTypeNode, parse, responsePathAsArray, } from 'graphql'; import { lru } from 'tiny-lru'; import { addHiveTypenames, createHive as createHiveClient, getDefinedRootType, hideInjectedTypenames, isAsyncIterable, isHiveClient, } from '@graphql-hive/core'; import { isEntityRequest } from './is-entity-request.js'; import { version } from './version.js'; export { atLeastOnceSampler, createSchemaFetcher, createServicesFetcher, createSupergraphSDLFetcher, } from '@graphql-hive/core'; export function createHive(clientOrOptions) { return createHiveClient(Object.assign(Object.assign({}, clientOrOptions), { agent: Object.assign({ name: 'hive-client-gateway-sdk', version }, clientOrOptions.agent) })); } export function useHive(clientOrOptions) { var _a, _b; const hive = isHiveClient(clientOrOptions) ? clientOrOptions : createHive(Object.assign(Object.assign({}, clientOrOptions), { agent: Object.assign({ name: 'hive-client-gateway-sdk' }, clientOrOptions.agent) })); void hive.info(); const contextualCache = new WeakMap(); const statusMap = new WeakMap(); const fieldLevelMetricsEnabled = isHiveClient(clientOrOptions) ? false : (typeof clientOrOptions.usage === 'object' && ((_a = clientOrOptions.usage) === null || _a === void 0 ? void 0 : _a.fieldLevelMetricsEnabled)) || false; const operationCache = fieldLevelMetricsEnabled ? lru(isHiveClient(clientOrOptions) ? 10000 : ((_b = clientOrOptions.cache) !== null && _b !== void 0 ? _b : 10000)) : null; let latestSchema = null; return { onFetch({ executionRequest }) { if (!executionRequest) { return; } return function onFetchDone({ response }) { statusMap.set(executionRequest, response.status); }; }, onSubgraphExecute({ executionRequest, subgraphName, subgraph: subgraphSchema }) { var _a, _b, _c; if (!fieldLevelMetricsEnabled || !executionRequest.context) { return; } const cache = contextualCache.get(executionRequest.context); if (!cache) { return; } const finishSubRequest = cache.collector.subrequest({ subgraph: subgraphName, type: isEntityRequest(executionRequest.document) ? 'ENTITY' : 'ROOT', paths: ((_a = executionRequest.info) === null || _a === void 0 ? void 0 : _a.path) ? [responsePathAsArray(executionRequest.info.path).join('.')] : (_c = getDefinedRootType(subgraphSchema, (_b = executionRequest.operationType) !== null && _b !== void 0 ? _b : OperationTypeNode.QUERY)) === null || _c === void 0 ? void 0 : _c.name, }); return function onSubgraphExecuteDone({ result }) { var _a; if (!isAsyncIterable(result)) { finishSubRequest({ status: (_a = statusMap.get(executionRequest)) !== null && _a !== void 0 ? _a : 200, subgraphSchema, result, // The Rust query planner generates and caches this document up front. // This depends on the operation and variables. // So if we need to add typenames to the request, it needs to happen // here also. E.g. `addHiveTypenames(executionRequest.document, subgraphSchema)`. // But for the js gateway execution, this is redundant and an unnecessary expense. document: executionRequest.document, }); } }; }, onSchemaChange({ schema }) { hive.reportSchema({ schema }); latestSchema = schema; operationCache === null || operationCache === void 0 ? void 0 : operationCache.clear(); }, onParams(context) { if ((context.params.query || 'documentId' in context.params) && latestSchema) { contextualCache.set(context.context, { collector: hive.collectUsage(), paramsArgs: context.params, }); } }, onExecute({ args, context, setExecuteFn, executeFn }) { var _a; const ctx = args.contextValue || context; const cache = contextualCache.get(ctx); if (!cache) return; cache.executionArgs = args; if (fieldLevelMetricsEnabled && operationCache && latestSchema) { // Validation must run against the client document. Add the metadata fields only // to the document passed to execution and cache that transformed document. const query = (_a = args.document.loc) === null || _a === void 0 ? void 0 : _a.source.body; const cachedDocument = query ? operationCache.get(query) : undefined; const modifiedDocument = cachedDocument === true ? args.document : cachedDocument || addHiveTypenames(args.document, latestSchema); if (query && cachedDocument === undefined) { operationCache.set(query, args.document === modifiedDocument || modifiedDocument); } if (args.document !== modifiedDocument) { setExecuteFn(executionArgs => executeFn(Object.assign(Object.assign({}, executionArgs), { document: modifiedDocument }))); } cache.document = modifiedDocument; } return { onExecuteDone({ result, args }) { var _a, _b, _c; if (!isAsyncIterable(result)) { if (result.errors) { const gatewayErrors = (_a = result.errors) === null || _a === void 0 ? void 0 : _a.filter(e => { var _a, _b; /** * DOWNSTREAM_SERVICE_ERROR is set by the executor to wrap subgraph errors. A serviceName is also * used to indicate the source of the error. If either of these are found, then it's safe to assume * the error was not thrown in the gateway. */ return ((_a = e.extensions) === null || _a === void 0 ? void 0 : _a.code) !== 'DOWNSTREAM_SERVICE_ERROR' && !((_b = e.extensions) === null || _b === void 0 ? void 0 : _b.serviceName); }); if (cache && (gatewayErrors === null || gatewayErrors === void 0 ? void 0 : gatewayErrors.length) > 0) { cache.collector.trackGatewayErrors({ errors: gatewayErrors }); } } args.contextValue.waitUntil(cache.collector.finish(Object.assign(Object.assign({}, args), { document: (_c = (_b = cache.document) !== null && _b !== void 0 ? _b : ctx.document) !== null && _c !== void 0 ? _c : args.document }), result, cache.experimental__documentId)); return; } const errors = []; return { onNext({ result: iterResult }) { if (iterResult.errors) { errors.push(...iterResult.errors); } }, onEnd() { var _a; ctx.waitUntil(cache.collector.finish(Object.assign(Object.assign({}, args), { document: (_a = cache.document) !== null && _a !== void 0 ? _a : args.document }), // how to pass in data here? errors.length ? { errors } : {}, cache.experimental__documentId)); }, }; }, }; }, onSubscribe({ args, context }) { const ctx = args.contextValue || context; const record = contextualCache.get(ctx); return { onSubscribeResult() { var _a, _b, _c; const experimental__persistedDocumentHash = record === null || record === void 0 ? void 0 : record.experimental__documentId; hive.collectSubscriptionUsage({ args: Object.assign(Object.assign({}, args), { document: (_c = (_a = record === null || record === void 0 ? void 0 : record.document) !== null && _a !== void 0 ? _a : (_b = record === null || record === void 0 ? void 0 : record.executionArgs) === null || _b === void 0 ? void 0 : _b.document) !== null && _c !== void 0 ? _c : args.document }), experimental__persistedDocumentHash, }); }, }; }, async onResultProcess({ serverContext, result, setResult }) { const record = contextualCache.get(serverContext); if (!record || Array.isArray(result) || isAsyncIterable(result) || record.executionArgs) { if (fieldLevelMetricsEnabled) { if (isAsyncIterable(result)) { const modifyStream = function () { return __asyncGenerator(this, arguments, function* () { var _a, e_1, _b, _c; try { for (var _d = true, result_1 = __asyncValues(result), result_1_1; result_1_1 = yield __await(result_1.next()), _a = result_1_1.done, !_a; _d = true) { _c = result_1_1.value; _d = false; const r = _c; hideInjectedTypenames(r.data); yield yield __await(r); } } catch (e_1_1) { e_1 = { error: e_1_1 }; } finally { try { if (!_d && !_a && (_b = result_1.return)) yield __await(_b.call(result_1)); } finally { if (e_1) throw e_1.error; } } }); }; setResult(modifyStream()); } else if (Array.isArray(result)) { for (let r of result) { hideInjectedTypenames(r.data); } } else { hideInjectedTypenames(result.data); } } return; } if (record.paramsArgs.query && latestSchema) { try { let doc = record.document; if (!doc) { doc = parse(record.paramsArgs.query); } serverContext.waitUntil(record.collector.finish({ document: doc, schema: latestSchema, variableValues: record.paramsArgs.variables, operationName: record.paramsArgs.operationName, contextValue: serverContext, }, result, record.experimental__documentId)); } catch (err) { // Fail silently if parse fails inside cached block handling } } if (fieldLevelMetricsEnabled) { hideInjectedTypenames(result.data); } }, onDispose() { return hive.dispose(); }, }; }