UNPKG

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

Version:
149 lines (148 loc) 7.46 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 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(); const fieldLevelMetricsEnabled = (0, core_1.isHiveClient)(clientOrOptions) ? false : (typeof clientOrOptions.usage === 'object' && ((_a = clientOrOptions.usage) === null || _a === void 0 ? void 0 : _a.fieldLevelMetricsEnabled)) || false; /** stores the original query SDL to avoid having to print */ const operationCache = fieldLevelMetricsEnabled ? (0, tiny_lru_1.lru)((0, core_1.isHiveClient)(clientOrOptions) ? 10000 : ((_b = clientOrOptions.cache) !== null && _b !== void 0 ? _b : 10000)) : null; let latestSchema = null; 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, _c, _d; 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('.')] : (_d = (0, core_1.getDefinedRootType)(subgraphSchema, (_c = executionRequest.operationType) !== null && _c !== void 0 ? _c : graphql_1.OperationTypeNode.QUERY)) === null || _d === void 0 ? void 0 : _d.name, }); 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 }); latestSchema = schema; operationCache === null || operationCache === void 0 ? void 0 : operationCache.clear(); }, onParse(parseCtx) { return ctx => { if (ctx.result.kind === 'Document' && fieldLevelMetricsEnabled && operationCache) { // 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 = parseCtx.params.source; 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) { parseCtx.setParsedDocument(cachedDocument); } } else if (latestSchema) { const modifiedDocument = (0, core_1.addHiveTypenames)(ctx.result, latestSchema); operationCache.set(query, ctx.result === modifiedDocument || modifiedDocument); if (ctx.result !== modifiedDocument) { parseCtx.setParsedDocument(modifiedDocument); } } } }; }, onExecute({ args }) { 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; } return { onExecuteDone({ result }) { if (!(0, core_1.isAsyncIterable)(result)) { if (result.data && fieldLevelMetricsEnabled) { (0, core_1.hideInjectedTypenames)(result.data); } void collection.finish(args, result); return; } const errors = []; return { onNext({ result }) { if (result.data && fieldLevelMetricsEnabled) { (0, core_1.hideInjectedTypenames)(result.data); } if (result.errors) { errors.push(...result.errors); } }, onEnd() { void collection.finish(args, errors.length ? { errors } : {}); }, }; }, }; }, onSubscribe({ args }) { hive.collectSubscriptionUsage({ args }); }, onDispose: async () => { await hive.dispose(); }, }; }