@graphql-hive/nestjs
Version:
307 lines (303 loc) • 11.3 kB
JavaScript
var gateway = require('@graphql-hive/gateway');
var utils = require('@graphql-tools/utils');
var common = require('@nestjs/common');
var graphql = require('@nestjs/graphql');
var promiseHelpers = require('@whatwg-node/promise-helpers');
var graphql$1 = require('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 = [common.Injectable()];
class HiveGatewayDriver extends (_a = graphql.AbstractGraphQLDriver) {
_gatewayRuntime;
_subscriptionService;
async ensureGatewayRuntime({
typeDefs,
resolvers,
...options
}) {
const additionalTypeDefs = [];
if (typeDefs) {
additionalTypeDefs.push(typeDefs);
}
const additionalResolvers = [];
if (resolvers) {
additionalResolvers.push(...utils.asArray(resolvers));
}
const logger = new NestJSLoggerAdapter(
"Hive Gateway",
{},
new common.Logger("Hive Gateway"),
options.debug ?? truthy(process.env["DEBUG"])
);
const configCtx = {
logger,
cwd: process.cwd(),
pubsub: options.pubsub || new gateway.PubSub()
};
const cache = await gateway.getCacheInstanceFromConfig(options, configCtx);
const builtinPlugins = await gateway.getBuiltinPluginsFromConfig(options, {
...configCtx,
cache
});
this._gatewayRuntime = gateway.createGatewayRuntime({
logging: configCtx.logger,
cache,
graphqlEndpoint: options.path,
additionalTypeDefs,
additionalResolvers,
disableIntrospection: options.introspection === false ? { disableIf: () => options.introspection || false } : void 0,
...options,
...options.context || options.transformSchema || options.sortSchema ? {
plugins: (ctx) => {
const existingPlugins = options.plugins?.(ctx) || [];
if (options.context) {
const contextPlugin = {
onContextBuilding: ({ context, extendContext }) => promiseHelpers.handleMaybePromise(
() => typeof options.context === "function" ? options.context(context) : options.context,
extendContext
)
};
existingPlugins.push(contextPlugin);
}
if (options.transformSchema) {
const schemaTransformPlugin = {
onSchemaChange({ schema, replaceSchema }) {
return promiseHelpers.handleMaybePromise(
() => options.transformSchema(schema),
replaceSchema
);
}
};
existingPlugins.push(schemaTransformPlugin);
}
if (options.sortSchema) {
const schemaSortPlugin = {
onSchemaChange({ schema, replaceSchema }) {
replaceSchema(graphql$1.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 = gateway.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) => {
if (!this._gatewayRuntime) {
throw new Error("Hive Gateway is not initialized");
}
const {
schema,
execute,
subscribe,
contextFactory,
parse,
validate
} = this._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 graphql.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 this._subscriptionService?.stop();
await this._gatewayRuntime?.dispose();
}
async generateSchema(options) {
const gatewayRuntime = await this.ensureGatewayRuntime(options);
return gatewayRuntime.getSchema();
}
registerExpress() {
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);
class NestJSLoggerAdapter {
constructor(name, meta, logger, isDebug) {
this.name = name;
this.meta = meta;
this.logger = logger;
this.isDebug = isDebug;
}
prepareMessage(args) {
const obj = {
...this.meta || {}
};
const strs = [];
const flattenedArgs = args.flatMap((arg) => typeof arg === "function" ? arg() : arg).flat(Number.POSITIVE_INFINITY);
for (const arg of flattenedArgs) {
if (typeof arg === "string" || typeof arg === "number") {
strs.push(arg.toString());
} else {
Object.assign(obj, arg);
}
}
return { obj, str: strs.join(", ") };
}
log(...args) {
const { obj, str } = this.prepareMessage(args);
if (Object.keys(obj).length) {
this.logger.log(obj, str);
} else {
this.logger.log(str);
}
}
info(...args) {
const { obj, str } = this.prepareMessage(args);
if (Object.keys(obj).length) {
this.logger.log(obj, str);
} else {
this.logger.log(str);
}
}
error(...args) {
const { obj, str } = this.prepareMessage(args);
if (Object.keys(obj).length) {
this.logger.error(obj, str);
} else {
this.logger.error(str);
}
}
warn(...args) {
const { obj, str } = this.prepareMessage(args);
if (Object.keys(obj).length) {
this.logger.warn(obj, str);
} else {
this.logger.warn(str);
}
}
debug(...args) {
if (!this.isDebug) {
return;
}
const { obj, str } = this.prepareMessage(args);
if (Object.keys(obj).length) {
this.logger.debug(obj, str);
} else {
this.logger.debug(str);
}
}
child(newNameOrMeta) {
const newName = typeof newNameOrMeta === "string" ? this.name ? `${this.name}, ${newNameOrMeta}` : newNameOrMeta : this.name;
const newMeta = typeof newNameOrMeta === "string" ? this.meta : { ...this.meta, ...newNameOrMeta };
return new NestJSLoggerAdapter(
newName,
newMeta,
new common.Logger(newName),
this.isDebug
);
}
}
function truthy(val) {
return val === true || val === 1 || ["1", "t", "true", "y", "yes"].includes(String(val));
}
exports.HiveGatewayDriver = HiveGatewayDriver;
;