UNPKG

@graphql-mesh/fusion-runtime

Version:

Runtime for GraphQL Mesh Fusion Supergraph

159 lines (158 loc) • 7.3 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.UnifiedGraphManager = void 0; exports.ensureSchema = ensureSchema; const graphql_1 = require("graphql"); const runtime_1 = require("@graphql-mesh/runtime"); const utils_1 = require("@graphql-mesh/utils"); const utils_2 = require("@graphql-tools/utils"); const disposablestack_1 = require("@whatwg-node/disposablestack"); const supergraph_js_1 = require("./federation/supergraph.js"); const utils_js_1 = require("./utils.js"); function ensureSchema(source) { if ((0, graphql_1.isSchema)(source)) { return source; } if (typeof source === 'string') { return (0, graphql_1.buildSchema)(source, { assumeValid: true, assumeValidSDL: true }); } if ((0, utils_2.isDocumentNode)(source)) { return (0, graphql_1.buildASTSchema)(source, { assumeValid: true, assumeValidSDL: true }); } return source; } class UnifiedGraphManager { constructor(opts) { this.opts = opts; this.disposableStack = new disposablestack_1.AsyncDisposableStack(); this.batch = opts.batch ?? true; this.handleUnifiedGraph = opts.handleUnifiedGraph || supergraph_js_1.handleFederationSupergraph; this.onSubgraphExecuteHooks = opts?.onSubgraphExecuteHooks || []; this.disposableStack.defer(() => { this.unifiedGraph = undefined; this.lastLoadedUnifiedGraph = undefined; this.inContextSDK = undefined; this.initialUnifiedGraph$ = undefined; this.pausePolling(); return this._transportExecutorStack?.disposeAsync(); }); } pausePolling() { if (this.currentTimeout) { clearTimeout(this.currentTimeout); this.currentTimeout = undefined; } } continuePolling() { if (this.opts.pollingInterval) { this.currentTimeout = setTimeout(() => { this.currentTimeout = undefined; return this.getAndSetUnifiedGraph(); }, this.opts.pollingInterval); } } ensureUnifiedGraph() { if (!this.initialUnifiedGraph$ && !this.unifiedGraph) { this.initialUnifiedGraph$ = this.getAndSetUnifiedGraph(); } return this.initialUnifiedGraph$; } getAndSetUnifiedGraph() { this.pausePolling(); try { return (0, utils_1.mapMaybePromise)(this.opts.getUnifiedGraph(this.opts.transportContext), (loadedUnifiedGraph) => { if (loadedUnifiedGraph != null && this.lastLoadedUnifiedGraph != null && (0, utils_js_1.compareSchemas)(loadedUnifiedGraph, this.lastLoadedUnifiedGraph)) { this.opts.transportContext?.logger?.debug('Unified Graph has not changed, skipping...'); this.continuePolling(); return; } if (this.lastLoadedUnifiedGraph != null) { this.opts.transportContext?.logger?.debug('Unified Graph changed, updating...'); } let cleanupJob$; if (this._transportExecutorStack) { cleanupJob$ = this._transportExecutorStack.disposeAsync(); } return (0, utils_1.mapMaybePromise)(cleanupJob$, () => { this._transportExecutorStack = new disposablestack_1.AsyncDisposableStack(); this.lastLoadedUnifiedGraph ||= loadedUnifiedGraph; this.lastLoadedUnifiedGraph = loadedUnifiedGraph; this.unifiedGraph = ensureSchema(loadedUnifiedGraph); const { unifiedGraph: newUnifiedGraph, transportEntryMap, subschemas, additionalResolvers, } = this.handleUnifiedGraph({ unifiedGraph: this.unifiedGraph, additionalTypeDefs: this.opts.additionalTypeDefs, additionalResolvers: this.opts.additionalResolvers, onSubgraphExecute(subgraphName, execReq) { return onSubgraphExecute(subgraphName, execReq); }, transportEntryAdditions: this.opts.transportEntryAdditions, batch: this.batch, }); this.unifiedGraph = newUnifiedGraph; const onSubgraphExecute = (0, utils_js_1.getOnSubgraphExecute)({ onSubgraphExecuteHooks: this.onSubgraphExecuteHooks, transports: this.opts.transports, transportContext: this.opts.transportContext, transportEntryMap, getSubgraphSchema(subgraphName) { const subgraph = subschemas.find(s => (0, utils_js_1.compareSubgraphNames)(s.name, subgraphName)); if (!subgraph) { throw new Error(`Subgraph ${subgraphName} not found`); } return subgraph.schema; }, transportExecutorStack: this._transportExecutorStack, }); if (this.opts.additionalResolvers || additionalResolvers.length) { this.inContextSDK = (0, runtime_1.getInContextSDK)(this.unifiedGraph, // @ts-expect-error Legacy Mesh RawSource is not compatible with new Mesh subschemas, this.opts.transportContext?.logger, this.opts.onDelegateHooks || []); } this.continuePolling(); this._transportEntryMap = transportEntryMap; this.opts.onSchemaChange?.(this.unifiedGraph); return true; }); }, err => { this.opts.transportContext?.logger?.error('Failed to load Supergraph', err); this.continuePolling(); if (!this.unifiedGraph) { throw err; } return true; }); } catch (e) { this.opts.transportContext?.logger?.error('Failed to load Supergraph', e); this.continuePolling(); if (!this.unifiedGraph) { throw e; } return true; } } getUnifiedGraph() { return (0, utils_1.mapMaybePromise)(this.ensureUnifiedGraph(), () => this.unifiedGraph); } getContext(base = {}) { return (0, utils_1.mapMaybePromise)(this.ensureUnifiedGraph(), () => { if (this.inContextSDK) { Object.assign(base, this.inContextSDK); } Object.assign(base, this.opts.transportContext); return base; }); } getTransportEntryMap() { return (0, utils_1.mapMaybePromise)(this.ensureUnifiedGraph(), () => this._transportEntryMap); } invalidateUnifiedGraph() { return this.getAndSetUnifiedGraph(); } [disposablestack_1.DisposableSymbols.asyncDispose]() { return this.disposableStack.disposeAsync(); } } exports.UnifiedGraphManager = UnifiedGraphManager;