UNPKG

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

Version:

GraphQL Hive + GraphQL Hive Gateway

140 lines (139 loc) • 6.74 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.createHive = createHive; exports.useHive = useHive; const graphql_1 = require("graphql"); const tiny_lru_1 = require("tiny-lru"); const core_1 = require("@graphql-hive/core"); const add_typenames_js_1 = require("./add-typenames.js"); const is_entity_request_js_1 = require("./is-entity-request.js"); const version_js_1 = require("./version.js"); function createHive(clientOrOptions) { return (0, core_1.createHive)(Object.assign(Object.assign({}, clientOrOptions), { agent: Object.assign({ name: 'hive-client-gateway-sdk', version: version_js_1.version }, clientOrOptions.agent) })); } function useHive(clientOrOptions) { var _a, _b; const hive = (0, core_1.isHiveClient)(clientOrOptions) ? clientOrOptions : createHive(Object.assign(Object.assign({}, clientOrOptions), { agent: Object.assign({ name: 'hive-client-gateway-sdk' }, clientOrOptions.agent) })); void hive.info(); /** stores the resulting status from fetches */ const statusMap = new WeakMap(); /** stores the original query SDL to avoid having to print */ const operationCache = (0, tiny_lru_1.lru)((0, core_1.isHiveClient)(clientOrOptions) ? 10000 : ((_a = clientOrOptions.cache) !== null && _a !== void 0 ? _a : 10000)); if (hive[core_1.autoDisposeSymbol]) { if (global.process) { const signals = Array.isArray(hive[core_1.autoDisposeSymbol]) ? hive[core_1.autoDisposeSymbol] : ['SIGINT', 'SIGTERM']; for (const signal of signals) { process.once(signal, () => hive.dispose()); } } else { console.error('It seems that GraphQL Hive is not being executed in Node.js. ' + 'Please attempt manual client disposal and use autoDispose: false option.'); } } const fieldLevelMetricsEnabled = (0, core_1.isHiveClient)(clientOrOptions) ? false : ((_b = clientOrOptions.fieldLevelMetricsEnabled) !== null && _b !== void 0 ? _b : false); return { onFetch({ executionRequest }) { /** Only if the execution request is set, then this is a subgraph execution. */ if (!executionRequest) { return; } return function onFetchDone({ response }) { statusMap.set(executionRequest, response.status); }; }, onSubgraphExecute({ executionRequest, subgraphName, subgraph: subgraphSchema }) { var _a, _b; if (!fieldLevelMetricsEnabled) { // short circuit the entire hook to avoid processing this data. return; } const collection = (_a = executionRequest.context) === null || _a === void 0 ? void 0 : _a.__hiveUsageCollection; if (!collection) { // This is set onExecute so this should exist... but just to be safe return; } /** * Note that we need __typename on every abstract type in the subgraph call. * This is added in the "onExecute" hook to the entire document. So subgraph * calls should also include this field. */ const finishSubRequest = collection.subrequest({ subgraph: subgraphName, type: (0, is_entity_request_js_1.isEntityRequest)(executionRequest.document) ? 'ENTITY' : 'ROOT', /** @NOTE this field's format supports batched requests, but onSubgraphExecute does not. */ paths: ((_b = executionRequest.info) === null || _b === void 0 ? void 0 : _b.path) ? [(0, graphql_1.responsePathAsArray)(executionRequest.info.path).join('.')] : [], }); return function onSubgraphExecuteDone({ result }) { var _a; if (!(0, core_1.isAsyncIterable)(result)) { finishSubRequest({ status: (_a = statusMap.get(executionRequest)) !== null && _a !== void 0 ? _a : 200, subgraphSchema, result, document: executionRequest.document, }); } }; }, onSchemaChange({ schema }) { hive.reportSchema({ schema }); }, onExecute({ args }) { var _a; const collection = hive.collectUsage(); // Inject the collection object into the GraphQL context // so it can be accessed downstream by subgraph executions. if (args.contextValue) { args.contextValue.__hiveUsageCollection = collection; } // We need __typename on every object in the subgraph result so we can // resolve abstract types (unions/interfaces) to concrete type coordinates // when recording field-level metrics downstream. // This is done here for more performant caching of the result. const query = (_a = args.contextValue.params.query) !== null && _a !== void 0 ? _a : (0, graphql_1.print)(args.document); const cachedDocument = operationCache.get(query); if (cachedDocument) { // If "true" is cached, then this operation doesn't need stored because it's identical to the original. // Else, the document hash been modified and cached if (cachedDocument !== true) { args.document = cachedDocument; } } else { const modifiedDocument = (0, add_typenames_js_1.addTypenames)(args.document, args.schema); operationCache.set(query, args.document === modifiedDocument || args.document); } return { onExecuteDone({ result }) { if (!(0, core_1.isAsyncIterable)(result)) { void collection.finish(args, result); return; } const errors = []; return { onNext(ctx) { if (ctx.result.errors) { errors.push(...ctx.result.errors); } }, onEnd() { void collection.finish(args, errors.length ? { errors } : {}); }, }; }, }; }, onSubscribe({ args }) { hive.collectSubscriptionUsage({ args }); }, }; }