diff --git a/CHANGELOG.md b/CHANGELOG.md index 71b41dec8a2..63071932bac 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,7 @@ ### vNEXT +- Implement an in-memory cache store to save parsed and validated documents and provide performance benefits for successful executions of the same document. [PR #2111](https://github.com/apollographql/apollo-server/pull/2111) (`2.4.0-alpha.0`) - Switch from `json-stable-stringify` to `fast-json-stable-stringify`. [PR #2065](https://github.com/apollographql/apollo-server/pull/2065) ### v2.3.1 diff --git a/packages/apollo-cache-control/package.json b/packages/apollo-cache-control/package.json index 0e59fac4d05..eb19d742ceb 100644 --- a/packages/apollo-cache-control/package.json +++ b/packages/apollo-cache-control/package.json @@ -1,6 +1,6 @@ { "name": "apollo-cache-control", - "version": "0.4.0", + "version": "0.5.0-alpha.1", "description": "A GraphQL extension for cache control", "main": "./dist/index.js", "types": "./dist/index.d.ts", diff --git a/packages/apollo-datasource-rest/package.json b/packages/apollo-datasource-rest/package.json index 353f7070964..13ec7f928e5 100644 --- a/packages/apollo-datasource-rest/package.json +++ b/packages/apollo-datasource-rest/package.json @@ -1,6 +1,6 @@ { "name": "apollo-datasource-rest", - "version": "0.2.1", + "version": "0.3.0-alpha.1", "author": "opensource@apollographql.com", "license": "MIT", "repository": { diff --git a/packages/apollo-datasource/package.json b/packages/apollo-datasource/package.json index 98fb98ab1cf..c1e5476bb78 100644 --- a/packages/apollo-datasource/package.json +++ b/packages/apollo-datasource/package.json @@ -1,6 +1,6 @@ { "name": "apollo-datasource", - "version": "0.2.1", + "version": "0.3.0-alpha.1", "author": "opensource@apollographql.com", "license": "MIT", "repository": { diff --git a/packages/apollo-engine-reporting/package.json b/packages/apollo-engine-reporting/package.json index c823fb30f00..9736a3bddb6 100644 --- a/packages/apollo-engine-reporting/package.json +++ b/packages/apollo-engine-reporting/package.json @@ -1,6 +1,6 @@ { "name": "apollo-engine-reporting", - "version": "0.2.0", + "version": "0.3.0-alpha.1", "description": "Send reports about your GraphQL services to Apollo Engine", "main": "./dist/index.js", "types": "./dist/index.d.ts", diff --git a/packages/apollo-server-azure-functions/package.json b/packages/apollo-server-azure-functions/package.json index 1ddb9fec9a8..469be4b7ed6 100644 --- a/packages/apollo-server-azure-functions/package.json +++ b/packages/apollo-server-azure-functions/package.json @@ -1,6 +1,6 @@ { "name": "apollo-server-azure-functions", - "version": "2.3.1", + "version": "2.4.0-alpha.2", "description": "Production-ready Node.js GraphQL server for Azure Functions", "keywords": [ "GraphQL", diff --git a/packages/apollo-server-cache-memcached/package.json b/packages/apollo-server-cache-memcached/package.json index f575ca6d252..8e4d5df3b96 100644 --- a/packages/apollo-server-cache-memcached/package.json +++ b/packages/apollo-server-cache-memcached/package.json @@ -1,6 +1,6 @@ { "name": "apollo-server-cache-memcached", - "version": "0.2.1", + "version": "0.3.0-alpha.1", "author": "opensource@apollographql.com", "license": "MIT", "repository": { diff --git a/packages/apollo-server-cache-redis/package.json b/packages/apollo-server-cache-redis/package.json index 50703b8c782..eb49a61a8a8 100644 --- a/packages/apollo-server-cache-redis/package.json +++ b/packages/apollo-server-cache-redis/package.json @@ -1,6 +1,6 @@ { "name": "apollo-server-cache-redis", - "version": "0.2.1", + "version": "0.3.0-alpha.1", "author": "opensource@apollographql.com", "license": "MIT", "repository": { diff --git a/packages/apollo-server-caching/package.json b/packages/apollo-server-caching/package.json index 4d148b84fe0..b605aa38ad3 100644 --- a/packages/apollo-server-caching/package.json +++ b/packages/apollo-server-caching/package.json @@ -1,6 +1,6 @@ { "name": "apollo-server-caching", - "version": "0.2.1", + "version": "0.3.0-alpha.1", "author": "opensource@apollographql.com", "license": "MIT", "repository": { diff --git a/packages/apollo-server-caching/src/InMemoryLRUCache.ts b/packages/apollo-server-caching/src/InMemoryLRUCache.ts index b75dfcb37d0..53f0e6bfc2c 100644 --- a/packages/apollo-server-caching/src/InMemoryLRUCache.ts +++ b/packages/apollo-server-caching/src/InMemoryLRUCache.ts @@ -1,32 +1,33 @@ import LRU from 'lru-cache'; import { KeyValueCache } from './KeyValueCache'; +function defaultLengthCalculation(item: any) { + if (Array.isArray(item) || typeof item === 'string') { + return item.length; + } + + // Go with the lru-cache default "naive" size, in lieu anything better: + // https://github.com/isaacs/node-lru-cache/blob/a71be6cd/index.js#L17 + return 1; +} + export class InMemoryLRUCache implements KeyValueCache { private store: LRU.Cache; // FIXME: Define reasonable default max size of the cache - constructor({ maxSize = Infinity }: { maxSize?: number } = {}) { + constructor({ + maxSize = Infinity, + sizeCalculator = defaultLengthCalculation, + onDispose, + }: { + maxSize?: number; + sizeCalculator?: (value: V, key: string) => number; + onDispose?: (key: string, value: V) => void; + } = {}) { this.store = new LRU({ max: maxSize, - length(item) { - if (Array.isArray(item) || typeof item === 'string') { - return item.length; - } - - // If it's an object, we'll use the length to get an approximate, - // relative size of what it would take to store it. It's certainly not - // 100% accurate, but it's a very, very fast implementation and it - // doesn't require bringing in other dependencies or logic which we need - // to maintain. In the future, we might consider something like: - // npm.im/object-sizeof, but this should be sufficient for now. - if (typeof item === 'object') { - return JSON.stringify(item).length; - } - - // Go with the lru-cache default "naive" size, in lieu anything better: - // https://github.com/isaacs/node-lru-cache/blob/a71be6cd/index.js#L17 - return 1; - }, + length: sizeCalculator, + dispose: onDispose, }); } @@ -43,4 +44,7 @@ export class InMemoryLRUCache implements KeyValueCache { async flush(): Promise { this.store.reset(); } + async getTotalSize() { + return this.store.length; + } } diff --git a/packages/apollo-server-cloud-functions/package.json b/packages/apollo-server-cloud-functions/package.json index 869d2ab04a8..9c18c029f1a 100644 --- a/packages/apollo-server-cloud-functions/package.json +++ b/packages/apollo-server-cloud-functions/package.json @@ -1,6 +1,6 @@ { "name": "apollo-server-cloud-functions", - "version": "2.3.1", + "version": "2.4.0-alpha.2", "description": "Production-ready Node.js GraphQL server for Google Cloud Functions", "keywords": [ "GraphQL", diff --git a/packages/apollo-server-cloudflare/package.json b/packages/apollo-server-cloudflare/package.json index 1e222fba2eb..af9a73c8600 100644 --- a/packages/apollo-server-cloudflare/package.json +++ b/packages/apollo-server-cloudflare/package.json @@ -1,6 +1,6 @@ { "name": "apollo-server-cloudflare", - "version": "2.3.1", + "version": "2.4.0-alpha.2", "description": "Production-ready Node.js GraphQL server for Cloudflare workers", "main": "dist/index.js", "types": "dist/index.d.ts", diff --git a/packages/apollo-server-core/package.json b/packages/apollo-server-core/package.json index c02ce0fff65..bd39cb8e7f6 100644 --- a/packages/apollo-server-core/package.json +++ b/packages/apollo-server-core/package.json @@ -1,6 +1,6 @@ { "name": "apollo-server-core", - "version": "2.3.1", + "version": "2.4.0-alpha.2", "description": "Core engine for Apollo GraphQL server", "main": "dist/index.js", "types": "dist/index.d.ts", diff --git a/packages/apollo-server-core/src/ApolloServer.ts b/packages/apollo-server-core/src/ApolloServer.ts index 8d81e2f0794..7aef4030b7a 100644 --- a/packages/apollo-server-core/src/ApolloServer.ts +++ b/packages/apollo-server-core/src/ApolloServer.ts @@ -9,6 +9,7 @@ import { GraphQLFieldResolver, ValidationContext, FieldDefinitionNode, + DocumentNode, } from 'graphql'; import { GraphQLExtension } from 'graphql-extensions'; import { EngineReportingAgent } from 'apollo-engine-reporting'; @@ -92,6 +93,10 @@ function getEngineServiceId(engine: Config['engine']): string | undefined { const forbidUploadsForTesting = process && process.env.NODE_ENV === 'test' && !supportsUploadsInNode; +function approximateObjectSize(obj: T): number { + return Buffer.byteLength(JSON.stringify(obj), 'utf8'); +} + export class ApolloServerBase { public subscriptionsPath?: string; public graphqlPath: string = '/graphql'; @@ -114,6 +119,11 @@ export class ApolloServerBase { // the default version is specified in playground.ts protected playgroundOptions?: PlaygroundRenderPageOptions; + // A store that, when enabled (default), will store the parsed and validated + // versions of operations in-memory, allowing subsequent parses/validates + // on the same operation to be executed immediately. + private documentStore?: InMemoryLRUCache; + // The constructor should be universal across all environments. All environment specific behavior should be set by adding or overriding methods constructor(config: Config) { if (!config) throw new Error('ApolloServer requires options.'); @@ -136,6 +146,9 @@ export class ApolloServerBase { ...requestOptions } = config; + // Initialize the document store. This cannot currently be disabled. + this.initializeDocumentStore(); + // Plugins will be instantiated if they aren't already, and this.plugins // is populated accordingly. this.ensurePluginInstantiation(plugins); @@ -486,6 +499,18 @@ export class ApolloServerBase { }); } + private initializeDocumentStore(): void { + this.documentStore = new InMemoryLRUCache({ + // Create ~about~ a 30MiB InMemoryLRUCache. This is less than precise + // since the technique to calculate the size of a DocumentNode is + // only using JSON.stringify on the DocumentNode (and thus doesn't account + // for unicode characters, etc.), but it should do a reasonable job at + // providing a caching document store for most operations. + maxSize: Math.pow(2, 20) * 30, + sizeCalculator: approximateObjectSize, + }); + } + // This function is used by the integrations to generate the graphQLOptions // from an object containing the request and other integration specific // options @@ -509,6 +534,7 @@ export class ApolloServerBase { return { schema: this.schema, plugins: this.plugins, + documentStore: this.documentStore, extensions: this.extensions, context, // Allow overrides from options. Be explicit about a couple of them to diff --git a/packages/apollo-server-core/src/__tests__/runQuery.test.ts b/packages/apollo-server-core/src/__tests__/runQuery.test.ts index d18f1b2517e..6c3d9804c29 100644 --- a/packages/apollo-server-core/src/__tests__/runQuery.test.ts +++ b/packages/apollo-server-core/src/__tests__/runQuery.test.ts @@ -20,6 +20,11 @@ import { import { processGraphQLRequest, GraphQLRequest } from '../requestPipeline'; import { Request } from 'apollo-server-env'; import { GraphQLOptions, Context as GraphQLContext } from 'apollo-server-core'; +import { + ApolloServerPlugin, + GraphQLRequestListener, +} from 'apollo-server-plugin-base'; +import { InMemoryLRUCache } from 'apollo-server-caching'; // This is a temporary kludge to ensure we preserve runQuery behavior with the // GraphQLRequestProcessor refactoring. @@ -49,10 +54,12 @@ interface QueryOptions | 'cacheControl' | 'context' | 'debug' + | 'documentStore' | 'extensions' | 'fieldResolver' | 'formatError' | 'formatResponse' + | 'plugins' | 'rootValue' | 'schema' | 'tracing' @@ -444,6 +451,172 @@ describe('runQuery', () => { }); }); + describe('parsing and validation cache', () => { + function createLifecyclePluginMocks() { + const validationDidStart = jest.fn(); + const parsingDidStart = jest.fn(); + + const plugins: ApolloServerPlugin[] = [ + { + requestDidStart() { + return { + validationDidStart, + parsingDidStart, + } as GraphQLRequestListener; + }, + }, + ]; + + return { + plugins, + events: { validationDidStart, parsingDidStart }, + }; + } + + function runRequest({ + queryString = '{ testString }', + plugins = [], + documentStore, + }: { + queryString?: string; + plugins?: ApolloServerPlugin[]; + documentStore?: QueryOptions['documentStore']; + }) { + return runQuery({ + schema, + documentStore, + queryString, + plugins, + request: new MockReq(), + }); + } + + function forgeLargerTestQuery( + count: number, + prefix: string = 'prefix', + ): string { + if (count <= 0) { + count = 1; + } + + let query: string = ''; + + for (let q = 0; q < count; q++) { + query += ` ${prefix}_${count}: testString\n`; + } + + return '{\n' + query + '}'; + } + + // This should use the same logic as the calculation in InMemoryLRUCache: + // https://github.com/apollographql/apollo-server/blob/94b98ff3/packages/apollo-server-caching/src/InMemoryLRUCache.ts#L23 + function approximateObjectSize(obj: T): number { + return Buffer.byteLength(JSON.stringify(obj), 'utf8'); + } + + it('validates each time when the documentStore is not present', async () => { + expect.assertions(4); + + const { + plugins, + events: { parsingDidStart, validationDidStart }, + } = createLifecyclePluginMocks(); + + // The first request will do a parse and validate. (1/1) + await runRequest({ plugins }); + expect(parsingDidStart.mock.calls.length).toBe(1); + expect(validationDidStart.mock.calls.length).toBe(1); + + // The second request should ALSO do a parse and validate. (2/2) + await runRequest({ plugins }); + expect(parsingDidStart.mock.calls.length).toBe(2); + expect(validationDidStart.mock.calls.length).toBe(2); + }); + + it('caches the DocumentNode in the documentStore when instrumented', async () => { + expect.assertions(4); + const documentStore = new InMemoryLRUCache(); + + const { + plugins, + events: { parsingDidStart, validationDidStart }, + } = createLifecyclePluginMocks(); + + // An uncached request will have 1 parse and 1 validate call. + await runRequest({ plugins, documentStore }); + expect(parsingDidStart.mock.calls.length).toBe(1); + expect(validationDidStart.mock.calls.length).toBe(1); + + // The second request should still only have a 1 validate and 1 parse. + await runRequest({ plugins, documentStore }); + expect(parsingDidStart.mock.calls.length).toBe(1); + expect(validationDidStart.mock.calls.length).toBe(1); + + console.log(documentStore); + }); + + it("the documentStore calculates the DocumentNode's length by its JSON.stringify'd representation", async () => { + expect.assertions(14); + const { + plugins, + events: { parsingDidStart, validationDidStart }, + } = createLifecyclePluginMocks(); + + const queryLarge = forgeLargerTestQuery(3, 'large'); + const querySmall1 = forgeLargerTestQuery(1, 'small1'); + const querySmall2 = forgeLargerTestQuery(1, 'small2'); + + // We're going to create a smaller-than-default cache which will be the + // size of the two smaller queries. All three of these queries will never + // fit into this cache, so we'll roll through them all. + const maxSize = + approximateObjectSize(parse(querySmall1)) + + approximateObjectSize(parse(querySmall2)); + + const documentStore = new InMemoryLRUCache({ + maxSize, + sizeCalculator: approximateObjectSize, + }); + + await runRequest({ plugins, documentStore, queryString: querySmall1 }); + expect(parsingDidStart.mock.calls.length).toBe(1); + expect(validationDidStart.mock.calls.length).toBe(1); + + await runRequest({ plugins, documentStore, queryString: querySmall2 }); + expect(parsingDidStart.mock.calls.length).toBe(2); + expect(validationDidStart.mock.calls.length).toBe(2); + + // This query should be large enough to evict both of the previous + // from the LRU cache since it's larger than the TOTAL limit of the cache + // (which is capped at the length of small1 + small2) — though this will + // still fit (barely). + await runRequest({ plugins, documentStore, queryString: queryLarge }); + expect(parsingDidStart.mock.calls.length).toBe(3); + expect(validationDidStart.mock.calls.length).toBe(3); + + // Make sure the large query is still cached (No incr. to parse/validate.) + await runRequest({ plugins, documentStore, queryString: queryLarge }); + expect(parsingDidStart.mock.calls.length).toBe(3); + expect(validationDidStart.mock.calls.length).toBe(3); + + // This small (and the other) should both trigger parse/validate since + // the cache had to have evicted them both after accommodating the larger. + await runRequest({ plugins, documentStore, queryString: querySmall1 }); + expect(parsingDidStart.mock.calls.length).toBe(4); + expect(validationDidStart.mock.calls.length).toBe(4); + + await runRequest({ plugins, documentStore, queryString: querySmall2 }); + expect(parsingDidStart.mock.calls.length).toBe(5); + expect(validationDidStart.mock.calls.length).toBe(5); + + // Finally, make sure that the large query is gone (it should be, after + // the last two have taken its spot again.) + await runRequest({ plugins, documentStore, queryString: queryLarge }); + expect(parsingDidStart.mock.calls.length).toBe(6); + expect(validationDidStart.mock.calls.length).toBe(6); + }); + }); + describe('async_hooks', () => { let asyncHooks: typeof import('async_hooks'); let asyncHook: import('async_hooks').AsyncHook; diff --git a/packages/apollo-server-core/src/graphqlOptions.ts b/packages/apollo-server-core/src/graphqlOptions.ts index afed78ab98a..c1e36ffa2c6 100644 --- a/packages/apollo-server-core/src/graphqlOptions.ts +++ b/packages/apollo-server-core/src/graphqlOptions.ts @@ -6,7 +6,7 @@ import { } from 'graphql'; import { GraphQLExtension } from 'graphql-extensions'; import { CacheControlExtensionOptions } from 'apollo-cache-control'; -import { KeyValueCache } from 'apollo-server-caching'; +import { KeyValueCache, InMemoryLRUCache } from 'apollo-server-caching'; import { DataSource } from 'apollo-datasource'; import { ApolloServerPlugin } from 'apollo-server-plugin-base'; @@ -43,6 +43,7 @@ export interface GraphQLServerOptions< cache?: KeyValueCache; persistedQueries?: PersistedQueryOptions; plugins?: ApolloServerPlugin[]; + documentStore?: InMemoryLRUCache; } export type DataSources = { diff --git a/packages/apollo-server-core/src/requestPipeline.ts b/packages/apollo-server-core/src/requestPipeline.ts index 7c4429c3f60..d8313a304b4 100644 --- a/packages/apollo-server-core/src/requestPipeline.ts +++ b/packages/apollo-server-core/src/requestPipeline.ts @@ -44,6 +44,7 @@ import { } from 'apollo-server-plugin-base'; import { Dispatcher } from './utils/dispatcher'; +import { InMemoryLRUCache } from 'apollo-server-caching'; export { GraphQLRequest, @@ -76,6 +77,7 @@ export interface GraphQLRequestPipelineConfig { formatResponse?: Function; plugins?: ApolloServerPlugin[]; + documentStore?: InMemoryLRUCache; } export type DataSources = { @@ -162,42 +164,81 @@ export async function processGraphQLRequest( requestContext, }); - const parsingDidEnd = await dispatcher.invokeDidStartHook( - 'parsingDidStart', - requestContext, - ); - try { - let document: DocumentNode; - try { - document = parse(query); - parsingDidEnd(); - } catch (syntaxError) { - parsingDidEnd(syntaxError); - return sendErrorResponse(syntaxError, SyntaxError); + // If we're configured with a document store (by default, we are), we'll + // utilize the operation's hash to lookup the AST from the previously + // parsed-and-validated operation. Failure to retrieve anything from the + // cache just means we're committed to doing the parsing and validation. + if (config.documentStore) { + try { + requestContext.document = await config.documentStore.get(queryHash); + } catch (err) { + console.warn( + 'An error occurred while attempting to read from the documentStore.', + err, + ); + } } - requestContext.document = document; + // If we still don't have a document, we'll need to parse and validate it. + // With success, we'll attempt to save it into the store for future use. + if (!requestContext.document) { + const parsingDidEnd = await dispatcher.invokeDidStartHook( + 'parsingDidStart', + requestContext, + ); - const validationDidEnd = await dispatcher.invokeDidStartHook( - 'validationDidStart', - requestContext as WithRequired, - ); + try { + requestContext.document = parse(query); + parsingDidEnd(); + } catch (syntaxError) { + parsingDidEnd(syntaxError); + return sendErrorResponse(syntaxError, SyntaxError); + } - const validationErrors = validate(document); + const validationDidEnd = await dispatcher.invokeDidStartHook( + 'validationDidStart', + requestContext as WithRequired, + ); - if (validationErrors.length === 0) { - validationDidEnd(); - } else { - validationDidEnd(validationErrors); - return sendErrorResponse(validationErrors, ValidationError); + const validationErrors = validate(requestContext.document); + + if (validationErrors.length === 0) { + validationDidEnd(); + } else { + validationDidEnd(validationErrors); + return sendErrorResponse(validationErrors, ValidationError); + } + + if (config.documentStore) { + // The underlying cache store behind the `documentStore` returns a + // `Promise` which is resolved (or rejected), eventually, based on the + // success or failure (respectively) of the cache save attempt. While + // it's certainly possible to `await` this `Promise`, we don't care about + // whether or not it's successful at this point. We'll instead proceed + // to serve the rest of the request and just hope that this works out. + // If it doesn't work, the next request will have another opportunity to + // try again. Errors will surface as warnings, as appropriate. + // + // While it shouldn't normally be necessary to wrap this `Promise` in a + // `Promise.resolve` invocation, it seems that the underlying cache store + // is returning a non-native `Promise` (e.g. Bluebird, etc.). + Promise.resolve( + config.documentStore.set(queryHash, requestContext.document), + ).catch(err => + console.warn('Could not store validated document.', err), + ); + } } // FIXME: If we want to guarantee an operation has been set when invoking // `willExecuteOperation` and executionDidStart`, we need to throw an // error here and not leave this to `buildExecutionContext` in // `graphql-js`. - const operation = getOperationAST(document, request.operationName); + const operation = getOperationAST( + requestContext.document, + request.operationName, + ); requestContext.operation = operation || undefined; // We'll set `operationName` to `null` for anonymous operations. @@ -224,7 +265,7 @@ export async function processGraphQLRequest( try { response = (await execute( - document, + requestContext.document, request.operationName, request.variables, )) as GraphQLResponse; diff --git a/packages/apollo-server-core/src/runHttpQuery.ts b/packages/apollo-server-core/src/runHttpQuery.ts index 977593bcdd3..87da2ebd9ee 100644 --- a/packages/apollo-server-core/src/runHttpQuery.ts +++ b/packages/apollo-server-core/src/runHttpQuery.ts @@ -158,6 +158,7 @@ export async function runHttpQuery( | CacheControlExtensionOptions | undefined, dataSources: options.dataSources, + documentStore: options.documentStore, extensions: options.extensions, persistedQueries: options.persistedQueries, diff --git a/packages/apollo-server-express/package.json b/packages/apollo-server-express/package.json index 06ff254a40a..a4ffb93326f 100644 --- a/packages/apollo-server-express/package.json +++ b/packages/apollo-server-express/package.json @@ -1,6 +1,6 @@ { "name": "apollo-server-express", - "version": "2.3.1", + "version": "2.4.0-alpha.2", "description": "Production-ready Node.js GraphQL server for Express and Connect", "main": "dist/index.js", "types": "dist/index.d.ts", diff --git a/packages/apollo-server-hapi/package.json b/packages/apollo-server-hapi/package.json index b04b20513b8..eb4c033a71b 100644 --- a/packages/apollo-server-hapi/package.json +++ b/packages/apollo-server-hapi/package.json @@ -1,6 +1,6 @@ { "name": "apollo-server-hapi", - "version": "2.3.1", + "version": "2.4.0-alpha.2", "description": "Production-ready Node.js GraphQL server for Hapi", "main": "dist/index.js", "types": "dist/index.d.ts", diff --git a/packages/apollo-server-integration-testsuite/package.json b/packages/apollo-server-integration-testsuite/package.json index 1d81058bc01..8a82db43919 100644 --- a/packages/apollo-server-integration-testsuite/package.json +++ b/packages/apollo-server-integration-testsuite/package.json @@ -1,7 +1,7 @@ { "name": "apollo-server-integration-testsuite", "private": true, - "version": "2.3.1", + "version": "2.4.0-alpha.2", "description": "Apollo Server Integrations testsuite", "main": "dist/index.js", "types": "dist/index.d.ts", diff --git a/packages/apollo-server-koa/package.json b/packages/apollo-server-koa/package.json index d5daa7a25e1..dc41d844f75 100644 --- a/packages/apollo-server-koa/package.json +++ b/packages/apollo-server-koa/package.json @@ -1,6 +1,6 @@ { "name": "apollo-server-koa", - "version": "2.3.1", + "version": "2.4.0-alpha.2", "description": "Production-ready Node.js GraphQL server for Koa", "main": "dist/index.js", "types": "dist/index.d.ts", diff --git a/packages/apollo-server-lambda/package.json b/packages/apollo-server-lambda/package.json index e5bfa84a82a..838ba36b011 100644 --- a/packages/apollo-server-lambda/package.json +++ b/packages/apollo-server-lambda/package.json @@ -1,6 +1,6 @@ { "name": "apollo-server-lambda", - "version": "2.3.1", + "version": "2.4.0-alpha.2", "description": "Production-ready Node.js GraphQL server for AWS Lambda", "keywords": [ "GraphQL", diff --git a/packages/apollo-server-micro/package.json b/packages/apollo-server-micro/package.json index 66f687638e5..d2bfea1f6ec 100644 --- a/packages/apollo-server-micro/package.json +++ b/packages/apollo-server-micro/package.json @@ -1,6 +1,6 @@ { "name": "apollo-server-micro", - "version": "2.3.1", + "version": "2.4.0-alpha.2", "description": "Production-ready Node.js GraphQL server for Micro", "main": "dist/index.js", "types": "dist/index.d.ts", diff --git a/packages/apollo-server-plugin-base/package.json b/packages/apollo-server-plugin-base/package.json index c8e4590cf41..fb563947800 100644 --- a/packages/apollo-server-plugin-base/package.json +++ b/packages/apollo-server-plugin-base/package.json @@ -1,6 +1,6 @@ { "name": "apollo-server-plugin-base", - "version": "0.2.1", + "version": "0.3.0-alpha.2", "description": "Apollo Server plugin base classes", "main": "dist/index.js", "types": "dist/index.d.ts", diff --git a/packages/apollo-server-testing/package.json b/packages/apollo-server-testing/package.json index e56a2d0b909..1d1f628dbcd 100644 --- a/packages/apollo-server-testing/package.json +++ b/packages/apollo-server-testing/package.json @@ -1,6 +1,6 @@ { "name": "apollo-server-testing", - "version": "2.3.1", + "version": "2.4.0-alpha.2", "description": "Test utils for apollo-server", "main": "dist/index.js", "types": "dist/index.d.ts", diff --git a/packages/apollo-server/package.json b/packages/apollo-server/package.json index 0f915e0ec3e..4a7ba329cc0 100644 --- a/packages/apollo-server/package.json +++ b/packages/apollo-server/package.json @@ -1,6 +1,6 @@ { "name": "apollo-server", - "version": "2.3.1", + "version": "2.4.0-alpha.2", "description": "Production ready GraphQL Server", "author": "opensource@apollographql.com", "main": "dist/index.js", diff --git a/packages/apollo-tracing/package.json b/packages/apollo-tracing/package.json index 5a492d1ad78..3b50d8e693a 100644 --- a/packages/apollo-tracing/package.json +++ b/packages/apollo-tracing/package.json @@ -1,6 +1,6 @@ { "name": "apollo-tracing", - "version": "0.4.0", + "version": "0.5.0-alpha.1", "description": "Collect and expose trace data for GraphQL requests", "main": "./dist/index.js", "types": "./dist/index.d.ts", diff --git a/packages/graphql-extensions/package.json b/packages/graphql-extensions/package.json index a932e46f589..185a9e22ee4 100644 --- a/packages/graphql-extensions/package.json +++ b/packages/graphql-extensions/package.json @@ -1,6 +1,6 @@ { "name": "graphql-extensions", - "version": "0.4.1", + "version": "0.5.0-alpha.2", "description": "Add extensions to GraphQL servers", "main": "./dist/index.js", "types": "./dist/index.d.ts",