diff --git a/models/graphql/resolvers.ts b/models/graphql/resolvers.ts index 63befa7..e383c1a 100644 --- a/models/graphql/resolvers.ts +++ b/models/graphql/resolvers.ts @@ -861,6 +861,19 @@ export const resolvers = { }), }, + // Field resolvers for statistics types + FileTypeStats: { + id: (stats: any) => stats._id || stats.id, + }, + + PublisherStats: { + id: (stats: any) => stats._id || stats.id, + }, + + IssueStats: { + id: (stats: any) => stats._id || stats.id, + }, + UserPreferences: { id: (prefs: any) => prefs._id.toString(), fieldPreferences: (prefs: any) => { diff --git a/models/graphql/typedef.ts b/models/graphql/typedef.ts index 8dbd774..fd6d439 100644 --- a/models/graphql/typedef.ts +++ b/models/graphql/typedef.ts @@ -133,6 +133,9 @@ export const typeDefs = gql` # Raw sourced metadata (for transparency) sourcedMetadata: SourcedMetadata + # Inferred metadata (from filename parsing) + inferredMetadata: InferredMetadata + # File information rawFileDetails: RawFileDetails @@ -387,6 +390,18 @@ export const typeDefs = gql` subtitle: String } + # Inferred metadata output type + type InferredMetadata { + issue: Issue + } + + type Issue { + name: String + number: Int + year: String + subtitle: String + } + input RawFileDetailsInput { name: String! filePath: String! diff --git a/package-lock.json b/package-lock.json index 1eba8ce..f06ff59 100644 --- a/package-lock.json +++ b/package-lock.json @@ -11,6 +11,11 @@ "@apollo/server": "^4.12.2", "@bluelovers/fast-glob": "https://github.com/rishighan/fast-glob-v2-api.git", "@elastic/elasticsearch": "^8.13.1", + "@graphql-tools/delegate": "^12.0.8", + "@graphql-tools/schema": "^10.0.31", + "@graphql-tools/stitch": "^10.1.12", + "@graphql-tools/utils": "^11.0.0", + "@graphql-tools/wrap": "^11.1.8", "@jorgeferrero/stream-to-buffer": "^2.0.6", "@npcz/magic": "^1.3.14", "@root/walk": "^1.1.0", @@ -56,6 +61,7 @@ "sharp": "^0.33.3", "threetwo-ui-typings": "^1.0.14", "through2": "^4.0.2", + "undici": "^7.22.0", "unrar": "^0.2.0", "xml2js": "^0.6.2" }, @@ -189,6 +195,47 @@ "graphql": "14.x || 15.x || 16.x" } }, + "node_modules/@apollo/server/node_modules/@graphql-tools/merge": { + "version": "8.4.2", + "resolved": "https://registry.npmjs.org/@graphql-tools/merge/-/merge-8.4.2.tgz", + "integrity": "sha512-XbrHAaj8yDuINph+sAfuq3QCZ/tKblrTLOpirK0+CAgNlZUCHs0Fa+xtMUURgwCVThLle1AF7svJCxFizygLsw==", + "license": "MIT", + "dependencies": { + "@graphql-tools/utils": "^9.2.1", + "tslib": "^2.4.0" + }, + "peerDependencies": { + "graphql": "^14.0.0 || ^15.0.0 || ^16.0.0 || ^17.0.0" + } + }, + "node_modules/@apollo/server/node_modules/@graphql-tools/schema": { + "version": "9.0.19", + "resolved": "https://registry.npmjs.org/@graphql-tools/schema/-/schema-9.0.19.tgz", + "integrity": "sha512-oBRPoNBtCkk0zbUsyP4GaIzCt8C0aCI4ycIRUL67KK5pOHljKLBBtGT+Jr6hkzA74C8Gco8bpZPe7aWFjiaK2w==", + "license": "MIT", + "dependencies": { + "@graphql-tools/merge": "^8.4.1", + "@graphql-tools/utils": "^9.2.1", + "tslib": "^2.4.0", + "value-or-promise": "^1.0.12" + }, + "peerDependencies": { + "graphql": "^14.0.0 || ^15.0.0 || ^16.0.0 || ^17.0.0" + } + }, + "node_modules/@apollo/server/node_modules/@graphql-tools/utils": { + "version": "9.2.1", + "resolved": "https://registry.npmjs.org/@graphql-tools/utils/-/utils-9.2.1.tgz", + "integrity": "sha512-WUw506Ql6xzmOORlriNrD6Ugx+HjVgYxt9KCXD9mHAak+eaXSwuGGPyE60hy9xaDEoXKBsG7SkG69ybitaVl6A==", + "license": "MIT", + "dependencies": { + "@graphql-typed-document-node/core": "^3.1.1", + "tslib": "^2.4.0" + }, + "peerDependencies": { + "graphql": "^14.0.0 || ^15.0.0 || ^16.0.0 || ^17.0.0" + } + }, "node_modules/@apollo/server/node_modules/lru-cache": { "version": "7.18.3", "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-7.18.3.tgz", @@ -1735,6 +1782,27 @@ "node": ">=16" } }, + "node_modules/@elastic/transport/node_modules/@fastify/busboy": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/@fastify/busboy/-/busboy-2.1.1.tgz", + "integrity": "sha512-vBZP4NlzfOlerQTnba4aqZoMhE/a9HY7HRqoOPaETQcSQuWEIyZMHGfVu6w9wGtGK5fED5qRs2DteVCjOH60sA==", + "license": "MIT", + "engines": { + "node": ">=14" + } + }, + "node_modules/@elastic/transport/node_modules/undici": { + "version": "5.29.0", + "resolved": "https://registry.npmjs.org/undici/-/undici-5.29.0.tgz", + "integrity": "sha512-raqeBD6NQK4SkWhQzeYKd1KmIG6dllBOTt55Rmkt4HtI9mwdWtJljnrXjAFUBLTSN67HWrOIZ3EPF4kjUw80Bg==", + "license": "MIT", + "dependencies": { + "@fastify/busboy": "^2.0.0" + }, + "engines": { + "node": ">=14.0" + } + }, "node_modules/@emnapi/runtime": { "version": "1.7.1", "resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.7.1.tgz", @@ -1822,43 +1890,174 @@ "node": ">=14" } }, - "node_modules/@graphql-tools/merge": { - "version": "8.4.2", - "resolved": "https://registry.npmjs.org/@graphql-tools/merge/-/merge-8.4.2.tgz", - "integrity": "sha512-XbrHAaj8yDuINph+sAfuq3QCZ/tKblrTLOpirK0+CAgNlZUCHs0Fa+xtMUURgwCVThLle1AF7svJCxFizygLsw==", + "node_modules/@graphql-tools/batch-delegate": { + "version": "10.0.14", + "resolved": "https://registry.npmjs.org/@graphql-tools/batch-delegate/-/batch-delegate-10.0.14.tgz", + "integrity": "sha512-jHp3TLbetZus5GGTU1CC/syfb/hrJc1d+HcZwlh4atjrZaWPWgWNAP033899FNnVPZY4w9A+sOwCVFe1wxKL8w==", "license": "MIT", "dependencies": { - "@graphql-tools/utils": "^9.2.1", + "@graphql-tools/delegate": "^12.0.8", + "@graphql-tools/utils": "^11.0.0", + "@whatwg-node/promise-helpers": "^1.3.2", + "dataloader": "^2.2.3", + "tslib": "^2.8.1" + }, + "engines": { + "node": ">=20.0.0" + }, + "peerDependencies": { + "graphql": "^14.0.0 || ^15.0.0 || ^16.0.0 || ^17.0.0" + } + }, + "node_modules/@graphql-tools/batch-execute": { + "version": "10.0.5", + "resolved": "https://registry.npmjs.org/@graphql-tools/batch-execute/-/batch-execute-10.0.5.tgz", + "integrity": "sha512-dL13tXkfGvAzLq2XfzTKAy9logIcltKYRuPketxdh3Ok3U6PN1HKMCHfrE9cmtAsxD96/8Hlghz5AtM+LRv/ig==", + "license": "MIT", + "dependencies": { + "@graphql-tools/utils": "^11.0.0", + "@whatwg-node/promise-helpers": "^1.3.2", + "dataloader": "^2.2.3", + "tslib": "^2.8.1" + }, + "engines": { + "node": ">=20.0.0" + }, + "peerDependencies": { + "graphql": "^14.0.0 || ^15.0.0 || ^16.0.0 || ^17.0.0" + } + }, + "node_modules/@graphql-tools/delegate": { + "version": "12.0.8", + "resolved": "https://registry.npmjs.org/@graphql-tools/delegate/-/delegate-12.0.8.tgz", + "integrity": "sha512-yltGepWaJ9KsBY3QREJrZUKadhaiT4mO4ZO42hF/vfD2fIIOKZjn99qCSZBJ0YpVbLctPrgWrgDs3WgAl13fsA==", + "license": "MIT", + "dependencies": { + "@graphql-tools/batch-execute": "^10.0.5", + "@graphql-tools/executor": "^1.4.13", + "@graphql-tools/schema": "^10.0.29", + "@graphql-tools/utils": "^11.0.0", + "@repeaterjs/repeater": "^3.0.6", + "@whatwg-node/promise-helpers": "^1.3.2", + "dataloader": "^2.2.3", + "tslib": "^2.8.1" + }, + "engines": { + "node": ">=20.0.0" + }, + "peerDependencies": { + "graphql": "^14.0.0 || ^15.0.0 || ^16.0.0 || ^17.0.0" + } + }, + "node_modules/@graphql-tools/executor": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/@graphql-tools/executor/-/executor-1.5.1.tgz", + "integrity": "sha512-n94Qcu875Mji9GQ52n5UbgOTxlgvFJicBPYD+FRks9HKIQpdNPjkkrKZUYNG51XKa+bf03rxNflm4+wXhoHHrA==", + "license": "MIT", + "dependencies": { + "@graphql-tools/utils": "^11.0.0", + "@graphql-typed-document-node/core": "^3.2.0", + "@repeaterjs/repeater": "^3.0.4", + "@whatwg-node/disposablestack": "^0.0.6", + "@whatwg-node/promise-helpers": "^1.0.0", "tslib": "^2.4.0" }, + "engines": { + "node": ">=16.0.0" + }, + "peerDependencies": { + "graphql": "^14.0.0 || ^15.0.0 || ^16.0.0 || ^17.0.0" + } + }, + "node_modules/@graphql-tools/merge": { + "version": "9.1.7", + "resolved": "https://registry.npmjs.org/@graphql-tools/merge/-/merge-9.1.7.tgz", + "integrity": "sha512-Y5E1vTbTabvcXbkakdFUt4zUIzB1fyaEnVmIWN0l0GMed2gdD01TpZWLUm4RNAxpturvolrb24oGLQrBbPLSoQ==", + "license": "MIT", + "dependencies": { + "@graphql-tools/utils": "^11.0.0", + "tslib": "^2.4.0" + }, + "engines": { + "node": ">=16.0.0" + }, "peerDependencies": { "graphql": "^14.0.0 || ^15.0.0 || ^16.0.0 || ^17.0.0" } }, "node_modules/@graphql-tools/schema": { - "version": "9.0.19", - "resolved": "https://registry.npmjs.org/@graphql-tools/schema/-/schema-9.0.19.tgz", - "integrity": "sha512-oBRPoNBtCkk0zbUsyP4GaIzCt8C0aCI4ycIRUL67KK5pOHljKLBBtGT+Jr6hkzA74C8Gco8bpZPe7aWFjiaK2w==", + "version": "10.0.31", + "resolved": "https://registry.npmjs.org/@graphql-tools/schema/-/schema-10.0.31.tgz", + "integrity": "sha512-ZewRgWhXef6weZ0WiP7/MV47HXiuFbFpiDUVLQl6mgXsWSsGELKFxQsyUCBos60Qqy1JEFAIu3Ns6GGYjGkqkQ==", "license": "MIT", "dependencies": { - "@graphql-tools/merge": "^8.4.1", - "@graphql-tools/utils": "^9.2.1", - "tslib": "^2.4.0", - "value-or-promise": "^1.0.12" + "@graphql-tools/merge": "^9.1.7", + "@graphql-tools/utils": "^11.0.0", + "tslib": "^2.4.0" + }, + "engines": { + "node": ">=16.0.0" + }, + "peerDependencies": { + "graphql": "^14.0.0 || ^15.0.0 || ^16.0.0 || ^17.0.0" + } + }, + "node_modules/@graphql-tools/stitch": { + "version": "10.1.12", + "resolved": "https://registry.npmjs.org/@graphql-tools/stitch/-/stitch-10.1.12.tgz", + "integrity": "sha512-dx5dRDVC2OOBXrXgekCmJh22EXGlMrfESMWaNFJKlypP40BK36bPAlUBpMyM1kwx5BQWwjTKUlSghB1Z5j/PgA==", + "license": "MIT", + "dependencies": { + "@graphql-tools/batch-delegate": "^10.0.14", + "@graphql-tools/delegate": "^12.0.8", + "@graphql-tools/executor": "^1.4.13", + "@graphql-tools/merge": "^9.1.5", + "@graphql-tools/schema": "^10.0.29", + "@graphql-tools/utils": "^11.0.0", + "@graphql-tools/wrap": "^11.1.8", + "@whatwg-node/promise-helpers": "^1.3.2", + "tslib": "^2.8.1" + }, + "engines": { + "node": ">=20.0.0" }, "peerDependencies": { "graphql": "^14.0.0 || ^15.0.0 || ^16.0.0 || ^17.0.0" } }, "node_modules/@graphql-tools/utils": { - "version": "9.2.1", - "resolved": "https://registry.npmjs.org/@graphql-tools/utils/-/utils-9.2.1.tgz", - "integrity": "sha512-WUw506Ql6xzmOORlriNrD6Ugx+HjVgYxt9KCXD9mHAak+eaXSwuGGPyE60hy9xaDEoXKBsG7SkG69ybitaVl6A==", + "version": "11.0.0", + "resolved": "https://registry.npmjs.org/@graphql-tools/utils/-/utils-11.0.0.tgz", + "integrity": "sha512-bM1HeZdXA2C3LSIeLOnH/bcqSgbQgKEDrjxODjqi3y58xai2TkNrtYcQSoWzGbt9VMN1dORGjR7Vem8SPnUFQA==", "license": "MIT", "dependencies": { "@graphql-typed-document-node/core": "^3.1.1", + "@whatwg-node/promise-helpers": "^1.0.0", + "cross-inspect": "1.0.1", "tslib": "^2.4.0" }, + "engines": { + "node": ">=16.0.0" + }, + "peerDependencies": { + "graphql": "^14.0.0 || ^15.0.0 || ^16.0.0 || ^17.0.0" + } + }, + "node_modules/@graphql-tools/wrap": { + "version": "11.1.8", + "resolved": "https://registry.npmjs.org/@graphql-tools/wrap/-/wrap-11.1.8.tgz", + "integrity": "sha512-VnU7K6IDvj7kM9Viz6oAQNc6lV380u7oOG1hYau5pzHB+h1VrTYg/jHXNtWrXwB88lhCgGHjrQCJJt4wz4QdQQ==", + "license": "MIT", + "dependencies": { + "@graphql-tools/delegate": "^12.0.8", + "@graphql-tools/schema": "^10.0.29", + "@graphql-tools/utils": "^11.0.0", + "@whatwg-node/promise-helpers": "^1.3.2", + "tslib": "^2.8.1" + }, + "engines": { + "node": ">=20.0.0" + }, "peerDependencies": { "graphql": "^14.0.0 || ^15.0.0 || ^16.0.0 || ^17.0.0" } @@ -3073,6 +3272,12 @@ "@redis/client": "^1.0.0" } }, + "node_modules/@repeaterjs/repeater": { + "version": "3.0.6", + "resolved": "https://registry.npmjs.org/@repeaterjs/repeater/-/repeater-3.0.6.tgz", + "integrity": "sha512-Javneu5lsuhwNCryN+pXH93VPQ8g0dBX7wItHFgYiwQmzE1sVdg5tWHiOgHywzL2W21XQopa7IwIEnNbmeUJYA==", + "license": "MIT" + }, "node_modules/@root/walk": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/@root/walk/-/walk-1.1.0.tgz", @@ -4266,6 +4471,19 @@ "url": "https://opencollective.com/typescript-eslint" } }, + "node_modules/@whatwg-node/disposablestack": { + "version": "0.0.6", + "resolved": "https://registry.npmjs.org/@whatwg-node/disposablestack/-/disposablestack-0.0.6.tgz", + "integrity": "sha512-LOtTn+JgJvX8WfBVJtF08TGrdjuFzGJc4mkP8EdDI8ADbvO7kiexYep1o8dwnt0okb0jYclCDXF13xU7Ge4zSw==", + "license": "MIT", + "dependencies": { + "@whatwg-node/promise-helpers": "^1.0.0", + "tslib": "^2.6.3" + }, + "engines": { + "node": ">=18.0.0" + } + }, "node_modules/@whatwg-node/promise-helpers": { "version": "1.3.2", "resolved": "https://registry.npmjs.org/@whatwg-node/promise-helpers/-/promise-helpers-1.3.2.tgz", @@ -11147,57 +11365,6 @@ "node": ">=16" } }, - "node_modules/moleculer-apollo-server/node_modules/@graphql-tools/merge": { - "version": "9.1.7", - "resolved": "https://registry.npmjs.org/@graphql-tools/merge/-/merge-9.1.7.tgz", - "integrity": "sha512-Y5E1vTbTabvcXbkakdFUt4zUIzB1fyaEnVmIWN0l0GMed2gdD01TpZWLUm4RNAxpturvolrb24oGLQrBbPLSoQ==", - "license": "MIT", - "dependencies": { - "@graphql-tools/utils": "^11.0.0", - "tslib": "^2.4.0" - }, - "engines": { - "node": ">=16.0.0" - }, - "peerDependencies": { - "graphql": "^14.0.0 || ^15.0.0 || ^16.0.0 || ^17.0.0" - } - }, - "node_modules/moleculer-apollo-server/node_modules/@graphql-tools/schema": { - "version": "10.0.31", - "resolved": "https://registry.npmjs.org/@graphql-tools/schema/-/schema-10.0.31.tgz", - "integrity": "sha512-ZewRgWhXef6weZ0WiP7/MV47HXiuFbFpiDUVLQl6mgXsWSsGELKFxQsyUCBos60Qqy1JEFAIu3Ns6GGYjGkqkQ==", - "license": "MIT", - "dependencies": { - "@graphql-tools/merge": "^9.1.7", - "@graphql-tools/utils": "^11.0.0", - "tslib": "^2.4.0" - }, - "engines": { - "node": ">=16.0.0" - }, - "peerDependencies": { - "graphql": "^14.0.0 || ^15.0.0 || ^16.0.0 || ^17.0.0" - } - }, - "node_modules/moleculer-apollo-server/node_modules/@graphql-tools/utils": { - "version": "11.0.0", - "resolved": "https://registry.npmjs.org/@graphql-tools/utils/-/utils-11.0.0.tgz", - "integrity": "sha512-bM1HeZdXA2C3LSIeLOnH/bcqSgbQgKEDrjxODjqi3y58xai2TkNrtYcQSoWzGbt9VMN1dORGjR7Vem8SPnUFQA==", - "license": "MIT", - "dependencies": { - "@graphql-typed-document-node/core": "^3.1.1", - "@whatwg-node/promise-helpers": "^1.0.0", - "cross-inspect": "1.0.1", - "tslib": "^2.4.0" - }, - "engines": { - "node": ">=16.0.0" - }, - "peerDependencies": { - "graphql": "^14.0.0 || ^15.0.0 || ^16.0.0 || ^17.0.0" - } - }, "node_modules/moleculer-apollo-server/node_modules/body-parser": { "version": "2.2.2", "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-2.2.2.tgz", @@ -17515,23 +17682,12 @@ } }, "node_modules/undici": { - "version": "5.29.0", - "resolved": "https://registry.npmjs.org/undici/-/undici-5.29.0.tgz", - "integrity": "sha512-raqeBD6NQK4SkWhQzeYKd1KmIG6dllBOTt55Rmkt4HtI9mwdWtJljnrXjAFUBLTSN67HWrOIZ3EPF4kjUw80Bg==", + "version": "7.22.0", + "resolved": "https://registry.npmjs.org/undici/-/undici-7.22.0.tgz", + "integrity": "sha512-RqslV2Us5BrllB+JeiZnK4peryVTndy9Dnqq62S3yYRRTj0tFQCwEniUy2167skdGOy3vqRzEvl1Dm4sV2ReDg==", "license": "MIT", - "dependencies": { - "@fastify/busboy": "^2.0.0" - }, "engines": { - "node": ">=14.0" - } - }, - "node_modules/undici/node_modules/@fastify/busboy": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/@fastify/busboy/-/busboy-2.1.1.tgz", - "integrity": "sha512-vBZP4NlzfOlerQTnba4aqZoMhE/a9HY7HRqoOPaETQcSQuWEIyZMHGfVu6w9wGtGK5fED5qRs2DteVCjOH60sA==", - "engines": { - "node": ">=14" + "node": ">=20.18.1" } }, "node_modules/unit-compare": { diff --git a/package.json b/package.json index 830c844..d3a3bf8 100644 --- a/package.json +++ b/package.json @@ -39,10 +39,13 @@ "uuid": "^9.0.0" }, "dependencies": { - "@apollo/server": "^4.12.2", - "moleculer-apollo-server": "^0.4.0", "@bluelovers/fast-glob": "https://github.com/rishighan/fast-glob-v2-api.git", "@elastic/elasticsearch": "^8.13.1", + "@graphql-tools/delegate": "^12.0.8", + "@graphql-tools/schema": "^10.0.31", + "@graphql-tools/stitch": "^10.1.12", + "@graphql-tools/utils": "^11.0.0", + "@graphql-tools/wrap": "^11.1.8", "@jorgeferrero/stream-to-buffer": "^2.0.6", "@npcz/magic": "^1.3.14", "@root/walk": "^1.1.0", @@ -71,6 +74,7 @@ "leven": "^3.1.0", "lodash": "^4.17.21", "mkdirp": "^0.5.5", + "moleculer-apollo-server": "^0.4.0", "moleculer-bullmq": "^3.0.0", "moleculer-db": "^0.8.23", "moleculer-db-adapter-mongoose": "^0.9.2", @@ -87,6 +91,7 @@ "sharp": "^0.33.3", "threetwo-ui-typings": "^1.0.14", "through2": "^4.0.2", + "undici": "^7.22.0", "unrar": "^0.2.0", "xml2js": "^0.6.2" }, diff --git a/services/api.service.ts b/services/api.service.ts index 0a5a510..da1a0b6 100644 --- a/services/api.service.ts +++ b/services/api.service.ts @@ -66,81 +66,8 @@ export default class ApiService extends Service { maxAge: 3600, }, aliases: { - "POST /": async (req: any, res: any) => { - try { - const { query, variables, operationName } = req.body; - const result = await req.$service.broker.call("graphql.query", { - query, - variables, - operationName, - }); - res.setHeader("Content-Type", "application/json"); - res.end(JSON.stringify(result)); - } catch (error: any) { - res.statusCode = 500; - res.setHeader("Content-Type", "application/json"); - res.end( - JSON.stringify({ - errors: [{ message: error.message }], - }) - ); - } - }, - "GET /": async (req: any, res: any) => { - // Support GraphQL Playground or introspection queries via GET - const query = req.$params.query; - const variables = req.$params.variables - ? JSON.parse(req.$params.variables) - : undefined; - const operationName = req.$params.operationName; - - if (query) { - try { - const result = await req.$service.broker.call("graphql.query", { - query, - variables, - operationName, - }); - res.setHeader("Content-Type", "application/json"); - res.end(JSON.stringify(result)); - } catch (error: any) { - res.statusCode = 500; - res.setHeader("Content-Type", "application/json"); - res.end( - JSON.stringify({ - errors: [{ message: error.message }], - }) - ); - } - } else { - // Return GraphQL Playground HTML - res.setHeader("Content-Type", "text/html"); - res.end(` - - -
-