diff --git a/e2e/auto-type-merging/__snapshots__/auto-type-merging.test.ts.snap b/e2e/auto-type-merging/__snapshots__/auto-type-merging.test.ts.snap index b0e97099dafb8..e520d151d5ec1 100644 --- a/e2e/auto-type-merging/__snapshots__/auto-type-merging.test.ts.snap +++ b/e2e/auto-type-merging/__snapshots__/auto-type-merging.test.ts.snap @@ -524,16 +524,3 @@ input User_Input @join__type(graph: PETSTORE) { " `; - -exports[`should execute GetPet 1`] = ` -{ - "data": { - "getPetById": { - "__typename": "Pet", - "id": 1, - "name": "Cat 1", - "vaccinated": false, - }, - }, -} -`; diff --git a/e2e/auto-type-merging/auto-type-merging.test.ts b/e2e/auto-type-merging/auto-type-merging.test.ts index efa6cb8900c0b..7d486ce4afe56 100644 --- a/e2e/auto-type-merging/auto-type-merging.test.ts +++ b/e2e/auto-type-merging/auto-type-merging.test.ts @@ -1,44 +1,55 @@ -import { createTenv, type Container } from '@e2e/tenv'; +import { createTenv, type Tenv } from '@e2e/tenv'; -const { compose, service, serve, container } = createTenv(__dirname); - -let petstore!: Container; -beforeAll(async () => { - petstore = await container({ +function createPetstore(tenv: Tenv) { + return tenv.container({ name: 'petstore', image: 'swaggerapi/petstore3:1.0.7', containerPort: 8080, healthcheck: ['CMD-SHELL', 'wget --spider http://localhost:8080'], }); -}); +} -it('should compose the appropriate schema', async () => { - const { result } = await compose({ - services: [petstore, await service('vaccination')], +it.concurrent('should compose the appropriate schema', async () => { + await using tenv = createTenv(__dirname); + await using petstore = await createPetstore(tenv); + await using vaccination = await tenv.service('vaccination'); + const { supergraphSdl: result } = await tenv.compose({ + services: [petstore, vaccination], maskServicePorts: true, }); expect(result).toMatchSnapshot(); }); -it.concurrent.each([ - { - name: 'GetPet', - query: /* GraphQL */ ` - query GetPet { - getPetById(petId: 1) { - __typename - id - name - vaccinated - } - } - `, - }, -])('should execute $name', async ({ query }) => { - const { output } = await compose({ +it.concurrent('should execute GetPet', async () => { + await using tenv = createTenv(__dirname); + await using petstore = await createPetstore(tenv); + await using vaccination = await tenv.service('vaccination'); + await using composition = await tenv.compose({ output: 'graphql', - services: [petstore, await service('vaccination')], + services: [petstore, vaccination], + }); + await using gw = await tenv.gateway({ supergraph: composition.supergraphPath }); + await expect( + gw.execute({ + query: /* GraphQL */ ` + query GetPet { + getPetById(petId: 1) { + __typename + id + name + vaccinated + } + } + `, + }), + ).resolves.toMatchObject({ + data: { + getPetById: { + __typename: 'Pet', + id: 1, + name: 'Cat 1', + vaccinated: false, + }, + }, }); - const { execute } = await serve({ supergraph: output }); - await expect(execute({ query })).resolves.toMatchSnapshot(); }); diff --git a/e2e/cjs-project/cjs-project.test.ts b/e2e/cjs-project/cjs-project.test.ts index af75d12d50699..7669996b77c63 100644 --- a/e2e/cjs-project/cjs-project.test.ts +++ b/e2e/cjs-project/cjs-project.test.ts @@ -1,17 +1,17 @@ import { createTenv } from '@e2e/tenv'; import { fetch } from '@whatwg-node/fetch'; -const { serve, compose, fs } = createTenv(__dirname); - -it('should serve', async () => { - const proc = await serve({ - supergraph: await fs.tempfile('supergraph.graphql', 'type Query { hello: String }'), +it.concurrent('should serve', async () => { + await using tenv = createTenv(__dirname); + await using proc = await tenv.gateway({ + supergraph: await tenv.fs.tempfile('supergraph.graphql', 'type Query { hello: String }'), }); const res = await fetch(`http://${proc.hostname}:${proc.port}/healthcheck`); expect(res.ok).toBeTruthy(); }); -it('should compose', async () => { - const proc = await compose(); - expect(proc.result).toMatchSnapshot(); +it.concurrent('should compose', async () => { + await using tenv = createTenv(__dirname); + await using proc = await tenv.compose(); + expect(proc.supergraphSdl).toMatchSnapshot(); }); diff --git a/e2e/compose-to-output/compose-to-output.test.ts b/e2e/compose-to-output/compose-to-output.test.ts index b3de73babb065..a2a2f1cadb26e 100644 --- a/e2e/compose-to-output/compose-to-output.test.ts +++ b/e2e/compose-to-output/compose-to-output.test.ts @@ -1,23 +1,11 @@ import { createTenv } from '@e2e/tenv'; -const { compose, fs } = createTenv(__dirname); - -it('should write compose output to supergraph.graphql', async () => { - const { output } = await compose({ output: 'graphql' }); - await expect(fs.read(output)).resolves.toMatchSnapshot(); -}); - -it('should write compose output to supergraph.json', async () => { - const { output } = await compose({ output: 'json' }); - await expect(fs.read(output)).resolves.toMatchSnapshot(); -}); - -it('should write compose output to supergraph.js', async () => { - const { output } = await compose({ output: 'js' }); - await expect(fs.read(output)).resolves.toMatchSnapshot(); -}); - -it('should write compose output to supergraph.ts', async () => { - const { output } = await compose({ output: 'ts' }); - await expect(fs.read(output)).resolves.toMatchSnapshot(); -}); +const outputTypes = ['graphql', 'json', 'js', 'ts'] as const; + +for (const output of outputTypes) { + it.concurrent(`should write compose output to supergraph.${output}`, async () => { + await using tenv = createTenv(__dirname); + await using composition = await tenv.compose({ output }); + await expect(tenv.fs.read(composition.supergraphPath)).resolves.toMatchSnapshot(); + }); +} diff --git a/e2e/esm-config-in-cjs-project/esm-config-in-cjs-project.test.ts b/e2e/esm-config-in-cjs-project/esm-config-in-cjs-project.test.ts index af75d12d50699..8c1c01637f093 100644 --- a/e2e/esm-config-in-cjs-project/esm-config-in-cjs-project.test.ts +++ b/e2e/esm-config-in-cjs-project/esm-config-in-cjs-project.test.ts @@ -1,17 +1,17 @@ import { createTenv } from '@e2e/tenv'; import { fetch } from '@whatwg-node/fetch'; -const { serve, compose, fs } = createTenv(__dirname); - -it('should serve', async () => { - const proc = await serve({ - supergraph: await fs.tempfile('supergraph.graphql', 'type Query { hello: String }'), +it.concurrent('should serve', async () => { + await using tenv = createTenv(__dirname); + await using gw = await tenv.gateway({ + supergraph: await tenv.fs.tempfile('supergraph.graphql', 'type Query { hello: String }'), }); - const res = await fetch(`http://${proc.hostname}:${proc.port}/healthcheck`); + const res = await fetch(`http://${gw.hostname}:${gw.port}/healthcheck`); expect(res.ok).toBeTruthy(); }); -it('should compose', async () => { - const proc = await compose(); - expect(proc.result).toMatchSnapshot(); +it.concurrent('should compose', async () => { + await using tenv = createTenv(__dirname); + await using proc = await tenv.compose(); + expect(proc.supergraphSdl).toMatchSnapshot(); }); diff --git a/e2e/esm-project/esm-project.test.ts b/e2e/esm-project/esm-project.test.ts index af75d12d50699..9d7274efd38ac 100644 --- a/e2e/esm-project/esm-project.test.ts +++ b/e2e/esm-project/esm-project.test.ts @@ -1,17 +1,17 @@ import { createTenv } from '@e2e/tenv'; import { fetch } from '@whatwg-node/fetch'; -const { serve, compose, fs } = createTenv(__dirname); - -it('should serve', async () => { - const proc = await serve({ - supergraph: await fs.tempfile('supergraph.graphql', 'type Query { hello: String }'), +it.concurrent('should serve', async () => { + await using tenv = createTenv(__dirname); + await using gw = await tenv.gateway({ + supergraph: await tenv.fs.tempfile('supergraph.graphql', 'type Query { hello: String }'), }); - const res = await fetch(`http://${proc.hostname}:${proc.port}/healthcheck`); + const res = await fetch(`http://${gw.hostname}:${gw.port}/healthcheck`); expect(res.ok).toBeTruthy(); }); -it('should compose', async () => { - const proc = await compose(); - expect(proc.result).toMatchSnapshot(); +it.concurrent('should compose', async () => { + await using tenv = createTenv(__dirname); + await using composition = await tenv.compose(); + expect(composition.supergraphSdl).toMatchSnapshot(); }); diff --git a/e2e/extra-fields/extra-fields.test.ts b/e2e/extra-fields/extra-fields.test.ts index 4c81289abd5dd..a53282a5a2aca 100644 --- a/e2e/extra-fields/extra-fields.test.ts +++ b/e2e/extra-fields/extra-fields.test.ts @@ -1,15 +1,16 @@ import { createTenv } from '@e2e/tenv'; -const { serve, compose, service } = createTenv(__dirname); - -it('works', async () => { - const { output } = await compose({ - services: [await service('foo'), await service('bar')], +it.concurrent('works', async () => { + await using tenv = createTenv(__dirname); + await using foo = await tenv.service('foo'); + await using bar = await tenv.service('bar'); + await using composition = await tenv.compose({ + services: [foo, bar], output: 'graphql', }); - const { execute } = await serve({ supergraph: output }); + await using gw = await tenv.gateway({ supergraph: composition.supergraphPath }); await expect( - execute({ + gw.execute({ query: /* GraphQL */ ` query FooBarFoo { foo { diff --git a/e2e/federation-mixed/federation-mixed.test.ts b/e2e/federation-mixed/federation-mixed.test.ts index be640cc7bb171..dcc2c61431dce 100644 --- a/e2e/federation-mixed/federation-mixed.test.ts +++ b/e2e/federation-mixed/federation-mixed.test.ts @@ -1,18 +1,16 @@ import { createTenv } from '@e2e/tenv'; -const { service, serve, compose } = createTenv(__dirname); - -it('should compose the appropriate schema', async () => { - const { result } = await compose({ - services: [ - await service('accounts'), - await service('inventory'), - await service('products'), - await service('reviews'), - ], +it.concurrent('should compose the appropriate schema', async () => { + await using tenv = createTenv(__dirname); + await using accounts = await tenv.service('accounts'); + await using inventory = await tenv.service('inventory'); + await using products = await tenv.service('products'); + await using reviews = await tenv.service('reviews'); + await using composition = await tenv.compose({ + services: [accounts, inventory, products, reviews], maskServicePorts: true, }); - expect(result).toMatchSnapshot(); + expect(composition.supergraphSdl).toMatchSnapshot(); }); it.concurrent.each([ @@ -80,15 +78,15 @@ it.concurrent.each([ `, }, ])('should execute $name', async ({ query }) => { - const { output } = await compose({ + await using tenv = createTenv(__dirname); + await using accounts = await tenv.service('accounts'); + await using inventory = await tenv.service('inventory'); + await using products = await tenv.service('products'); + await using reviews = await tenv.service('reviews'); + await using composition = await tenv.compose({ output: 'graphql', - services: [ - await service('accounts'), - await service('inventory'), - await service('products'), - await service('reviews'), - ], + services: [accounts, inventory, products, reviews], }); - const { execute } = await serve({ supergraph: output }); - await expect(execute({ query })).resolves.toMatchSnapshot(); + await using gw = await tenv.gateway({ supergraph: composition.supergraphPath }); + await expect(gw.execute({ query })).resolves.toMatchSnapshot(); }); diff --git a/e2e/file-upload/file-upload.test.ts b/e2e/file-upload/file-upload.test.ts index ac766d570fa32..b88542a1a3df4 100644 --- a/e2e/file-upload/file-upload.test.ts +++ b/e2e/file-upload/file-upload.test.ts @@ -1,11 +1,11 @@ import { createTenv } from '@e2e/tenv'; import { fetch, File, FormData } from '@whatwg-node/fetch'; -const { compose, serve, service } = createTenv(__dirname); - -it('should upload file', async () => { - const { output } = await compose({ output: 'graphql', services: [await service('bucket')] }); - const { hostname, port } = await serve({ supergraph: output }); +it.concurrent('should upload file', async () => { + await using tenv = createTenv(__dirname); + await using bucketService = await tenv.service('bucket'); + await using composition = await tenv.compose({ output: 'graphql', services: [bucketService] }); + await using gw = await tenv.gateway({ supergraph: composition.supergraphPath }); const form = new FormData(); form.append( @@ -23,16 +23,14 @@ it('should upload file', async () => { ); form.append('map', JSON.stringify({ 0: ['variables.file'] })); form.append('0', new File(['Hello World!'], 'hello.txt', { type: 'text/plain' })); - const res = await fetch(`http://${hostname}:${port}/graphql`, { + const res = await fetch(`http://${gw.hostname}:${gw.port}/graphql`, { method: 'POST', body: form, }); - await expect(res.json()).resolves.toMatchInlineSnapshot(` -{ - "data": { - "readFile": "Hello World!", - }, -} -`); + await expect(res.json()).resolves.toMatchObject({ + data: { + readFile: 'Hello World!', + }, + }); }); diff --git a/e2e/grpc-example/grpc-example.test.ts b/e2e/grpc-example/grpc-example.test.ts index c90e4ae82154c..75ae85f1ce51b 100644 --- a/e2e/grpc-example/grpc-example.test.ts +++ b/e2e/grpc-example/grpc-example.test.ts @@ -6,18 +6,17 @@ import { buildHTTPExecutor } from '@graphql-tools/executor-http'; import { isAsyncIterable } from '@graphql-tools/utils'; describe('gRPC Example', () => { - const { compose, serve, service } = createTenv(__dirname); - let movies: Service; - beforeAll(async () => { - movies = await service('movies'); + it.concurrent('generates the correct schema', async () => { + await using tenv = createTenv(__dirname); + await using movies = await tenv.service('movies'); + await using composition = await tenv.compose({ services: [movies], maskServicePorts: true }); + expect(composition.supergraphSdl).toMatchSnapshot(); }); - it('generates the correct schema', async () => { - const { result } = await compose({ services: [movies], maskServicePorts: true }); - expect(result).toMatchSnapshot(); - }); - it('gets movies correctly', async () => { - const { output } = await compose({ services: [movies], output: 'graphql' }); - const { execute } = await serve({ supergraph: output }); + it.concurrent('gets movies correctly', async () => { + await using tenv = createTenv(__dirname); + await using movies = await tenv.service('movies'); + await using composition = await tenv.compose({ services: [movies], output: 'graphql' }); + await using gw = await tenv.gateway({ supergraph: composition.supergraphPath }); const query = /* GraphQL */ ` query GetMovies { exampleGetMovies(input: { movie: { genre: DRAMA, year: 2015 } }) { @@ -33,13 +32,15 @@ describe('gRPC Example', () => { } } `; - await expect(execute({ query })).resolves.toMatchSnapshot('get-movies-grpc-example-result'); + await expect(gw.execute({ query })).resolves.toMatchSnapshot('get-movies-grpc-example-result'); }); - it('streams movies by cast correctly', async () => { - const { output } = await compose({ services: [movies], output: 'graphql' }); - const { hostname, port } = await serve({ supergraph: output }); - const executor = buildHTTPExecutor({ - endpoint: `http://${hostname}:${port}/graphql`, + it.concurrent('streams movies by cast correctly', async () => { + await using tenv = createTenv(__dirname); + await using movies = await tenv.service('movies'); + await using composition = await tenv.compose({ services: [movies], output: 'graphql' }); + await using gw = await tenv.gateway({ supergraph: composition.supergraphPath }); + await using executor = buildHTTPExecutor({ + endpoint: `http://${gw.hostname}:${gw.port}/graphql`, }); const document = parse(/* GraphQL */ ` query SearchMoviesByCast { @@ -63,11 +64,13 @@ describe('gRPC Example', () => { i++; } }); - it('fetches movies by cast as a subscription correctly', async () => { - const { output } = await compose({ services: [movies], output: 'graphql' }); - const { hostname, port } = await serve({ supergraph: output }); - const executor = buildHTTPExecutor({ - endpoint: `http://${hostname}:${port}/graphql`, + it.concurrent('fetches movies by cast as a subscription correctly', async () => { + await using tenv = createTenv(__dirname); + await using movies = await tenv.service('movies'); + await using composition = await tenv.compose({ services: [movies], output: 'graphql' }); + await using gw = await tenv.gateway({ supergraph: composition.supergraphPath }); + await using executor = buildHTTPExecutor({ + endpoint: `http://${gw.hostname}:${gw.port}/graphql`, }); const document = parse(/* GraphQL */ ` subscription SearchMoviesByCast { diff --git a/e2e/grpc-multiple/__snapshots__/grpc-multiple.test.ts.snap b/e2e/grpc-multiple/__snapshots__/grpc-multiple.test.ts.snap index eedf1fd83581f..b315f5b9c4abf 100644 --- a/e2e/grpc-multiple/__snapshots__/grpc-multiple.test.ts.snap +++ b/e2e/grpc-multiple/__snapshots__/grpc-multiple.test.ts.snap @@ -1,5 +1,67 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP +exports[`gRPC Multiple GetAllPetStores 1`] = ` +{ + "data": { + "GetAllPetStores": { + "petStores": [ + { + "id": 1, + "name": "Happy Paws Pet Store", + }, + { + "id": 2, + "name": "Pet Paradise", + }, + { + "id": 3, + "name": "Furry Friends", + }, + { + "id": 4, + "name": "Paws and Claws", + }, + { + "id": 5, + "name": "The Pet Shop", + }, + ], + }, + }, +} +`; + +exports[`gRPC Multiple GetAllPets 1`] = ` +{ + "data": { + "GetAllPets": { + "pets": [ + { + "id": 1, + "name": "Pet1", + }, + { + "id": 2, + "name": "Pet2", + }, + { + "id": 3, + "name": "Pet3", + }, + { + "id": 4, + "name": "Pet4", + }, + { + "id": 5, + "name": "Pet5", + }, + ], + }, + }, +} +`; + exports[`gRPC Multiple composes 1`] = ` " schema @@ -220,65 +282,3 @@ input petstore__PetStore_Input @join__type(graph: STORES) { " `; - -exports[`gRPC Multiple works: GetAllPetStores 1`] = ` -{ - "data": { - "GetAllPetStores": { - "petStores": [ - { - "id": 1, - "name": "Happy Paws Pet Store", - }, - { - "id": 2, - "name": "Pet Paradise", - }, - { - "id": 3, - "name": "Furry Friends", - }, - { - "id": 4, - "name": "Paws and Claws", - }, - { - "id": 5, - "name": "The Pet Shop", - }, - ], - }, - }, -} -`; - -exports[`gRPC Multiple works: GetAllPets 1`] = ` -{ - "data": { - "GetAllPets": { - "pets": [ - { - "id": 1, - "name": "Pet1", - }, - { - "id": 2, - "name": "Pet2", - }, - { - "id": 3, - "name": "Pet3", - }, - { - "id": 4, - "name": "Pet4", - }, - { - "id": 5, - "name": "Pet5", - }, - ], - }, - }, -} -`; diff --git a/e2e/grpc-multiple/grpc-multiple.test.ts b/e2e/grpc-multiple/grpc-multiple.test.ts index 10be344d4e550..b4dbde76d4a34 100644 --- a/e2e/grpc-multiple/grpc-multiple.test.ts +++ b/e2e/grpc-multiple/grpc-multiple.test.ts @@ -1,54 +1,57 @@ import { createTenv, type Serve } from '@e2e/tenv'; describe('gRPC Multiple', () => { - const { compose, service, serve } = createTenv(__dirname); - const queries = { - GetAllPets: /* GraphQL */ ` - query GetAllPets { - GetAllPets { - pets { - id - name + it.concurrent('composes', async () => { + await using tenv = createTenv(__dirname); + await using Pets = await tenv.service('Pets'); + await using Stores = await tenv.service('Stores'); + await using composition = await tenv.compose({ + services: [Pets, Stores], + maskServicePorts: true, + }); + expect(composition.supergraphSdl).toMatchSnapshot(); + }); + it.concurrent.each([ + { + name: 'GetAllPets', + query: /* GraphQL */ ` + query GetAllPets { + GetAllPets { + pets { + id + name + } } } - } - `, - GetAllPetStores: /* GraphQL */ ` - query GetAllPetStores { - GetAllPetStores { - petStores { - id - name + `, + }, + { + name: 'GetAllPetStores', + query: /* GraphQL */ ` + query GetAllPetStores { + GetAllPetStores { + petStores { + id + name + } } } - } - `, - }; - let gw: Serve; - let supergraph: string; - beforeAll(async () => { - const { output, result } = await compose({ - services: [await service('Pets'), await service('Stores')], + `, + }, + ])(`$name`, async ({ query }) => { + await using tenv = createTenv(__dirname); + await using Pets = await tenv.service('Pets'); + await using Stores = await tenv.service('Stores'); + await using composition = await tenv.compose({ + services: [Pets, Stores], output: 'graphql', }); - supergraph = result; - gw = await serve({ - supergraph: output, + await using gw = await tenv.gateway({ + supergraph: composition.supergraphPath, }); - }); - it('composes', async () => { - const { result } = await compose({ - services: [await service('Pets'), await service('Stores')], - maskServicePorts: true, + const result = await gw.execute({ + query, }); expect(result).toMatchSnapshot(); }); - for (const queryName in queries) { - it('works', async () => { - const result = await gw.execute({ - query: queries[queryName], - }); - expect(result).toMatchSnapshot(queryName); - }); - } }); diff --git a/e2e/hoist-and-prefix-transform/hoist-and-prefix-transform.test.ts b/e2e/hoist-and-prefix-transform/hoist-and-prefix-transform.test.ts index fcf19b9a9eb52..9fb80c13ef4a0 100644 --- a/e2e/hoist-and-prefix-transform/hoist-and-prefix-transform.test.ts +++ b/e2e/hoist-and-prefix-transform/hoist-and-prefix-transform.test.ts @@ -1,6 +1,6 @@ import { createTenv, type Service } from '@e2e/tenv'; -const { compose, serve, service, fs } = createTenv(__dirname); +const { compose, gateway, service, fs } = createTenv(__dirname); let weather: Service; @@ -8,23 +8,23 @@ beforeAll(async () => { weather = await service('weather'); }); -it('should compose the appropriate schema', async () => { - const { result } = await compose({ +it.concurrent('should compose the appropriate schema', async () => { + const { supergraphSdl: result } = await compose({ services: [weather], maskServicePorts: true, }); expect(result).toMatchSnapshot(); }); -it('should compose and execute', async () => { - const { output } = await compose({ output: 'graphql', services: [weather] }); +it.concurrent('should compose and execute', async () => { + const { supergraphPath } = await compose({ output: 'graphql', services: [weather] }); // hoisted - const supergraph = await fs.read(output); + const supergraph = await fs.read(supergraphPath); expect(supergraph).toContain('Test_Weather'); expect(supergraph).toContain('chanceOfRain'); - const { execute } = await serve({ supergraph: output }); + const { execute } = await gateway({ supergraph: supergraphPath }); await expect( execute({ query: /* GraphQL */ ` diff --git a/e2e/js-config/js-config.test.ts b/e2e/js-config/js-config.test.ts index 09feebff0d8b4..7110e5a3761a3 100644 --- a/e2e/js-config/js-config.test.ts +++ b/e2e/js-config/js-config.test.ts @@ -1,15 +1,15 @@ import { createTenv } from '@e2e/tenv'; import { fetch } from '@whatwg-node/fetch'; -const { serve, compose, fs } = createTenv(__dirname); +const { gateway, compose, fs } = createTenv(__dirname); -it('should compose and serve', async () => { - const { result: composedSchema } = await compose(); +it.concurrent('should compose and serve', async () => { + const { supergraphSdl: composedSchema } = await compose(); expect(composedSchema).toMatchSnapshot(); const supergraphPath = await fs.tempfile('supergraph.graphql'); await fs.write(supergraphPath, composedSchema); - const { hostname, port } = await serve({ supergraph: supergraphPath }); + const { hostname, port } = await gateway({ supergraph: supergraphPath }); const res = await fetch(`http://${hostname}:${port}/graphql?query={hello}`); expect(res.ok).toBeTruthy(); await expect(res.text()).resolves.toMatchInlineSnapshot(`"{"data":{"hello":"world"}}"`); diff --git a/e2e/json-schema-subscriptions/json-schema-subscriptions.test.ts b/e2e/json-schema-subscriptions/json-schema-subscriptions.test.ts index ca329d1ed8f40..9e19a13804ac3 100644 --- a/e2e/json-schema-subscriptions/json-schema-subscriptions.test.ts +++ b/e2e/json-schema-subscriptions/json-schema-subscriptions.test.ts @@ -3,21 +3,24 @@ import { createTenv } from '@e2e/tenv'; import { fetch } from '@whatwg-node/fetch'; import { getAvailablePort } from '../../packages/testing/getAvailablePort'; -const { compose, serve, service } = createTenv(__dirname); +const { compose, gateway, service } = createTenv(__dirname); -it('should compose the appropriate schema', async () => { +it.concurrent('should compose the appropriate schema', async () => { const api = await service('api'); - const { result } = await compose({ services: [api], maskServicePorts: true }); + const { supergraphSdl: result } = await compose({ services: [api], maskServicePorts: true }); expect(result).toMatchSnapshot(); }); ['todoAddedFromSource', 'todoAddedFromExtensions'].forEach(subscriptionField => { describe(`Listen to ${subscriptionField}`, () => { - it('should query, mutate and subscribe', async () => { + it.concurrent('should query, mutate and subscribe', async () => { const servePort = await getAvailablePort(); const api = await service('api', { servePort }); - const { output } = await compose({ output: 'graphql', services: [api] }); - const { hostname, port, execute } = await serve({ supergraph: output, port: servePort }); + const { supergraphPath } = await compose({ output: 'graphql', services: [api] }); + const { hostname, port, execute } = await gateway({ + supergraph: supergraphPath, + port: servePort, + }); await expect( execute({ diff --git a/e2e/logs-to-stderr-results-to-stdout/logs-to-stderr-results-to-stdout.test.ts b/e2e/logs-to-stderr-results-to-stdout/logs-to-stderr-results-to-stdout.test.ts index 8c73126fd2299..5b24b4b7f860d 100644 --- a/e2e/logs-to-stderr-results-to-stdout/logs-to-stderr-results-to-stdout.test.ts +++ b/e2e/logs-to-stderr-results-to-stdout/logs-to-stderr-results-to-stdout.test.ts @@ -2,7 +2,7 @@ import { createTenv } from '@e2e/tenv'; const { compose } = createTenv(__dirname); -it('should write compose output to stdout and logs to stderr', async () => { +it.concurrent('should write compose output to stdout and logs to stderr', async () => { const { getStd } = await compose(); expect(getStd('out')).toContain('type Query @join__type(graph: HELLOWORLD)'); expect(getStd('err')).toContain('Done!'); diff --git a/e2e/manual-transport-def/manual-transport-def.test.ts b/e2e/manual-transport-def/manual-transport-def.test.ts index 4c9e6f0e4fe70..1c0cffaf05f29 100644 --- a/e2e/manual-transport-def/manual-transport-def.test.ts +++ b/e2e/manual-transport-def/manual-transport-def.test.ts @@ -1,21 +1,21 @@ import { createTenv } from '@e2e/tenv'; -const { compose, serve, service } = createTenv(__dirname); +const { compose, gateway, service } = createTenv(__dirname); -it('should compose the appropriate schema', async () => { - const { result } = await compose({ +it.concurrent('should compose the appropriate schema', async () => { + const { supergraphSdl: result } = await compose({ services: [await service('greetings'), await service('helloer')], maskServicePorts: true, }); expect(result).toMatchSnapshot(); }); -it('should execute the query', async () => { - const { output } = await compose({ +it.concurrent('should execute the query', async () => { + const { supergraphPath } = await compose({ output: 'graphql', services: [await service('greetings'), await service('helloer')], }); - const { execute } = await serve({ supergraph: output }); + const { execute } = await gateway({ supergraph: supergraphPath }); await expect( execute({ query: /* GraphQL */ ` diff --git a/e2e/mysql-employees/mysql-employees.test.ts b/e2e/mysql-employees/mysql-employees.test.ts index dc299d4826983..7d21ff6710249 100644 --- a/e2e/mysql-employees/mysql-employees.test.ts +++ b/e2e/mysql-employees/mysql-employees.test.ts @@ -1,6 +1,6 @@ import { createTenv, type Container } from '@e2e/tenv'; -const { compose, serve, container } = createTenv(__dirname); +const { compose, gateway, container } = createTenv(__dirname); let mysql!: Container; beforeAll(async () => { @@ -20,8 +20,8 @@ beforeAll(async () => { }); }); -it('should compose the appropriate schema', async () => { - const { result } = await compose({ +it.concurrent('should compose the appropriate schema', async () => { + const { supergraphSdl: result } = await compose({ services: [mysql], maskServicePorts: true, }); @@ -59,7 +59,7 @@ it.concurrent.each([ `, }, ])('should execute $name', async ({ query }) => { - const { output } = await compose({ output: 'graphql', services: [mysql] }); - const { execute } = await serve({ supergraph: output }); + const { supergraphPath } = await compose({ output: 'graphql', services: [mysql] }); + const { execute } = await gateway({ supergraph: supergraphPath }); await expect(execute({ query })).resolves.toMatchSnapshot(); }); diff --git a/e2e/mysql-rfam/mysql-rfam.test.ts b/e2e/mysql-rfam/mysql-rfam.test.ts index 970bed4bcd3e5..923fbc7d6c341 100644 --- a/e2e/mysql-rfam/mysql-rfam.test.ts +++ b/e2e/mysql-rfam/mysql-rfam.test.ts @@ -1,9 +1,9 @@ import { createTenv } from '@e2e/tenv'; -const { compose, serve } = createTenv(__dirname); +const { compose, gateway } = createTenv(__dirname); -it('should compose the appropriate schema', async () => { - const { result } = await compose(); +it.concurrent('should compose the appropriate schema', async () => { + const { supergraphSdl: result } = await compose(); expect(result).toMatchSnapshot(); }); @@ -25,7 +25,7 @@ it.concurrent.each([ `, }, ])('should execute $name', async ({ query }) => { - const { output } = await compose({ output: 'graphql' }); - const { execute } = await serve({ supergraph: output }); + const { supergraphPath } = await compose({ output: 'graphql' }); + const { execute } = await gateway({ supergraph: supergraphPath }); await expect(execute({ query })).resolves.toMatchSnapshot(); }); diff --git a/e2e/neo4j-example/neo4j-example.test.ts b/e2e/neo4j-example/neo4j-example.test.ts index ee1f9cb345098..7db7b4f5dacf3 100644 --- a/e2e/neo4j-example/neo4j-example.test.ts +++ b/e2e/neo4j-example/neo4j-example.test.ts @@ -1,6 +1,6 @@ import { createTenv, type Container } from '@e2e/tenv'; -const { compose, container, serve, spawn } = createTenv(__dirname); +const { compose, container, gateway, spawn } = createTenv(__dirname); let neo4j: Container; beforeAll(async () => { @@ -31,8 +31,8 @@ beforeAll(async () => { await waitForLoad; }); -it('should compose the appropriate schema', async () => { - const { result } = await compose({ +it.concurrent('should compose the appropriate schema', async () => { + const { supergraphSdl: result } = await compose({ services: [neo4j], maskServicePorts: true, }); @@ -56,10 +56,10 @@ it.concurrent.each([ `, }, ])('should execute $name', async ({ query }) => { - const { output } = await compose({ + const { supergraphPath } = await compose({ services: [neo4j], output: 'graphql', }); - const { execute } = await serve({ supergraph: output }); + const { execute } = await gateway({ supergraph: supergraphPath }); await expect(execute({ query })).resolves.toMatchSnapshot(); }); diff --git a/e2e/odata-trippin/odata-trippin.test.ts b/e2e/odata-trippin/odata-trippin.test.ts index 1b4e70f6d50c5..31d9bfea2bb31 100644 --- a/e2e/odata-trippin/odata-trippin.test.ts +++ b/e2e/odata-trippin/odata-trippin.test.ts @@ -1,17 +1,17 @@ import { createTenv } from '@e2e/tenv'; -const { compose, serve } = createTenv(__dirname); +const { compose, gateway } = createTenv(__dirname); -it('should compose the appropriate schema', async () => { - const { result } = await compose(); +it.concurrent('should compose the appropriate schema', async () => { + const { supergraphSdl: result } = await compose(); expect(result).toMatchSnapshot(); }); -it('executes a query', async () => { - const { output } = await compose({ +it.concurrent('executes a query', async () => { + const { supergraphPath } = await compose({ output: 'graphql', }); - const { execute } = await serve({ supergraph: output }); + const { execute } = await gateway({ supergraph: supergraphPath }); const result = await execute({ query: /* GraphQL */ ` query GetMe { diff --git a/e2e/openapi-additional-resolvers/openapi-additional-resolvers.test.ts b/e2e/openapi-additional-resolvers/openapi-additional-resolvers.test.ts index 6c434f5a0b58b..2ab95c9568d73 100644 --- a/e2e/openapi-additional-resolvers/openapi-additional-resolvers.test.ts +++ b/e2e/openapi-additional-resolvers/openapi-additional-resolvers.test.ts @@ -1,10 +1,10 @@ import { createTenv } from '@e2e/tenv'; -const { compose, serve } = createTenv(__dirname); +const { compose, gateway } = createTenv(__dirname); -it('should execute Metrics with banana', async () => { - const { output } = await compose({ output: 'graphql' }); - const { execute } = await serve({ supergraph: output }); +it.concurrent('should execute Metrics with banana', async () => { + const { supergraphPath } = await compose({ output: 'graphql' }); + const { execute } = await gateway({ supergraph: supergraphPath }); const result = await execute({ query: /* GraphQL */ ` query Metrics { @@ -36,9 +36,9 @@ it('should execute Metrics with banana', async () => { ).toEqual('🍌'); }); -it('should execute Metrics with apple', async () => { - const { output } = await compose({ output: 'graphql' }); - const { execute } = await serve({ supergraph: output }); +it.concurrent('should execute Metrics with apple', async () => { + const { supergraphPath } = await compose({ output: 'graphql' }); + const { execute } = await gateway({ supergraph: supergraphPath }); const result = await execute({ query: /* GraphQL */ ` query Metrics { diff --git a/e2e/openapi-arg-rename/openapi-arg-rename.test.ts b/e2e/openapi-arg-rename/openapi-arg-rename.test.ts index f1926be4f5142..351e05b4bfd01 100644 --- a/e2e/openapi-arg-rename/openapi-arg-rename.test.ts +++ b/e2e/openapi-arg-rename/openapi-arg-rename.test.ts @@ -1,9 +1,9 @@ import { createTenv } from '@e2e/tenv'; describe('OpenAPI Arg Rename', () => { - const { compose, serve, service } = createTenv(__dirname); - it('composes the schema', async () => { - const { result } = await compose({ + const { compose, gateway, service } = createTenv(__dirname); + it.concurrent('composes the schema', async () => { + const { supergraphSdl: result } = await compose({ output: 'graphql', services: [await service('Wiki')], maskServicePorts: true, @@ -11,13 +11,13 @@ describe('OpenAPI Arg Rename', () => { expect(result).toMatchSnapshot(); }); - it('should work with untouched schema', async () => { - const { output } = await compose({ + it.concurrent('should work with untouched schema', async () => { + const { supergraphPath } = await compose({ output: 'graphql', services: [await service('Wiki')], }); - const { execute } = await serve({ supergraph: output }); + const { execute } = await gateway({ supergraph: supergraphPath }); const queryResult = await execute({ query: /* GraphQL */ ` mutation Good { @@ -37,13 +37,13 @@ describe('OpenAPI Arg Rename', () => { }); }); - it('should work with renamed argument', async () => { - const { output } = await compose({ + it.concurrent('should work with renamed argument', async () => { + const { supergraphPath } = await compose({ output: 'graphql', services: [await service('Wiki')], }); - const { execute } = await serve({ supergraph: output }); + const { execute } = await gateway({ supergraph: supergraphPath }); const queryResult = await execute({ query: /* GraphQL */ ` mutation Bad { diff --git a/e2e/openapi-hateoas/openapi-hateoas.test.ts b/e2e/openapi-hateoas/openapi-hateoas.test.ts index 73ae7c8461845..c8ce396678aab 100644 --- a/e2e/openapi-hateoas/openapi-hateoas.test.ts +++ b/e2e/openapi-hateoas/openapi-hateoas.test.ts @@ -1,33 +1,29 @@ -import { createTenv, type Service } from '@e2e/tenv'; +import { createTenv } from '@e2e/tenv'; describe('OpenAPI HATEOAS', () => { - const { compose, serve, service } = createTenv(__dirname); - - let oasService: Service; - - beforeAll(async () => { - oasService = await service('OASService'); - }); - - it('should compose', async () => { - const { result } = await compose({ + it.concurrent('should compose', async () => { + await using tenv = createTenv(__dirname); + await using OASService = await tenv.service('OASService'); + await using composition = await tenv.compose({ output: 'graphql', - services: [oasService], + services: [OASService], maskServicePorts: true, }); - expect(result).toMatchSnapshot(); + expect(composition.supergraphSdl).toMatchSnapshot(); }); - it('should execute and follow HATEOAS links', async () => { - const { output } = await compose({ + it.concurrent('should execute and follow HATEOAS links', async () => { + await using tenv = createTenv(__dirname); + await using OASService = await tenv.service('OASService'); + await using composition = await tenv.compose({ output: 'graphql', - services: [oasService], + services: [OASService], }); - const { execute } = await serve({ - supergraph: output, + const gw = await tenv.gateway({ + supergraph: composition.supergraphPath, }); - const queryResult = await execute({ + const queryResult = await gw.execute({ query: /* GraphQL */ ` query GetProductsById { getProductById(id: 1) { diff --git a/e2e/openapi-javascript-wiki/openapi-javascript-wiki.test.ts b/e2e/openapi-javascript-wiki/openapi-javascript-wiki.test.ts index 91a84534146a2..72a5acd6d8f10 100644 --- a/e2e/openapi-javascript-wiki/openapi-javascript-wiki.test.ts +++ b/e2e/openapi-javascript-wiki/openapi-javascript-wiki.test.ts @@ -1,9 +1,9 @@ import { createTenv } from '@e2e/tenv'; -const { compose, serve } = createTenv(__dirname); +const { compose, gateway } = createTenv(__dirname); -it('should compose the appropriate schema', async () => { - const { result } = await compose(); +it.concurrent('should compose the appropriate schema', async () => { + const { supergraphSdl: result } = await compose(); expect(result).toMatchSnapshot(); }); @@ -30,7 +30,7 @@ it.concurrent.each([ `, }, ])('should execute $name', async ({ query }) => { - const { output } = await compose({ output: 'graphql' }); - const { execute } = await serve({ supergraph: output }); + const { supergraphPath } = await compose({ output: 'graphql' }); + const { execute } = await gateway({ supergraph: supergraphPath }); await expect(execute({ query })).resolves.toMatchSnapshot(); }); diff --git a/e2e/openapi-min-length/openapi-min-length.test.ts b/e2e/openapi-min-length/openapi-min-length.test.ts index 85dc605fc895f..cfeae90aa52cc 100644 --- a/e2e/openapi-min-length/openapi-min-length.test.ts +++ b/e2e/openapi-min-length/openapi-min-length.test.ts @@ -1,16 +1,16 @@ import { createTenv } from '@e2e/tenv'; -const { compose, serve } = createTenv(__dirname); +const { compose, gateway } = createTenv(__dirname); -it('should compose', async () => { - const { result } = await compose({ output: 'graphql' }); +it.concurrent('should compose', async () => { + const { supergraphSdl: result } = await compose({ output: 'graphql' }); expect(result).toMatchSnapshot(); }); -it('should execute Metrics with banana', async () => { - const { output } = await compose({ output: 'graphql' }); +it.concurrent('should execute Metrics with banana', async () => { + const { supergraphPath } = await compose({ output: 'graphql' }); - const { execute } = await serve({ supergraph: output }); + const { execute } = await gateway({ supergraph: supergraphPath }); const queryResult = await execute({ query: /* GraphQL */ ` query Categories { diff --git a/e2e/openapi-naming-convention/openapi-naming-convention.test.ts b/e2e/openapi-naming-convention/openapi-naming-convention.test.ts index 85dc605fc895f..cfeae90aa52cc 100644 --- a/e2e/openapi-naming-convention/openapi-naming-convention.test.ts +++ b/e2e/openapi-naming-convention/openapi-naming-convention.test.ts @@ -1,16 +1,16 @@ import { createTenv } from '@e2e/tenv'; -const { compose, serve } = createTenv(__dirname); +const { compose, gateway } = createTenv(__dirname); -it('should compose', async () => { - const { result } = await compose({ output: 'graphql' }); +it.concurrent('should compose', async () => { + const { supergraphSdl: result } = await compose({ output: 'graphql' }); expect(result).toMatchSnapshot(); }); -it('should execute Metrics with banana', async () => { - const { output } = await compose({ output: 'graphql' }); +it.concurrent('should execute Metrics with banana', async () => { + const { supergraphPath } = await compose({ output: 'graphql' }); - const { execute } = await serve({ supergraph: output }); + const { execute } = await gateway({ supergraph: supergraphPath }); const queryResult = await execute({ query: /* GraphQL */ ` query Categories { diff --git a/e2e/openapi-prune/openapi-prune.test.ts b/e2e/openapi-prune/openapi-prune.test.ts index 255d0131eea10..3994a083f14f5 100644 --- a/e2e/openapi-prune/openapi-prune.test.ts +++ b/e2e/openapi-prune/openapi-prune.test.ts @@ -1,23 +1,23 @@ import { createTenv } from '@e2e/tenv'; -const { compose, serve, service } = createTenv(__dirname); +const { compose, gateway, service } = createTenv(__dirname); describe('OpenAPI w/ Prune Transform', () => { - it('composes', async () => { - const { result } = await compose({ + it.concurrent('composes', async () => { + const { supergraphSdl: result } = await compose({ output: 'graphql', services: [await service('Wiki')], maskServicePorts: true, }); expect(result).toMatchSnapshot(); }); - it('should work when pruned', async () => { - const { output } = await compose({ + it.concurrent('should work when pruned', async () => { + const { supergraphPath } = await compose({ output: 'graphql', services: [await service('Wiki')], }); - const { execute } = await serve({ supergraph: output }); + const { execute } = await gateway({ supergraph: supergraphPath }); const queryResult = await execute({ query: /* GraphQL */ ` mutation Main { diff --git a/e2e/openapi-subscriptions/openapi-subscriptions.test.ts b/e2e/openapi-subscriptions/openapi-subscriptions.test.ts index 4bea10fd9eef9..f8f8a4d8b9586 100644 --- a/e2e/openapi-subscriptions/openapi-subscriptions.test.ts +++ b/e2e/openapi-subscriptions/openapi-subscriptions.test.ts @@ -2,19 +2,19 @@ import { createClient } from 'graphql-sse'; import { createTenv } from '@e2e/tenv'; import { fetch } from '@whatwg-node/fetch'; -const { compose, service, serve } = createTenv(__dirname); +const { compose, service, gateway } = createTenv(__dirname); -it('should compose the appropriate schema', async () => { - const { result } = await compose({ +it.concurrent('should compose the appropriate schema', async () => { + const { supergraphSdl: result } = await compose({ services: [await service('api')], maskServicePorts: true, }); expect(result).toMatchSnapshot(); }); -it('should listen for webhooks', async () => { - const { output } = await compose({ output: 'graphql', services: [await service('api')] }); - const { hostname, execute, port } = await serve({ supergraph: output }); +it.concurrent('should listen for webhooks', async () => { + const { supergraphPath } = await compose({ output: 'graphql', services: [await service('api')] }); + const { hostname, execute, port } = await gateway({ supergraph: supergraphPath }); const res = await execute({ query: /* GraphQL */ ` diff --git a/e2e/programmatic-batching/programmatic-batching.test.ts b/e2e/programmatic-batching/programmatic-batching.test.ts index ccc4c94790664..f42099ec31e92 100644 --- a/e2e/programmatic-batching/programmatic-batching.test.ts +++ b/e2e/programmatic-batching/programmatic-batching.test.ts @@ -1,9 +1,9 @@ import { createTenv } from '@e2e/tenv'; -const { compose, service, serve } = createTenv(__dirname); +const { compose, service, gateway } = createTenv(__dirname); -it('should compose the appropriate schema', async () => { - const { result } = await compose({ +it.concurrent('should compose the appropriate schema', async () => { + const { supergraphSdl: result } = await compose({ services: [await service('api')], maskServicePorts: true, }); @@ -29,7 +29,7 @@ it.concurrent.each([ `, }, ])('should execute $name', async ({ query }) => { - const { output } = await compose({ output: 'graphql', services: [await service('api')] }); - const { execute } = await serve({ supergraph: output }); + const { supergraphPath } = await compose({ output: 'graphql', services: [await service('api')] }); + const { execute } = await gateway({ supergraph: supergraphPath }); await expect(execute({ query })).resolves.toMatchSnapshot(); }); diff --git a/e2e/reprod-shareable/reprod-shareable.test.ts b/e2e/reprod-shareable/reprod-shareable.test.ts index 5a27e96648ec6..ac834dd6bc96e 100644 --- a/e2e/reprod-shareable/reprod-shareable.test.ts +++ b/e2e/reprod-shareable/reprod-shareable.test.ts @@ -2,7 +2,7 @@ import { createTenv } from '@e2e/tenv'; const { compose } = createTenv(__dirname); -it('composes', async () => { - const { result } = await compose(); +it.concurrent('composes', async () => { + const { supergraphSdl: result } = await compose(); expect(result).toMatchSnapshot(); }); diff --git a/e2e/soap-demo/soap-demo.test.ts b/e2e/soap-demo/soap-demo.test.ts index 421469ce34a19..c899f03fff5ff 100644 --- a/e2e/soap-demo/soap-demo.test.ts +++ b/e2e/soap-demo/soap-demo.test.ts @@ -1,6 +1,6 @@ import { createTenv, type Container } from '@e2e/tenv'; -const { compose, serve, container } = createTenv(__dirname); +const { compose, gateway, container } = createTenv(__dirname); let soapDemo: Container; @@ -19,8 +19,8 @@ beforeAll(async () => { }); }); -it('should compose the appropriate schema', async () => { - const { result } = await compose({ +it.concurrent('should compose the appropriate schema', async () => { + const { supergraphSdl: result } = await compose({ services: [soapDemo], maskServicePorts: true, }); @@ -153,7 +153,7 @@ it.concurrent.each([ }, }, ])('should execute $name', async ({ query, expected }) => { - const { output } = await compose({ output: 'graphql', services: [soapDemo] }); - const { execute } = await serve({ supergraph: output }); + const { supergraphPath } = await compose({ output: 'graphql', services: [soapDemo] }); + const { execute } = await gateway({ supergraph: supergraphPath }); await expect(execute({ query })).resolves.toEqual(expected); }); diff --git a/e2e/sqlite-chinook/sqlite-chinook.test.ts b/e2e/sqlite-chinook/sqlite-chinook.test.ts index af00c196d9cd6..658a9dc6af045 100644 --- a/e2e/sqlite-chinook/sqlite-chinook.test.ts +++ b/e2e/sqlite-chinook/sqlite-chinook.test.ts @@ -1,9 +1,9 @@ import { createTenv } from '@e2e/tenv'; -const { compose, serve } = createTenv(__dirname); +const { compose, gateway } = createTenv(__dirname); -it('should compose the appropriate schema', async () => { - const { result } = await compose({ trimHostPaths: true }); +it.concurrent('should compose the appropriate schema', async () => { + const { supergraphSdl: result } = await compose({ trimHostPaths: true }); expect(result).toMatchSnapshot(); }); @@ -23,8 +23,8 @@ it.concurrent.each([ `, }, ])('should execute $name', async ({ query }) => { - const { output } = await compose({ output: 'graphql' }); + const { supergraphPath } = await compose({ output: 'graphql' }); - const { execute } = await serve({ supergraph: output }); + const { execute } = await gateway({ supergraph: supergraphPath }); await expect(execute({ query })).resolves.toMatchSnapshot(); }); diff --git a/e2e/supergraph-url/supergraph-url.test.ts b/e2e/supergraph-url/supergraph-url.test.ts index 888b65bffb393..507b6a43afd01 100644 --- a/e2e/supergraph-url/supergraph-url.test.ts +++ b/e2e/supergraph-url/supergraph-url.test.ts @@ -1,32 +1,32 @@ import { getIntrospectionQuery } from 'graphql'; import { createTenv } from '@e2e/tenv'; -const { serve, service } = createTenv(__dirname); +const { gateway, service } = createTenv(__dirname); -it('should serve a schema from a url without pathname', async () => { +it.concurrent('should serve a schema from a url without pathname', async () => { const cdn = await service('cdn'); - const { execute } = await serve({ + const { execute } = await gateway({ supergraph: `http://localhost:${cdn.port}`, }); await expect(execute({ query: getIntrospectionQuery() })).resolves.toMatchSnapshot(); }); -it('should serve a schema from a url with pathname', async () => { +it.concurrent('should serve a schema from a url with pathname', async () => { const cdn = await service('cdn'); - const { execute } = await serve({ + const { execute } = await gateway({ supergraph: `http://localhost:${cdn.port}/schema`, }); await expect(execute({ query: getIntrospectionQuery() })).resolves.toMatchSnapshot(); }); -it('should serve a schema from a url with pathname and extension', async () => { +it.concurrent('should serve a schema from a url with pathname and extension', async () => { const cdn = await service('cdn'); - const { execute } = await serve({ + const { execute } = await gateway({ supergraph: `http://localhost:${cdn.port}/schema.graphql`, }); diff --git a/e2e/thrift-calculator/thrift-calculator.test.ts b/e2e/thrift-calculator/thrift-calculator.test.ts index fe7b009f8dbcf..9e0dd2986b1c1 100644 --- a/e2e/thrift-calculator/thrift-calculator.test.ts +++ b/e2e/thrift-calculator/thrift-calculator.test.ts @@ -1,9 +1,9 @@ import { createTenv } from '@e2e/tenv'; -const { compose, service, serve } = createTenv(__dirname); +const { compose, service, gateway } = createTenv(__dirname); -it('should compose the appropriate schema', async () => { - const { result } = await compose({ +it.concurrent('should compose the appropriate schema', async () => { + const { supergraphSdl: result } = await compose({ services: [await service('calculator')], maskServicePorts: true, }); @@ -20,11 +20,11 @@ it.concurrent.each([ `, }, ])('should execute $name', async ({ query }) => { - const { output } = await compose({ + const { supergraphPath } = await compose({ services: [await service('calculator')], output: 'graphql', }); - const { execute } = await serve({ supergraph: output }); + const { execute } = await gateway({ supergraph: supergraphPath }); await expect(execute({ query })).resolves.toMatchSnapshot(); }); diff --git a/e2e/top-level-await/top-level-await.test.ts b/e2e/top-level-await/top-level-await.test.ts index af75d12d50699..c1063f9ea0060 100644 --- a/e2e/top-level-await/top-level-await.test.ts +++ b/e2e/top-level-await/top-level-await.test.ts @@ -1,17 +1,17 @@ import { createTenv } from '@e2e/tenv'; import { fetch } from '@whatwg-node/fetch'; -const { serve, compose, fs } = createTenv(__dirname); +const { gateway, compose, fs } = createTenv(__dirname); -it('should serve', async () => { - const proc = await serve({ +it.concurrent('should serve', async () => { + const proc = await gateway({ supergraph: await fs.tempfile('supergraph.graphql', 'type Query { hello: String }'), }); const res = await fetch(`http://${proc.hostname}:${proc.port}/healthcheck`); expect(res.ok).toBeTruthy(); }); -it('should compose', async () => { +it.concurrent('should compose', async () => { const proc = await compose(); - expect(proc.result).toMatchSnapshot(); + expect(proc.supergraphSdl).toMatchSnapshot(); }); diff --git a/e2e/tsconfig-paths/tsconfig-paths.test.ts b/e2e/tsconfig-paths/tsconfig-paths.test.ts index 68f5f54bd81be..ae12d37f4515f 100644 --- a/e2e/tsconfig-paths/tsconfig-paths.test.ts +++ b/e2e/tsconfig-paths/tsconfig-paths.test.ts @@ -2,11 +2,12 @@ import { createTenv } from '@e2e/tenv'; const { compose } = createTenv(__dirname); -it('should compose', async () => { - const proc = await compose({ +it.concurrent('should compose', async () => { + await using tenv = createTenv(__dirname); + await using composition = await tenv.compose({ env: { MESH_INCLUDE_TSCONFIG_SEARCH_PATH: 'tsconfig-paths.tsconfig.json', }, }); - expect(proc.result).toMatchSnapshot(); + expect(composition.supergraphSdl).toMatchSnapshot(); }); diff --git a/e2e/type-merging-batching/type-merging-batching.test.ts b/e2e/type-merging-batching/type-merging-batching.test.ts index d59d1995609e5..58d829af18b2d 100644 --- a/e2e/type-merging-batching/type-merging-batching.test.ts +++ b/e2e/type-merging-batching/type-merging-batching.test.ts @@ -1,9 +1,9 @@ import { createTenv } from '@e2e/tenv'; -const { compose, service, serve } = createTenv(__dirname); +const { compose, service, gateway } = createTenv(__dirname); -it('should compose the appropriate schema', async () => { - const { result } = await compose({ +it.concurrent('should compose the appropriate schema', async () => { + const { supergraphSdl: result } = await compose({ services: [await service('authors'), await service('books')], maskServicePorts: true, }); @@ -90,11 +90,11 @@ const queries = [ ]; it.concurrent.each(queries)('should execute $name', async ({ query }) => { - const { output } = await compose({ + const { supergraphPath } = await compose({ services: [await service('authors'), await service('books')], output: 'graphql', }); - const { execute } = await serve({ supergraph: output }); + const { execute } = await gateway({ supergraph: supergraphPath }); await expect(execute({ query })).resolves.toMatchSnapshot(); }); diff --git a/e2e/type-merging-with-transforms/type-merging-with-transforms.test.ts b/e2e/type-merging-with-transforms/type-merging-with-transforms.test.ts index 5f539c52ec8fe..f18b3bf63232a 100644 --- a/e2e/type-merging-with-transforms/type-merging-with-transforms.test.ts +++ b/e2e/type-merging-with-transforms/type-merging-with-transforms.test.ts @@ -1,9 +1,9 @@ import { createTenv } from '@e2e/tenv'; -const { compose, service, serve } = createTenv(__dirname); +const { compose, service, gateway } = createTenv(__dirname); -it('should compose the appropriate schema', async () => { - const { result } = await compose({ +it.concurrent('should compose the appropriate schema', async () => { + const { supergraphSdl: result } = await compose({ services: [await service('authors'), await service('books')], maskServicePorts: true, }); @@ -90,11 +90,11 @@ const queries = [ ]; it.concurrent.each(queries)('should execute $name', async ({ query }) => { - const { output } = await compose({ + const { supergraphPath } = await compose({ services: [await service('authors'), await service('books')], output: 'graphql', }); - const { execute } = await serve({ supergraph: output }); + const { execute } = await gateway({ supergraph: supergraphPath }); await expect(execute({ query })).resolves.toMatchSnapshot(); }); diff --git a/e2e/utils/leftoverStack.ts b/e2e/utils/leftoverStack.ts deleted file mode 100644 index 72dc6246155ba..0000000000000 --- a/e2e/utils/leftoverStack.ts +++ /dev/null @@ -1,29 +0,0 @@ -import { AsyncDisposableStack, SuppressedError } from '@whatwg-node/disposablestack'; -import { trimError } from './trimError'; - -export let leftoverStack = new AsyncDisposableStack(); - -function handleSuppressedError(e: any) { - let currErr = e; - while (currErr instanceof SuppressedError) { - if (currErr.error) { - console.error(`Suppressed error`, trimError(currErr.error)); - } - currErr = currErr.suppressed; - } - if (currErr) { - console.error('Failed to dispose leftover stack', trimError(currErr)); - } -} - -if (typeof afterAll === 'function') { - afterAll(async () => { - try { - await leftoverStack.disposeAsync(); - } catch (e) { - handleSuppressedError(e); - } finally { - leftoverStack = new AsyncDisposableStack(); - } - }); -} diff --git a/e2e/utils/tenv.ts b/e2e/utils/tenv.ts index f5338fa119877..04ea649b3cc36 100644 --- a/e2e/utils/tenv.ts +++ b/e2e/utils/tenv.ts @@ -12,10 +12,10 @@ import { RemoteGraphQLDataSource, type ServiceEndpointDefinition, } from '@apollo/gateway'; -import { DisposableSymbols } from '@whatwg-node/disposablestack'; +import { registerTerminateHandler } from '@graphql-mesh/utils'; +import { AsyncDisposableStack, DisposableSymbols } from '@whatwg-node/disposablestack'; import { fetch } from '@whatwg-node/fetch'; import { getLocalHostName, localHostnames } from '../../packages/testing/getLocalHostName'; -import { leftoverStack } from './leftoverStack'; import { createOpt, createPortOpt, createServicePortOpt } from './opts'; import { trimError } from './trimError'; @@ -125,8 +125,8 @@ export interface Compose extends Proc { * The path to the composed file. * If output was not specified in the options, an empty string will be provided. */ - output: string; - result: string; + supergraphPath: string; + supergraphSdl: string; } export interface ContainerOptions extends ProcOptions { @@ -182,7 +182,7 @@ export interface Container extends Service { additionalPorts: Record; } -export interface Tenv { +export interface Tenv extends AsyncDisposable { fs: { read(path: string): Promise; delete(path: string): Promise; @@ -193,7 +193,7 @@ export interface Tenv { command: string | (string | number)[], opts?: ProcOptions, ): Promise<[proc: Proc, waitForExit: Promise]>; - serve(opts?: ServeOptions): Promise; + gateway(opts?: ServeOptions): Promise; compose(opts?: ComposeOptions): Promise; /** * Starts a service by name. Services are services that serve data, not necessarily GraphQL. @@ -205,8 +205,23 @@ export interface Tenv { composeWithApollo(services: Service[]): Promise; } +const tenvs = new Set(); + +function disposeTenvs() { + return Promise.all([...tenvs].map(tenv => tenv[DisposableSymbols.asyncDispose]())); +} + +registerTerminateHandler(disposeTenvs); + +afterAll(disposeTenvs); + export function createTenv(cwd: string): Tenv { + const leftoverStack = new AsyncDisposableStack(); const tenv: Tenv = { + [DisposableSymbols.asyncDispose]() { + tenvs.delete(tenv); + return leftoverStack.disposeAsync(); + }, fs: { read(filePath) { return fs.readFile(isAbsolute(filePath) ? filePath : path.join(cwd, filePath), 'utf8'); @@ -227,9 +242,9 @@ export function createTenv(cwd: string): Tenv { }, spawn(command, { args: extraArgs = [], ...opts } = {}) { const [cmd, ...args] = Array.isArray(command) ? command : command.split(' '); - return spawn({ ...opts, cwd }, String(cmd), ...args, ...extraArgs); + return spawn(leftoverStack, { ...opts, cwd }, String(cmd), ...args, ...extraArgs); }, - async serve(opts) { + async gateway(opts) { let { port = await getAvailablePort(), supergraph, @@ -239,6 +254,7 @@ export function createTenv(cwd: string): Tenv { } = opts || {}; const [proc, waitForExit] = await spawn( + leftoverStack, { env, cwd, pipeLogs }, 'node', // TODO: using yarn does not work on Windows in the CI path.join(__project, 'node_modules', '@graphql-hive', 'gateway', 'dist', 'bin.js'), @@ -301,59 +317,67 @@ export function createTenv(cwd: string): Tenv { env, args = [], } = opts || {}; - let output = ''; + let supergraphPath = ''; if (opts?.output) { const tempDir = await fs.mkdtemp(path.join(os.tmpdir(), 'graphql-mesh_e2e_compose')); leftoverStack.defer(() => fs.rm(tempDir, { recursive: true })); - output = path.join(tempDir, `${Math.random().toString(32).slice(2)}.${opts.output}`); + supergraphPath = path.join( + tempDir, + `${Math.random().toString(32).slice(2)}.${opts.output}`, + ); } const [proc, waitForExit] = await spawn( + leftoverStack, { cwd, pipeLogs, env }, 'node', '--import', 'tsx', path.resolve(__project, 'packages', 'compose-cli', 'src', 'bin.ts'), - output && createOpt('output', output), + supergraphPath && createOpt('output', supergraphPath), ...services.map(({ name, port }) => createServicePortOpt(name, port)), ...args, ); await waitForExit; - let result = ''; - if (output) { + let supergraphSdl = ''; + if (supergraphPath) { try { - result = await fs.readFile(output, 'utf-8'); + supergraphSdl = await fs.readFile(supergraphPath, 'utf-8'); } catch (err) { if ('code' in err && err.code === 'ENOENT') { throw new Error( - `Compose command has "output" argument but file was not created at ${output}`, + `Compose command has "output" argument but file was not created at ${supergraphPath}`, ); } throw err; } } else { - result = proc.getStd('out'); + supergraphSdl = proc.getStd('out'); } if (trimHostPaths || maskServicePorts) { if (trimHostPaths) { - result = result.replaceAll(__project, ''); + supergraphSdl = supergraphSdl.replaceAll(__project, ''); } for (const subgraph of services) { if (maskServicePorts) { - result = result.replaceAll(subgraph.port.toString(), `<${subgraph.name}_port>`); + supergraphSdl = supergraphSdl.replaceAll( + subgraph.port.toString(), + `<${subgraph.name}_port>`, + ); } } - if (output) { - await fs.writeFile(output, result, 'utf8'); + if (supergraphPath) { + await fs.writeFile(supergraphPath, supergraphSdl, 'utf8'); } } - return { ...proc, output, result }; + return { ...proc, supergraphPath, supergraphSdl }; }, async service(name, { port, servePort, pipeLogs = boolEnv('DEBUG'), args = [] } = {}) { port ||= await getAvailablePort(); const ctrl = new AbortController(); const [proc, waitForExit] = await spawn( + leftoverStack, { cwd, pipeLogs, signal: ctrl.signal }, 'node', '--import', @@ -628,6 +652,7 @@ interface SpawnOptions extends ProcOptions { } function spawn( + leftoverStack: AsyncDisposableStack, { cwd, pipeLogs = boolEnv('DEBUG'), env = {}, shell, signal }: SpawnOptions, cmd: string, ...args: (string | number | boolean)[] @@ -671,6 +696,7 @@ function spawn( }, async getStats() { const [proc, waitForExit] = await spawn( + leftoverStack, { cwd, pipeLogs: false }, 'ps', '-o', diff --git a/yarn.lock b/yarn.lock index 1ba4eccca0a3d..7ea601aad0c73 100644 --- a/yarn.lock +++ b/yarn.lock @@ -80,7 +80,7 @@ __metadata: languageName: node linkType: hard -"@apollo/client@npm:3.12.6, @apollo/client@npm:^3.8.0": +"@apollo/client@npm:3.12.6": version: 3.12.6 resolution: "@apollo/client@npm:3.12.6" dependencies: @@ -117,6 +117,43 @@ __metadata: languageName: node linkType: hard +"@apollo/client@npm:^3.8.0": + version: 3.12.5 + resolution: "@apollo/client@npm:3.12.5" + dependencies: + "@graphql-typed-document-node/core": "npm:^3.1.1" + "@wry/caches": "npm:^1.0.0" + "@wry/equality": "npm:^0.5.6" + "@wry/trie": "npm:^0.5.0" + graphql-tag: "npm:^2.12.6" + hoist-non-react-statics: "npm:^3.3.2" + optimism: "npm:^0.18.0" + prop-types: "npm:^15.7.2" + rehackt: "npm:^0.1.0" + response-iterator: "npm:^0.2.6" + symbol-observable: "npm:^4.0.0" + ts-invariant: "npm:^0.10.3" + tslib: "npm:^2.3.0" + zen-observable-ts: "npm:^1.2.5" + peerDependencies: + graphql: ^15.0.0 || ^16.0.0 + graphql-ws: ^5.5.5 + react: ^16.8.0 || ^17.0.0 || ^18.0.0 || >=19.0.0-rc + react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 || >=19.0.0-rc + subscriptions-transport-ws: ^0.9.0 || ^0.11.0 + peerDependenciesMeta: + graphql-ws: + optional: true + react: + optional: true + react-dom: + optional: true + subscriptions-transport-ws: + optional: true + checksum: 10c0/fbc102b22ef59228020e6bdaee4b7483306afa031699bc8c882ecaa5cd6d0b2938d388478c69a8c3dd245114f0d24b26085a2e6cb3b1a45ed2b6bcb9d4879fcb + languageName: node + linkType: hard + "@apollo/composition@npm:2.9.3": version: 2.9.3 resolution: "@apollo/composition@npm:2.9.3" @@ -1300,13 +1337,20 @@ __metadata: languageName: node linkType: hard -"@babel/compat-data@npm:^7.20.5, @babel/compat-data@npm:^7.22.6, @babel/compat-data@npm:^7.25.9, @babel/compat-data@npm:^7.26.0": +"@babel/compat-data@npm:^7.20.5, @babel/compat-data@npm:^7.22.6, @babel/compat-data@npm:^7.26.0": version: 7.26.5 resolution: "@babel/compat-data@npm:7.26.5" checksum: 10c0/9d2b41f0948c3dfc5de44d9f789d2208c2ea1fd7eb896dfbb297fe955e696728d6f363c600cd211e7f58ccbc2d834fe516bb1e4cf883bbabed8a32b038afc1a0 languageName: node linkType: hard +"@babel/compat-data@npm:^7.25.9": + version: 7.26.3 + resolution: "@babel/compat-data@npm:7.26.3" + checksum: 10c0/d63e71845c34dfad8d7ff8c15b562e620dbf60e68e3abfa35681d24d612594e8e5ec9790d831a287ecd79ce00f48e7ffddc85c5ce94af7242d45917b9c1a5f90 + languageName: node + linkType: hard + "@babel/core@npm:7.26.0, @babel/core@npm:^7.1.0, @babel/core@npm:^7.11.1, @babel/core@npm:^7.11.6, @babel/core@npm:^7.12.3, @babel/core@npm:^7.14.0, @babel/core@npm:^7.16.0, @babel/core@npm:^7.22.9, @babel/core@npm:^7.23.9, @babel/core@npm:^7.26.0, @babel/core@npm:^7.7.2, @babel/core@npm:^7.8.0": version: 7.26.0 resolution: "@babel/core@npm:7.26.0" @@ -1344,7 +1388,7 @@ __metadata: languageName: node linkType: hard -"@babel/generator@npm:^7.14.0, @babel/generator@npm:^7.18.13, @babel/generator@npm:^7.26.0, @babel/generator@npm:^7.26.2, @babel/generator@npm:^7.26.3, @babel/generator@npm:^7.7.2": +"@babel/generator@npm:^7.14.0, @babel/generator@npm:^7.18.13, @babel/generator@npm:^7.26.0, @babel/generator@npm:^7.26.2, @babel/generator@npm:^7.7.2": version: 7.26.5 resolution: "@babel/generator@npm:7.26.5" dependencies: @@ -1357,6 +1401,19 @@ __metadata: languageName: node linkType: hard +"@babel/generator@npm:^7.26.3": + version: 7.26.3 + resolution: "@babel/generator@npm:7.26.3" + dependencies: + "@babel/parser": "npm:^7.26.3" + "@babel/types": "npm:^7.26.3" + "@jridgewell/gen-mapping": "npm:^0.3.5" + "@jridgewell/trace-mapping": "npm:^0.3.25" + jsesc: "npm:^3.0.2" + checksum: 10c0/54f260558e3e4ec8942da3cde607c35349bb983c3a7c5121243f96893fba3e8cd62e1f1773b2051f936f8c8a10987b758d5c7d76dbf2784e95bb63ab4843fa00 + languageName: node + linkType: hard + "@babel/helper-annotate-as-pure@npm:^7.18.6, @babel/helper-annotate-as-pure@npm:^7.25.9": version: 7.25.9 resolution: "@babel/helper-annotate-as-pure@npm:7.25.9" @@ -1551,7 +1608,7 @@ __metadata: languageName: node linkType: hard -"@babel/parser@npm:^7.1.0, @babel/parser@npm:^7.14.0, @babel/parser@npm:^7.14.7, @babel/parser@npm:^7.16.8, @babel/parser@npm:^7.20.7, @babel/parser@npm:^7.23.9, @babel/parser@npm:^7.25.9, @babel/parser@npm:^7.26.0, @babel/parser@npm:^7.26.2, @babel/parser@npm:^7.26.3, @babel/parser@npm:^7.26.5": +"@babel/parser@npm:^7.1.0, @babel/parser@npm:^7.14.0, @babel/parser@npm:^7.14.7, @babel/parser@npm:^7.16.8, @babel/parser@npm:^7.20.7, @babel/parser@npm:^7.23.9, @babel/parser@npm:^7.25.9, @babel/parser@npm:^7.26.0, @babel/parser@npm:^7.26.2, @babel/parser@npm:^7.26.5": version: 7.26.5 resolution: "@babel/parser@npm:7.26.5" dependencies: @@ -1562,6 +1619,17 @@ __metadata: languageName: node linkType: hard +"@babel/parser@npm:^7.26.3": + version: 7.26.3 + resolution: "@babel/parser@npm:7.26.3" + dependencies: + "@babel/types": "npm:^7.26.3" + bin: + parser: ./bin/babel-parser.js + checksum: 10c0/48f736374e61cfd10ddbf7b80678514ae1f16d0e88bc793d2b505d73d9b987ea786fc8c2f7ee8f8b8c467df062030eb07fd0eb2168f0f541ca1f542775852cad + languageName: node + linkType: hard + "@babel/plugin-bugfix-firefox-class-in-computed-class-key@npm:^7.25.9": version: 7.25.9 resolution: "@babel/plugin-bugfix-firefox-class-in-computed-class-key@npm:7.25.9" @@ -2846,7 +2914,7 @@ __metadata: languageName: node linkType: hard -"@babel/types@npm:^7.0.0, @babel/types@npm:^7.12.6, @babel/types@npm:^7.16.8, @babel/types@npm:^7.18.13, @babel/types@npm:^7.20.7, @babel/types@npm:^7.25.9, @babel/types@npm:^7.26.0, @babel/types@npm:^7.26.3, @babel/types@npm:^7.26.5, @babel/types@npm:^7.3.3, @babel/types@npm:^7.4.4": +"@babel/types@npm:^7.0.0, @babel/types@npm:^7.12.6, @babel/types@npm:^7.16.8, @babel/types@npm:^7.18.13, @babel/types@npm:^7.20.7, @babel/types@npm:^7.25.9, @babel/types@npm:^7.26.0, @babel/types@npm:^7.26.5, @babel/types@npm:^7.3.3, @babel/types@npm:^7.4.4": version: 7.26.5 resolution: "@babel/types@npm:7.26.5" dependencies: @@ -2856,6 +2924,16 @@ __metadata: languageName: node linkType: hard +"@babel/types@npm:^7.26.3": + version: 7.26.3 + resolution: "@babel/types@npm:7.26.3" + dependencies: + "@babel/helper-string-parser": "npm:^7.25.9" + "@babel/helper-validator-identifier": "npm:^7.25.9" + checksum: 10c0/966c5242c5e55c8704bf7a7418e7be2703a0afa4d19a8480999d5a4ef13d095dd60686615fe5983cb7593b4b06ba3a7de8d6ca501c1d78bdd233a10d90be787b + languageName: node + linkType: hard + "@balena/dockerignore@npm:^1.0.2": version: 1.0.2 resolution: "@balena/dockerignore@npm:1.0.2" @@ -7814,7 +7892,7 @@ __metadata: languageName: node linkType: hard -"@graphql-tools/graphql-tag-pluck@npm:8.3.10, @graphql-tools/graphql-tag-pluck@npm:^8.3.9": +"@graphql-tools/graphql-tag-pluck@npm:8.3.10": version: 8.3.10 resolution: "@graphql-tools/graphql-tag-pluck@npm:8.3.10" dependencies: @@ -7831,7 +7909,7 @@ __metadata: languageName: node linkType: hard -"@graphql-tools/graphql-tag-pluck@npm:8.3.9": +"@graphql-tools/graphql-tag-pluck@npm:8.3.9, @graphql-tools/graphql-tag-pluck@npm:^8.3.9": version: 8.3.9 resolution: "@graphql-tools/graphql-tag-pluck@npm:8.3.9" dependencies: @@ -7982,6 +8060,18 @@ __metadata: languageName: node linkType: hard +"@graphql-tools/merge@npm:^9.0.15": + version: 9.0.15 + resolution: "@graphql-tools/merge@npm:9.0.15" + dependencies: + "@graphql-tools/utils": "npm:^10.7.0" + tslib: "npm:^2.4.0" + peerDependencies: + graphql: ^14.0.0 || ^15.0.0 || ^16.0.0 || ^17.0.0 + checksum: 10c0/f40e4b32dc296f7d258e2cf64c3dbca4761a8665d2117d19c2765921e329fe35d4f006acf661d4fc5d5c951e773ad44ad803ee2acd2d14d4f3f542b9478835b8 + languageName: node + linkType: hard + "@graphql-tools/mock@npm:^8.1.2": version: 8.7.20 resolution: "@graphql-tools/mock@npm:8.7.20" @@ -8098,7 +8188,7 @@ __metadata: languageName: node linkType: hard -"@graphql-tools/schema@npm:10.0.16, @graphql-tools/schema@npm:^10.0.0, @graphql-tools/schema@npm:^10.0.11, @graphql-tools/schema@npm:^10.0.13, @graphql-tools/schema@npm:^10.0.14, @graphql-tools/schema@npm:^10.0.5, @graphql-tools/schema@npm:^10.0.6": +"@graphql-tools/schema@npm:10.0.16, @graphql-tools/schema@npm:^10.0.0, @graphql-tools/schema@npm:^10.0.11, @graphql-tools/schema@npm:^10.0.13, @graphql-tools/schema@npm:^10.0.5, @graphql-tools/schema@npm:^10.0.6": version: 10.0.16 resolution: "@graphql-tools/schema@npm:10.0.16" dependencies: @@ -8138,6 +8228,20 @@ __metadata: languageName: node linkType: hard +"@graphql-tools/schema@npm:^10.0.14": + version: 10.0.14 + resolution: "@graphql-tools/schema@npm:10.0.14" + dependencies: + "@graphql-tools/merge": "npm:^9.0.15" + "@graphql-tools/utils": "npm:^10.7.0" + tslib: "npm:^2.4.0" + value-or-promise: "npm:^1.0.12" + peerDependencies: + graphql: ^14.0.0 || ^15.0.0 || ^16.0.0 || ^17.0.0 + checksum: 10c0/c8779781da9d43ad97dd6fc77c49cd093d88df236a097c6739b65b5e908a3f7df30f79a15f2616a250512f14ccf67ed2e3d58ddd8ee38ec829f54edb7c0f9d11 + languageName: node + linkType: hard + "@graphql-tools/schema@npm:^9.0.0, @graphql-tools/schema@npm:^9.0.18": version: 9.0.19 resolution: "@graphql-tools/schema@npm:9.0.19" @@ -8345,7 +8449,7 @@ __metadata: languageName: node linkType: hard -"@graphql-yoga/plugin-apollo-inline-trace@npm:3.10.10, @graphql-yoga/plugin-apollo-inline-trace@npm:^3.10.6": +"@graphql-yoga/plugin-apollo-inline-trace@npm:3.10.10": version: 3.10.10 resolution: "@graphql-yoga/plugin-apollo-inline-trace@npm:3.10.10" dependencies: @@ -8361,6 +8465,22 @@ __metadata: languageName: node linkType: hard +"@graphql-yoga/plugin-apollo-inline-trace@npm:^3.10.6": + version: 3.10.6 + resolution: "@graphql-yoga/plugin-apollo-inline-trace@npm:3.10.6" + dependencies: + "@apollo/usage-reporting-protobuf": "npm:^4.1.1" + "@envelop/on-resolve": "npm:^4.1.1" + tslib: "npm:^2.5.2" + peerDependencies: + "@graphql-tools/utils": ^10.6.1 + "@whatwg-node/fetch": ^0.10.1 + graphql: ^15.2.0 || ^16.0.0 + graphql-yoga: ^5.10.6 + checksum: 10c0/2746846de394559bb7dda1106972b624ee7549027bffd2493d9b3c50ea4db896885e719aa75080db85a5643d6a444454f36013ca1d0c4d0725ed04b2b4f48481 + languageName: node + linkType: hard + "@graphql-yoga/plugin-apollo-usage-report@npm:^0.5.3": version: 0.5.3 resolution: "@graphql-yoga/plugin-apollo-usage-report@npm:0.5.3" @@ -11417,7 +11537,7 @@ __metadata: languageName: node linkType: hard -"@sinclair/typebox@npm:0.34.14, @sinclair/typebox@npm:^0.34.0": +"@sinclair/typebox@npm:0.34.14": version: 0.34.14 resolution: "@sinclair/typebox@npm:0.34.14" checksum: 10c0/880a99ea958aed1b8074c10feb554dc588f6a1ee649f54d143855311c919699216690b88ff210a3023fd8552a6c3005f7cf58b2c6e9bc1e1a122dea06fd54433 @@ -11438,6 +11558,13 @@ __metadata: languageName: node linkType: hard +"@sinclair/typebox@npm:^0.34.0": + version: 0.34.13 + resolution: "@sinclair/typebox@npm:0.34.13" + checksum: 10c0/3095d62d697f332d2b2f6b75ea05ee7e0b3e97666c82aea6ea95798b79087509ddcece3bb39126d560fa3eb978c418275df8c01a086ba6cc20b0a31cfd5a49b8 + languageName: node + linkType: hard + "@sindresorhus/is@npm:^4.0.0": version: 4.6.0 resolution: "@sindresorhus/is@npm:4.6.0" @@ -13515,7 +13642,14 @@ __metadata: languageName: node linkType: hard -"@types/qs@npm:*, @types/qs@npm:6.9.18, @types/qs@npm:^6.2.31": +"@types/qs@npm:*, @types/qs@npm:^6.2.31": + version: 6.9.17 + resolution: "@types/qs@npm:6.9.17" + checksum: 10c0/a183fa0b3464267f8f421e2d66d960815080e8aab12b9aadab60479ba84183b1cdba8f4eff3c06f76675a8e42fe6a3b1313ea76c74f2885c3e25d32499c17d1b + languageName: node + linkType: hard + +"@types/qs@npm:6.9.18": version: 6.9.18 resolution: "@types/qs@npm:6.9.18" checksum: 10c0/790b9091348e06dde2c8e4118b5771ab386a8c22a952139a2eb0675360a2070d0b155663bf6f75b23f258fd0a1f7ffc0ba0f059d99a719332c03c40d9e9cd63b @@ -13824,7 +13958,7 @@ __metadata: languageName: node linkType: hard -"@typescript-eslint/eslint-plugin@npm:8.21.0, @typescript-eslint/eslint-plugin@npm:^5.4.2 || ^6.0.0 || ^7.0.0 || ^8.0.0": +"@typescript-eslint/eslint-plugin@npm:8.21.0": version: 8.21.0 resolution: "@typescript-eslint/eslint-plugin@npm:8.21.0" dependencies: @@ -13845,6 +13979,27 @@ __metadata: languageName: node linkType: hard +"@typescript-eslint/eslint-plugin@npm:^5.4.2 || ^6.0.0 || ^7.0.0 || ^8.0.0": + version: 8.18.1 + resolution: "@typescript-eslint/eslint-plugin@npm:8.18.1" + dependencies: + "@eslint-community/regexpp": "npm:^4.10.0" + "@typescript-eslint/scope-manager": "npm:8.18.1" + "@typescript-eslint/type-utils": "npm:8.18.1" + "@typescript-eslint/utils": "npm:8.18.1" + "@typescript-eslint/visitor-keys": "npm:8.18.1" + graphemer: "npm:^1.4.0" + ignore: "npm:^5.3.1" + natural-compare: "npm:^1.4.0" + ts-api-utils: "npm:^1.3.0" + peerDependencies: + "@typescript-eslint/parser": ^8.0.0 || ^8.0.0-alpha.0 + eslint: ^8.57.0 || ^9.0.0 + typescript: ">=4.8.4 <5.8.0" + checksum: 10c0/7994d323228f3fc3ec124291cd02761251bcd9a5a6356001d2cb8f68abdb400c3cfbeb343d6941d8e6b6c8d2d616a278bbb3b6d9ed839ba5148a05f60a1f67b4 + languageName: node + linkType: hard + "@typescript-eslint/eslint-plugin@npm:^5.5.0": version: 5.62.0 resolution: "@typescript-eslint/eslint-plugin@npm:5.62.0" @@ -13880,7 +14035,7 @@ __metadata: languageName: node linkType: hard -"@typescript-eslint/parser@npm:8.21.0, @typescript-eslint/parser@npm:^5.4.2 || ^6.0.0 || ^7.0.0 || ^8.0.0": +"@typescript-eslint/parser@npm:8.21.0": version: 8.21.0 resolution: "@typescript-eslint/parser@npm:8.21.0" dependencies: @@ -13896,6 +14051,22 @@ __metadata: languageName: node linkType: hard +"@typescript-eslint/parser@npm:^5.4.2 || ^6.0.0 || ^7.0.0 || ^8.0.0": + version: 8.18.1 + resolution: "@typescript-eslint/parser@npm:8.18.1" + dependencies: + "@typescript-eslint/scope-manager": "npm:8.18.1" + "@typescript-eslint/types": "npm:8.18.1" + "@typescript-eslint/typescript-estree": "npm:8.18.1" + "@typescript-eslint/visitor-keys": "npm:8.18.1" + debug: "npm:^4.3.4" + peerDependencies: + eslint: ^8.57.0 || ^9.0.0 + typescript: ">=4.8.4 <5.8.0" + checksum: 10c0/23ab30b3f00b86108137e7df03710a088046ead3582595b0f8e17d5062770365e24e0a1ae3398bb3a1c29aa0f05a0de30887e2e0f6fb86163e878dd0eed1b25c + languageName: node + linkType: hard + "@typescript-eslint/parser@npm:^5.5.0": version: 5.62.0 resolution: "@typescript-eslint/parser@npm:5.62.0" @@ -13923,6 +14094,16 @@ __metadata: languageName: node linkType: hard +"@typescript-eslint/scope-manager@npm:8.18.1": + version: 8.18.1 + resolution: "@typescript-eslint/scope-manager@npm:8.18.1" + dependencies: + "@typescript-eslint/types": "npm:8.18.1" + "@typescript-eslint/visitor-keys": "npm:8.18.1" + checksum: 10c0/97c503b2ece79b6c99ca8e6a5f1f40855cf72f17fbf05e42e62d19c2666e7e6f5df9bf71f13dbc4720c5ee0397670ba8052482a90441fbffa901da5f2e739565 + languageName: node + linkType: hard + "@typescript-eslint/scope-manager@npm:8.21.0": version: 8.21.0 resolution: "@typescript-eslint/scope-manager@npm:8.21.0" @@ -13950,6 +14131,21 @@ __metadata: languageName: node linkType: hard +"@typescript-eslint/type-utils@npm:8.18.1": + version: 8.18.1 + resolution: "@typescript-eslint/type-utils@npm:8.18.1" + dependencies: + "@typescript-eslint/typescript-estree": "npm:8.18.1" + "@typescript-eslint/utils": "npm:8.18.1" + debug: "npm:^4.3.4" + ts-api-utils: "npm:^1.3.0" + peerDependencies: + eslint: ^8.57.0 || ^9.0.0 + typescript: ">=4.8.4 <5.8.0" + checksum: 10c0/cfe5362a22fa5e18a2662928904da024e42c84cb58a46238b9b61edafcd046f53c9505637176c8cd1c386165c6a6ed15a2b51700495cad6c20e0e33499d483a1 + languageName: node + linkType: hard + "@typescript-eslint/type-utils@npm:8.21.0": version: 8.21.0 resolution: "@typescript-eslint/type-utils@npm:8.21.0" @@ -13972,6 +14168,13 @@ __metadata: languageName: node linkType: hard +"@typescript-eslint/types@npm:8.18.1": + version: 8.18.1 + resolution: "@typescript-eslint/types@npm:8.18.1" + checksum: 10c0/0a2ca5f7cdebcc844b6bc1e5afc5d83b563f55917d20e3fea3a17ed39c54b003178e26b5ec535113f45c93c569b46628d9a67defa70c01cbdfa801573fed69a2 + languageName: node + linkType: hard + "@typescript-eslint/types@npm:8.21.0": version: 8.21.0 resolution: "@typescript-eslint/types@npm:8.21.0" @@ -13997,6 +14200,24 @@ __metadata: languageName: node linkType: hard +"@typescript-eslint/typescript-estree@npm:8.18.1": + version: 8.18.1 + resolution: "@typescript-eslint/typescript-estree@npm:8.18.1" + dependencies: + "@typescript-eslint/types": "npm:8.18.1" + "@typescript-eslint/visitor-keys": "npm:8.18.1" + debug: "npm:^4.3.4" + fast-glob: "npm:^3.3.2" + is-glob: "npm:^4.0.3" + minimatch: "npm:^9.0.4" + semver: "npm:^7.6.0" + ts-api-utils: "npm:^1.3.0" + peerDependencies: + typescript: ">=4.8.4 <5.8.0" + checksum: 10c0/7ecb061dc63c729b23f4f15db5736ca93b1ae633108400e6c31cf8af782494912f25c3683f9f952dbfd10cb96031caba247a1ad406abf5d163639a00ac3ce5a3 + languageName: node + linkType: hard + "@typescript-eslint/typescript-estree@npm:8.21.0": version: 8.21.0 resolution: "@typescript-eslint/typescript-estree@npm:8.21.0" @@ -14033,6 +14254,21 @@ __metadata: languageName: node linkType: hard +"@typescript-eslint/utils@npm:8.18.1": + version: 8.18.1 + resolution: "@typescript-eslint/utils@npm:8.18.1" + dependencies: + "@eslint-community/eslint-utils": "npm:^4.4.0" + "@typescript-eslint/scope-manager": "npm:8.18.1" + "@typescript-eslint/types": "npm:8.18.1" + "@typescript-eslint/typescript-estree": "npm:8.18.1" + peerDependencies: + eslint: ^8.57.0 || ^9.0.0 + typescript: ">=4.8.4 <5.8.0" + checksum: 10c0/1e29408bd8fbda9f3386dabdb2b7471dacff28342d5bd6521ca3b7932df0cae100030d2eac75d946a82cbefa33f78000eed4ce789128fdea069ffeabd4429d80 + languageName: node + linkType: hard + "@typescript-eslint/utils@npm:8.21.0": version: 8.21.0 resolution: "@typescript-eslint/utils@npm:8.21.0" @@ -14058,6 +14294,16 @@ __metadata: languageName: node linkType: hard +"@typescript-eslint/visitor-keys@npm:8.18.1": + version: 8.18.1 + resolution: "@typescript-eslint/visitor-keys@npm:8.18.1" + dependencies: + "@typescript-eslint/types": "npm:8.18.1" + eslint-visitor-keys: "npm:^4.2.0" + checksum: 10c0/68651ae1825dbd660ea39b4e1d1618f6ad0026fa3a04aecec296750977cab316564e3e2ace8edbebf1ae86bd17d86acc98cac7b6e9aad4e1c666bd26f18706ad + languageName: node + linkType: hard + "@typescript-eslint/visitor-keys@npm:8.21.0": version: 8.21.0 resolution: "@typescript-eslint/visitor-keys@npm:8.21.0" @@ -15795,7 +16041,7 @@ __metadata: languageName: node linkType: hard -"browserslist@npm:^4.0.0, browserslist@npm:^4.18.1, browserslist@npm:^4.19.1, browserslist@npm:^4.21.4, browserslist@npm:^4.23.3, browserslist@npm:^4.24.0, browserslist@npm:^4.24.2": +"browserslist@npm:^4.0.0, browserslist@npm:^4.18.1, browserslist@npm:^4.19.1, browserslist@npm:^4.21.4, browserslist@npm:^4.23.3, browserslist@npm:^4.24.0": version: 4.24.4 resolution: "browserslist@npm:4.24.4" dependencies: @@ -15809,6 +16055,20 @@ __metadata: languageName: node linkType: hard +"browserslist@npm:^4.24.2": + version: 4.24.3 + resolution: "browserslist@npm:4.24.3" + dependencies: + caniuse-lite: "npm:^1.0.30001688" + electron-to-chromium: "npm:^1.5.73" + node-releases: "npm:^2.0.19" + update-browserslist-db: "npm:^1.1.1" + bin: + browserslist: cli.js + checksum: 10c0/bab261ef7b6e1656a719a9fa31240ae7ce4d5ba68e479f6b11e348d819346ab4c0ff6f4821f43adcc9c193a734b186775a83b37979e70a69d182965909fe569a + languageName: node + linkType: hard + "bs-logger@npm:^0.2.6": version: 0.2.6 resolution: "bs-logger@npm:0.2.6" @@ -31032,7 +31292,16 @@ __metadata: languageName: node linkType: hard -"qs@npm:^6.11.2, qs@npm:^6.14.0, qs@npm:^6.4.0": +"qs@npm:^6.11.2, qs@npm:^6.4.0": + version: 6.13.1 + resolution: "qs@npm:6.13.1" + dependencies: + side-channel: "npm:^1.0.6" + checksum: 10c0/5ef527c0d62ffca5501322f0832d800ddc78eeb00da3b906f1b260ca0492721f8cdc13ee4b8fd8ac314a6ec37b948798c7b603ccc167e954088df392092f160c + languageName: node + linkType: hard + +"qs@npm:^6.14.0": version: 6.14.0 resolution: "qs@npm:6.14.0" dependencies: @@ -31636,7 +31905,7 @@ __metadata: languageName: node linkType: hard -"reflect.getprototypeof@npm:^1.0.6, reflect.getprototypeof@npm:^1.0.8, reflect.getprototypeof@npm:^1.0.9": +"reflect.getprototypeof@npm:^1.0.6, reflect.getprototypeof@npm:^1.0.9": version: 1.0.10 resolution: "reflect.getprototypeof@npm:1.0.10" dependencies: @@ -31652,6 +31921,22 @@ __metadata: languageName: node linkType: hard +"reflect.getprototypeof@npm:^1.0.8": + version: 1.0.9 + resolution: "reflect.getprototypeof@npm:1.0.9" + dependencies: + call-bind: "npm:^1.0.8" + define-properties: "npm:^1.2.1" + dunder-proto: "npm:^1.0.1" + es-abstract: "npm:^1.23.6" + es-errors: "npm:^1.3.0" + get-intrinsic: "npm:^1.2.6" + gopd: "npm:^1.2.0" + which-builtin-type: "npm:^1.2.1" + checksum: 10c0/db42118a8699fa8b5856e6aa06eac32498a7bbc3c22832729049501733d060662bf16f204c546db87df8bb78b36491ecd6b3b0478c0a27be6c8302cc0770a42e + languageName: node + linkType: hard + "regenerate-unicode-properties@npm:^10.2.0": version: 10.2.0 resolution: "regenerate-unicode-properties@npm:10.2.0" @@ -35034,6 +35319,15 @@ __metadata: languageName: node linkType: hard +"ts-api-utils@npm:^1.3.0": + version: 1.4.3 + resolution: "ts-api-utils@npm:1.4.3" + peerDependencies: + typescript: ">=4.2.0" + checksum: 10c0/e65dc6e7e8141140c23e1dc94984bf995d4f6801919c71d6dc27cf0cd51b100a91ffcfe5217626193e5bea9d46831e8586febdc7e172df3f1091a7384299e23a + languageName: node + linkType: hard + "ts-api-utils@npm:^2.0.0": version: 2.0.0 resolution: "ts-api-utils@npm:2.0.0"