Socket
Socket
Sign inDemoInstall

apollo-server-core

Package Overview
Dependencies
Maintainers
6
Versions
314
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

apollo-server-core - npm Package Compare versions

Comparing version 2.0.0-beta.0 to 2.0.0-beta.1

dist/logging.d.ts

4

CHANGELOG.md

@@ -5,3 +5,7 @@ # Changelog

* `apollo-server-core`: custom errors allow instanceof checks [PR#1074](https://github.com/apollographql/apollo-server/pull/1074)
* `apollo-server-core`: move subscriptions options into listen [PR#1059](https://github.com/apollographql/apollo-server/pull/1059)
* `apollo-server-core`: Replace console.error with logFunction for opt-in logging [PR #1024](https://github.com/apollographql/apollo-server/pull/1024)
* `apollo-server-core`: context creation can be async and errors are formatted to include error code [PR #1024](https://github.com/apollographql/apollo-server/pull/1024)
* `apollo-server-core`: add `mocks` parameter to the base constructor(applies to all variants) [PR#1017](https://github.com/apollographql/apollo-server/pull/1017)
* `apollo-server-core`: Remove printing of stack traces with `debug` option and include response in logging function[PR#1018](https://github.com/apollographql/apollo-server/pull/1018)

19

dist/ApolloServer.d.ts

@@ -1,9 +0,9 @@

/// <reference types="node" />
/// <reference types="@types/node" />
import { Server as HttpServer } from 'http';
import { GraphQLSchema, GraphQLError, GraphQLResolveInfo, ValidationContext } from 'graphql';
import { LogFunction } from './runQuery';
import { GraphQLSchema, GraphQLResolveInfo, ValidationContext } from 'graphql';
import { LogFunction } from './logging';
import { Config, ListenOptions, RegistrationOptions, ServerInfo } from './types';
export declare class ApolloServerBase<Request = RequestInit> {
subscriptions: Config<Request>['subscriptions'];
disableTools: boolean;
subscriptionsPath: string;
private schema;

@@ -13,5 +13,6 @@ private context?;

private graphqlPath;
private engine;
private engineProxy;
private engineEnabled;
private http?;
private subscriptionServer?;
protected getHttp: () => HttpServer;

@@ -23,6 +24,6 @@ constructor(config: Config<Request>);

private createSubscriptionServer(server, config);
private createEngine({engineInRequestPath, engine});
request(request: Request): Promise<{
private createEngine({engineInRequestPath, engineProxy});
request(request: Request): {
schema: GraphQLSchema;
formatError: Function | ((e: GraphQLError) => GraphQLError);
formatError?: Function;
rootValue?: any;

@@ -40,3 +41,3 @@ context: any;

cacheControl: any;
}>;
};
}

@@ -59,8 +59,6 @@ "use strict";

var errors_1 = require("./errors");
var env = process.env.NODE_ENV;
var isDev = env !== 'production' && env !== 'test';
var NoIntrospection = function (context) { return ({
Field: function (node) {
if (node.name.value === '__schema' || node.name.value === '__type') {
context.reportError(new graphql_1.GraphQLError('GraphQL introspection is not allowed by Apollo Server, but the query containted __schema or __type. To enable introspection, pass enableIntrospection: true to ApolloServer in production', [node]));
context.reportError(new graphql_1.GraphQLError('GraphQL introspection is not allowed by Apollo Server, but the query contained __schema or __type. To enable introspection, pass introspection: true to ApolloServer in production', [node]));
}

@@ -71,8 +69,11 @@ },

function ApolloServerBase(config) {
this.disableTools = !isDev;
this.graphqlPath = '/graphql';
this.engineEnabled = false;
var context = config.context, resolvers = config.resolvers, schema = config.schema, schemaDirectives = config.schemaDirectives, subscriptions = config.subscriptions, typeDefs = config.typeDefs, enableIntrospection = config.enableIntrospection, mocks = config.mocks, requestOptions = __rest(config, ["context", "resolvers", "schema", "schemaDirectives", "subscriptions", "typeDefs", "enableIntrospection", "mocks"]);
if (enableIntrospection || isDev)
this.disableTools = false;
var context = config.context, resolvers = config.resolvers, schema = config.schema, schemaDirectives = config.schemaDirectives, typeDefs = config.typeDefs, introspection = config.introspection, mocks = config.mocks, requestOptions = __rest(config, ["context", "resolvers", "schema", "schemaDirectives", "typeDefs", "introspection", "mocks"]);
var env = process.env.NODE_ENV;
var isDev = env !== 'production' && env !== 'test';
if (typeof introspection === 'boolean')
this.disableTools = !introspection;
else
this.disableTools = !isDev;
if (this.disableTools) {

@@ -89,5 +90,3 @@ var noIntro = [NoIntrospection];

: graphql_tools_1.makeExecutableSchema({
typeDefs: Array.isArray(typeDefs)
? typeDefs.reduce(function (prev, next) { return prev + '\n' + next; })
: typeDefs,
typeDefs: Array.isArray(typeDefs) ? typeDefs.join('\n') : typeDefs,
schemaDirectives: schemaDirectives,

@@ -103,3 +102,2 @@ resolvers: resolvers,

}
this.subscriptions = subscriptions;
}

@@ -115,45 +113,56 @@ ApolloServerBase.prototype.use = function (_a) {

this.http = this.getHttp();
var options = __assign({ port: process.env.PORT || 4000 }, opts);
if (this.subscriptions !== false) {
var config = this.subscriptions === true || typeof this.subscriptions === 'undefined'
? {
var options = __assign({}, opts, { http: __assign({ port: process.env.PORT || 4000 }, opts.http) });
if (opts.subscriptions !== false) {
var config = void 0;
if (opts.subscriptions === true ||
typeof opts.subscriptions === 'undefined') {
config = {
path: this.graphqlPath,
}
: this.subscriptions;
this.createSubscriptionServer(this.http, config);
};
}
else if (typeof opts.subscriptions === 'string') {
config = { path: opts.subscriptions };
}
else {
config = __assign({ path: this.graphqlPath }, opts.subscriptions);
}
this.subscriptionsPath = config.path;
this.subscriptionServer = this.createSubscriptionServer(this.http, config);
}
if (opts.engine || opts.engineInRequestPath)
if (opts.engineProxy || opts.engineInRequestPath)
this.createEngine(opts);
return new Promise(function (success, fail) {
if (_this.engine) {
_this.engine.listen(Object.assign({}, options.engineLauncherOptions, {
return new Promise(function (resolve, reject) {
if (_this.engineProxy) {
_this.engineProxy.listen({
graphqlPaths: [_this.graphqlPath],
port: options.port,
port: options.http.port,
httpServer: _this.http,
}), function () {
_this.engine.engineListeningAddress.url = require('url').resolve(_this.engine.engineListeningAddress.url, _this.graphqlPath);
success(_this.engine.engineListeningAddress);
launcherOptions: options.engineLauncherOptions,
}, function () {
_this.engineProxy.engineListeningAddress.url = require('url').resolve(_this.engineProxy.engineListeningAddress.url, _this.graphqlPath);
resolve(_this.engineProxy.engineListeningAddress);
});
_this.engine.on('error', fail);
_this.engineProxy.on('error', reject);
return;
}
_this.http.listen({
port: options.port,
host: options.host,
path: options.path,
backlog: options.backlog,
exclusive: options.exclusive,
}, function () {
var la = _this.http.address();
var hostForUrl = la.address;
if (la.address === '' || la.address === '::')
function listenCallback() {
var listeningAddress = this.http.address();
var hostForUrl = listeningAddress.address;
if (listeningAddress.address === '' ||
listeningAddress.address === '::')
hostForUrl = 'localhost';
la.url = require('url').format({
listeningAddress.url = require('url').format({
protocol: 'http',
hostname: hostForUrl,
port: la.port,
pathname: _this.graphqlPath,
port: listeningAddress.port,
pathname: this.graphqlPath,
});
success(la);
});
resolve(listeningAddress);
}
if (options.http.handle) {
_this.http.listen(options.http.handle, options.http.backlog, listenCallback.bind(_this));
}
else {
_this.http.listen(options.http, listenCallback.bind(_this));
}
});

@@ -167,4 +176,4 @@ };

case 0:
if (!this.engine) return [3, 2];
return [4, this.engine.stop()];
if (!this.engineProxy) return [3, 2];
return [4, this.engineProxy.stop()];
case 1:

@@ -174,8 +183,14 @@ _a.sent();

case 2:
if (!this.http) return [3, 4];
return [4, new Promise(function (s) { return _this.http.close(s); })];
if (!this.subscriptionServer) return [3, 4];
return [4, this.subscriptionServer.close()];
case 3:
_a.sent();
_a.label = 4;
case 4: return [2];
case 4:
if (!this.http) return [3, 6];
return [4, new Promise(function (s) { return _this.http.close(s); })];
case 5:
_a.sent();
_a.label = 6;
case 6: return [2];
}

@@ -187,4 +202,4 @@ });

var _this = this;
var onDisconnect = config.onDisconnect, onConnect = config.onConnect, keepAlive = config.keepAlive;
subscriptions_transport_ws_1.SubscriptionServer.create({
var onDisconnect = config.onDisconnect, onConnect = config.onConnect, keepAlive = config.keepAlive, path = config.path;
return subscriptions_transport_ws_1.SubscriptionServer.create({
schema: this.schema,

@@ -198,2 +213,3 @@ execute: graphql_1.execute,

onOperation: function (_, connection) { return __awaiter(_this, void 0, void 0, function () {
var _this = this;
var context, _a, e_1;

@@ -203,3 +219,8 @@ return __generator(this, function (_b) {

case 0:
connection.formatResponse = function (value) { return (__assign({}, value, { errors: value.errors && value.errors.map(function (err) { return errors_1.internalFormatError(err); }) })); };
connection.formatResponse = function (value) { return (__assign({}, value, { errors: value.errors &&
errors_1.formatApolloErrors(value.errors.slice(), {
formatter: _this.requestOptions.formatError,
debug: _this.requestOptions.debug,
logFunction: _this.requestOptions.logFunction,
}) })); };
context = this.context ? this.context : { connection: connection };

@@ -222,4 +243,7 @@ _b.label = 1;

e_1 = _b.sent();
console.error(e_1);
throw e_1;
throw errors_1.formatApolloErrors([e_1], {
formatter: this.requestOptions.formatError,
debug: this.requestOptions.debug,
logFunction: this.requestOptions.logFunction,
})[0];
case 6: return [2, __assign({}, connection, { context: context })];

@@ -232,13 +256,13 @@ }

server: server,
path: this.graphqlPath,
path: path,
});
};
ApolloServerBase.prototype.createEngine = function (_a) {
var engineInRequestPath = _a.engineInRequestPath, engine = _a.engine;
var engineInRequestPath = _a.engineInRequestPath, engineProxy = _a.engineProxy;
var _b = process.env, ENGINE_API_KEY = _b.ENGINE_API_KEY, ENGINE_CONFIG = _b.ENGINE_CONFIG;
if (engine === false && (ENGINE_API_KEY || ENGINE_CONFIG)) {
if (engineProxy === false && (ENGINE_API_KEY || ENGINE_CONFIG)) {
console.warn('engine is set to false when creating ApolloServer but either ENGINE_CONFIG or ENGINE_API_KEY was found in the environment');
}
var ApolloEngine;
if (engine) {
if (engineProxy) {
try {

@@ -250,31 +274,15 @@ ApolloEngine = require('apollo-engine').ApolloEngine;

}
this.engine = new ApolloEngine(typeof engine === 'boolean' ? undefined : engine);
this.engineProxy = new ApolloEngine(typeof engineProxy === 'boolean' ? undefined : engineProxy);
}
if (this.engine || engineInRequestPath)
if (this.engineProxy || engineInRequestPath)
this.engineEnabled = true;
};
ApolloServerBase.prototype.request = function (request) {
return __awaiter(this, void 0, void 0, function () {
var _this = this;
var context, _a;
return __generator(this, function (_b) {
switch (_b.label) {
case 0:
context = this.context ? this.context : { request: request };
if (!(typeof this.context === 'function')) return [3, 2];
return [4, this.context({ req: request })];
case 1:
_a = _b.sent();
return [3, 3];
case 2:
_a = context;
_b.label = 3;
case 3:
context = _a;
return [2, __assign({ schema: this.schema, tracing: Boolean(this.engineEnabled), cacheControl: Boolean(this.engineEnabled), formatError: function (e) {
return errors_1.internalFormatError(e, _this.requestOptions.debug);
}, context: context }, this.requestOptions)];
}
});
});
var _this = this;
var context = this.context ? this.context : { request: request };
context =
typeof this.context === 'function'
? function () { return _this.context({ req: request }); }
: context;
return __assign({ schema: this.schema, tracing: this.engineEnabled, cacheControl: this.engineEnabled, context: context }, this.requestOptions);
};

@@ -281,0 +289,0 @@ return ApolloServerBase;

import { GraphQLError } from 'graphql';
export declare class ApolloError extends Error {
extensions: any;
import { LogFunction } from './logging';
export declare class ApolloError extends Error implements GraphQLError {
extensions: Record<string, any>;
readonly name: string;
readonly locations: any;
readonly path: any;
readonly source: any;
readonly positions: any;
readonly nodes: any;
originalError: any;
[key: string]: any;
constructor(message: string, code?: string, properties?: Record<string, any>);
}
export declare function internalFormatError(error: GraphQLError, debug?: boolean): GraphQLError;
export declare function toApolloError(error: Error, code?: string): Error & {
export declare function toApolloError(error: Error & {
extensions?: Record<string, any>;
}, code?: string): Error & {
extensions: Record<string, any>;

@@ -14,3 +24,3 @@ };

}
export declare function fromGraphQLError(error: GraphQLError, options?: ErrorOptions): GraphQLError;
export declare function fromGraphQLError(error: GraphQLError, options?: ErrorOptions): ApolloError;
export declare class SyntaxError extends ApolloError {

@@ -28,1 +38,6 @@ constructor(message: string);

}
export declare function formatApolloErrors(errors: Array<Error>, options?: {
formatter?: Function;
logFunction?: LogFunction;
debug?: boolean;
}): Array<ApolloError>;

@@ -21,2 +21,4 @@ "use strict";

Object.defineProperty(exports, "__esModule", { value: true });
var graphql_1 = require("graphql");
var logging_1 = require("./logging");
var ApolloError = (function (_super) {

@@ -26,3 +28,10 @@ __extends(ApolloError, _super);

var _this = _super.call(this, message) || this;
_this.extensions = __assign({}, properties, { code: code });
_this.name = 'ApolloError';
Object.setPrototypeOf(_this, ApolloError.prototype);
if (properties) {
Object.keys(properties).forEach(function (key) {
_this[key] = properties[key];
});
}
_this.extensions = { code: code };
return _this;

@@ -33,5 +42,36 @@ }

exports.ApolloError = ApolloError;
function internalFormatError(error, debug) {
function enrichError(error, debug) {
if (debug === void 0) { debug = false; }
var expanded = __assign({ message: error.message, path: error.path, locations: error.locations }, error, { extensions: __assign({}, error.extensions, { code: (error.extensions && error.extensions.code) || 'INTERNAL_SERVER_ERROR', exception: __assign({}, (error.extensions && error.extensions.exception), error.originalError) }) });
var expanded = {};
Object.defineProperties(expanded, {
name: {
value: error.name,
},
message: {
value: error.message,
enumerable: true,
writable: true,
},
locations: {
value: error.locations || undefined,
enumerable: true,
},
path: {
value: error.path || undefined,
enumerable: true,
},
nodes: {
value: error.nodes || undefined,
},
source: {
value: error.source || undefined,
},
positions: {
value: error.positions || undefined,
},
originalError: {
value: error.originalError,
},
});
expanded.extensions = __assign({}, error.extensions, { code: (error.extensions && error.extensions.code) || 'INTERNAL_SERVER_ERROR', exception: __assign({}, (error.extensions && error.extensions.exception), error.originalError) });
delete expanded.extensions.exception.extensions;

@@ -50,3 +90,2 @@ if (debug && !expanded.extensions.exception.stacktrace) {

}
exports.internalFormatError = internalFormatError;
function toApolloError(error, code) {

@@ -76,3 +115,3 @@ if (code === void 0) { code = 'INTERNAL_SERVER_ERROR'; }

Object.defineProperty(copy, 'originalError', { value: {} });
Reflect.ownKeys(error).forEach(function (key) {
Object.getOwnPropertyNames(error).forEach(function (key) {
Object.defineProperty(copy.originalError, key, { value: error[key] });

@@ -86,3 +125,6 @@ });

function SyntaxError(message) {
return _super.call(this, message, 'GRAPHQL_PARSE_FAILED') || this;
var _this = _super.call(this, message, 'GRAPHQL_PARSE_FAILED') || this;
Object.setPrototypeOf(_this, SyntaxError.prototype);
Object.defineProperty(_this, 'name', { value: 'SyntaxError' });
return _this;
}

@@ -95,3 +137,6 @@ return SyntaxError;

function ValidationError(message) {
return _super.call(this, message, 'GRAPHQL_VALIDATION_FAILED') || this;
var _this = _super.call(this, message, 'GRAPHQL_VALIDATION_FAILED') || this;
Object.setPrototypeOf(_this, ValidationError.prototype);
Object.defineProperty(_this, 'name', { value: 'ValidationError' });
return _this;
}

@@ -104,3 +149,6 @@ return ValidationError;

function AuthenticationError(message) {
return _super.call(this, message, 'UNAUTHENTICATED') || this;
var _this = _super.call(this, message, 'UNAUTHENTICATED') || this;
Object.setPrototypeOf(_this, AuthenticationError.prototype);
Object.defineProperty(_this, 'name', { value: 'AuthenticationError' });
return _this;
}

@@ -113,3 +161,6 @@ return AuthenticationError;

function ForbiddenError(message) {
return _super.call(this, message, 'FORBIDDEN') || this;
var _this = _super.call(this, message, 'FORBIDDEN') || this;
Object.setPrototypeOf(_this, ForbiddenError.prototype);
Object.defineProperty(_this, 'name', { value: 'ForbiddenError' });
return _this;
}

@@ -119,2 +170,33 @@ return ForbiddenError;

exports.ForbiddenError = ForbiddenError;
function formatApolloErrors(errors, options) {
if (!options) {
return errors.map(function (error) { return enrichError(error); });
}
var formatter = options.formatter, debug = options.debug, logFunction = options.logFunction;
var enrichedErrors = errors.map(function (error) { return enrichError(error, debug); });
if (!formatter) {
return enrichedErrors;
}
return enrichedErrors.map(function (error) {
try {
return formatter(error);
}
catch (err) {
logFunction({
action: logging_1.LogAction.cleanup,
step: logging_1.LogStep.status,
data: err,
key: 'error',
});
if (debug) {
return enrichError(err, debug);
}
else {
var newError = fromGraphQLError(new graphql_1.GraphQLError('Internal server error'));
return enrichError(newError, debug);
}
}
});
}
exports.formatApolloErrors = formatApolloErrors;
//# sourceMappingURL=errors.js.map
import { GraphQLSchema, ValidationContext, GraphQLFieldResolver } from 'graphql';
import { LogFunction } from './runQuery';
export interface GraphQLServerOptions<TContext = any> {
import { LogFunction } from './logging';
export interface GraphQLServerOptions<TContext = (() => Promise<Record<string, any>> | Record<string, any>) | Record<string, any>> {
schema: GraphQLSchema;

@@ -18,2 +18,2 @@ formatError?: Function;

export default GraphQLServerOptions;
export declare function resolveGraphqlOptions(options: GraphQLServerOptions | Function, ...args: any[]): Promise<GraphQLServerOptions>;
export declare function resolveGraphqlOptions(options: GraphQLServerOptions | ((...args: Array<any>) => Promise<GraphQLServerOptions> | GraphQLServerOptions), ...args: Array<any>): Promise<GraphQLServerOptions>;

@@ -44,18 +44,9 @@ "use strict";

return __awaiter(this, void 0, void 0, function () {
var e_1;
return __generator(this, function (_a) {
switch (_a.label) {
case 0:
if (!(typeof options === 'function')) return [3, 5];
_a.label = 1;
case 1:
_a.trys.push([1, 3, , 4]);
if (!(typeof options === 'function')) return [3, 2];
return [4, options.apply(void 0, args)];
case 2: return [2, _a.sent()];
case 3:
e_1 = _a.sent();
throw new Error("Invalid options provided to ApolloServer: " + e_1.message);
case 4: return [3, 6];
case 5: return [2, options];
case 6: return [2];
case 1: return [2, _a.sent()];
case 2: return [2, options];
}

@@ -62,0 +53,0 @@ });

@@ -1,6 +0,7 @@

export { runQuery, LogFunction, LogMessage, LogStep, LogAction } from './runQuery';
export { runQuery } from './runQuery';
export { LogFunction, LogMessage, LogStep, LogAction } from './logging';
export { runHttpQuery, HttpQueryRequest, HttpQueryError } from './runHttpQuery';
export { default as GraphQLOptions, resolveGraphqlOptions } from './graphqlOptions';
export { ApolloError, toApolloError, SyntaxError, ValidationError, AuthenticationError, ForbiddenError, internalFormatError } from './errors';
export { ApolloError, toApolloError, SyntaxError, ValidationError, AuthenticationError, ForbiddenError, formatApolloErrors } from './errors';
export { ApolloServerBase } from './ApolloServer';
export * from './types';

@@ -5,4 +5,5 @@ "use strict";

exports.runQuery = runQuery_1.runQuery;
exports.LogStep = runQuery_1.LogStep;
exports.LogAction = runQuery_1.LogAction;
var logging_1 = require("./logging");
exports.LogStep = logging_1.LogStep;
exports.LogAction = logging_1.LogAction;
var runHttpQuery_1 = require("./runHttpQuery");

@@ -20,5 +21,5 @@ exports.runHttpQuery = runHttpQuery_1.runHttpQuery;

exports.ForbiddenError = errors_1.ForbiddenError;
exports.internalFormatError = errors_1.internalFormatError;
exports.formatApolloErrors = errors_1.formatApolloErrors;
var ApolloServer_1 = require("./ApolloServer");
exports.ApolloServerBase = ApolloServer_1.ApolloServerBase;
//# sourceMappingURL=index.js.map
import { default as GraphQLOptions } from './graphqlOptions';
export interface HttpQueryRequest {
method: string;
query: Record<string, any>;
options: GraphQLOptions | Function;
query: Record<string, any> | Array<Record<string, any>>;
options: GraphQLOptions | ((...args: Array<any>) => Promise<GraphQLOptions> | GraphQLOptions);
}

@@ -7,0 +7,0 @@ export declare class HttpQueryError extends Error {

@@ -68,7 +68,8 @@ "use strict";

var operationAST = graphql_1.getOperationAST(query, operationName);
return operationAST.operation === 'query';
return (Boolean(operationAST) && operationAST && operationAST.operation === 'query');
}
function runHttpQuery(handlerArguments, request) {
return __awaiter(this, void 0, void 0, function () {
var isGetRequest, optionsObject, e_1, formatErrorFn, debugDefault, debug, requestPayload, isBatch, requests, responses, gqlResponse;
var _this = this;
var isGetRequest, optionsObject, debugDefault, e_1, debug, requestPayload, isBatch, requests, responses, gqlResponse;
return __generator(this, function (_a) {

@@ -78,2 +79,3 @@ switch (_a.label) {

isGetRequest = false;
debugDefault = process.env.NODE_ENV !== 'production' && process.env.NODE_ENV !== 'test';
_a.label = 1;

@@ -88,8 +90,12 @@ case 1:

e_1 = _a.sent();
throw new HttpQueryError(500, e_1.message);
e_1.message = "Invalid options provided to ApolloServer: " + e_1.message;
if (!debugDefault) {
e_1.warning = "To remove the stacktrace, set the NODE_ENV environment variable to production if the options creation can fail";
}
throw new HttpQueryError(500, JSON.stringify({
errors: errors_1.formatApolloErrors([e_1], { debug: debugDefault }),
}), true, {
'Content-Type': 'application/json',
});
case 4:
formatErrorFn = optionsObject.formatError
? function (error) { return optionsObject.formatError(errors_1.internalFormatError(error)); }
: errors_1.internalFormatError;
debugDefault = process.env.NODE_ENV !== 'production' && process.env.NODE_ENV !== 'test';
debug = optionsObject.debug !== undefined ? optionsObject.debug : debugDefault;

@@ -120,83 +126,120 @@ switch (request.method) {

}
requests = requestPayload.map(function (requestParams) {
try {
var query = requestParams.query;
var extensions = requestParams.extensions;
if (isGetRequest && extensions) {
try {
extensions = JSON.parse(extensions);
}
catch (error) {
throw new HttpQueryError(400, 'Extensions are invalid JSON.');
}
}
if (query === undefined && extensions && extensions.persistedQuery) {
throw new HttpQueryError(200, JSON.stringify({
errors: [
{
message: 'PersistedQueryNotSupported',
},
],
}), true, {
'Content-Type': 'application/json',
});
}
if (isGetRequest) {
if (typeof query === 'string') {
query = graphql_1.parse(query);
}
else if (!query) {
throw new HttpQueryError(400, 'Must provide query string.');
}
if (!isQueryOperation(query, requestParams.operationName)) {
throw new HttpQueryError(405, "GET supports only query operation", false, {
Allow: 'POST',
requests = requestPayload.map(function (requestParams) { return __awaiter(_this, void 0, void 0, function () {
var query, extensions, operationName, variables, context_1, e_2, params, e_3;
return __generator(this, function (_a) {
switch (_a.label) {
case 0:
_a.trys.push([0, 8, , 9]);
query = requestParams.query;
extensions = requestParams.extensions;
if (isGetRequest && extensions) {
try {
extensions = JSON.parse(extensions);
}
catch (error) {
throw new HttpQueryError(400, 'Extensions are invalid JSON.');
}
}
if (query === undefined && extensions && extensions.persistedQuery) {
throw new HttpQueryError(200, JSON.stringify({
errors: [
{
message: 'PersistedQueryNotSupported',
},
],
}), true, {
'Content-Type': 'application/json',
});
}
if (isGetRequest) {
if (typeof query === 'string') {
query = graphql_1.parse(query);
}
else if (!query) {
throw new HttpQueryError(400, 'Must provide query string.');
}
if (!isQueryOperation(query, requestParams.operationName)) {
throw new HttpQueryError(405, "GET supports only query operation", false, {
Allow: 'POST',
});
}
}
operationName = requestParams.operationName;
variables = requestParams.variables;
if (typeof variables === 'string') {
try {
variables = JSON.parse(variables);
}
catch (error) {
throw new HttpQueryError(400, 'Variables are invalid JSON.');
}
}
context_1 = optionsObject.context;
if (!!context_1) return [3, 1];
context_1 = {};
return [3, 7];
case 1:
if (!(typeof context_1 === 'function')) return [3, 6];
_a.label = 2;
case 2:
_a.trys.push([2, 4, , 5]);
return [4, context_1()];
case 3:
context_1 = _a.sent();
return [3, 5];
case 4:
e_2 = _a.sent();
e_2.message = "Context creation failed: " + e_2.message;
throw new HttpQueryError(500, JSON.stringify({
errors: errors_1.formatApolloErrors([e_2], {
formatter: optionsObject.formatError,
debug: debug,
logFunction: optionsObject.logFunction,
}),
}), true, {
'Content-Type': 'application/json',
});
}
case 5: return [3, 7];
case 6:
if (isBatch) {
context_1 = Object.assign(Object.create(Object.getPrototypeOf(context_1)), context_1);
}
_a.label = 7;
case 7:
params = {
schema: optionsObject.schema,
query: query,
variables: variables,
context: context_1,
rootValue: optionsObject.rootValue,
operationName: operationName,
logFunction: optionsObject.logFunction,
validationRules: optionsObject.validationRules,
formatError: optionsObject.formatError,
formatResponse: optionsObject.formatResponse,
fieldResolver: optionsObject.fieldResolver,
debug: optionsObject.debug,
tracing: optionsObject.tracing,
cacheControl: optionsObject.cacheControl,
};
if (optionsObject.formatParams) {
params = optionsObject.formatParams(params);
}
return [2, runQuery_1.runQuery(params)];
case 8:
e_3 = _a.sent();
if (e_3.name === 'HttpQueryError') {
throw e_3;
}
return [2, {
errors: errors_1.formatApolloErrors([e_3], {
formatter: optionsObject.formatError,
debug: debug,
logFunction: optionsObject.logFunction,
}),
}];
case 9: return [2];
}
var operationName = requestParams.operationName;
var variables = requestParams.variables;
if (typeof variables === 'string') {
try {
variables = JSON.parse(variables);
}
catch (error) {
throw new HttpQueryError(400, 'Variables are invalid JSON.');
}
}
var context_1 = optionsObject.context || {};
if (typeof context_1 === 'function') {
context_1 = context_1();
}
else if (isBatch) {
context_1 = Object.assign(Object.create(Object.getPrototypeOf(context_1)), context_1);
}
var params = {
schema: optionsObject.schema,
query: query,
variables: variables,
context: context_1,
rootValue: optionsObject.rootValue,
operationName: operationName,
logFunction: optionsObject.logFunction,
validationRules: optionsObject.validationRules,
formatError: formatErrorFn,
formatResponse: optionsObject.formatResponse,
fieldResolver: optionsObject.fieldResolver,
debug: optionsObject.debug,
tracing: optionsObject.tracing,
cacheControl: optionsObject.cacheControl,
};
if (optionsObject.formatParams) {
params = optionsObject.formatParams(params);
}
return runQuery_1.runQuery(params);
}
catch (e) {
if (e.name === 'HttpQueryError') {
return Promise.reject(e);
}
return Promise.resolve({ errors: [formatErrorFn(e)] });
}
});
});
}); });
return [4, Promise.all(requests)];

@@ -203,0 +246,0 @@ case 5:

import { GraphQLSchema, GraphQLFieldResolver, DocumentNode, GraphQLError, ValidationContext } from 'graphql';
import { LogFunction } from './logging';
export interface GraphQLResponse {

@@ -7,22 +8,2 @@ data?: object;

}
export declare enum LogAction {
request = 0,
parse = 1,
validation = 2,
execute = 3,
}
export declare enum LogStep {
start = 0,
end = 1,
status = 2,
}
export interface LogMessage {
action: LogAction;
step: LogStep;
key?: string;
data?: any;
}
export interface LogFunction {
(message: LogMessage): any;
}
export interface QueryOptions {

@@ -29,0 +10,0 @@ schema: GraphQLSchema;

@@ -8,15 +8,3 @@ "use strict";

var errors_1 = require("./errors");
var LogAction;
(function (LogAction) {
LogAction[LogAction["request"] = 0] = "request";
LogAction[LogAction["parse"] = 1] = "parse";
LogAction[LogAction["validation"] = 2] = "validation";
LogAction[LogAction["execute"] = 3] = "execute";
})(LogAction = exports.LogAction || (exports.LogAction = {}));
var LogStep;
(function (LogStep) {
LogStep[LogStep["start"] = 0] = "start";
LogStep[LogStep["end"] = 1] = "end";
LogStep[LogStep["status"] = 2] = "status";
})(LogStep = exports.LogStep || (exports.LogStep = {}));
var logging_1 = require("./logging");
function runQuery(options) {

@@ -26,20 +14,2 @@ return Promise.resolve().then(function () { return doRunQuery(options); });

exports.runQuery = runQuery;
function format(errors, options) {
var formatter = options.formatter, debug = options.debug;
return errors.map(function (error) { return errors_1.internalFormatError(error, debug); }).map(function (error) {
if (formatter !== undefined) {
try {
return formatter(error);
}
catch (err) {
console.error('Error in formatError function:', err);
var newError = errors_1.fromGraphQLError(new graphql_1.GraphQLError('Internal server error'));
return errors_1.internalFormatError(newError, debug);
}
}
else {
return error;
}
});
}
function doRunQuery(options) {

@@ -53,3 +23,3 @@ var documentAST;

var debug = options.debug !== undefined ? options.debug : debugDefault;
logFunction({ action: LogAction.request, step: LogStep.start });
logFunction({ action: logging_1.LogAction.request, step: logging_1.LogStep.start });
var context = options.context || {};

@@ -74,4 +44,4 @@ var extensions = [];

logFunction({
action: LogAction.request,
step: LogStep.status,
action: logging_1.LogAction.request,
step: logging_1.LogStep.status,
key: 'query',

@@ -81,4 +51,4 @@ data: qry,

logFunction({
action: LogAction.request,
step: LogStep.status,
action: logging_1.LogAction.request,
step: logging_1.LogStep.status,
key: 'variables',

@@ -88,4 +58,4 @@ data: options.variables,

logFunction({
action: LogAction.request,
step: LogStep.status,
action: logging_1.LogAction.request,
step: logging_1.LogStep.status,
key: 'operationName',

@@ -96,10 +66,10 @@ data: options.operationName,

try {
logFunction({ action: LogAction.parse, step: LogStep.start });
logFunction({ action: logging_1.LogAction.parse, step: logging_1.LogStep.start });
documentAST = graphql_1.parse(options.query);
logFunction({ action: LogAction.parse, step: LogStep.end });
logFunction({ action: logging_1.LogAction.parse, step: logging_1.LogStep.end });
}
catch (syntaxError) {
logFunction({ action: LogAction.parse, step: LogStep.end });
logFunction({ action: logging_1.LogAction.parse, step: logging_1.LogStep.end });
return Promise.resolve({
errors: format([
errors: errors_1.formatApolloErrors([
errors_1.fromGraphQLError(syntaxError, {

@@ -122,11 +92,12 @@ errorClass: errors_1.SyntaxError,

}
logFunction({ action: LogAction.validation, step: LogStep.start });
logFunction({ action: logging_1.LogAction.validation, step: logging_1.LogStep.start });
var validationErrors = graphql_1.validate(options.schema, documentAST, rules);
logFunction({ action: LogAction.validation, step: LogStep.end });
logFunction({ action: logging_1.LogAction.validation, step: logging_1.LogStep.end });
if (validationErrors.length) {
return Promise.resolve({
errors: format(validationErrors.map(function (err) {
errors: errors_1.formatApolloErrors(validationErrors.map(function (err) {
return errors_1.fromGraphQLError(err, { errorClass: errors_1.ValidationError });
}), {
formatter: options.formatError,
logFunction: logFunction,
debug: debug,

@@ -140,5 +111,5 @@ }),

try {
logFunction({ action: LogAction.execute, step: LogStep.start });
logFunction({ action: logging_1.LogAction.execute, step: logging_1.LogStep.start });
return Promise.resolve(graphql_1.execute(options.schema, documentAST, options.rootValue, context, options.variables, options.operationName, options.fieldResolver)).then(function (result) {
logFunction({ action: LogAction.execute, step: LogStep.end });
logFunction({ action: logging_1.LogAction.execute, step: logging_1.LogStep.end });
var response = {

@@ -148,4 +119,5 @@ data: result.data,

if (result.errors) {
response.errors = format(result.errors, {
response.errors = errors_1.formatApolloErrors(result.errors.slice(), {
formatter: options.formatError,
logFunction: logFunction,
debug: debug,

@@ -163,4 +135,4 @@ });

logFunction({
action: LogAction.request,
step: LogStep.end,
action: logging_1.LogAction.request,
step: logging_1.LogStep.end,
key: 'response',

@@ -173,6 +145,6 @@ data: response,

catch (executionError) {
logFunction({ action: LogAction.execute, step: LogStep.end });
logFunction({ action: LogAction.request, step: LogStep.end });
logFunction({ action: logging_1.LogAction.execute, step: logging_1.LogStep.end });
logFunction({ action: logging_1.LogAction.request, step: logging_1.LogStep.end });
return Promise.resolve({
errors: format([errors_1.fromGraphQLError(executionError)], {
errors: errors_1.formatApolloErrors([errors_1.fromGraphQLError(executionError)], {
formatter: options.formatError,

@@ -179,0 +151,0 @@ debug: debug,

@@ -1,2 +0,2 @@

/// <reference types="node" />
/// <reference types="@types/node" />
import { GraphQLSchema } from 'graphql';

@@ -6,2 +6,3 @@ import { SchemaDirectiveVisitor, IResolvers, IMocks } from 'graphql-tools';

import { Server as HttpServer } from 'http';
import { ListenOptions as HttpListenOptions } from 'net';
import { GraphQLServerOptions as GraphQLOptions } from './graphqlOptions';

@@ -11,6 +12,6 @@ export declare type Context<T = any> = T;

export interface SubscriptionServerOptions {
path?: string;
onConnect?: Function;
onDisconnect?: Function;
path: string;
keepAlive?: number;
onConnect?: (connectionParams: Object, websocket: WebSocket, context: ConnectionContext) => any;
onDisconnect?: (websocket: WebSocket, context: ConnectionContext) => any;
}

@@ -21,6 +22,5 @@ export interface Config<Server> extends Pick<GraphQLOptions<Context<any>>, 'formatError' | 'debug' | 'rootValue' | 'logFunction' | 'formatParams' | 'validationRules' | 'formatResponse' | 'fieldResolver' | 'debug' | 'cacheControl' | 'tracing'> {

schema?: GraphQLSchema;
schemaDirectives: Record<string, typeof SchemaDirectiveVisitor>;
schemaDirectives?: Record<string, typeof SchemaDirectiveVisitor>;
context?: Context<any> | ContextFunction<any>;
subscriptions?: SubscriptionServerOptions | string | false;
enableIntrospection?: boolean;
introspection?: boolean;
mocks?: boolean | IMocks;

@@ -36,13 +36,10 @@ }

export interface ListenOptions {
port?: string | number;
host?: string;
path?: string;
backlog?: number;
exclusive?: boolean;
http?: HttpListenOptions | any | {
handle: any;
backlog?: number;
};
engineInRequestPath?: boolean;
engine?: boolean | Object;
engineProxy?: boolean | Record<string, any>;
engineLauncherOptions?: EngineLauncherOptions;
keepAlive?: number;
onConnect?: (connectionParams: Object, websocket: WebSocket, context: ConnectionContext) => any;
onDisconnect?: (websocket: WebSocket, context: ConnectionContext) => any;
subscriptions?: Partial<SubscriptionServerOptions> | string | false;
}

@@ -49,0 +46,0 @@ export interface MiddlewareOptions {

{
"name": "apollo-server-core",
"version": "2.0.0-beta.0",
"version": "2.0.0-beta.1",
"description": "Core engine for Apollo GraphQL server",

@@ -29,7 +29,9 @@ "main": "dist/index.js",

"@types/fibers": "0.0.30",
"@types/graphql": "0.12.7",
"@types/node": "^9.6.1",
"@types/graphql": "^0.13.1",
"@types/node": "^10.1.2",
"@types/ws": "^4.0.2",
"apollo-engine": "^1.0.6",
"apollo-engine": "^1.1.1",
"apollo-fetch": "^0.7.0",
"fibers": "1.0.15",
"graphql-tag": "^2.9.2",
"meteor-promise": "0.8.6",

@@ -50,6 +52,6 @@ "typescript": "2.8.3"

"graphql-subscriptions": "^0.5.8",
"graphql-tools": "^2.23.1",
"subscriptions-transport-ws": "^0.9.7",
"graphql-tools": "^3.0.2",
"subscriptions-transport-ws": "^0.9.9",
"ws": "^5.1.1"
}
}

@@ -20,5 +20,5 @@ import { makeExecutableSchema, addMockFunctionsToSchema } from 'graphql-tools';

import { internalFormatError } from './errors';
import { formatApolloErrors } from './errors';
import { GraphQLServerOptions as GraphQLOptions } from './graphqlOptions';
import { LogFunction } from './runQuery';
import { LogFunction, LogAction, LogStep } from './logging';

@@ -33,7 +33,5 @@ import {

ContextFunction,
SubscriptionServerOptions,
} from './types';
const env = process.env.NODE_ENV;
const isDev = env !== 'production' && env !== 'test';
const NoIntrospection = (context: ValidationContext) => ({

@@ -44,3 +42,3 @@ Field(node: FieldDefinitionNode) {

new GraphQLError(
'GraphQL introspection is not allowed by Apollo Server, but the query containted __schema or __type. To enable introspection, pass enableIntrospection: true to ApolloServer in production',
'GraphQL introspection is not allowed by Apollo Server, but the query contained __schema or __type. To enable introspection, pass introspection: true to ApolloServer in production',
[node],

@@ -54,4 +52,5 @@ ),

export class ApolloServerBase<Request = RequestInit> {
public subscriptions: Config<Request>['subscriptions'];
public disableTools: boolean = !isDev;
public disableTools: boolean;
// set in the listen function if subscriptions are enabled
public subscriptionsPath: string;

@@ -62,6 +61,7 @@ private schema: GraphQLSchema;

private graphqlPath: string = '/graphql';
private engine: ApolloEngine;
private engineProxy: ApolloEngine;
private engineEnabled: boolean = false;
private http?: HttpServer;
private subscriptionServer?: SubscriptionServer;
protected getHttp: () => HttpServer;

@@ -75,5 +75,4 @@

schemaDirectives,
subscriptions,
typeDefs,
enableIntrospection,
introspection,
mocks,

@@ -83,8 +82,17 @@ ...requestOptions

//While reading process.env is slow, a server should only be constructed
//once per run, so we place the env check inside the constructor. If env
//should be used outside of the constructor context, place it as a private
//or protected field of the class instead of a global. Keeping the read in
//the contructor enables testing of different environments
const env = process.env.NODE_ENV;
const isDev = env !== 'production' && env !== 'test';
// if this is local dev, we want graphql gui and introspection to be turned on
// in production, you can manually turn these on by passing { enableIntrospection: true }
// in production, you can manually turn these on by passing { introspection: true }
// to the constructor of ApolloServer
// we use this.disableTools to track this internally for later use when
// constructing middleware by frameworks
if (enableIntrospection || isDev) this.disableTools = false;
if (typeof introspection === 'boolean') this.disableTools = !introspection;
else this.disableTools = !isDev;

@@ -104,5 +112,3 @@ if (this.disableTools) {

: makeExecutableSchema({
typeDefs: Array.isArray(typeDefs)
? typeDefs.reduce((prev, next) => prev + '\n' + next)
: typeDefs,
typeDefs: Array.isArray(typeDefs) ? typeDefs.join('\n') : typeDefs,
schemaDirectives,

@@ -119,4 +125,2 @@ resolvers,

}
this.subscriptions = subscriptions;
}

@@ -133,36 +137,53 @@

this.http = this.getHttp();
const options = {
port: process.env.PORT || 4000,
...opts,
http: {
port: process.env.PORT || 4000,
...opts.http,
},
};
if (this.subscriptions !== false) {
const config: any =
this.subscriptions === true || typeof this.subscriptions === 'undefined'
? {
path: this.graphqlPath,
}
: this.subscriptions;
this.createSubscriptionServer(this.http, config);
if (opts.subscriptions !== false) {
let config: SubscriptionServerOptions;
if (
opts.subscriptions === true ||
typeof opts.subscriptions === 'undefined'
) {
config = {
path: this.graphqlPath,
};
} else if (typeof opts.subscriptions === 'string') {
config = { path: opts.subscriptions };
} else {
config = { path: this.graphqlPath, ...opts.subscriptions };
}
this.subscriptionsPath = config.path;
this.subscriptionServer = this.createSubscriptionServer(
this.http,
config,
);
}
if (opts.engine || opts.engineInRequestPath) this.createEngine(opts);
if (opts.engineProxy || opts.engineInRequestPath) this.createEngine(opts);
return new Promise((success, fail) => {
if (this.engine) {
this.engine.listen(
Object.assign({}, options.engineLauncherOptions, {
return new Promise((resolve, reject) => {
if (this.engineProxy) {
this.engineProxy.listen(
{
graphqlPaths: [this.graphqlPath],
port: options.port,
port: options.http.port,
httpServer: this.http,
}),
launcherOptions: options.engineLauncherOptions,
},
() => {
this.engine.engineListeningAddress.url = require('url').resolve(
this.engine.engineListeningAddress.url,
this.engineProxy.engineListeningAddress.url = require('url').resolve(
this.engineProxy.engineListeningAddress.url,
this.graphqlPath,
);
success(this.engine.engineListeningAddress);
resolve(this.engineProxy.engineListeningAddress);
},
);
this.engine.on('error', fail);
this.engineProxy.on('error', reject);
return;

@@ -173,32 +194,38 @@ }

// https://nodejs.org/api/net.html#net_server_listen_options_callback
this.http.listen(
{
port: options.port,
host: options.host,
path: options.path,
backlog: options.backlog,
exclusive: options.exclusive,
},
() => {
const la: any = this.http.address();
// Convert IPs which mean "any address" (IPv4 or IPv6) into localhost
// corresponding loopback ip. Note that the url field we're setting is
// primarily for consumption by our test suite. If this heuristic is
// wrong for your use case, explicitly specify a frontend host (in the
// `frontends.host` field in your engine config, or in the `host`
// option to ApolloServer.listen).
let hostForUrl = la.address;
if (la.address === '' || la.address === '::')
hostForUrl = 'localhost';
// https://github.com/apollographql/apollo-server/pull/979/files/33ea0c92a1e4e76c8915ff08806f15dae391e1f0#discussion_r184470435
// https://github.com/apollographql/apollo-server/pull/979#discussion_r184471445
function listenCallback() {
const listeningAddress: any = this.http.address();
// Convert IPs which mean "any address" (IPv4 or IPv6) into localhost
// corresponding loopback ip. Note that the url field we're setting is
// primarily for consumption by our test suite. If this heuristic is
// wrong for your use case, explicitly specify a frontend host (in the
// `frontends.host` field in your engine config, or in the `host`
// option to ApolloServer.listen).
let hostForUrl = listeningAddress.address;
if (
listeningAddress.address === '' ||
listeningAddress.address === '::'
)
hostForUrl = 'localhost';
la.url = require('url').format({
protocol: 'http',
hostname: hostForUrl,
port: la.port,
pathname: this.graphqlPath,
});
listeningAddress.url = require('url').format({
protocol: 'http',
hostname: hostForUrl,
port: listeningAddress.port,
pathname: this.graphqlPath,
});
success(la);
},
);
resolve(listeningAddress);
}
if (options.http.handle) {
this.http.listen(
options.http.handle,
options.http.backlog,
listenCallback.bind(this),
);
} else {
this.http.listen(options.http, listenCallback.bind(this));
}
});

@@ -208,9 +235,14 @@ }

public async stop() {
if (this.engine) await this.engine.stop();
if (this.engineProxy) await this.engineProxy.stop();
if (this.subscriptionServer) await this.subscriptionServer.close();
if (this.http) await new Promise(s => this.http.close(s));
}
private createSubscriptionServer(server: HttpServer, config: ListenOptions) {
const { onDisconnect, onConnect, keepAlive } = config;
SubscriptionServer.create(
private createSubscriptionServer(
server: HttpServer,
config: SubscriptionServerOptions,
) {
const { onDisconnect, onConnect, keepAlive, path } = config;
return SubscriptionServer.create(
{

@@ -228,3 +260,8 @@ schema: this.schema,

errors:
value.errors && value.errors.map(err => internalFormatError(err)),
value.errors &&
formatApolloErrors([...value.errors], {
formatter: this.requestOptions.formatError,
debug: this.requestOptions.debug,
logFunction: this.requestOptions.logFunction,
}),
});

@@ -239,4 +276,7 @@ let context: Context = this.context ? this.context : { connection };

} catch (e) {
console.error(e);
throw e;
throw formatApolloErrors([e], {
formatter: this.requestOptions.formatError,
debug: this.requestOptions.debug,
logFunction: this.requestOptions.logFunction,
})[0];
}

@@ -250,3 +290,3 @@

server,
path: this.graphqlPath,
path,
},

@@ -256,6 +296,6 @@ );

private createEngine({ engineInRequestPath, engine }: ListenOptions) {
private createEngine({ engineInRequestPath, engineProxy }: ListenOptions) {
// only access this onces as its slower on node
const { ENGINE_API_KEY, ENGINE_CONFIG } = process.env;
if (engine === false && (ENGINE_API_KEY || ENGINE_CONFIG)) {
if (engineProxy === false && (ENGINE_API_KEY || ENGINE_CONFIG)) {
console.warn(

@@ -266,3 +306,3 @@ 'engine is set to false when creating ApolloServer but either ENGINE_CONFIG or ENGINE_API_KEY was found in the environment',

let ApolloEngine;
if (engine) {
if (engineProxy) {
// detect engine if it is set to true or has a config, and possibly load it

@@ -278,4 +318,4 @@ try {

this.engine = new ApolloEngine(
typeof engine === 'boolean' ? undefined : engine,
this.engineProxy = new ApolloEngine(
typeof engineProxy === 'boolean' ? undefined : engineProxy,
);

@@ -285,11 +325,12 @@ }

// XXX should this allow for header overrides from graphql-playground?
if (this.engine || engineInRequestPath) this.engineEnabled = true;
if (this.engineProxy || engineInRequestPath) this.engineEnabled = true;
}
async request(request: Request) {
request(request: Request) {
let context: Context = this.context ? this.context : { request };
//Defer context resolution to inside of runQuery
context =
typeof this.context === 'function'
? await this.context({ req: request })
? () => this.context({ req: request })
: context;

@@ -299,6 +340,4 @@

schema: this.schema,
tracing: Boolean(this.engineEnabled),
cacheControl: Boolean(this.engineEnabled),
formatError: (e: GraphQLError) =>
internalFormatError(e, this.requestOptions.debug),
tracing: this.engineEnabled,
cacheControl: this.engineEnabled,
context,

@@ -305,0 +344,0 @@ // allow overrides from options

import { GraphQLError } from 'graphql';
import { LogStep, LogAction, LogMessage, LogFunction } from './logging';
export class ApolloError extends Error {
public extensions;
export class ApolloError extends Error implements GraphQLError {
public extensions: Record<string, any>;
readonly name = 'ApolloError';
readonly locations;
readonly path;
readonly source;
readonly positions;
readonly nodes;
public originalError;
[key: string]: any;
constructor(

@@ -11,24 +22,61 @@ message: string,

super(message);
this.extensions = { ...properties, code };
// Set the prototype explicitly.
// https://stackoverflow.com/a/41102306
Object.setPrototypeOf(this, ApolloError.prototype);
if (properties) {
Object.keys(properties).forEach(key => {
this[key] = properties[key];
});
}
//extensions are flattened to be included in the root of GraphQLError's, so
//don't add properties to extensions
this.extensions = { code };
}
}
export function internalFormatError(
error: GraphQLError,
debug: boolean = false,
) {
const expanded: GraphQLError = {
message: error.message,
path: error.path,
locations: error.locations,
...error,
extensions: {
...error.extensions,
code:
(error.extensions && error.extensions.code) || 'INTERNAL_SERVER_ERROR',
exception: {
...(error.extensions && error.extensions.exception),
...(error.originalError as any),
},
function enrichError(error: Partial<GraphQLError>, debug: boolean = false) {
const expanded = {} as any;
// follows similar structure to https://github.com/graphql/graphql-js/blob/master/src/error/GraphQLError.js#L145-L193
// with the addition of name
Object.defineProperties(expanded, {
name: {
value: error.name,
},
message: {
value: error.message,
enumerable: true,
writable: true,
},
locations: {
value: error.locations || undefined,
enumerable: true,
},
path: {
value: error.path || undefined,
enumerable: true,
},
nodes: {
value: error.nodes || undefined,
},
source: {
value: error.source || undefined,
},
positions: {
value: error.positions || undefined,
},
originalError: {
value: error.originalError,
},
});
expanded.extensions = {
...error.extensions,
code:
(error.extensions && error.extensions.code) || 'INTERNAL_SERVER_ERROR',
exception: {
...(error.extensions && error.extensions.exception),
...(error.originalError as any),
},
};

@@ -53,10 +101,10 @@

return expanded;
return expanded as ApolloError;
}
export function toApolloError(
error: Error,
error: Error & { extensions?: Record<string, any> },
code: string = 'INTERNAL_SERVER_ERROR',
): Error & { extensions: Record<string, any> } {
let err: GraphQLError = error;
let err = error;
if (err.extensions) {

@@ -76,3 +124,3 @@ err.extensions.code = code;

export function fromGraphQLError(error: GraphQLError, options?: ErrorOptions) {
const copy: GraphQLError =
const copy: ApolloError =
options && options.errorClass

@@ -101,3 +149,3 @@ ? new options.errorClass(error.message)

Object.defineProperty(copy, 'originalError', { value: {} });
Reflect.ownKeys(error).forEach(key => {
Object.getOwnPropertyNames(error).forEach(key => {
Object.defineProperty(copy.originalError, key, { value: error[key] });

@@ -110,6 +158,9 @@ });

export class SyntaxError extends ApolloError {
// TODO make the name nonenumerable
// name = 'SyntaxError';
constructor(message: string) {
super(message, 'GRAPHQL_PARSE_FAILED');
// Set the prototype explicitly.
// https://stackoverflow.com/a/41102306
Object.setPrototypeOf(this, SyntaxError.prototype);
Object.defineProperty(this, 'name', { value: 'SyntaxError' });
}

@@ -119,6 +170,9 @@ }

export class ValidationError extends ApolloError {
// TODO make the name nonenumerable
// name = 'ValidationError';
constructor(message: string) {
super(message, 'GRAPHQL_VALIDATION_FAILED');
// Set the prototype explicitly.
// https://stackoverflow.com/a/41102306
Object.setPrototypeOf(this, ValidationError.prototype);
Object.defineProperty(this, 'name', { value: 'ValidationError' });
}

@@ -128,6 +182,9 @@ }

export class AuthenticationError extends ApolloError {
// TODO make the name nonenumerable
// name = 'AuthenticationError';
constructor(message: string) {
super(message, 'UNAUTHENTICATED');
// Set the prototype explicitly.
// https://stackoverflow.com/a/41102306
Object.setPrototypeOf(this, AuthenticationError.prototype);
Object.defineProperty(this, 'name', { value: 'AuthenticationError' });
}

@@ -137,7 +194,53 @@ }

export class ForbiddenError extends ApolloError {
// TODO make the name nonenumerable
// name = 'ForbiddenError';
constructor(message: string) {
super(message, 'FORBIDDEN');
// Set the prototype explicitly.
// https://stackoverflow.com/a/41102306
Object.setPrototypeOf(this, ForbiddenError.prototype);
Object.defineProperty(this, 'name', { value: 'ForbiddenError' });
}
}
export function formatApolloErrors(
errors: Array<Error>,
options?: {
formatter?: Function;
logFunction?: LogFunction;
debug?: boolean;
},
): Array<ApolloError> {
if (!options) {
return errors.map(error => enrichError(error));
}
const { formatter, debug, logFunction } = options;
const enrichedErrors = errors.map(error => enrichError(error, debug));
if (!formatter) {
return enrichedErrors;
}
return enrichedErrors.map(error => {
try {
return formatter(error);
} catch (err) {
logFunction({
action: LogAction.cleanup,
step: LogStep.status,
data: err,
key: 'error',
});
if (debug) {
return enrichError(err, debug);
} else {
//obscure error
const newError = fromGraphQLError(
new GraphQLError('Internal server error'),
);
return enrichError(newError, debug);
}
}
}) as Array<ApolloError>;
}

@@ -6,3 +6,3 @@ import {

} from 'graphql';
import { LogFunction } from './runQuery';
import { LogFunction } from './logging';
import { GraphQLExtension } from 'graphql-extensions';

@@ -25,3 +25,7 @@

*/
export interface GraphQLServerOptions<TContext = any> {
export interface GraphQLServerOptions<
TContext =
| (() => Promise<Record<string, any>> | Record<string, any>)
| Record<string, any>
> {
schema: GraphQLSchema;

@@ -45,11 +49,11 @@ formatError?: Function;

export async function resolveGraphqlOptions(
options: GraphQLServerOptions | Function,
...args
options:
| GraphQLServerOptions
| ((
...args: Array<any>
) => Promise<GraphQLServerOptions> | GraphQLServerOptions),
...args: Array<any>
): Promise<GraphQLServerOptions> {
if (typeof options === 'function') {
try {
return await options(...args);
} catch (e) {
throw new Error(`Invalid options provided to ApolloServer: ${e.message}`);
}
return await options(...args);
} else {

@@ -56,0 +60,0 @@ return options;

@@ -1,8 +0,3 @@

export {
runQuery,
LogFunction,
LogMessage,
LogStep,
LogAction,
} from './runQuery';
export { runQuery } from './runQuery';
export { LogFunction, LogMessage, LogStep, LogAction } from './logging';
export { runHttpQuery, HttpQueryRequest, HttpQueryError } from './runHttpQuery';

@@ -20,3 +15,3 @@ export {

ForbiddenError,
internalFormatError,
formatApolloErrors,
} from './errors';

@@ -23,0 +18,0 @@

@@ -7,8 +7,10 @@ import { parse, getOperationAST, DocumentNode, ExecutionResult } from 'graphql';

} from './graphqlOptions';
import { internalFormatError } from './errors';
import { formatApolloErrors } from './errors';
export interface HttpQueryRequest {
method: string;
query: Record<string, any>;
options: GraphQLOptions | Function;
query: Record<string, any> | Array<Record<string, any>>;
options:
| GraphQLOptions
| ((...args: Array<any>) => Promise<GraphQLOptions> | GraphQLOptions);
}

@@ -37,3 +39,5 @@

const operationAST = getOperationAST(query, operationName);
return operationAST.operation === 'query';
return (
Boolean(operationAST) && operationAST && operationAST.operation === 'query'
);
}

@@ -47,2 +51,4 @@

let optionsObject: GraphQLOptions;
const debugDefault =
process.env.NODE_ENV !== 'production' && process.env.NODE_ENV !== 'test';

@@ -55,9 +61,21 @@ try {

} catch (e) {
throw new HttpQueryError(500, e.message);
// The options can be generated asynchronously, so we don't have access to
// the normal options provided by the user, such as: formatError,
// logFunction, debug. Therefore, we need to do some unnatural things, such
// as use NODE_ENV to determine the debug settings
e.message = `Invalid options provided to ApolloServer: ${e.message}`;
if (!debugDefault) {
e.warning = `To remove the stacktrace, set the NODE_ENV environment variable to production if the options creation can fail`;
}
throw new HttpQueryError(
500,
JSON.stringify({
errors: formatApolloErrors([e], { debug: debugDefault }),
}),
true,
{
'Content-Type': 'application/json',
},
);
}
const formatErrorFn = optionsObject.formatError
? error => optionsObject.formatError(internalFormatError(error))
: internalFormatError;
const debugDefault =
process.env.NODE_ENV !== 'production' && process.env.NODE_ENV !== 'test';
const debug =

@@ -106,3 +124,3 @@ optionsObject.debug !== undefined ? optionsObject.debug : debugDefault;

const requests: Array<ExecutionResult> = requestPayload.map(requestParams => {
const requests = requestPayload.map(async requestParams => {
try {

@@ -187,5 +205,26 @@ let query = requestParams.query;

let context = optionsObject.context || {};
if (typeof context === 'function') {
context = context();
let context = optionsObject.context;
if (!context) {
//appease typescript compiler, otherwise could use || {}
context = {};
} else if (typeof context === 'function') {
try {
context = await context();
} catch (e) {
e.message = `Context creation failed: ${e.message}`;
throw new HttpQueryError(
500,
JSON.stringify({
errors: formatApolloErrors([e], {
formatter: optionsObject.formatError,
debug,
logFunction: optionsObject.logFunction,
}),
}),
true,
{
'Content-Type': 'application/json',
},
);
}
} else if (isBatch) {

@@ -207,3 +246,3 @@ context = Object.assign(

validationRules: optionsObject.validationRules,
formatError: formatErrorFn,
formatError: optionsObject.formatError,
formatResponse: optionsObject.formatResponse,

@@ -225,8 +264,16 @@ fieldResolver: optionsObject.fieldResolver,

if (e.name === 'HttpQueryError') {
return Promise.reject(e);
//async function wraps this in a Promise
throw e;
}
return Promise.resolve({ errors: [formatErrorFn(e)] });
return {
errors: formatApolloErrors([e], {
formatter: optionsObject.formatError,
debug,
logFunction: optionsObject.logFunction,
}),
};
}
});
}) as Array<Promise<ExecutionResult>>;
const responses = await Promise.all(requests);

@@ -233,0 +280,0 @@

@@ -15,3 +15,4 @@ /* tslint:disable:no-unused-expression */

import { runQuery, LogAction, LogStep } from './runQuery';
import { runQuery } from './runQuery';
import { LogAction, LogStep } from './logging';

@@ -18,0 +19,0 @@ // Make the global Promise constructor Fiber-aware to simulate a Meteor

@@ -25,3 +25,3 @@ import {

fromGraphQLError,
internalFormatError,
formatApolloErrors,
ValidationError,

@@ -31,2 +31,4 @@ SyntaxError,

import { LogStep, LogAction, LogMessage, LogFunction } from './logging';
export interface GraphQLResponse {

@@ -38,26 +40,2 @@ data?: object;

export enum LogAction {
request,
parse,
validation,
execute,
}
export enum LogStep {
start,
end,
status,
}
export interface LogMessage {
action: LogAction;
step: LogStep;
key?: string;
data?: any;
}
export interface LogFunction {
(message: LogMessage);
}
export interface QueryOptions {

@@ -89,27 +67,2 @@ schema: GraphQLSchema;

function format(
errors: Array<Error>,
options?: {
formatter?: Function;
debug?: boolean;
},
): Array<Error> {
const { formatter, debug } = options;
return errors.map(error => internalFormatError(error, debug)).map(error => {
if (formatter !== undefined) {
try {
return formatter(error);
} catch (err) {
console.error('Error in formatError function:', err);
const newError: GraphQLError = fromGraphQLError(
new GraphQLError('Internal server error'),
);
return internalFormatError(newError, debug);
}
} else {
return error;
}
}) as Array<Error>;
}
function doRunQuery(options: QueryOptions): Promise<GraphQLResponse> {

@@ -180,3 +133,3 @@ let documentAST: DocumentNode;

return Promise.resolve({
errors: format(
errors: formatApolloErrors(
[

@@ -208,3 +161,3 @@ fromGraphQLError(syntaxError, {

return Promise.resolve({
errors: format(
errors: formatApolloErrors(
validationErrors.map(err =>

@@ -215,2 +168,3 @@ fromGraphQLError(err, { errorClass: ValidationError }),

formatter: options.formatError,
logFunction,
debug,

@@ -246,4 +200,5 @@ },

if (result.errors) {
response.errors = format(result.errors, {
response.errors = formatApolloErrors([...result.errors], {
formatter: options.formatError,
logFunction,
debug,

@@ -282,3 +237,3 @@ });

// Options: PREPROCESSING_FAILED, GRAPHQL_RUNTIME_CHECK_FAILED
errors: format([fromGraphQLError(executionError)], {
errors: formatApolloErrors([fromGraphQLError(executionError)], {
formatter: options.formatError,

@@ -285,0 +240,0 @@ debug,

@@ -5,2 +5,3 @@ import { GraphQLSchema } from 'graphql';

import { Server as HttpServer } from 'http';
import { ListenOptions as HttpListenOptions } from 'net';

@@ -15,6 +16,10 @@ import { GraphQLServerOptions as GraphQLOptions } from './graphqlOptions';

export interface SubscriptionServerOptions {
path?: string;
onConnect?: Function;
onDisconnect?: Function;
path: string;
keepAlive?: number;
onConnect?: (
connectionParams: Object,
websocket: WebSocket,
context: ConnectionContext,
) => any;
onDisconnect?: (websocket: WebSocket, context: ConnectionContext) => any;
}

@@ -40,6 +45,5 @@

schema?: GraphQLSchema;
schemaDirectives: Record<string, typeof SchemaDirectiveVisitor>;
schemaDirectives?: Record<string, typeof SchemaDirectiveVisitor>;
context?: Context<any> | ContextFunction<any>;
subscriptions?: SubscriptionServerOptions | string | false;
enableIntrospection?: boolean;
introspection?: boolean;
mocks?: boolean | IMocks;

@@ -60,20 +64,11 @@ }

// https://nodejs.org/api/net.html#net_server_listen_options_callback
port?: string | number;
host?: string;
path?: string;
backlog?: number;
exclusive?: boolean;
// https://github.com/apollographql/apollo-server/pull/979#discussion_r184483094
http?: HttpListenOptions | any | { handle: any; backlog?: number };
// XXX clean this up
engineInRequestPath?: boolean;
engine?: boolean | Object;
engineProxy?: boolean | Record<string, any>;
// engine launcher options
engineLauncherOptions?: EngineLauncherOptions;
// WebSocket options
keepAlive?: number;
onConnect?: (
connectionParams: Object,
websocket: WebSocket,
context: ConnectionContext,
) => any;
onDisconnect?: (websocket: WebSocket, context: ConnectionContext) => any;
subscriptions?: Partial<SubscriptionServerOptions> | string | false;
}

@@ -89,3 +84,2 @@

path: string;
// subscriptions?: boolean;
getHttp: () => HttpServer;

@@ -92,0 +86,0 @@ }

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc