From 82f5893446e3c55519194a1ca1d784120cbe7098 Mon Sep 17 00:00:00 2001 From: Arda TANRIKULU Date: Mon, 26 Dec 2022 18:57:24 +0300 Subject: [PATCH] Fix ESLint setup, improve tests and small fix for more accurate HTTP status code (#2250) * Fix ESLint setup * Update green-yaks-shave.md * Fix ESLint --- .changeset/green-yaks-shave.md | 10 ++ .eslintrc.cjs | 17 +++- .../__integration-tests__/apollo-link.spec.ts | 15 +-- packages/client/apollo-link/package.json | 3 +- packages/client/apollo-link/src/index.ts | 3 +- .../urql-exchange.spec.ts | 13 +-- packages/client/urql-exchange/package.json | 3 +- packages/client/urql-exchange/src/index.ts | 1 + .../__tests__/redis-event-target.spec.ts | 3 +- .../redis-event-target/src/index.ts | 2 +- packages/graphiql/src/YogaGraphiQL.tsx | 19 ++-- packages/graphiql/src/bundle.tsx | 1 + packages/graphiql/vite.config.ts | 4 +- .../__integration-tests__/browser.spec.ts | 44 +++++---- .../file-uploads.spec.ts | 15 +-- .../graphql-scalars.spec.ts | 10 +- .../incremental-delivery.spec.ts | 12 ++- .../__integration-tests__/node-http.spec.ts | 14 ++- .../subscription.spec.ts | 10 +- packages/graphql-yoga/__tests__/404.spec.ts | 2 +- packages/graphql-yoga/__tests__/500.spec.ts | 1 - .../__tests__/accept-header.spec.ts | 25 ++--- .../graphql-yoga/__tests__/context.spec.ts | 3 +- .../__tests__/error-masking.spec.ts | 4 +- .../__tests__/graphql-http.spec.ts | 3 +- .../__tests__/health-check.spec.ts | 2 +- .../__tests__/http-extensions.spec.ts | 2 +- .../__tests__/introspection.spec.ts | 6 +- .../graphql-yoga/__tests__/logging.spec.ts | 11 ++- .../__tests__/readiness-check.spec.ts | 3 +- .../graphql-yoga/__tests__/recipes.spec.ts | 2 +- .../graphql-yoga/__tests__/requests.spec.ts | 17 +++- .../graphql-yoga/__tests__/schema.spec.ts | 9 +- .../__tests__/subscriptions.spec.ts | 3 +- packages/graphql-yoga/package.json | 1 + .../scripts/generate-graphiql-html.js | 6 +- packages/graphql-yoga/src/error.ts | 3 +- packages/graphql-yoga/src/index.ts | 55 ++++++----- packages/graphql-yoga/src/logger.ts | 1 + .../graphql-yoga/src/plugins/plugins.test.ts | 9 +- .../src/plugins/requestParser/POSTJson.ts | 3 +- .../plugins/requestParser/POSTMultipart.ts | 1 + .../src/plugins/requestParser/utils.ts | 2 +- .../useCheckGraphQLQueryParams.ts | 1 + .../useCheckMethodForGraphQL.ts | 1 + .../useHTTPValidationError.ts | 3 +- .../usePreventMutationViaGET.ts | 9 +- .../src/plugins/resultProcessor/multipart.ts | 3 +- .../src/plugins/resultProcessor/push.ts | 3 +- .../src/plugins/resultProcessor/regular.ts | 1 + .../src/plugins/resultProcessor/stringify.ts | 1 + packages/graphql-yoga/src/plugins/types.ts | 5 +- packages/graphql-yoga/src/plugins/useCORS.ts | 5 +- .../graphql-yoga/src/plugins/useCors.spec.ts | 9 +- .../graphql-yoga/src/plugins/useGraphiQL.ts | 8 +- .../src/plugins/useHealthCheck.ts | 2 +- .../src/plugins/useRequestParser.ts | 3 +- .../src/plugins/useResultProcessor.ts | 1 + .../graphql-yoga/src/plugins/useSchema.ts | 3 +- .../src/plugins/useUnhandledRoute.ts | 4 +- packages/graphql-yoga/src/process-request.ts | 7 +- packages/graphql-yoga/src/schema.ts | 1 + packages/graphql-yoga/src/server.ts | 96 ++++++++++--------- packages/graphql-yoga/src/types.ts | 1 + .../src/utils/yoga-default-format-error.ts | 3 +- packages/graphql-yoga/type-api-check.ts | 6 +- .../__tests__/apollo-inline-trace.spec.ts | 6 +- .../plugins/apollo-inline-trace/src/index.ts | 10 +- packages/plugins/apq/__tests__/apq.spec.ts | 2 +- packages/plugins/apq/src/index.ts | 25 +++-- .../defer-stream.spec.ts | 19 ++-- .../__tests__/defer-stream.spec.ts | 7 +- .../defer-stream-directive-label.spec.ts | 1 - ...fer-stream-directive-on-root-field.spec.ts | 1 + .../__tests__/validations/harness.ts | 17 ++-- .../overlapping-fields-can-be-merged.spec.ts | 1 + packages/plugins/defer-stream/src/index.ts | 7 +- .../defer-stream-directive-label.ts | 2 +- .../overlapping-fields-can-be-merged.ts | 16 ++-- .../stream-directive-on-list-field.ts | 6 +- .../__tests__/disable-introspection.spec.ts | 2 +- .../disable-introspection/src/index.ts | 2 +- .../__tests__/persisted-operations.spec.ts | 2 +- .../plugins/persisted-operations/src/index.ts | 2 +- packages/plugins/prometheus/src/index.ts | 10 +- .../__tests__/response-cache.spec.ts | 2 +- packages/plugins/sofa/src/index.ts | 37 ++++--- packages/plugins/sofa/src/swagger-ui.ts | 1 + packages/render-graphiql/src/index.ts | 3 +- packages/subscription/package.json | 3 +- packages/subscription/src/create-pub-sub.ts | 2 +- .../subscription/src/createPubSub.spec.ts | 5 +- packages/subscription/src/index.ts | 10 +- .../subscription/src/operator/filter.spec.ts | 1 + .../subscription/src/operator/map.spec.ts | 1 + pnpm-lock.yaml | 8 ++ .../src/components/latest-version-notice.tsx | 2 +- website/src/index-page.tsx | 22 ++--- 98 files changed, 462 insertions(+), 322 deletions(-) create mode 100644 .changeset/green-yaks-shave.md diff --git a/.changeset/green-yaks-shave.md b/.changeset/green-yaks-shave.md new file mode 100644 index 0000000000..fa1b6ce94d --- /dev/null +++ b/.changeset/green-yaks-shave.md @@ -0,0 +1,10 @@ +--- +'graphql-yoga': patch +--- + +More accurate HTTP status code when unsupported media type is sent as a request body. + +Before it was returning `400: Bad Request` with `Request is not valid` text body in the response but now it returns `415: Unsupported Media Type` with an empty body. + +Also see this unit test; +https://github.com/dotansimha/graphql-yoga/pull/2250/files#diff-78bcfa5f6d33aceeabdacd26e353641fea6fd125838ed0e1565762221568c777R380 diff --git a/.eslintrc.cjs b/.eslintrc.cjs index 1fb25b53b0..13465b972c 100644 --- a/.eslintrc.cjs +++ b/.eslintrc.cjs @@ -1,5 +1,9 @@ module.exports = { extends: ['@theguild'], + parserOptions: { + tsconfigRootDir: __dirname, + project: './tsconfig.json', + }, overrides: [ { files: ['packages/graphql-yoga/src/plugins/**/*.ts'], @@ -9,6 +13,10 @@ module.exports = { }, { files: ['website/**'], + parserOptions: { + tsconfigRootDir: __dirname, + project: './website/tsconfig.json', + }, rules: { 'import/no-default-export': 'off' }, }, { @@ -53,7 +61,14 @@ module.exports = { rules: { 'import/no-extraneous-dependencies': [ 'error', - { devDependencies: ['**/*.test.ts', '**/*.spec.ts'] }, + { + devDependencies: [ + '**/*.test.ts', + '**/*.spec.ts', + '**/scripts/*.js', + '**/vite.config.ts', + ], + }, ], 'no-restricted-imports': [ 'error', diff --git a/packages/client/apollo-link/__integration-tests__/apollo-link.spec.ts b/packages/client/apollo-link/__integration-tests__/apollo-link.spec.ts index 1577f6ad3d..27a8db4615 100644 --- a/packages/client/apollo-link/__integration-tests__/apollo-link.spec.ts +++ b/packages/client/apollo-link/__integration-tests__/apollo-link.spec.ts @@ -1,10 +1,9 @@ -import { ApolloClient, FetchResult, InMemoryCache } from '@apollo/client/core' -import { createYoga, createSchema } from 'graphql-yoga' -import { createServer, Server } from 'http' +import { createServer, Server } from 'node:http' +import { AddressInfo } from 'node:net' import { parse } from 'graphql' +import { ApolloClient, FetchResult, InMemoryCache } from '@apollo/client/core' import { YogaLink } from '@graphql-yoga/apollo-link' -import { File } from '@whatwg-node/fetch' -import { AddressInfo } from 'net' +import { createSchema, createYoga } from 'graphql-yoga' describe.skip('Yoga Apollo Link', () => { const endpoint = '/graphql' @@ -50,7 +49,7 @@ describe.skip('Yoga Apollo Link', () => { let server: Server let url: string - let client: ApolloClient + let client: ApolloClient beforeAll(async () => { server = createServer(yoga) @@ -118,7 +117,9 @@ describe.skip('Yoga Apollo Link', () => { } `), variables: { - file: new File(['Hello World'], 'file.txt', { type: 'text/plain' }), + file: new yoga.fetchAPI.File(['Hello World'], 'file.txt', { + type: 'text/plain', + }), }, }) expect(result.errors?.length).toBeFalsy() diff --git a/packages/client/apollo-link/package.json b/packages/client/apollo-link/package.json index 8b4b60ed5b..a7533e05fd 100644 --- a/packages/client/apollo-link/package.json +++ b/packages/client/apollo-link/package.json @@ -54,7 +54,8 @@ "tslib": "^2.3.1" }, "devDependencies": { - "@apollo/client": "3.7.2" + "@apollo/client": "3.7.2", + "graphql-yoga": "3.1.2" }, "peerDependencies": { "graphql": "^15.2.0 || ^16.0.0", diff --git a/packages/client/apollo-link/src/index.ts b/packages/client/apollo-link/src/index.ts index 0ab3d06020..9464037c06 100644 --- a/packages/client/apollo-link/src/index.ts +++ b/packages/client/apollo-link/src/index.ts @@ -1,13 +1,14 @@ import { ExecutorLink } from '@graphql-tools/executor-apollo-link' import { - HTTPExecutorOptions, buildHTTPExecutor, + HTTPExecutorOptions, } from '@graphql-tools/executor-http' export type YogaLinkOptions = HTTPExecutorOptions export class YogaLink extends ExecutorLink { constructor(options: YogaLinkOptions) { + // eslint-disable-next-line @typescript-eslint/no-explicit-any super(buildHTTPExecutor(options as any)) } } diff --git a/packages/client/urql-exchange/__integration-tests__/urql-exchange.spec.ts b/packages/client/urql-exchange/__integration-tests__/urql-exchange.spec.ts index 96df2809be..2fdfcc5677 100644 --- a/packages/client/urql-exchange/__integration-tests__/urql-exchange.spec.ts +++ b/packages/client/urql-exchange/__integration-tests__/urql-exchange.spec.ts @@ -1,10 +1,9 @@ -import { Client, createClient } from '@urql/core' +import { createServer, Server } from 'node:http' +import { AddressInfo } from 'node:net' import { yogaExchange } from '@graphql-yoga/urql-exchange' +import { Client, createClient } from '@urql/core' +import { createSchema, createYoga } from 'graphql-yoga' import { pipe, toObservable } from 'wonka' -import { createYoga, createSchema } from 'graphql-yoga' -import { File } from '@whatwg-node/fetch' -import { createServer, Server } from 'http' -import { AddressInfo } from 'net' describe.skip('URQL Yoga Exchange', () => { const endpoint = '/graphql' @@ -133,7 +132,9 @@ describe.skip('URQL Yoga Exchange', () => { ` const result = await client .mutation(query, { - file: new File(['Hello World'], 'file.txt', { type: 'text/plain' }), + file: new yoga.fetchAPI.File(['Hello World'], 'file.txt', { + type: 'text/plain', + }), }) .toPromise() expect(result.error).toBeFalsy() diff --git a/packages/client/urql-exchange/package.json b/packages/client/urql-exchange/package.json index 62dd87b57f..2d942ba47a 100644 --- a/packages/client/urql-exchange/package.json +++ b/packages/client/urql-exchange/package.json @@ -55,7 +55,8 @@ }, "devDependencies": { "@urql/core": "3.0.5", - "wonka": "6.1.2" + "wonka": "6.1.2", + "graphql-yoga": "3.1.2" }, "peerDependencies": { "graphql": "^15.2.0 || ^16.0.0", diff --git a/packages/client/urql-exchange/src/index.ts b/packages/client/urql-exchange/src/index.ts index 38127dcb4e..8baac7283a 100644 --- a/packages/client/urql-exchange/src/index.ts +++ b/packages/client/urql-exchange/src/index.ts @@ -8,5 +8,6 @@ import { Exchange } from '@urql/core' export type YogaExchangeOptions = HTTPExecutorOptions export function yogaExchange(options?: HTTPExecutorOptions): Exchange { + // eslint-disable-next-line @typescript-eslint/no-explicit-any return executorExchange(buildHTTPExecutor(options as any)) } diff --git a/packages/event-target/redis-event-target/__tests__/redis-event-target.spec.ts b/packages/event-target/redis-event-target/__tests__/redis-event-target.spec.ts index 34b7b2f6b3..04ea9db28e 100644 --- a/packages/event-target/redis-event-target/__tests__/redis-event-target.spec.ts +++ b/packages/event-target/redis-event-target/__tests__/redis-event-target.spec.ts @@ -1,6 +1,7 @@ +import { CustomEvent } from '@whatwg-node/events' import Redis from 'ioredis-mock' + import { createRedisEventTarget } from '../src' -import { CustomEvent } from '@whatwg-node/events' describe('createRedisEventTarget', () => { it('can listen to a simple publish', (done) => { diff --git a/packages/event-target/redis-event-target/src/index.ts b/packages/event-target/redis-event-target/src/index.ts index 234872b89d..a83942a9cb 100644 --- a/packages/event-target/redis-event-target/src/index.ts +++ b/packages/event-target/redis-event-target/src/index.ts @@ -1,6 +1,6 @@ import type { TypedEventTarget } from '@graphql-yoga/typed-event-target' import { CustomEvent } from '@whatwg-node/events' -import type { Redis, Cluster } from 'ioredis' +import type { Cluster, Redis } from 'ioredis' export type CreateRedisEventTargetArgs = { publishClient: Redis | Cluster diff --git a/packages/graphiql/src/YogaGraphiQL.tsx b/packages/graphiql/src/YogaGraphiQL.tsx index 09025df7f7..968782d58c 100644 --- a/packages/graphiql/src/YogaGraphiQL.tsx +++ b/packages/graphiql/src/YogaGraphiQL.tsx @@ -1,24 +1,25 @@ +import 'json-bigint-patch' import React, { useMemo, useState } from 'react' +import { DocumentNode, Kind, parse } from 'graphql' import { useExplorerPlugin } from '@graphiql/plugin-explorer' +import { Fetcher, FetcherOpts, FetcherParams } from '@graphiql/toolkit' +import { + LoadFromUrlOptions, + SubscriptionProtocol, + UrlLoader, +} from '@graphql-tools/url-loader' import { GraphiQL, GraphiQLInterface, GraphiQLProps, GraphiQLProvider, } from 'graphiql' -import { Fetcher, FetcherParams, FetcherOpts } from '@graphiql/toolkit' -import { - LoadFromUrlOptions, - SubscriptionProtocol, - UrlLoader, -} from '@graphql-tools/url-loader' import { useUrlSearchParams } from 'use-url-search-params' -import { DocumentNode, Kind, parse } from 'graphql' + +import { YogaLogo } from './YogaLogo' import 'graphiql/graphiql.css' import '@graphiql/plugin-explorer/dist/style.css' import './styles.css' -import 'json-bigint-patch' -import { YogaLogo } from './YogaLogo' const getOperationWithFragments = ( document: DocumentNode, diff --git a/packages/graphiql/src/bundle.tsx b/packages/graphiql/src/bundle.tsx index 1c62c506ad..f968fa2d0c 100644 --- a/packages/graphiql/src/bundle.tsx +++ b/packages/graphiql/src/bundle.tsx @@ -1,5 +1,6 @@ import React from 'react' import ReactDOM from 'react-dom' + import { YogaGraphiQL, YogaGraphiQLProps } from './YogaGraphiQL.js' export function renderYogaGraphiQL(element: Element, opts?: YogaGraphiQLProps) { diff --git a/packages/graphiql/vite.config.ts b/packages/graphiql/vite.config.ts index 7a07a5083d..77a414c4c1 100644 --- a/packages/graphiql/vite.config.ts +++ b/packages/graphiql/vite.config.ts @@ -1,6 +1,6 @@ -import { defineConfig } from 'vite' +import * as path from 'node:path' import react from '@vitejs/plugin-react' -import * as path from 'path' +import { defineConfig } from 'vite' // https://vitejs.dev/config/ export default defineConfig({ diff --git a/packages/graphql-yoga/__integration-tests__/browser.spec.ts b/packages/graphql-yoga/__integration-tests__/browser.spec.ts index 8227079498..56b0da71f2 100644 --- a/packages/graphql-yoga/__integration-tests__/browser.spec.ts +++ b/packages/graphql-yoga/__integration-tests__/browser.spec.ts @@ -1,23 +1,24 @@ -import { InMemoryLiveQueryStore } from '@n1ru4l/in-memory-live-query-store' -import { GraphQLLiveDirective, useLiveQuery } from '@envelop/live-query' -import { CORSOptions, createYoga, Repeater } from '../src/index.js' -import { renderGraphiQL } from '@graphql-yoga/render-graphiql' -import puppeteer, { Browser, ElementHandle, Page } from 'puppeteer' -import { createServer, Server } from 'http' +import 'json-bigint-patch' +import { createServer, Server } from 'node:http' +import { AddressInfo } from 'node:net' import { - GraphQLObjectType, - GraphQLSchema, - GraphQLString, - GraphQLInt, GraphQLBoolean, - GraphQLList, GraphQLFloat, + GraphQLInt, + GraphQLList, GraphQLNonNull, + GraphQLObjectType, + GraphQLSchema, + GraphQLString, } from 'graphql' -import { GraphQLBigInt } from 'graphql-scalars' -import 'json-bigint-patch' -import { AddressInfo } from 'net' +import { GraphQLLiveDirective, useLiveQuery } from '@envelop/live-query' import { useDeferStream } from '@graphql-yoga/plugin-defer-stream' +import { renderGraphiQL } from '@graphql-yoga/render-graphiql' +import { InMemoryLiveQueryStore } from '@n1ru4l/in-memory-live-query-store' +import { GraphQLBigInt } from 'graphql-scalars' +import puppeteer, { Browser, ElementHandle, Page } from 'puppeteer' + +import { CORSOptions, createYoga, Repeater } from '../src/index.js' let resolveOnReturn: VoidFunction const timeouts = new Set() @@ -122,13 +123,14 @@ export function createTestSchema() { }, error: { type: GraphQLBoolean, - // eslint-disable-next-line require-yield + // eslint-disable-next-line async *subscribe() { throw new Error('This is not okay') }, }, eventEmitted: { type: GraphQLFloat, + // eslint-disable-next-line async *subscribe() { yield { eventEmitted: Date.now() } }, @@ -220,7 +222,7 @@ describe('browser', () => { await page.waitForFunction( // eslint-disable-next-line @typescript-eslint/ban-ts-comment // @ts-ignore - () => !!window.g.resultComponent.viewer.getValue(), + () => Boolean(window.g.resultComponent.viewer.getValue()), ) const resultContents = await page.evaluate(() => { // eslint-disable-next-line @typescript-eslint/ban-ts-comment @@ -344,7 +346,7 @@ describe('browser', () => { // eslint-disable-next-line @typescript-eslint/ban-ts-comment // @ts-ignore window.g.resultComponent.viewer.getValue(), - !!window.document.querySelector(stopButtonSelector), + Boolean(window.document.querySelector(stopButtonSelector)), ] }, stopButtonSelector, @@ -373,7 +375,7 @@ describe('browser', () => { // eslint-disable-next-line @typescript-eslint/ban-ts-comment // @ts-ignore window.g.resultComponent.viewer.getValue(), - !!window.document.querySelector(stopButtonSelector), + Boolean(window.document.querySelector(stopButtonSelector)), ] }, stopButtonSelector, @@ -391,7 +393,7 @@ describe('browser', () => { // eslint-disable-next-line @typescript-eslint/ban-ts-comment // @ts-ignore window.g.resultComponent.viewer.getValue(), - !!window.document.querySelector(playButtonSelector), + Boolean(window.document.querySelector(playButtonSelector)), ] }, playButtonSelector, @@ -451,7 +453,7 @@ describe('browser', () => { // eslint-disable-next-line @typescript-eslint/ban-ts-comment // @ts-ignore window.g.resultComponent.viewer.getValue(), - !!window.document.querySelector(stopButtonSelector), + Boolean(window.document.querySelector(stopButtonSelector)), ] }, stopButtonSelector) const resultJson = JSON.parse(resultContents) @@ -479,7 +481,7 @@ describe('browser', () => { // eslint-disable-next-line @typescript-eslint/ban-ts-comment // @ts-ignore window.g.resultComponent.viewer.getValue(), - !!window.document.querySelector(playButtonSelector), + Boolean(window.document.querySelector(playButtonSelector)), ] }, playButtonSelector) const resultJson1 = JSON.parse(resultContents1) diff --git a/packages/graphql-yoga/__integration-tests__/file-uploads.spec.ts b/packages/graphql-yoga/__integration-tests__/file-uploads.spec.ts index ea03e1dc79..b840936827 100644 --- a/packages/graphql-yoga/__integration-tests__/file-uploads.spec.ts +++ b/packages/graphql-yoga/__integration-tests__/file-uploads.spec.ts @@ -1,11 +1,12 @@ -import * as fs from 'fs' -import * as crypto from 'crypto' -import * as path from 'path' -import * as os from 'os' -import { createServer } from 'http' -import { createYoga, createSchema } from 'graphql-yoga' +import * as crypto from 'node:crypto' +import * as fs from 'node:fs' +import { createServer } from 'node:http' +import { AddressInfo } from 'node:net' +import * as os from 'node:os' +import * as path from 'node:path' import { fetch, File, FormData } from '@whatwg-node/fetch' -import { AddressInfo } from 'net' + +import { createSchema, createYoga } from '../src' function md5File(path: string) { return new Promise((resolve, reject) => { diff --git a/packages/graphql-yoga/__integration-tests__/graphql-scalars.spec.ts b/packages/graphql-yoga/__integration-tests__/graphql-scalars.spec.ts index 4cadb994fd..941f57a389 100644 --- a/packages/graphql-yoga/__integration-tests__/graphql-scalars.spec.ts +++ b/packages/graphql-yoga/__integration-tests__/graphql-scalars.spec.ts @@ -1,9 +1,10 @@ -import { createSchema, createYoga } from '../src/index.js' +import { specifiedScalarTypes } from 'graphql' import { - typeDefs as scalarsTypeDefs, resolvers as scalarsResolvers, + typeDefs as scalarsTypeDefs, } from 'graphql-scalars' -import { specifiedScalarTypes } from 'graphql' + +import { createSchema, createYoga } from '../src/index.js' describe('graphql-scalars', () => { const ignoredScalars = [ @@ -40,7 +41,8 @@ describe('graphql-scalars', () => { scalarsResolvers, ...allScalars.map((scalar) => ({ Query: { - [`get${scalar.name}`]: (_: never, { input }: any) => input, + [`get${scalar.name}`]: (_: never, { input }: { input: unknown }) => + input, }, })), ], diff --git a/packages/graphql-yoga/__integration-tests__/incremental-delivery.spec.ts b/packages/graphql-yoga/__integration-tests__/incremental-delivery.spec.ts index e0c153fe43..0168510d4a 100644 --- a/packages/graphql-yoga/__integration-tests__/incremental-delivery.spec.ts +++ b/packages/graphql-yoga/__integration-tests__/incremental-delivery.spec.ts @@ -1,3 +1,5 @@ +import { createServer, Server } from 'node:http' +import { AddressInfo } from 'node:net' import { ExecutionResult, GraphQLInt, @@ -6,11 +8,10 @@ import { GraphQLSchema, GraphQLString, } from 'graphql' -import { createYoga, Plugin, Repeater } from 'graphql-yoga' import { Push } from '@repeaterjs/repeater' -import { createServer, Server } from 'http' import { createFetch, fetch, File, FormData } from '@whatwg-node/fetch' -import { AddressInfo } from 'net' + +import { createYoga, Plugin, Repeater } from '../src' describe('incremental delivery', () => { it('incremental delivery source is closed properly', async () => { @@ -18,6 +19,7 @@ describe('incremental delivery', () => { const fakeIterator: AsyncIterableIterator = { [Symbol.asyncIterator]: () => fakeIterator, + // eslint-disable-next-line @typescript-eslint/require-await async next() { counter++ return { @@ -33,7 +35,7 @@ describe('incremental delivery', () => { } const plugin: Plugin = { onExecute(ctx) { - ctx.setExecuteFn(() => Promise.resolve(fakeIterator) as any) + ctx.setExecuteFn(() => Promise.resolve(fakeIterator) as unknown) }, /* skip validation :) */ onValidate(ctx) { @@ -133,7 +135,7 @@ describe('incremental delivery: node-fetch', () => { type: GraphQLFile, }, }, - resolve: async (_, { file }) => file, + resolve: (_, { file }) => file, }, parseFileStream: { type: GraphQLString, diff --git a/packages/graphql-yoga/__integration-tests__/node-http.spec.ts b/packages/graphql-yoga/__integration-tests__/node-http.spec.ts index a90fa8605f..6618189eac 100644 --- a/packages/graphql-yoga/__integration-tests__/node-http.spec.ts +++ b/packages/graphql-yoga/__integration-tests__/node-http.spec.ts @@ -1,7 +1,13 @@ -import { IncomingMessage, ServerResponse, createServer, Server } from 'http' -import { createYoga, createSchema } from 'graphql-yoga' +import { + createServer, + IncomingMessage, + Server, + ServerResponse, +} from 'node:http' +import { AddressInfo } from 'node:net' import { fetch } from '@whatwg-node/fetch' -import { AddressInfo } from 'net' + +import { createSchema, createYoga } from '../src/index.js' it('should expose Node req and res objects in the context', async () => { let server: Server @@ -18,7 +24,7 @@ it('should expose Node req and res objects in the context', async () => { `, resolvers: { Query: { - isNode: (_, __, { req, res }) => !!req && !!res, + isNode: (_, __, { req, res }) => Boolean(req) && Boolean(res), }, }, }), diff --git a/packages/graphql-yoga/__integration-tests__/subscription.spec.ts b/packages/graphql-yoga/__integration-tests__/subscription.spec.ts index 06c47db8fc..fbcfd195cf 100644 --- a/packages/graphql-yoga/__integration-tests__/subscription.spec.ts +++ b/packages/graphql-yoga/__integration-tests__/subscription.spec.ts @@ -1,8 +1,9 @@ -import { createYoga, createSchema } from 'graphql-yoga' -import { createServer } from 'http' -import { fetch } from '@whatwg-node/fetch' -import { AddressInfo } from 'net' +import { createServer } from 'node:http' +import { AddressInfo } from 'node:net' import { ExecutionResult } from 'graphql' +import { fetch } from '@whatwg-node/fetch' + +import { createSchema, createYoga } from '../src' describe('subscription', () => { test('Subscription is closed properly', async () => { @@ -10,6 +11,7 @@ describe('subscription', () => { const fakeIterator: AsyncIterableIterator = { [Symbol.asyncIterator]: () => fakeIterator, + // eslint-disable-next-line @typescript-eslint/require-await async next() { counter++ return { diff --git a/packages/graphql-yoga/__tests__/404.spec.ts b/packages/graphql-yoga/__tests__/404.spec.ts index 15f13fc22a..628199be97 100644 --- a/packages/graphql-yoga/__tests__/404.spec.ts +++ b/packages/graphql-yoga/__tests__/404.spec.ts @@ -1,4 +1,4 @@ -import { createYoga } from 'graphql-yoga' +import { createYoga } from '../src/index.js' describe('404', () => { it('returns 404 if request path does not match with the defined graphql endpoint (POST)', async () => { diff --git a/packages/graphql-yoga/__tests__/500.spec.ts b/packages/graphql-yoga/__tests__/500.spec.ts index 8a2fee56a0..011e34c366 100644 --- a/packages/graphql-yoga/__tests__/500.spec.ts +++ b/packages/graphql-yoga/__tests__/500.spec.ts @@ -1,4 +1,3 @@ -import { createGraphQLError } from '@graphql-tools/utils' import { createSchema } from '../src/schema' import { createYoga } from '../src/server' diff --git a/packages/graphql-yoga/__tests__/accept-header.spec.ts b/packages/graphql-yoga/__tests__/accept-header.spec.ts index 8184b38dd6..668e438b41 100644 --- a/packages/graphql-yoga/__tests__/accept-header.spec.ts +++ b/packages/graphql-yoga/__tests__/accept-header.spec.ts @@ -1,5 +1,6 @@ import { ExecutionResult } from 'graphql' -import { createSchema, createYoga, Repeater, Plugin } from 'graphql-yoga' + +import { createSchema, createYoga, Plugin, Repeater } from '../src/index.js' describe('accept header', () => { it('instruct server to return an event-stream with GET parameters', async () => { @@ -77,7 +78,7 @@ describe('accept header', () => { const expectedStrs = [ `Content-Type: application/json; charset=utf-8`, `Content-Length: 24`, - `${JSON.stringify({ data: { ping: 'pong' } })}`, + JSON.stringify({ data: { ping: 'pong' } }), ] for await (const chunk of response.body!) { const valueStr = Buffer.from(chunk).toString('utf-8') @@ -115,21 +116,23 @@ describe('accept header', () => { expect(response.headers.get('content-type')).toEqual( 'multipart/mixed; boundary="-"', ) - const expectedStrs = [ + const expectedStrs = new Set([ `Content-Type: application/json; charset=utf-8`, `Content-Length: 24`, - `${JSON.stringify({ data: { ping: 'pong' } })}`, - ] + JSON.stringify({ data: { ping: 'pong' } }), + ]) for await (const chunk of response.body!) { const valueStr = Buffer.from(chunk).toString('utf-8') - if (expectedStrs.includes(valueStr)) { - expectedStrs.splice(expectedStrs.indexOf(valueStr), 1) + for (const expectedStr of expectedStrs) { + if (valueStr.includes(expectedStr)) { + expectedStrs.delete(expectedStr) + } } - if (expectedStrs.length === 0) { + if (expectedStrs.size === 0) { break } } - expect(expectedStrs.length).toEqual(0) + expect(expectedStrs.size).toEqual(0) }) it('server rejects request for AsyncIterable source (subscription) when client only accepts application/json', async () => { @@ -176,9 +179,9 @@ describe('accept header', () => { onExecute(args) { args.setExecuteFn(() => Promise.resolve( - new Repeater>((_push, end) => { + new Repeater((_push, end) => { end() - }) as any, + }), ), ) }, diff --git a/packages/graphql-yoga/__tests__/context.spec.ts b/packages/graphql-yoga/__tests__/context.spec.ts index 546c49855f..dba37123e2 100644 --- a/packages/graphql-yoga/__tests__/context.spec.ts +++ b/packages/graphql-yoga/__tests__/context.spec.ts @@ -1,9 +1,9 @@ /* eslint-disable @typescript-eslint/ban-types */ /* eslint-disable @typescript-eslint/no-empty-function */ +import { Plugin } from '../src/plugins/types' import { createSchema } from '../src/schema' import { createYoga } from '../src/server' import { YogaInitialContext } from '../src/types' -import { Plugin } from '../src/plugins/types' describe('Context', () => { interface UserContext { @@ -27,6 +27,7 @@ describe('Context', () => { }, Subscription: { greetings: { + // eslint-disable-next-line @typescript-eslint/require-await async *subscribe() { yield { greetings: 'Hi' } }, diff --git a/packages/graphql-yoga/__tests__/error-masking.spec.ts b/packages/graphql-yoga/__tests__/error-masking.spec.ts index 2a5b3f5342..60928444db 100644 --- a/packages/graphql-yoga/__tests__/error-masking.spec.ts +++ b/packages/graphql-yoga/__tests__/error-masking.spec.ts @@ -1,8 +1,10 @@ import { inspect } from '@graphql-tools/utils' -import { createGraphQLError, createSchema, createYoga } from 'graphql-yoga' + +import { createGraphQLError, createSchema, createYoga } from '../src/index.js' describe('error masking', () => { function createTestSchema() { + // eslint-disable-next-line @typescript-eslint/no-explicit-any return createSchema({ typeDefs: /* GraphQL */ ` type Query { diff --git a/packages/graphql-yoga/__tests__/graphql-http.spec.ts b/packages/graphql-yoga/__tests__/graphql-http.spec.ts index cd46658851..ee9b015312 100644 --- a/packages/graphql-yoga/__tests__/graphql-http.spec.ts +++ b/packages/graphql-yoga/__tests__/graphql-http.spec.ts @@ -1,6 +1,7 @@ -import { createSchema, createYoga } from 'graphql-yoga' import { serverAudits } from 'graphql-http' +import { createSchema, createYoga } from '../src/index.js' + const yoga = createYoga({ schema: createSchema({ typeDefs: /* GraphQL */ ` diff --git a/packages/graphql-yoga/__tests__/health-check.spec.ts b/packages/graphql-yoga/__tests__/health-check.spec.ts index eed5825651..2bfd69e6c6 100644 --- a/packages/graphql-yoga/__tests__/health-check.spec.ts +++ b/packages/graphql-yoga/__tests__/health-check.spec.ts @@ -1,4 +1,4 @@ -import { createYoga } from 'graphql-yoga' +import { createYoga } from '../src/index.js' describe('health check', () => { it('return 200 status code for health check endpoint', async () => { diff --git a/packages/graphql-yoga/__tests__/http-extensions.spec.ts b/packages/graphql-yoga/__tests__/http-extensions.spec.ts index a4d3ebe285..f12d66d896 100644 --- a/packages/graphql-yoga/__tests__/http-extensions.spec.ts +++ b/packages/graphql-yoga/__tests__/http-extensions.spec.ts @@ -1,4 +1,4 @@ -import { createSchema, createYoga, createGraphQLError } from 'graphql-yoga' +import { createGraphQLError, createSchema, createYoga } from '../src/index.js' describe('GraphQLError.extensions.http', () => { it('sets correct status code and headers for thrown GraphQLError in a resolver', async () => { diff --git a/packages/graphql-yoga/__tests__/introspection.spec.ts b/packages/graphql-yoga/__tests__/introspection.spec.ts index 7152d3b8ef..4a5426c124 100644 --- a/packages/graphql-yoga/__tests__/introspection.spec.ts +++ b/packages/graphql-yoga/__tests__/introspection.spec.ts @@ -1,8 +1,10 @@ -import { useDisableIntrospection } from '@envelop/disable-introspection' import { getIntrospectionQuery } from 'graphql' -import { createSchema, createYoga, createGraphQLError } from 'graphql-yoga' +import { useDisableIntrospection } from '@envelop/disable-introspection' + +import { createGraphQLError, createSchema, createYoga } from '../src/index.js' function createTestSchema() { + // eslint-disable-next-line @typescript-eslint/no-explicit-any return createSchema({ typeDefs: /* GraphQL */ ` type Query { diff --git a/packages/graphql-yoga/__tests__/logging.spec.ts b/packages/graphql-yoga/__tests__/logging.spec.ts index 775cfef32e..3067e06b90 100644 --- a/packages/graphql-yoga/__tests__/logging.spec.ts +++ b/packages/graphql-yoga/__tests__/logging.spec.ts @@ -1,11 +1,12 @@ /* eslint-disable no-console */ -import { jest } from '@jest/globals' import { GraphQLError } from 'graphql' +import { jest } from '@jest/globals' + import { - createYoga, + createGraphQLError, createLogger, createSchema, - createGraphQLError, + createYoga, } from '../src' describe('logging', () => { @@ -31,7 +32,7 @@ describe('logging', () => { jest.spyOn(console, 'debug') const logger = createLogger() logger.debug('TEST') - // eslint-disable-next-line no-console + expect(console.debug).not.toHaveBeenCalled() }) it(`prints debug messages if DEBUG env var is set`, () => { @@ -42,7 +43,7 @@ describe('logging', () => { jest.spyOn(console, 'debug').mockImplementationOnce(() => {}) const logger = createLogger() logger.debug('TEST') - // eslint-disable-next-line no-console + expect(console.debug).toHaveBeenCalled() } finally { process.env.DEBUG = originalValue diff --git a/packages/graphql-yoga/__tests__/readiness-check.spec.ts b/packages/graphql-yoga/__tests__/readiness-check.spec.ts index 5878081c14..1f1d831529 100644 --- a/packages/graphql-yoga/__tests__/readiness-check.spec.ts +++ b/packages/graphql-yoga/__tests__/readiness-check.spec.ts @@ -1,4 +1,5 @@ -import { createYoga, createSchema } from 'graphql-yoga' +/* eslint-disable @typescript-eslint/require-await */ +import { createSchema, createYoga } from '../src/index.js' import { useReadinessCheck } from '../src/plugins/useReadinessCheck' describe('Readiness Check', () => { diff --git a/packages/graphql-yoga/__tests__/recipes.spec.ts b/packages/graphql-yoga/__tests__/recipes.spec.ts index 9eb97e6d31..ad94f333a6 100644 --- a/packages/graphql-yoga/__tests__/recipes.spec.ts +++ b/packages/graphql-yoga/__tests__/recipes.spec.ts @@ -3,7 +3,7 @@ import { createYoga, GraphQLParams, YogaInitialContext, -} from 'graphql-yoga' +} from '../src/index.js' describe('recipe', () => { it('id as custom top level POST body query parameter', async () => { diff --git a/packages/graphql-yoga/__tests__/requests.spec.ts b/packages/graphql-yoga/__tests__/requests.spec.ts index 9a855725cc..bbf5c76964 100644 --- a/packages/graphql-yoga/__tests__/requests.spec.ts +++ b/packages/graphql-yoga/__tests__/requests.spec.ts @@ -1,4 +1,4 @@ -import { createYoga, createSchema } from 'graphql-yoga' +import { createSchema, createYoga } from '../src' describe('requests', () => { const schema = createSchema({ @@ -345,7 +345,7 @@ describe('requests', () => { body: JSON.stringify({ query: '{ ping }' }), }) - expect(response.ok).toBeTruthy() + expect(response.status).toBe(200) const body = await response.json() expect(body).toMatchInlineSnapshot(` { @@ -376,4 +376,17 @@ describe('requests', () => { } `) }) + + it('should return 415 unsupported media type when content-type is not supported', async () => { + const response = await yoga.fetch('http://yoga/test-graphql', { + method: 'POST', + headers: { + 'content-type': 'application/xml', + }, + body: `{ ping }`, + }) + expect(response.status).toBe(415) + const body = await response.text() + expect(body).toBeFalsy() + }) }) diff --git a/packages/graphql-yoga/__tests__/schema.spec.ts b/packages/graphql-yoga/__tests__/schema.spec.ts index 68ea9c9df5..6d7793cde3 100644 --- a/packages/graphql-yoga/__tests__/schema.spec.ts +++ b/packages/graphql-yoga/__tests__/schema.spec.ts @@ -1,5 +1,7 @@ +/* eslint-disable @typescript-eslint/require-await */ import { GraphQLSchema } from 'graphql' -import { createSchema, createYoga, YogaInitialContext } from 'graphql-yoga' + +import { createSchema, createYoga, YogaInitialContext } from '../src/index.js' describe('schema', () => { it('missing schema causes a error', async () => { @@ -72,6 +74,7 @@ describe('schema', () => { it('fails if factory function does not return a schema', async () => { const schemaFactory = () => { + // eslint-disable-next-line @typescript-eslint/no-explicit-any return null as any } @@ -134,7 +137,7 @@ describe('schema', () => { }) it('fails if promise does not resolve to a schema', async () => { - const schemaPromise = Promise.resolve(null as any) + const schemaPromise = Promise.resolve(null as unknown as GraphQLSchema) const yoga = createYoga({ schema: schemaPromise, maskedErrors: false, @@ -197,7 +200,7 @@ describe('schema', () => { it('fails if factory function returning a promise does not resolve to a schema', async () => { const yoga = createYoga({ - schema: () => Promise.resolve(null as any), + schema: () => Promise.resolve(null as unknown as GraphQLSchema), maskedErrors: false, }) const query = /* GraphQL */ ` diff --git a/packages/graphql-yoga/__tests__/subscriptions.spec.ts b/packages/graphql-yoga/__tests__/subscriptions.spec.ts index 4e0596f2dd..6140a5d62f 100644 --- a/packages/graphql-yoga/__tests__/subscriptions.spec.ts +++ b/packages/graphql-yoga/__tests__/subscriptions.spec.ts @@ -1,4 +1,4 @@ -import { createSchema, createYoga, Repeater } from 'graphql-yoga' +import { createSchema, createYoga, Repeater } from '../src/index.js' function eventStream(source: ReadableStream) { return new Repeater(async (push, end) => { @@ -29,6 +29,7 @@ function eventStream(source: ReadableStream) { describe('Subscription', () => { test('eventStream', async () => { + // eslint-disable-next-line @typescript-eslint/require-await const source = (async function* foo() { yield { hi: 'hi' } yield { hi: 'hello' } diff --git a/packages/graphql-yoga/package.json b/packages/graphql-yoga/package.json index 3cb19eb627..330a9930e1 100644 --- a/packages/graphql-yoga/package.json +++ b/packages/graphql-yoga/package.json @@ -64,6 +64,7 @@ "devDependencies": { "@envelop/disable-introspection": "4.0.4", "@envelop/live-query": "5.0.4", + "@graphql-yoga/render-graphiql": "3.1.2", "@jest/globals": "^29.2.1", "@n1ru4l/in-memory-live-query-store": "0.10.0", "@repeaterjs/repeater": "^3.0.4", diff --git a/packages/graphql-yoga/scripts/generate-graphiql-html.js b/packages/graphql-yoga/scripts/generate-graphiql-html.js index ce9b31b4d3..e98dd6a390 100644 --- a/packages/graphql-yoga/scripts/generate-graphiql-html.js +++ b/packages/graphql-yoga/scripts/generate-graphiql-html.js @@ -1,7 +1,7 @@ +import * as fs from 'node:fs' +import * as path from 'node:path' +import { fileURLToPath } from 'node:url' import { minify as minifyT } from 'html-minifier-terser' -import * as fs from 'fs' -import * as path from 'path' -import { fileURLToPath } from 'url' const __dirname = path.dirname(fileURLToPath(import.meta.url)) diff --git a/packages/graphql-yoga/src/error.ts b/packages/graphql-yoga/src/error.ts index 3d3a3bbe43..cede017336 100644 --- a/packages/graphql-yoga/src/error.ts +++ b/packages/graphql-yoga/src/error.ts @@ -1,5 +1,6 @@ -import { createGraphQLError } from '@graphql-tools/utils' import { GraphQLError } from 'graphql' +import { createGraphQLError } from '@graphql-tools/utils' + import type { YogaLogger } from './logger.js' import type { ResultProcessorInput } from './plugins/types.js' import type { YogaMaskedErrorOpts } from './types.js' diff --git a/packages/graphql-yoga/src/index.ts b/packages/graphql-yoga/src/index.ts index 512b06da69..fb3a4c333f 100644 --- a/packages/graphql-yoga/src/index.ts +++ b/packages/graphql-yoga/src/index.ts @@ -1,39 +1,38 @@ -export * from './types.js' +export { createGraphQLError } from './error.js' export * from './logger.js' +export type { Plugin } from './plugins/types.js' +export type { CORSOptions } from './plugins/useCORS.js' +export type { GraphiQLOptions } from './plugins/useGraphiQL.js' +export { renderGraphiQL, shouldRenderGraphiQL } from './plugins/useGraphiQL.js' +export { useReadinessCheck } from './plugins/useReadinessCheck.js' +export { useSchema } from './plugins/useSchema.js' +export * from './schema.js' export * from './server.js' - +export * from './subscription.js' +export * from './types.js' +export type { + // Handy type utils + Maybe, + Optional, + PromiseOrValue, + Spread, +} from '@envelop/core' export { // useful for anyone creating a new envelop instance envelop, + errorAsyncIterator, + finalAsyncIterator, + handleStreamOrSingleExecutionResult, + isAsyncIterable, + // useful helpers + isIntrospectionOperationString, + makeExecute, + makeSubscribe, + mapAsyncIterator, // Default plugins useEnvelop, useErrorHandler, - useLogger, useExtendContext, + useLogger, usePayloadFormatter, - // useful helpers - isIntrospectionOperationString, - makeSubscribe, - mapAsyncIterator, - makeExecute, - handleStreamOrSingleExecutionResult, - finalAsyncIterator, - errorAsyncIterator, - isAsyncIterable, -} from '@envelop/core' -export type { - // Handy type utils - Maybe, - Optional, - PromiseOrValue, - Spread, } from '@envelop/core' -export type { CORSOptions } from './plugins/useCORS.js' -export type { GraphiQLOptions } from './plugins/useGraphiQL.js' -export type { Plugin } from './plugins/types.js' -export { shouldRenderGraphiQL, renderGraphiQL } from './plugins/useGraphiQL.js' -export { useSchema } from './plugins/useSchema.js' -export { useReadinessCheck } from './plugins/useReadinessCheck.js' -export * from './schema.js' -export * from './subscription.js' -export { createGraphQLError } from './error.js' diff --git a/packages/graphql-yoga/src/logger.ts b/packages/graphql-yoga/src/logger.ts index d6c90998b1..02caa3e320 100644 --- a/packages/graphql-yoga/src/logger.ts +++ b/packages/graphql-yoga/src/logger.ts @@ -1,3 +1,4 @@ +/* eslint-disable @typescript-eslint/no-explicit-any */ /* eslint-disable no-console */ const ansiCodes = { diff --git a/packages/graphql-yoga/src/plugins/plugins.test.ts b/packages/graphql-yoga/src/plugins/plugins.test.ts index bbe9ab529b..ad58ad4563 100644 --- a/packages/graphql-yoga/src/plugins/plugins.test.ts +++ b/packages/graphql-yoga/src/plugins/plugins.test.ts @@ -1,8 +1,9 @@ import { AfterValidateHook } from '@envelop/core' -import { Plugin } from './types.js' -import { createYoga } from '../server.js' -import { createSchema } from '../schema.js' + import { createGraphQLError } from '../error.js' +import { createSchema } from '../schema.js' +import { createYoga } from '../server.js' +import { Plugin } from './types.js' const schema = createSchema({ typeDefs: /* GraphQL */ ` @@ -14,7 +15,7 @@ const schema = createSchema({ describe('Yoga Plugins', () => { it(`should respect Envelop's OnPluginInit's addPlugin`, async () => { - const afterValidateHook: AfterValidateHook = jest + const afterValidateHook: AfterValidateHook> = jest .fn() .mockImplementation(({ setResult }) => { setResult([ diff --git a/packages/graphql-yoga/src/plugins/requestParser/POSTJson.ts b/packages/graphql-yoga/src/plugins/requestParser/POSTJson.ts index e3e7931c3a..f480a2d637 100644 --- a/packages/graphql-yoga/src/plugins/requestParser/POSTJson.ts +++ b/packages/graphql-yoga/src/plugins/requestParser/POSTJson.ts @@ -1,5 +1,6 @@ -import { createGraphQLError } from '@graphql-tools/utils' import { GraphQLErrorExtensions } from 'graphql' +import { createGraphQLError } from '@graphql-tools/utils' + import { GraphQLParams } from '../../types.js' import { isContentTypeMatch } from './utils.js' diff --git a/packages/graphql-yoga/src/plugins/requestParser/POSTMultipart.ts b/packages/graphql-yoga/src/plugins/requestParser/POSTMultipart.ts index 2028f614d0..673735b2d7 100644 --- a/packages/graphql-yoga/src/plugins/requestParser/POSTMultipart.ts +++ b/packages/graphql-yoga/src/plugins/requestParser/POSTMultipart.ts @@ -1,5 +1,6 @@ import { createGraphQLError } from '@graphql-tools/utils' import { dset } from 'dset' + import { GraphQLParams } from '../../types.js' import { isContentTypeMatch } from './utils.js' diff --git a/packages/graphql-yoga/src/plugins/requestParser/utils.ts b/packages/graphql-yoga/src/plugins/requestParser/utils.ts index 753b05910c..aaa34ea45e 100644 --- a/packages/graphql-yoga/src/plugins/requestParser/utils.ts +++ b/packages/graphql-yoga/src/plugins/requestParser/utils.ts @@ -25,6 +25,6 @@ export function isContentTypeMatch( return ( contentType === expectedContentType || - !!contentType?.startsWith(`${expectedContentType};`) + Boolean(contentType?.startsWith(`${expectedContentType};`)) ) } diff --git a/packages/graphql-yoga/src/plugins/requestValidation/useCheckGraphQLQueryParams.ts b/packages/graphql-yoga/src/plugins/requestValidation/useCheckGraphQLQueryParams.ts index ae9a47cfc1..973c6008d6 100644 --- a/packages/graphql-yoga/src/plugins/requestValidation/useCheckGraphQLQueryParams.ts +++ b/packages/graphql-yoga/src/plugins/requestValidation/useCheckGraphQLQueryParams.ts @@ -1,4 +1,5 @@ import { createGraphQLError } from '@graphql-tools/utils' + import type { GraphQLParams } from '../../types.js' import type { Plugin } from '../types.js' diff --git a/packages/graphql-yoga/src/plugins/requestValidation/useCheckMethodForGraphQL.ts b/packages/graphql-yoga/src/plugins/requestValidation/useCheckMethodForGraphQL.ts index 2a2ff8f4a3..ea64be4734 100644 --- a/packages/graphql-yoga/src/plugins/requestValidation/useCheckMethodForGraphQL.ts +++ b/packages/graphql-yoga/src/plugins/requestValidation/useCheckMethodForGraphQL.ts @@ -1,4 +1,5 @@ import { createGraphQLError } from '@graphql-tools/utils' + import type { Plugin } from '../types.js' export function isValidMethodForGraphQL( diff --git a/packages/graphql-yoga/src/plugins/requestValidation/useHTTPValidationError.ts b/packages/graphql-yoga/src/plugins/requestValidation/useHTTPValidationError.ts index 95b7696d5f..709b7884cc 100644 --- a/packages/graphql-yoga/src/plugins/requestValidation/useHTTPValidationError.ts +++ b/packages/graphql-yoga/src/plugins/requestValidation/useHTTPValidationError.ts @@ -1,5 +1,6 @@ -import { AggregateError } from '@graphql-tools/utils' import { GraphQLError } from 'graphql' +import { AggregateError } from '@graphql-tools/utils' + import type { Plugin } from '../types.js' export function getAggregateErrorFromErrors( diff --git a/packages/graphql-yoga/src/plugins/requestValidation/usePreventMutationViaGET.ts b/packages/graphql-yoga/src/plugins/requestValidation/usePreventMutationViaGET.ts index 24c22c697e..7f79907144 100644 --- a/packages/graphql-yoga/src/plugins/requestValidation/usePreventMutationViaGET.ts +++ b/packages/graphql-yoga/src/plugins/requestValidation/usePreventMutationViaGET.ts @@ -1,11 +1,12 @@ -import { Maybe } from '@envelop/core' -import { createGraphQLError } from '@graphql-tools/utils' import { - OperationDefinitionNode, + DocumentNode, getOperationAST, GraphQLError, - DocumentNode, + OperationDefinitionNode, } from 'graphql' +import { Maybe } from '@envelop/core' +import { createGraphQLError } from '@graphql-tools/utils' + import type { YogaInitialContext } from '../../types.js' import type { Plugin } from '../types.js' diff --git a/packages/graphql-yoga/src/plugins/resultProcessor/multipart.ts b/packages/graphql-yoga/src/plugins/resultProcessor/multipart.ts index 07f7cd283e..5b519ba85b 100644 --- a/packages/graphql-yoga/src/plugins/resultProcessor/multipart.ts +++ b/packages/graphql-yoga/src/plugins/resultProcessor/multipart.ts @@ -1,5 +1,6 @@ -import { isAsyncIterable } from '@envelop/core' import { ExecutionResult } from 'graphql' +import { isAsyncIterable } from '@envelop/core' + import { getResponseInitByRespectingErrors } from '../../error.js' import { FetchAPI, MaybeArray } from '../../types.js' import { ResultProcessorInput } from '../types.js' diff --git a/packages/graphql-yoga/src/plugins/resultProcessor/push.ts b/packages/graphql-yoga/src/plugins/resultProcessor/push.ts index d2517c7c95..a6c74ff96e 100644 --- a/packages/graphql-yoga/src/plugins/resultProcessor/push.ts +++ b/packages/graphql-yoga/src/plugins/resultProcessor/push.ts @@ -1,5 +1,6 @@ -import { isAsyncIterable } from '@envelop/core' import { ExecutionResult } from 'graphql' +import { isAsyncIterable } from '@envelop/core' + import { getResponseInitByRespectingErrors } from '../../error.js' import { FetchAPI, MaybeArray } from '../../types.js' import { ResultProcessorInput } from '../types.js' diff --git a/packages/graphql-yoga/src/plugins/resultProcessor/regular.ts b/packages/graphql-yoga/src/plugins/resultProcessor/regular.ts index 10a01fd355..ceca1c28cf 100644 --- a/packages/graphql-yoga/src/plugins/resultProcessor/regular.ts +++ b/packages/graphql-yoga/src/plugins/resultProcessor/regular.ts @@ -1,4 +1,5 @@ import { isAsyncIterable } from '@graphql-tools/utils' + import { getResponseInitByRespectingErrors } from '../../error.js' import { FetchAPI } from '../../types.js' import { ResultProcessorInput } from '../types.js' diff --git a/packages/graphql-yoga/src/plugins/resultProcessor/stringify.ts b/packages/graphql-yoga/src/plugins/resultProcessor/stringify.ts index d006b7341c..e7ca9c7a95 100644 --- a/packages/graphql-yoga/src/plugins/resultProcessor/stringify.ts +++ b/packages/graphql-yoga/src/plugins/resultProcessor/stringify.ts @@ -1,4 +1,5 @@ import { ExecutionResult } from '@graphql-tools/utils' + import type { MaybeArray } from '../../types.js' // JSON stringifier that adjusts the result extensions while serialising diff --git a/packages/graphql-yoga/src/plugins/types.ts b/packages/graphql-yoga/src/plugins/types.ts index a987beb35a..4b6c2dfb8b 100644 --- a/packages/graphql-yoga/src/plugins/types.ts +++ b/packages/graphql-yoga/src/plugins/types.ts @@ -1,11 +1,12 @@ /* eslint-disable @typescript-eslint/no-explicit-any */ import { - Plugin as EnvelopPlugin, - PromiseOrValue, OnExecuteHook, OnSubscribeHook, + Plugin as EnvelopPlugin, + PromiseOrValue, } from '@envelop/core' import { ExecutionResult } from '@graphql-tools/utils' + import { YogaServer } from '../server.js' import { FetchAPI, diff --git a/packages/graphql-yoga/src/plugins/useCORS.ts b/packages/graphql-yoga/src/plugins/useCORS.ts index 77593c2663..6eef308c7b 100644 --- a/packages/graphql-yoga/src/plugins/useCORS.ts +++ b/packages/graphql-yoga/src/plugins/useCORS.ts @@ -1,4 +1,5 @@ import { PromiseOrValue } from '@envelop/core' + import { Plugin } from './types.js' export type CORSOptions = @@ -124,6 +125,7 @@ async function getCORSResponseHeaders( return getCORSHeadersByRequestAndOptions(request, corsOptions) } +// eslint-disable-next-line @typescript-eslint/no-explicit-any export function useCORS>( options?: CORSPluginOptions, // eslint-disable-next-line @typescript-eslint/ban-types @@ -142,7 +144,7 @@ export function useCORS>( } } return { - async onRequest({ request, serverContext, fetchAPI, endResponse }) { + onRequest({ request, fetchAPI, endResponse }) { if (request.method.toUpperCase() === 'OPTIONS') { const response = new fetchAPI.Response(null, { status: 204, @@ -157,6 +159,7 @@ export function useCORS>( } }, async onResponse({ request, serverContext, response }) { + // eslint-disable-next-line @typescript-eslint/no-explicit-any const headers = await getCORSResponseHeaders( request, corsOptionsFactory, diff --git a/packages/graphql-yoga/src/plugins/useCors.spec.ts b/packages/graphql-yoga/src/plugins/useCors.spec.ts index 1a2da21720..f0f95cff9b 100644 --- a/packages/graphql-yoga/src/plugins/useCors.spec.ts +++ b/packages/graphql-yoga/src/plugins/useCors.spec.ts @@ -1,13 +1,14 @@ import { Request } from '@whatwg-node/fetch' + import { createSchema } from '../schema.js' import { createYoga } from '../server.js' -import { YogaInitialContext } from '../types.js' -import { getCORSHeadersByRequestAndOptions, CORSOptions } from './useCORS.js' +import { CORSOptions, getCORSHeadersByRequestAndOptions } from './useCORS.js' describe('CORS', () => { describe('OPTIONS call', () => { it('should respond with correct status & headers', async () => { - const schemaFactory = async (ctx: YogaInitialContext) => { + // eslint-disable-next-line @typescript-eslint/require-await + const schemaFactory = async () => { return createSchema({ typeDefs: /* GraphQL */ ` type Query { @@ -24,7 +25,7 @@ describe('CORS', () => { const yoga = createYoga({ schema: schemaFactory, }) - let result = await yoga.fetch('http://yoga/graphql', { + const result = await yoga.fetch('http://yoga/graphql', { method: 'OPTIONS', headers: { 'Content-Type': 'application/json', diff --git a/packages/graphql-yoga/src/plugins/useGraphiQL.ts b/packages/graphql-yoga/src/plugins/useGraphiQL.ts index 199c802a15..49ce9cd64a 100644 --- a/packages/graphql-yoga/src/plugins/useGraphiQL.ts +++ b/packages/graphql-yoga/src/plugins/useGraphiQL.ts @@ -1,10 +1,13 @@ import { PromiseOrValue } from '@envelop/core' + +import graphiqlHTML from '../graphiql-html.js' import { YogaLogger } from '../logger.js' import { Plugin } from './types.js' -import graphiqlHTML from '../graphiql-html.js' export function shouldRenderGraphiQL({ headers, method }: Request): boolean { - return method === 'GET' && !!headers?.get('accept')?.includes('text/html') + return ( + method === 'GET' && Boolean(headers?.get('accept')?.includes('text/html')) + ) } export type GraphiQLOptions = { @@ -82,6 +85,7 @@ export interface GraphiQLPluginConfig { logger?: YogaLogger } +// eslint-disable-next-line @typescript-eslint/no-explicit-any export function useGraphiQL>( config: GraphiQLPluginConfig, // eslint-disable-next-line @typescript-eslint/ban-types diff --git a/packages/graphql-yoga/src/plugins/useHealthCheck.ts b/packages/graphql-yoga/src/plugins/useHealthCheck.ts index c7b20e0301..493c2b55ee 100644 --- a/packages/graphql-yoga/src/plugins/useHealthCheck.ts +++ b/packages/graphql-yoga/src/plugins/useHealthCheck.ts @@ -13,7 +13,7 @@ export function useHealthCheck({ endpoint = '/health', }: HealthCheckPluginOptions = {}): Plugin { return { - async onRequest({ endResponse, fetchAPI, url }) { + onRequest({ endResponse, fetchAPI, url }) { const { pathname: requestPath } = url if (requestPath === endpoint) { logger.debug('Responding Health Check') diff --git a/packages/graphql-yoga/src/plugins/useRequestParser.ts b/packages/graphql-yoga/src/plugins/useRequestParser.ts index 0287ae94eb..5bc07b3752 100644 --- a/packages/graphql-yoga/src/plugins/useRequestParser.ts +++ b/packages/graphql-yoga/src/plugins/useRequestParser.ts @@ -1,6 +1,7 @@ -import { Plugin } from './types.js' import { PromiseOrValue } from '@envelop/core' + import { GraphQLParams } from '../types.js' +import { Plugin } from './types.js' interface RequestParserPluginOptions { match?(request: Request): boolean diff --git a/packages/graphql-yoga/src/plugins/useResultProcessor.ts b/packages/graphql-yoga/src/plugins/useResultProcessor.ts index fca5980923..66a7b785b0 100644 --- a/packages/graphql-yoga/src/plugins/useResultProcessor.ts +++ b/packages/graphql-yoga/src/plugins/useResultProcessor.ts @@ -1,4 +1,5 @@ import { isAsyncIterable } from '@envelop/core' + import { getMediaTypesForRequestInOrder, isMatchingMediaType, diff --git a/packages/graphql-yoga/src/plugins/useSchema.ts b/packages/graphql-yoga/src/plugins/useSchema.ts index 1a0f92afbd..58448b51bb 100644 --- a/packages/graphql-yoga/src/plugins/useSchema.ts +++ b/packages/graphql-yoga/src/plugins/useSchema.ts @@ -1,5 +1,6 @@ -import { PromiseOrValue } from '@envelop/core' import { GraphQLSchema, isSchema } from 'graphql' +import { PromiseOrValue } from '@envelop/core' + import type { GraphQLSchemaWithContext, YogaInitialContext } from '../types.js' import type { Plugin } from './types.js' diff --git a/packages/graphql-yoga/src/plugins/useUnhandledRoute.ts b/packages/graphql-yoga/src/plugins/useUnhandledRoute.ts index 709c423892..74063480e5 100644 --- a/packages/graphql-yoga/src/plugins/useUnhandledRoute.ts +++ b/packages/graphql-yoga/src/plugins/useUnhandledRoute.ts @@ -1,5 +1,5 @@ -import type { Plugin } from './types.js' import landingPageBody from '../landing-page-html.js' +import type { Plugin } from './types.js' export function useUnhandledRoute(args: { graphqlEndpoint: string @@ -12,7 +12,7 @@ export function useUnhandledRoute(args: { if ( args.showLandingPage === true && request.method === 'GET' && - !!request.headers?.get('accept')?.includes('text/html') + Boolean(request.headers?.get('accept')?.includes('text/html')) ) { endResponse( new fetchAPI.Response( diff --git a/packages/graphql-yoga/src/process-request.ts b/packages/graphql-yoga/src/process-request.ts index 0b56e42c82..4189828fc7 100644 --- a/packages/graphql-yoga/src/process-request.ts +++ b/packages/graphql-yoga/src/process-request.ts @@ -1,11 +1,12 @@ -import { getOperationAST, ExecutionArgs } from 'graphql' -import { FetchAPI, GraphQLParams } from './types.js' +import { ExecutionArgs, getOperationAST } from 'graphql' +import { GetEnvelopedFn } from '@envelop/core' + import { OnResultProcess, ResultProcessor, ResultProcessorInput, } from './plugins/types.js' -import { GetEnvelopedFn } from '@envelop/core' +import { FetchAPI, GraphQLParams } from './types.js' export async function processResult({ request, diff --git a/packages/graphql-yoga/src/schema.ts b/packages/graphql-yoga/src/schema.ts index ce75f7953e..1d95d5ff42 100644 --- a/packages/graphql-yoga/src/schema.ts +++ b/packages/graphql-yoga/src/schema.ts @@ -2,6 +2,7 @@ import { IExecutableSchemaDefinition, makeExecutableSchema, } from '@graphql-tools/schema' + import { GraphQLSchemaWithContext, YogaInitialContext } from './types.js' // eslint-disable-next-line @typescript-eslint/ban-types diff --git a/packages/graphql-yoga/src/server.ts b/packages/graphql-yoga/src/server.ts index 217224fcfd..529dc7e47f 100644 --- a/packages/graphql-yoga/src/server.ts +++ b/packages/graphql-yoga/src/server.ts @@ -1,22 +1,43 @@ -import { ExecutionResult, parse, validate, specifiedRules } from 'graphql' -import { normalizedExecutor } from '@graphql-tools/executor' +/* eslint-disable @typescript-eslint/no-explicit-any */ +import { ExecutionResult, parse, specifiedRules, validate } from 'graphql' import { - GetEnvelopedFn, envelop, + GetEnvelopedFn, + PromiseOrValue, useEngine, useExtendContext, - PromiseOrValue, useMaskedErrors, } from '@envelop/core' -import { useValidationCache, ValidationCache } from '@envelop/validation-cache' import { ParserCacheOptions, useParserCache } from '@envelop/parser-cache' +import { useValidationCache, ValidationCache } from '@envelop/validation-cache' +import { normalizedExecutor } from '@graphql-tools/executor' +import { createFetch } from '@whatwg-node/fetch' +import { createServerAdapter, ServerAdapter } from '@whatwg-node/server' + +import { handleError } from './error.js' +import { createLogger, LogLevel, YogaLogger } from './logger.js' +import { isGETRequest, parseGETRequest } from './plugins/requestParser/GET.js' import { - YogaInitialContext, - FetchAPI, - GraphQLParams, - YogaMaskedErrorOpts, - MaskError, -} from './types.js' + isPOSTFormUrlEncodedRequest, + parsePOSTFormUrlEncodedRequest, +} from './plugins/requestParser/POSTFormUrlEncoded.js' +import { + isPOSTGraphQLStringRequest, + parsePOSTGraphQLStringRequest, +} from './plugins/requestParser/POSTGraphQLString.js' +import { + isPOSTJsonRequest, + parsePOSTJsonRequest, +} from './plugins/requestParser/POSTJson.js' +import { + isPOSTMultipartRequest, + parsePOSTMultipartRequest, +} from './plugins/requestParser/POSTMultipart.js' +import { useCheckGraphQLQueryParams } from './plugins/requestValidation/useCheckGraphQLQueryParams.js' +import { useCheckMethodForGraphQL } from './plugins/requestValidation/useCheckMethodForGraphQL.js' +import { useHTTPValidationError } from './plugins/requestValidation/useHTTPValidationError.js' +import { useLimitBatching } from './plugins/requestValidation/useLimitBatching.js' +import { usePreventMutationViaGET } from './plugins/requestValidation/usePreventMutationViaGET.js' import { OnParamsHook, OnRequestHook, @@ -28,48 +49,29 @@ import { RequestParser, ResultProcessorInput, } from './plugins/types.js' -import { createFetch } from '@whatwg-node/fetch' -import { ServerAdapter, createServerAdapter } from '@whatwg-node/server' -import { - processRequest as processGraphQLParams, - processResult, -} from './process-request.js' -import { createLogger, LogLevel, YogaLogger } from './logger.js' import { CORSPluginOptions, useCORS } from './plugins/useCORS.js' -import { useHealthCheck } from './plugins/useHealthCheck.js' import { GraphiQLOptions, GraphiQLOptionsOrFactory, useGraphiQL, } from './plugins/useGraphiQL.js' +import { useHealthCheck } from './plugins/useHealthCheck.js' import { useRequestParser } from './plugins/useRequestParser.js' -import { isGETRequest, parseGETRequest } from './plugins/requestParser/GET.js' -import { - isPOSTJsonRequest, - parsePOSTJsonRequest, -} from './plugins/requestParser/POSTJson.js' -import { - isPOSTMultipartRequest, - parsePOSTMultipartRequest, -} from './plugins/requestParser/POSTMultipart.js' -import { - isPOSTGraphQLStringRequest, - parsePOSTGraphQLStringRequest, -} from './plugins/requestParser/POSTGraphQLString.js' import { useResultProcessors } from './plugins/useResultProcessor.js' -import { - isPOSTFormUrlEncodedRequest, - parsePOSTFormUrlEncodedRequest, -} from './plugins/requestParser/POSTFormUrlEncoded.js' -import { handleError } from './error.js' -import { useCheckMethodForGraphQL } from './plugins/requestValidation/useCheckMethodForGraphQL.js' -import { useCheckGraphQLQueryParams } from './plugins/requestValidation/useCheckGraphQLQueryParams.js' -import { useHTTPValidationError } from './plugins/requestValidation/useHTTPValidationError.js' -import { usePreventMutationViaGET } from './plugins/requestValidation/usePreventMutationViaGET.js' +import { useSchema, YogaSchemaDefinition } from './plugins/useSchema.js' import { useUnhandledRoute } from './plugins/useUnhandledRoute.js' +import { + processRequest as processGraphQLParams, + processResult, +} from './process-request.js' +import { + FetchAPI, + GraphQLParams, + MaskError, + YogaInitialContext, + YogaMaskedErrorOpts, +} from './types.js' import { yogaDefaultFormatError } from './utils/yoga-default-format-error.js' -import { useSchema, YogaSchemaDefinition } from './plugins/useSchema.js' -import { useLimitBatching } from './plugins/requestValidation/useLimitBatching.js' /** * Configuration options for the server @@ -281,7 +283,7 @@ export class YogaServer< specifiedRules, }), // Use the schema provided by the user - !!options?.schema && useSchema(options.schema), + Boolean(options?.schema) && useSchema(options!.schema), // Performance things options?.parserCache !== false && @@ -521,9 +523,9 @@ export class YogaServer< this.logger.debug(`Parsing request to extract GraphQL parameters`) if (!requestParser) { - return new this.fetchAPI.Response('Request is not valid', { - status: 400, - statusText: 'Bad Request', + return new this.fetchAPI.Response(null, { + status: 415, + statusText: 'Unsupported Media Type', }) } diff --git a/packages/graphql-yoga/src/types.ts b/packages/graphql-yoga/src/types.ts index 0a80d91ed4..f514346c1d 100644 --- a/packages/graphql-yoga/src/types.ts +++ b/packages/graphql-yoga/src/types.ts @@ -1,3 +1,4 @@ +/* eslint-disable @typescript-eslint/no-explicit-any */ import type { PromiseOrValue } from '@envelop/core' import type { createFetch } from '@whatwg-node/fetch' import type { GraphQLSchema } from 'graphql' diff --git a/packages/graphql-yoga/src/utils/yoga-default-format-error.ts b/packages/graphql-yoga/src/utils/yoga-default-format-error.ts index 9deb93217d..5f22875f9c 100644 --- a/packages/graphql-yoga/src/utils/yoga-default-format-error.ts +++ b/packages/graphql-yoga/src/utils/yoga-default-format-error.ts @@ -1,5 +1,6 @@ -import { createGraphQLError } from '@graphql-tools/utils' import { GraphQLErrorExtensions } from 'graphql' +import { createGraphQLError } from '@graphql-tools/utils' + import { isGraphQLError } from '../error.js' import { MaskError } from '../types.js' diff --git a/packages/graphql-yoga/type-api-check.ts b/packages/graphql-yoga/type-api-check.ts index fbbde40c69..6a94683ca9 100644 --- a/packages/graphql-yoga/type-api-check.ts +++ b/packages/graphql-yoga/type-api-check.ts @@ -1,10 +1,10 @@ /* eslint-disable @typescript-eslint/ban-types */ +import { ClientRequest } from 'node:http' import { IResolvers } from '@graphql-tools/utils' -import { ClientRequest } from 'http' - -import { createYoga, createSchema, YogaInitialContext } from './src/index.js' import type { GraphQLSchema } from 'graphql' +import { createSchema, createYoga, YogaInitialContext } from './src/index.js' + // eslint-disable-next-line @typescript-eslint/no-explicit-any const schema: GraphQLSchema = null as any // eslint-disable-next-line @typescript-eslint/no-explicit-any diff --git a/packages/plugins/apollo-inline-trace/__tests__/apollo-inline-trace.spec.ts b/packages/plugins/apollo-inline-trace/__tests__/apollo-inline-trace.spec.ts index 6d04542595..509e992544 100644 --- a/packages/plugins/apollo-inline-trace/__tests__/apollo-inline-trace.spec.ts +++ b/packages/plugins/apollo-inline-trace/__tests__/apollo-inline-trace.spec.ts @@ -1,6 +1,8 @@ -import { createYoga, createSchema, createGraphQLError } from 'graphql-yoga' -import { useApolloInlineTrace } from '../src/index.js' +/* eslint-disable @typescript-eslint/require-await */ import { Trace } from 'apollo-reporting-protobuf' +import { createGraphQLError, createSchema, createYoga } from 'graphql-yoga' + +import { useApolloInlineTrace } from '../src/index.js' describe('Inline Trace', () => { const schema = createSchema({ diff --git a/packages/plugins/apollo-inline-trace/src/index.ts b/packages/plugins/apollo-inline-trace/src/index.ts index d1578178c0..beca67aefe 100644 --- a/packages/plugins/apollo-inline-trace/src/index.ts +++ b/packages/plugins/apollo-inline-trace/src/index.ts @@ -1,13 +1,13 @@ +import { GraphQLError, ResponsePath } from 'graphql' +import { useOnResolve } from '@envelop/on-resolve' +import { btoa } from '@whatwg-node/fetch' +import ApolloReportingProtobuf from 'apollo-reporting-protobuf' import { + createGraphQLError, isAsyncIterable, Plugin, YogaInitialContext, - createGraphQLError, } from 'graphql-yoga' -import { GraphQLError, ResponsePath } from 'graphql' -import ApolloReportingProtobuf from 'apollo-reporting-protobuf' -import { btoa } from '@whatwg-node/fetch' -import { useOnResolve } from '@envelop/on-resolve' interface ApolloInlineTraceContext { startHrTime: [number, number] diff --git a/packages/plugins/apq/__tests__/apq.spec.ts b/packages/plugins/apq/__tests__/apq.spec.ts index 0d5b2152a6..0ea93cd17e 100644 --- a/packages/plugins/apq/__tests__/apq.spec.ts +++ b/packages/plugins/apq/__tests__/apq.spec.ts @@ -1,5 +1,5 @@ -import { createYoga, createSchema } from 'graphql-yoga' import { createInMemoryAPQStore, useAPQ } from '@graphql-yoga/plugin-apq' +import { createSchema, createYoga } from 'graphql-yoga' const schema = createSchema({ typeDefs: /* GraphQL */ ` diff --git a/packages/plugins/apq/src/index.ts b/packages/plugins/apq/src/index.ts index b6683907ec..3e362637ad 100644 --- a/packages/plugins/apq/src/index.ts +++ b/packages/plugins/apq/src/index.ts @@ -1,4 +1,4 @@ -import { Plugin, PromiseOrValue, createGraphQLError } from 'graphql-yoga' +import { createGraphQLError, Plugin, PromiseOrValue } from 'graphql-yoga' import { lru } from 'tiny-lru' export async function hashSHA256( @@ -27,7 +27,7 @@ export interface APQStoreOptions { export function createInMemoryAPQStore( options: APQStoreOptions = {}, ): APQStore { - return lru(options.max ?? 1000, options.ttl ?? 36000) + return lru(options.max ?? 1000, options.ttl ?? 36_000) } export interface APQOptions { @@ -40,6 +40,7 @@ export interface APQOptions { export interface APQStore { get(key: string): PromiseOrValue + // eslint-disable-next-line @typescript-eslint/no-explicit-any set(key: string, query: string): PromiseOrValue } @@ -48,23 +49,27 @@ export interface APQExtension { sha256Hash: string } -function decodeAPQExtension( - input: Record | null | undefined, -): null | APQExtension { - if ( +function isAPQExtension(input: unknown): input is APQExtension { + return ( input != null && typeof input === 'object' && + 'version' in input && input?.version === 1 && + 'sha256Hash' in input && typeof input?.sha256Hash === 'string' - ) { + ) +} + +function decodeAPQExtension( + input: Record | null | undefined, +): null | APQExtension { + if (isAPQExtension(input)) { return input as APQExtension } return null } -export function useAPQ>( - options: APQOptions = {}, -): Plugin { +export function useAPQ(options: APQOptions = {}): Plugin { const { store = createInMemoryAPQStore(), hash = hashSHA256 } = options return { diff --git a/packages/plugins/defer-stream/__integration-tests__/defer-stream.spec.ts b/packages/plugins/defer-stream/__integration-tests__/defer-stream.spec.ts index f624d6e3f5..dcd1511e7d 100644 --- a/packages/plugins/defer-stream/__integration-tests__/defer-stream.spec.ts +++ b/packages/plugins/defer-stream/__integration-tests__/defer-stream.spec.ts @@ -1,9 +1,10 @@ +import { createServer, get, IncomingMessage } from 'node:http' +import { AddressInfo } from 'node:net' +import { useDeferStream } from '@graphql-yoga/plugin-defer-stream' +import { AbortController, fetch } from '@whatwg-node/fetch' import { createSchema, createYoga } from 'graphql-yoga' -import { createServer } from 'node:http' + import { createPushPullAsyncIterable } from '../__tests__/push-pull-async-iterable.js' -import { useDeferStream } from '@graphql-yoga/plugin-defer-stream' -import { fetch, AbortController } from '@whatwg-node/fetch' -import { get, IncomingMessage } from 'http' it('correctly deals with the source upon aborted requests', async () => { const { source, push, terminate } = createPushPullAsyncIterable() @@ -34,7 +35,7 @@ it('correctly deals with the source upon aborted requests', async () => { }) }) - const port = (server.address() as any)?.port ?? null + const port = (server.address() as AddressInfo)?.port ?? null if (port === null) { throw new Error('Missing port...') } @@ -96,7 +97,7 @@ it('correctly deals with the source upon aborted requests', async () => { it('memory/cleanup leak by source that never publishes a value', async () => { let sourceGotCleanedUp = false let i = 1 - let interval: any + let interval: NodeJS.Timer const controller = new AbortController() const noop = new Promise<{ done: true; value: undefined }>(() => undefined) @@ -144,7 +145,7 @@ it('memory/cleanup leak by source that never publishes a value', async () => { }) }) - const port = (server.address() as any)?.port ?? null + const port = (server.address() as AddressInfo)?.port ?? null if (port === null) { throw new Error('Missing port...') } @@ -180,8 +181,8 @@ it('memory/cleanup leak by source that never publishes a value', async () => { ---" `) } - } catch (err: any) { - expect(err.message).toContain('aborted') + } catch (err: unknown) { + expect((err as Error).message).toContain('aborted') } // Wait a bit - just to make sure the time is cleaned up for sure... diff --git a/packages/plugins/defer-stream/__tests__/defer-stream.spec.ts b/packages/plugins/defer-stream/__tests__/defer-stream.spec.ts index 0c99523204..1043156287 100644 --- a/packages/plugins/defer-stream/__tests__/defer-stream.spec.ts +++ b/packages/plugins/defer-stream/__tests__/defer-stream.spec.ts @@ -1,11 +1,12 @@ -import { createSchema, createYoga, Repeater } from 'graphql-yoga' -import { useDeferStream } from '@graphql-yoga/plugin-defer-stream' import { GraphQLList, GraphQLObjectType, GraphQLSchema, GraphQLString, } from 'graphql' +import { useDeferStream } from '@graphql-yoga/plugin-defer-stream' +import { createSchema, createYoga, Repeater } from 'graphql-yoga' + import { createPushPullAsyncIterable } from './push-pull-async-iterable.js' function multipartStream(source: ReadableStream) { @@ -236,7 +237,7 @@ describe('Defer/Stream', () => { terminate() push('D') } else if (counter === 4) { - expect(toStr(chunk)).toBe(`{"hasNext":false}`) + expect(part).toBe(`{"hasNext":false}`) } else { throw new Error("LOL, this shouldn't happen.") } diff --git a/packages/plugins/defer-stream/__tests__/validations/defer-stream-directive-label.spec.ts b/packages/plugins/defer-stream/__tests__/validations/defer-stream-directive-label.spec.ts index c4250bdb1f..dcd1122574 100644 --- a/packages/plugins/defer-stream/__tests__/validations/defer-stream-directive-label.spec.ts +++ b/packages/plugins/defer-stream/__tests__/validations/defer-stream-directive-label.spec.ts @@ -1,5 +1,4 @@ import { DeferStreamDirectiveLabelRule } from '../../src/validations/defer-stream-directive-label.js' - import { expectValidationErrors } from './harness.js' function expectErrors(queryStr: string) { diff --git a/packages/plugins/defer-stream/__tests__/validations/defer-stream-directive-on-root-field.spec.ts b/packages/plugins/defer-stream/__tests__/validations/defer-stream-directive-on-root-field.spec.ts index dc09550a44..a57ae2d40c 100644 --- a/packages/plugins/defer-stream/__tests__/validations/defer-stream-directive-on-root-field.spec.ts +++ b/packages/plugins/defer-stream/__tests__/validations/defer-stream-directive-on-root-field.spec.ts @@ -1,4 +1,5 @@ import { buildSchema } from 'graphql' + import { DeferStreamDirectiveOnRootFieldRule } from '../../src/validations/defer-stream-directive-on-root-field.js' import { expectValidationErrorsWithSchema } from './harness.js' diff --git a/packages/plugins/defer-stream/__tests__/validations/harness.ts b/packages/plugins/defer-stream/__tests__/validations/harness.ts index 3b0730f10e..6dcec59e32 100644 --- a/packages/plugins/defer-stream/__tests__/validations/harness.ts +++ b/packages/plugins/defer-stream/__tests__/validations/harness.ts @@ -1,7 +1,7 @@ import { - parse, - GraphQLSchema, buildSchema, + GraphQLSchema, + parse, validate, ValidationRule, } from 'graphql' @@ -59,8 +59,8 @@ export function expectJSON(actual: unknown) { return { toDeepEqual(expected: unknown) { - const expectedJSON = toJSONDeep(expected) - expect(actualJSON).toMatchObject(expectedJSON as any) + const expectedJSON = toJSONDeep(expected) as Record + expect(actualJSON).toMatchObject(expectedJSON) }, toDeepNestedProperty(path: string, expected: unknown) { const expectedJSON = toJSONDeep(expected) @@ -189,16 +189,13 @@ export function expectValidationErrorsWithSchema( schema: GraphQLSchema, rule: ValidationRule, queryStr: string, -): any { +) { const doc = parse(queryStr) const errors = validate(schema, doc, [rule]) return expectJSON(errors) } -export function expectValidationErrors( - rule: ValidationRule, - queryStr: string, -): any { +export function expectValidationErrors(rule: ValidationRule, queryStr: string) { return expectValidationErrorsWithSchema(testSchema, rule, queryStr) } @@ -206,7 +203,7 @@ export function expectSDLValidationErrors( schema: Maybe, rule: SDLValidationRule, sdlStr: string, -): any { +) { const doc = parse(sdlStr) const errors = validateSDL(doc, schema, [rule]) return expectJSON(errors) diff --git a/packages/plugins/defer-stream/__tests__/validations/overlapping-fields-can-be-merged.spec.ts b/packages/plugins/defer-stream/__tests__/validations/overlapping-fields-can-be-merged.spec.ts index a4d6b040ba..009636a5e8 100644 --- a/packages/plugins/defer-stream/__tests__/validations/overlapping-fields-can-be-merged.spec.ts +++ b/packages/plugins/defer-stream/__tests__/validations/overlapping-fields-can-be-merged.spec.ts @@ -1,4 +1,5 @@ import { buildSchema, GraphQLSchema } from 'graphql' + import { OverlappingFieldsCanBeMergedRule } from '../../src/validations/overlapping-fields-can-be-merged.js' import { expectValidationErrors, diff --git a/packages/plugins/defer-stream/src/index.ts b/packages/plugins/defer-stream/src/index.ts index 449c4f9106..1461fbfefa 100644 --- a/packages/plugins/defer-stream/src/index.ts +++ b/packages/plugins/defer-stream/src/index.ts @@ -1,16 +1,17 @@ -import { Plugin } from 'graphql-yoga' -import { GraphQLSchema, GraphQLDirective, ValidationRule } from 'graphql' +import { GraphQLDirective, GraphQLSchema, ValidationRule } from 'graphql' import { GraphQLDeferDirective, GraphQLStreamDirective, } from '@graphql-tools/utils' +import { Plugin } from 'graphql-yoga' + import { DeferStreamDirectiveLabelRule } from './validations/defer-stream-directive-label.js' import { DeferStreamDirectiveOnRootFieldRule } from './validations/defer-stream-directive-on-root-field.js' import { OverlappingFieldsCanBeMergedRule } from './validations/overlapping-fields-can-be-merged.js' import { StreamDirectiveOnListFieldRule } from './validations/stream-directive-on-list-field.js' export function useDeferStream< - TPluginContext extends Record, + TPluginContext extends Record, >(): Plugin { return { onSchemaChange: ({ diff --git a/packages/plugins/defer-stream/src/validations/defer-stream-directive-label.ts b/packages/plugins/defer-stream/src/validations/defer-stream-directive-label.ts index 61adaddab9..76e45ba314 100644 --- a/packages/plugins/defer-stream/src/validations/defer-stream-directive-label.ts +++ b/packages/plugins/defer-stream/src/validations/defer-stream-directive-label.ts @@ -1,4 +1,4 @@ -import { Kind, ASTVisitor, ValidationContext } from 'graphql' +import { ASTVisitor, Kind, ValidationContext } from 'graphql' import { createGraphQLError, GraphQLDeferDirective, diff --git a/packages/plugins/defer-stream/src/validations/overlapping-fields-can-be-merged.ts b/packages/plugins/defer-stream/src/validations/overlapping-fields-can-be-merged.ts index 38409d9a2a..5eb8085008 100644 --- a/packages/plugins/defer-stream/src/validations/overlapping-fields-can-be-merged.ts +++ b/packages/plugins/defer-stream/src/validations/overlapping-fields-can-be-merged.ts @@ -1,27 +1,27 @@ import { + ASTVisitor, DirectiveNode, FieldNode, FragmentDefinitionNode, - ObjectValueNode, - SelectionSetNode, - Kind, - print, - ASTVisitor, + getNamedType, GraphQLField, GraphQLNamedType, GraphQLOutputType, - getNamedType, isInterfaceType, isLeafType, isListType, isNonNullType, isObjectType, + Kind, + ObjectFieldNode, + ObjectValueNode, + print, + SelectionSetNode, typeFromAST, ValidationContext, - ObjectFieldNode, ValueNode, } from 'graphql' -import { inspect, Maybe, createGraphQLError } from '@graphql-tools/utils' +import { createGraphQLError, inspect, Maybe } from '@graphql-tools/utils' /** * Returns a number indicating whether a reference string comes before, or after, diff --git a/packages/plugins/defer-stream/src/validations/stream-directive-on-list-field.ts b/packages/plugins/defer-stream/src/validations/stream-directive-on-list-field.ts index c04fc99599..8f5271b35a 100644 --- a/packages/plugins/defer-stream/src/validations/stream-directive-on-list-field.ts +++ b/packages/plugins/defer-stream/src/validations/stream-directive-on-list-field.ts @@ -1,9 +1,9 @@ import { - ValidationContext, + ASTVisitor, + DirectiveNode, isListType, isWrappingType, - DirectiveNode, - ASTVisitor, + ValidationContext, } from 'graphql' import { createGraphQLError, diff --git a/packages/plugins/disable-introspection/__tests__/disable-introspection.spec.ts b/packages/plugins/disable-introspection/__tests__/disable-introspection.spec.ts index f6b8cabd78..a11511033c 100644 --- a/packages/plugins/disable-introspection/__tests__/disable-introspection.spec.ts +++ b/packages/plugins/disable-introspection/__tests__/disable-introspection.spec.ts @@ -1,5 +1,5 @@ import { useDisableIntrospection } from '@graphql-yoga/plugin-disable-introspection' -import { createYoga, createSchema } from 'graphql-yoga' +import { createSchema, createYoga } from 'graphql-yoga' describe('disable introspection', () => { test('can disable introspection', async () => { diff --git a/packages/plugins/disable-introspection/src/index.ts b/packages/plugins/disable-introspection/src/index.ts index 0a96d7ea8e..1544313bea 100644 --- a/packages/plugins/disable-introspection/src/index.ts +++ b/packages/plugins/disable-introspection/src/index.ts @@ -1,5 +1,5 @@ -import type { Plugin, PromiseOrValue } from 'graphql-yoga' import { NoSchemaIntrospectionCustomRule } from 'graphql' +import type { Plugin, PromiseOrValue } from 'graphql-yoga' type UseDisableIntrospectionArgs = { isDisabled?: (request: Request) => PromiseOrValue diff --git a/packages/plugins/persisted-operations/__tests__/persisted-operations.spec.ts b/packages/plugins/persisted-operations/__tests__/persisted-operations.spec.ts index 1584308e59..c056eaeb44 100644 --- a/packages/plugins/persisted-operations/__tests__/persisted-operations.spec.ts +++ b/packages/plugins/persisted-operations/__tests__/persisted-operations.spec.ts @@ -1,5 +1,5 @@ -import { createYoga, createSchema, GraphQLParams } from 'graphql-yoga' import { usePersistedOperations } from '@graphql-yoga/plugin-persisted-operations' +import { createSchema, createYoga, GraphQLParams } from 'graphql-yoga' const schema = createSchema({ typeDefs: /* GraphQL */ ` diff --git a/packages/plugins/persisted-operations/src/index.ts b/packages/plugins/persisted-operations/src/index.ts index cf3e90966f..87c36fb240 100644 --- a/packages/plugins/persisted-operations/src/index.ts +++ b/packages/plugins/persisted-operations/src/index.ts @@ -1,8 +1,8 @@ import { + createGraphQLError, GraphQLParams, Plugin, PromiseOrValue, - createGraphQLError, } from 'graphql-yoga' export type ExtractPersistedOperationId = ( diff --git a/packages/plugins/prometheus/src/index.ts b/packages/plugins/prometheus/src/index.ts index 9e0057a503..ab54eddb11 100644 --- a/packages/plugins/prometheus/src/index.ts +++ b/packages/plugins/prometheus/src/index.ts @@ -1,9 +1,9 @@ import { - usePrometheus as useEnvelopPrometheus, PrometheusTracingPluginConfig as EnvelopPrometheusTracingPluginConfig, + usePrometheus as useEnvelopPrometheus, } from '@envelop/prometheus' -import { Histogram, register as defaultRegistry } from 'prom-client' import { Plugin } from 'graphql-yoga' +import { Histogram, register as defaultRegistry } from 'prom-client' export interface PrometheusTracingPluginConfig extends EnvelopPrometheusTracingPluginConfig { @@ -23,9 +23,7 @@ function headersToObj(headers: Headers) { return obj } -export function usePrometheus( - options: PrometheusTracingPluginConfig, -): Plugin { +export function usePrometheus(options: PrometheusTracingPluginConfig): Plugin { const endpoint = options.endpoint || '/metrics' const registry = options.registry || defaultRegistry @@ -47,7 +45,7 @@ export function usePrometheus( return { onPluginInit({ addPlugin }) { - addPlugin(useEnvelopPrometheus({ ...options, registry })) + addPlugin(useEnvelopPrometheus({ ...options, registry }) as Plugin) }, async onRequest({ request, url, fetchAPI, endResponse }) { startByRequest.set(request, Date.now()) diff --git a/packages/plugins/response-cache/__tests__/response-cache.spec.ts b/packages/plugins/response-cache/__tests__/response-cache.spec.ts index 8fc38a20a2..6949daa15e 100644 --- a/packages/plugins/response-cache/__tests__/response-cache.spec.ts +++ b/packages/plugins/response-cache/__tests__/response-cache.spec.ts @@ -1,5 +1,5 @@ -import { createYoga, createSchema } from 'graphql-yoga' import { useResponseCache } from '@graphql-yoga/plugin-response-cache' +import { createSchema, createYoga } from 'graphql-yoga' const schema = createSchema({ typeDefs: /* GraphQL */ ` diff --git a/packages/plugins/sofa/src/index.ts b/packages/plugins/sofa/src/index.ts index 9599eeee66..aa557e56c0 100644 --- a/packages/plugins/sofa/src/index.ts +++ b/packages/plugins/sofa/src/index.ts @@ -1,7 +1,8 @@ -import { OpenAPI, useSofa as createSofaHandler } from 'sofa-api' import { Plugin, YogaInitialContext, YogaServerInstance } from 'graphql-yoga' -import { SofaHandler } from './types.js' +import { OpenAPI, useSofa as createSofaHandler } from 'sofa-api' + import { getSwaggerUIHTMLForSofa } from './swagger-ui.js' +import { SofaHandler } from './types.js' export { OpenAPI } from 'sofa-api' @@ -69,14 +70,22 @@ export function useSofaWithSwaggerUI( export function useSofa(config: SofaPluginConfig): Plugin { let sofaHandler: SofaHandler - let getEnveloped: YogaServerInstance['getEnveloped'] + let getEnveloped: YogaServerInstance< + Record, + Record + >['getEnveloped'] const envelopedByContext = new WeakMap< - any, - ReturnType['getEnveloped']> + YogaInitialContext, + ReturnType< + YogaServerInstance< + Record, + Record + >['getEnveloped'] + > >() - const requestByContext = new WeakMap() + const requestByContext = new WeakMap() return { onYogaInit({ yoga }) { getEnveloped = yoga.getEnveloped @@ -89,18 +98,22 @@ export function useSofa(config: SofaPluginConfig): Plugin { const enveloped = getEnveloped(serverContext) const request = requestByContext.get(serverContext) const contextValue = await enveloped.contextFactory({ request }) - envelopedByContext.set(contextValue, enveloped) + envelopedByContext.set(contextValue as YogaInitialContext, enveloped) return contextValue }, - execute(args: any) { - const enveloped = envelopedByContext.get(args.contextValue) + execute(args) { + const enveloped = envelopedByContext.get( + args.contextValue as YogaInitialContext, + ) if (!enveloped) { throw new TypeError('Illegal invocation.') } return enveloped.execute(args) }, - subscribe(args: any) { - const enveloped = envelopedByContext.get(args.contextValue) + subscribe(args) { + const enveloped = envelopedByContext.get( + args.contextValue as YogaInitialContext, + ) if (!enveloped) { throw new TypeError('Illegal invocation.') } @@ -109,7 +122,7 @@ export function useSofa(config: SofaPluginConfig): Plugin { }) }, async onRequest({ request, serverContext, endResponse }) { - requestByContext.set(serverContext, request) + requestByContext.set(serverContext as YogaInitialContext, request) const response = await sofaHandler.handle(request, serverContext) if (response) { endResponse(response) diff --git a/packages/plugins/sofa/src/swagger-ui.ts b/packages/plugins/sofa/src/swagger-ui.ts index 9adddea82e..79f2979bad 100644 --- a/packages/plugins/sofa/src/swagger-ui.ts +++ b/packages/plugins/sofa/src/swagger-ui.ts @@ -1,4 +1,5 @@ import { memoize1 } from '@graphql-tools/utils' + import { OpenAPIInstance } from './types.js' export const getSwaggerUIHTMLForSofa = memoize1( diff --git a/packages/render-graphiql/src/index.ts b/packages/render-graphiql/src/index.ts index b85feb57d9..87ca7219e9 100644 --- a/packages/render-graphiql/src/index.ts +++ b/packages/render-graphiql/src/index.ts @@ -1,5 +1,6 @@ import type { GraphiQLOptions } from 'graphql-yoga' -import { js, css } from './graphiql.js' + +import { css, js } from './graphiql.js' export const renderGraphiQL = (opts?: GraphiQLOptions) => /* HTML */ ` diff --git a/packages/subscription/package.json b/packages/subscription/package.json index 84598d708a..e23c35e09b 100644 --- a/packages/subscription/package.json +++ b/packages/subscription/package.json @@ -69,6 +69,7 @@ "sideEffects": true, "devDependencies": { "@types/ioredis-mock": "8.2.0", - "ioredis-mock": "8.2.2" + "ioredis-mock": "8.2.2", + "@graphql-yoga/redis-event-target": "1.0.0" } } diff --git a/packages/subscription/src/create-pub-sub.ts b/packages/subscription/src/create-pub-sub.ts index e5e8927f58..ad3e22c6eb 100644 --- a/packages/subscription/src/create-pub-sub.ts +++ b/packages/subscription/src/create-pub-sub.ts @@ -1,5 +1,5 @@ -import { Repeater } from '@repeaterjs/repeater' import type { TypedEventTarget } from '@graphql-yoga/typed-event-target' +import { Repeater } from '@repeaterjs/repeater' import { CustomEvent, EventTarget } from '@whatwg-node/events' type PubSubPublishArgsByKey = { diff --git a/packages/subscription/src/createPubSub.spec.ts b/packages/subscription/src/createPubSub.spec.ts index d6ffc29f5c..c0482838f3 100644 --- a/packages/subscription/src/createPubSub.spec.ts +++ b/packages/subscription/src/createPubSub.spec.ts @@ -1,7 +1,8 @@ -import Redis from 'ioredis-mock' import { createRedisEventTarget } from '@graphql-yoga/redis-event-target' -import { createPubSub } from './create-pub-sub.js' import { EventTarget } from '@whatwg-node/events' +import Redis from 'ioredis-mock' + +import { createPubSub } from './create-pub-sub.js' async function collectAsyncIterableValues( asyncIterable: AsyncIterable, diff --git a/packages/subscription/src/index.ts b/packages/subscription/src/index.ts index 2d0fb492bc..4f99738307 100644 --- a/packages/subscription/src/index.ts +++ b/packages/subscription/src/index.ts @@ -1,10 +1,10 @@ -export { Repeater } from '@repeaterjs/repeater' -export { createPubSub } from './create-pub-sub.js' export type { - PubSubEventTarget, - PubSubEvent, PubSub, + PubSubEvent, + PubSubEventTarget, } from './create-pub-sub.js' -export { map } from './operator/map.js' +export { createPubSub } from './create-pub-sub.js' export { filter } from './operator/filter.js' +export { map } from './operator/map.js' export { pipe } from './utils/pipe.js' +export { Repeater } from '@repeaterjs/repeater' diff --git a/packages/subscription/src/operator/filter.spec.ts b/packages/subscription/src/operator/filter.spec.ts index c99e16cede..1987ee751f 100644 --- a/packages/subscription/src/operator/filter.spec.ts +++ b/packages/subscription/src/operator/filter.spec.ts @@ -12,6 +12,7 @@ async function collectAsyncIterableValues( describe('filter', () => { it('filters source stream', async () => { + // eslint-disable-next-line @typescript-eslint/require-await async function* source() { yield 1 yield 2 diff --git a/packages/subscription/src/operator/map.spec.ts b/packages/subscription/src/operator/map.spec.ts index b987d89f00..6bb30bda1a 100644 --- a/packages/subscription/src/operator/map.spec.ts +++ b/packages/subscription/src/operator/map.spec.ts @@ -12,6 +12,7 @@ async function collectAsyncIterableValues( describe('map', () => { it('maps source stream', async () => { + // eslint-disable-next-line @typescript-eslint/require-await async function* source() { yield 1 yield 2 diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index ccf4914974..3590c5e61c 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -769,6 +769,7 @@ importers: '@apollo/client': 3.7.2 '@graphql-tools/executor-apollo-link': 0.0.3 '@graphql-tools/executor-http': 0.0.4 + graphql-yoga: 3.1.2 tslib: ^2.3.1 dependencies: '@graphql-tools/executor-apollo-link': 0.0.3_@apollo+client@3.7.2 @@ -776,6 +777,7 @@ importers: tslib: 2.4.0 devDependencies: '@apollo/client': 3.7.2 + graphql-yoga: link:../../graphql-yoga publishDirectory: dist packages/client/urql-exchange: @@ -783,6 +785,7 @@ importers: '@graphql-tools/executor-http': 0.0.4 '@graphql-tools/executor-urql-exchange': 0.0.3 '@urql/core': 3.0.5 + graphql-yoga: 3.1.2 tslib: ^2.4.0 wonka: 6.1.2 dependencies: @@ -791,6 +794,7 @@ importers: tslib: 2.4.0 devDependencies: '@urql/core': 3.0.5 + graphql-yoga: link:../../graphql-yoga wonka: 6.1.2 publishDirectory: dist @@ -874,6 +878,7 @@ importers: '@graphql-tools/executor': 0.0.9 '@graphql-tools/schema': ^9.0.0 '@graphql-tools/utils': ^9.0.1 + '@graphql-yoga/render-graphiql': 3.1.2 '@graphql-yoga/subscription': ^3.0.0 '@jest/globals': ^29.2.1 '@n1ru4l/in-memory-live-query-store': 0.10.0 @@ -904,6 +909,7 @@ importers: devDependencies: '@envelop/disable-introspection': 4.0.4_a6sekiasy2tqr6d5gj7n2wtjli '@envelop/live-query': 5.0.4_a6sekiasy2tqr6d5gj7n2wtjli + '@graphql-yoga/render-graphiql': link:../render-graphiql '@jest/globals': 29.2.1 '@n1ru4l/in-memory-live-query-store': 0.10.0_graphql@16.6.0 '@repeaterjs/repeater': 3.0.4 @@ -1009,6 +1015,7 @@ importers: packages/subscription: specifiers: + '@graphql-yoga/redis-event-target': 1.0.0 '@graphql-yoga/typed-event-target': ^1.0.0 '@repeaterjs/repeater': ^3.0.4 '@types/ioredis-mock': 8.2.0 @@ -1021,6 +1028,7 @@ importers: '@whatwg-node/events': 0.0.2 tslib: 2.4.0 devDependencies: + '@graphql-yoga/redis-event-target': link:../event-target/redis-event-target '@types/ioredis-mock': 8.2.0 ioredis-mock: 8.2.2 publishDirectory: dist diff --git a/website/src/components/latest-version-notice.tsx b/website/src/components/latest-version-notice.tsx index bbb7fe2f44..c7de4ccf97 100644 --- a/website/src/components/latest-version-notice.tsx +++ b/website/src/components/latest-version-notice.tsx @@ -1,6 +1,6 @@ import * as React from 'react' -import { Callout } from '@theguild/components' import Link from 'next/link' +import { Callout } from '@theguild/components' export function LatestVersionNotice() { return ( diff --git a/website/src/index-page.tsx b/website/src/index-page.tsx index abe34b9a3c..c298a18e17 100644 --- a/website/src/index-page.tsx +++ b/website/src/index-page.tsx @@ -1,24 +1,23 @@ import { ReactElement, ReactNode } from 'react' +import { useRouter } from 'next/router' +import { Anchor, Image } from '@theguild/components' import clsx from 'clsx' -import { FiGithub, FiUpload } from 'react-icons/fi' -import { SiApollographql } from 'react-icons/si' -import { TbPlugConnected } from 'react-icons/tb' +import ecosystemImage from 'public/assets/ecosystem.svg' +import httpImage from 'public/assets/http.svg' +import subscriptionsImage from 'public/assets/subscriptions.svg' import { AiFillAppstore } from 'react-icons/ai' -import { GiHealthNormal } from 'react-icons/gi' -import { GrGraphQl } from 'react-icons/gr' import { BsCheckCircle, BsFillPlayFill, BsFillSafeFill, BsFillStopwatchFill, } from 'react-icons/bs' +import { FiGithub, FiUpload } from 'react-icons/fi' +import { GiHealthNormal } from 'react-icons/gi' +import { GrGraphQl } from 'react-icons/gr' import { MdCached, MdError } from 'react-icons/md' -import { Anchor, Image } from '@theguild/components' - -import httpImage from 'public/assets/http.svg' -import subscriptionsImage from 'public/assets/subscriptions.svg' -import ecosystemImage from 'public/assets/ecosystem.svg' -import { useRouter } from 'next/router' +import { SiApollographql } from 'react-icons/si' +import { TbPlugConnected } from 'react-icons/tb' const gradients: [string, string][] = [ ['#8b5cf6', '#6d28d9'], // violet @@ -468,6 +467,7 @@ function FeatureHighlights({ {icon && (