UNPKG

@graphql-hive/nestjs

Version:
251 lines (248 loc) • 9.78 kB
import { createLoggerFromLogging, PubSub, getCacheInstanceFromConfig, getBuiltinPluginsFromConfig, createGatewayRuntime, getGraphQLWSOptions } from '@graphql-hive/gateway'; import { Logger as Logger$1 } from '@graphql-hive/logger'; import { asArray } from '@graphql-tools/utils'; import { Injectable, Logger } from '@nestjs/common'; import { AbstractGraphQLDriver, GqlSubscriptionService } from '@nestjs/graphql'; import { handleMaybePromise } from '@whatwg-node/promise-helpers'; import { lexicographicSortSchema } from 'graphql'; var __create = Object.create; var __defProp = Object.defineProperty; var __getOwnPropDesc = Object.getOwnPropertyDescriptor; var __knownSymbol = (name, symbol) => (symbol = Symbol[name]) ? symbol : Symbol.for("Symbol." + name); var __typeError = (msg) => { throw TypeError(msg); }; var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value; var __name = (target, value) => __defProp(target, "name", { value, configurable: true }); var __decoratorStart = (base) => [, , , __create(base?.[__knownSymbol("metadata")] ?? null)]; var __decoratorStrings = ["class", "method", "getter", "setter", "accessor", "field", "value", "get", "set"]; var __expectFn = (fn) => fn !== void 0 && typeof fn !== "function" ? __typeError("Function expected") : fn; var __decoratorContext = (kind, name, done, metadata, fns) => ({ kind: __decoratorStrings[kind], name, metadata, addInitializer: (fn) => done._ ? __typeError("Already initialized") : fns.push(__expectFn(fn || null)) }); var __decoratorMetadata = (array, target) => __defNormalProp(target, __knownSymbol("metadata"), array[3]); var __runInitializers = (array, flags, self, value) => { for (var i = 0, fns = array[flags >> 1], n = fns && fns.length; i < n; i++) fns[i].call(self) ; return value; }; var __decorateElement = (array, flags, name, decorators, target, extra) => { var it, done, ctx, k = flags & 7, p = false; var j = 0; var extraInitializers = array[j] || (array[j] = []); var desc = k && ((target = target.prototype), k < 5 && (k > 3 || !p) && __getOwnPropDesc(target , name)); __name(target, name); for (var i = decorators.length - 1; i >= 0; i--) { ctx = __decoratorContext(k, name, done = {}, array[3], extraInitializers); it = (0, decorators[i])(target, ctx), done._ = 1; __expectFn(it) && (target = it); } return __decoratorMetadata(array, target), desc && __defProp(target, name, desc), p ? k ^ 4 ? extra : desc : target; }; var _HiveGatewayDriver_decorators, _init, _a; _HiveGatewayDriver_decorators = [Injectable()]; class HiveGatewayDriver extends (_a = AbstractGraphQLDriver) { _gatewayRuntime; _subscriptionService; async ensureGatewayRuntime({ typeDefs, resolvers, logging, ...options }) { if (this._gatewayRuntime) { return this._gatewayRuntime; } const additionalTypeDefs = []; if (typeDefs) { additionalTypeDefs.push(typeDefs); } const additionalResolvers = []; if (resolvers) { additionalResolvers.push(...asArray(resolvers)); } let log; if (logging != null) { log = createLoggerFromLogging(logging); } else { const nestLog = new Logger("Hive Gateway"); log = new Logger$1({ writers: [ { write(level, attrs, msg) { switch (level) { case "trace": nestLog.verbose(msg, attrs); break; case "info": nestLog.log(msg, attrs); break; default: nestLog[level](msg, attrs); } } } ] }); } const configCtx = { log, cwd: process.cwd(), pubsub: options.pubsub || new PubSub() }; const cache = await getCacheInstanceFromConfig(options, configCtx); const builtinPlugins = await getBuiltinPluginsFromConfig(options, { ...configCtx, cache }); this._gatewayRuntime = createGatewayRuntime({ ...options, logging: configCtx.log, cache, graphqlEndpoint: options.path, additionalTypeDefs, additionalResolvers, disableIntrospection: options.introspection === false ? { disableIf: () => options.introspection || false } : void 0, ...options.context || options.transformSchema || options.sortSchema ? { plugins: (ctx) => { const existingPlugins = options.plugins?.(ctx) || []; if (options.context) { const contextPlugin = { onContextBuilding: ({ context, extendContext }) => handleMaybePromise( () => typeof options.context === "function" ? options.context(context) : options.context, extendContext ) }; existingPlugins.push(contextPlugin); } if (options.transformSchema) { const schemaTransformPlugin = { onSchemaChange({ schema, replaceSchema }) { return handleMaybePromise( () => options.transformSchema(schema), replaceSchema ); } }; existingPlugins.push(schemaTransformPlugin); } if (options.sortSchema) { const schemaSortPlugin = { onSchemaChange({ schema, replaceSchema }) { replaceSchema(lexicographicSortSchema(schema)); } }; existingPlugins.push(schemaSortPlugin); } return [...builtinPlugins, ...existingPlugins]; } } : {} }); return this._gatewayRuntime; } async start(options) { const gatewayRuntime = await this.ensureGatewayRuntime(options); const platformName = this.httpAdapterHost.httpAdapter.getType(); if (platformName === "express") { this.registerExpress(); } else if (platformName === "fastify") { this.registerFastify(); } else { throw new Error(`No support for current HttpAdapter: ${platformName}`); } if (options.installSubscriptionHandlers || options.subscriptions) { const subscriptionsOptions = options.subscriptions || { "graphql-ws": {} }; if (subscriptionsOptions["graphql-ws"]) { const gwOptions = getGraphQLWSOptions( gatewayRuntime, (ctx) => ({ req: ctx.extra?.request, socket: ctx.extra?.socket }) ); subscriptionsOptions["graphql-ws"] = { ...gwOptions, ...typeof subscriptionsOptions["graphql-ws"] === "object" ? subscriptionsOptions["graphql-ws"] : {} }; } if (subscriptionsOptions["subscriptions-transport-ws"]) { subscriptionsOptions["subscriptions-transport-ws"] = typeof subscriptionsOptions["subscriptions-transport-ws"] === "object" ? subscriptionsOptions["subscriptions-transport-ws"] : {}; subscriptionsOptions["subscriptions-transport-ws"].onOperation = async (_msg, params, ws) => { const { schema, execute, subscribe, contextFactory, parse, validate } = gatewayRuntime.getEnveloped({ ...params.context, req: ( // @ts-expect-error upgradeReq does exist but is untyped ws.upgradeReq ), socket: ws, params }); const args = { schema, operationName: params.operationName, document: typeof params.query === "string" ? parse(params.query) : params.query, variables: params.variables, context: await contextFactory(), rootValue: { execute, subscribe } }; const errors = validate(args.schema, args.document); if (errors.length) return errors; return args; }; } this._subscriptionService = new GqlSubscriptionService( { schema: await gatewayRuntime.getSchema(), path: options.path, // @ts-expect-error - We know that execute and subscribe are defined execute: (args) => args.rootValue.execute(args), // @ts-expect-error - We know that execute and subscribe are defined subscribe: (args) => args.rootValue.subscribe(args), ...subscriptionsOptions }, this.httpAdapterHost.httpAdapter?.getHttpServer() ); } } async stop() { await Promise.all([ this._subscriptionService?.stop(), this._gatewayRuntime?.dispose() ]); } async generateSchema(options) { const gatewayRuntime = await this.ensureGatewayRuntime(options); return gatewayRuntime.getSchema(); } registerExpress() { if (!this._gatewayRuntime) { throw new Error("Hive Gateway is not initialized"); } this.httpAdapterHost.httpAdapter.use(this._gatewayRuntime); } registerFastify() { this.httpAdapterHost.httpAdapter.getInstance().all("*", async (req, reply) => { if (!this._gatewayRuntime) { throw new Error("Hive Gateway is not initialized"); } const response = await this._gatewayRuntime.handleNodeRequestAndResponse(req, reply, { req, reply }); response.headers.forEach((value, key) => { reply.header(key, value); }); reply.status(response.status); reply.send(response.body); return reply; }); } } _init = __decoratorStart(_a); HiveGatewayDriver = __decorateElement(_init, 0, "HiveGatewayDriver", _HiveGatewayDriver_decorators, HiveGatewayDriver); __runInitializers(_init, 1, HiveGatewayDriver); export { HiveGatewayDriver };