diff --git a/bun.lockb b/bun.lockb old mode 100644 new mode 100755 index 8d80863d8..a916bca27 Binary files a/bun.lockb and b/bun.lockb differ diff --git a/meta/definitions/graphql.gql b/meta/definitions/graphql.gql index d6a598b2c..f6a5bb081 100644 --- a/meta/definitions/graphql.gql +++ b/meta/definitions/graphql.gql @@ -27,7 +27,7 @@ type Query { """Find one card (using the id and set is deprecated)""" card( - id: ID!, + id: ID, set: String, """The new way to filter""" filters: CardsFilters @@ -35,14 +35,14 @@ type Query { """Find one set (using the id is deprecated)""" set( - id: ID!, + id: ID, """The new way to filter""" filters: SetFilters ): Set """Find one serie (using the id is deprecated)""" serie( - id: ID!, + id: ID, """The new way to filter""" filters: SerieFilters ): Serie diff --git a/server/bun.lockb b/server/bun.lockb old mode 100644 new mode 100755 index c549c9c34..f5a084c38 Binary files a/server/bun.lockb and b/server/bun.lockb differ diff --git a/server/compiler/index.ts b/server/compiler/index.ts index cdb6dfdd0..8bf6c67a6 100644 --- a/server/compiler/index.ts +++ b/server/compiler/index.ts @@ -1,9 +1,8 @@ /* eslint-disable max-statements */ -import { FileFunction } from './compilerInterfaces' import { promises as fs } from 'fs' -import { fetchRemoteFile } from './utils/util' -import { objectValues } from '@dzeio/object-util' import { SupportedLanguages } from '../../interfaces' +import { FileFunction } from './compilerInterfaces' +import { fetchRemoteFile } from './utils/util' const LANGS: Array = ['en', 'fr', 'es', 'it', 'pt', 'de'] diff --git a/server/compiler/utils/util.ts b/server/compiler/utils/util.ts index 25977828a..736859e4c 100644 --- a/server/compiler/utils/util.ts +++ b/server/compiler/utils/util.ts @@ -1,6 +1,5 @@ +import { glob } from 'glob' import { Card, Set } from '../../../interfaces' -import glob from 'glob' -import fetch from 'node-fetch' import * as legals from '../../../meta/legals' interface fileCacheInterface { @@ -18,9 +17,16 @@ const fileCache: fileCacheInterface = {} */ export async function fetchRemoteFile(url: string): Promise { if (!fileCache[url]) { + const signal = new AbortController() + + const finished = setTimeout(() => { + signal.abort() + }, 60 * 1000); + const resp = await fetch(url, { - timeout: 60 * 1000 + signal: signal.signal }) + clearTimeout(finished) fileCache[url] = resp.json() } return fileCache[url] @@ -30,9 +36,7 @@ const globCache: Record> = {} export async function smartGlob(query: string): Promise> { if (!globCache[query]) { - globCache[query] = await new Promise((res) => { - glob(query, (_, matches) => res(matches)) - }) + globCache[query] = await glob(query) } return globCache[query] } diff --git a/server/package.json b/server/package.json index bb92056f7..826d90c71 100644 --- a/server/package.json +++ b/server/package.json @@ -16,19 +16,15 @@ "@tcgdex/sdk": "^2", "apicache": "^1", "express": "^4", - "express-graphql": "^0.12.0", - "graphql": "^15" + "graphql": "^15", + "graphql-http": "^1.22.1", + "ruru": "^2.0.0-beta.11" }, "devDependencies": { "@types/apicache": "^1", "@types/express": "^4", - "@types/glob": "^8", - "@types/node": "^18", - "@types/node-fetch": "^2", - "glob": "^8", - "node-fetch": "^2", - "ts-node": "^10", - "ts-node-dev": "^2", - "typescript": "^4" + "@types/node": "^20", + "glob": "^10", + "typescript": "^5" } } diff --git a/server/src/V2/graphql/index.ts b/server/src/V2/graphql/index.ts index a569be0e6..384a16b78 100644 --- a/server/src/V2/graphql/index.ts +++ b/server/src/V2/graphql/index.ts @@ -1,9 +1,15 @@ import express from 'express' -import { graphqlHTTP } from 'express-graphql' import fs from 'fs' -import { buildSchema, formatError, GraphQLError } from 'graphql' +import { buildSchema, GraphQLError } from 'graphql' +import { createHandler } from 'graphql-http/lib/use/express' +import { type ruruHTML as RuruHTML } from 'ruru/dist/server' +/** @ts-expect-error typing is not correctly mapped (real type at ruru/dist/server.d.ts) */ +import { makeHTMLParts, ruruHTML as tmp } from 'ruru/server' import resolver from './resolver' + +const ruruHTML: typeof RuruHTML = tmp + // Init Express Router const router = express.Router() @@ -14,11 +20,19 @@ const router = express.Router() const schema = buildSchema(fs.readFileSync('./public/v2/graphql.gql', 'utf-8')) // Error Logging for debugging -function graphQLErrorHandle(error: GraphQLError) { +function graphQLErrorHandle(error: Readonly) { if (process.env.NODE_ENV !== 'production') { console.error(error) } - if (error.source) { + if (!('source' in error)) { + const columns = (process?.stdout?.columns ?? 32) - 7 + const dashes = ''.padEnd(columns / 2, '-') + + console.error(`\x1b[91m${dashes} ERROR ${dashes}\x1b[0m`) + console.error('GraphQL Error') + console.error(error.message) + console.error(`\x1b[91m${dashes} ERROR ${dashes}\x1b[0m`) + } else if (error.source) { const columns = (process?.stdout?.columns ?? 32) - 7 const dashes = ''.padEnd(columns / 2, '-') @@ -28,18 +42,24 @@ function graphQLErrorHandle(error: GraphQLError) { console.error(error.source?.body) console.error(`\x1b[91m${dashes} ERROR ${dashes}\x1b[0m`) } - return formatError(error) + return error } -const graphql = graphqlHTTP({ - schema, +const graphql = createHandler({ + schema: schema, rootValue: resolver, - graphiql: true, - customFormatErrorFn: graphQLErrorHandle + formatError: graphQLErrorHandle }) // Add graphql to the route -router.get('/', graphql) +router.get('/', (_, res) => { + res.type('html') + + res.end(ruruHTML({ endpoint: '/v2/graphql' }, { + ...makeHTMLParts(), + titleTag: 'GraphiQL - TCGdex API V2' + })) +}) router.post('/', graphql) export default router