diff --git a/backend/jest.config.cjs b/backend/jest.config.cjs index 8151c9b1a..1cbc054df 100644 --- a/backend/jest.config.cjs +++ b/backend/jest.config.cjs @@ -15,6 +15,7 @@ module.exports = { '!**/build/**', '!**/src/**/?(*.)+(spec|test).ts?(x)', '!**/src/db/**', + '!eslint.config.ts', ], coverageThreshold: { global: { diff --git a/backend/package.json b/backend/package.json index d3d68092f..72ffd3013 100644 --- a/backend/package.json +++ b/backend/package.json @@ -35,8 +35,7 @@ "@aws-sdk/lib-storage": "^3.990.0", "@sentry/node": "^5.30.0", "@types/mime-types": "^3.0.1", - "apollo-server": "~2.14.2", - "apollo-server-express": "^2.14.2", + "@apollo/server": "^4.11.3", "bcryptjs": "~3.0.3", "body-parser": "^1.20.3", "cheerio": "~1.2.0", @@ -44,13 +43,13 @@ "dotenv": "~17.0.1", "email-templates": "^13.0.1", "express": "^4.22.1", - "graphql": "^14.6.0", + "graphql": "^16.11.0", + "graphql-ws": "^5.16.2", "graphql-middleware": "~6.1.35", - "graphql-middleware-sentry": "^3.2.1", "graphql-redis-subscriptions": "^2.7.0", - "graphql-shield": "~7.2.2", - "graphql-subscriptions": "^1.1.0", - "graphql-tag": "~2.10.3", + "graphql-shield": "^7.6.5", + "graphql-subscriptions": "^2.0.0", + "graphql-tag": "^2.12.6", "graphql-upload": "^13.0.0", "helmet": "~8.1.0", "ioredis": "^5.9.3", @@ -59,7 +58,8 @@ "linkify-html": "^4.3.2", "linkifyjs": "^4.3.2", "lodash": "~4.17.23", - "merge-graphql-schemas": "^1.7.8", + "@graphql-tools/load-files": "^7.0.0", + "@graphql-tools/merge": "^9.0.0", "metascraper": "^5.49.19", "metascraper-author": "^5.49.19", "metascraper-date": "^5.49.19", @@ -92,6 +92,8 @@ "tslog": "^4.10.2", "uuid": "~9.0.1", "validator": "^13.15.26", + "subscriptions-transport-ws": "^0.11.0", + "ws": "^8.18.2", "xregexp": "^5.1.2" }, "devDependencies": { @@ -104,7 +106,7 @@ "@types/request": "^2.48.13", "@types/slug": "^5.0.9", "@types/uuid": "~9.0.1", - "apollo-server-testing": "~2.11.0", + "@types/ws": "^8.18.1", "eslint": "^9.27.0", "eslint-config-it4c": "^0.12.0", "jest": "^30.2.0", @@ -125,7 +127,9 @@ "**/string-width": "4.2.0", "**/wrap-ansi": "7.0.0", "**/jwa": "^2.0.1", - "**/@types/express": "4.17.25" + "**/@types/express": "4.17.25", + "neo4j-graphql-js/graphql": "^16.11.0", + "graphql-upload/graphql": "^16.11.0" }, "engines": { "node": ">=20.12.1" diff --git a/backend/src/context/index.ts b/backend/src/context/index.ts index fd429de49..3c43e3c3c 100644 --- a/backend/src/context/index.ts +++ b/backend/src/context/index.ts @@ -1,5 +1,3 @@ -/* eslint-disable @typescript-eslint/no-unsafe-return */ - import databaseContext from '@context/database' import pubsubContext from '@context/pubsub' import CONFIG from '@src/config' @@ -7,8 +5,6 @@ import { decode } from '@src/jwt/decode' import ocelotLogger from '@src/logger' import type { DecodedUser } from '@src/jwt/decode' -import type OcelotLogger from '@src/logger' -import type { ApolloServerExpressConfig } from 'apollo-server-express' const serverDatabase = databaseContext() const serverPubsub = pubsubContext() @@ -18,7 +14,7 @@ export const getContext = database?: ReturnType pubsub?: ReturnType authenticatedUser: DecodedUser | null | undefined - logger?: typeof OcelotLogger + logger?: typeof ocelotLogger config: typeof CONFIG }) => async (req: { headers: { authorization?: string } }) => { @@ -50,12 +46,4 @@ export const getContext = return result } -export const context: ApolloServerExpressConfig['context'] = async (options) => { - const { connection, req } = options - if (connection) { - return connection.context - } else { - return getContext()(req) - } -} export type Context = Awaited>> diff --git a/backend/src/db/seed.ts b/backend/src/db/seed.ts index 65937b4cb..107a787e2 100644 --- a/backend/src/db/seed.ts +++ b/backend/src/db/seed.ts @@ -42,7 +42,7 @@ const languages = ['de', 'en', 'es', 'fr', 'it', 'pt', 'pl'] authenticatedUser, config: CONFIG, }) - const apolloSetup = createApolloTestSetup({ context }) + const apolloSetup = await createApolloTestSetup({ context }) const { mutate, server, database } = apolloSetup const { neode } = database diff --git a/backend/src/graphql/errors.ts b/backend/src/graphql/errors.ts new file mode 100644 index 000000000..d52300833 --- /dev/null +++ b/backend/src/graphql/errors.ts @@ -0,0 +1,19 @@ +import { GraphQLError } from 'graphql' + +export class UserInputError extends GraphQLError { + constructor(message: string) { + super(message, { extensions: { code: 'BAD_USER_INPUT' } }) + } +} + +export class AuthenticationError extends GraphQLError { + constructor(message: string) { + super(message, { extensions: { code: 'UNAUTHENTICATED' } }) + } +} + +export class ForbiddenError extends GraphQLError { + constructor(message: string) { + super(message, { extensions: { code: 'FORBIDDEN' } }) + } +} diff --git a/backend/src/graphql/queries/AddEmailAddress.ts b/backend/src/graphql/queries/AddEmailAddress.ts index 9b84fea90..dcf81039a 100644 --- a/backend/src/graphql/queries/AddEmailAddress.ts +++ b/backend/src/graphql/queries/AddEmailAddress.ts @@ -1,4 +1,4 @@ -import gql from 'graphql-tag' +import { gql } from 'graphql-tag' export const AddEmailAddress = gql` mutation ($email: String!) { diff --git a/backend/src/graphql/queries/AddPostEmotions.ts b/backend/src/graphql/queries/AddPostEmotions.ts index 88c97da3c..5a0629e17 100644 --- a/backend/src/graphql/queries/AddPostEmotions.ts +++ b/backend/src/graphql/queries/AddPostEmotions.ts @@ -1,4 +1,4 @@ -import gql from 'graphql-tag' +import { gql } from 'graphql-tag' export const AddPostEmotions = gql` mutation ($to: _PostInput!, $data: _EMOTEDInput!) { diff --git a/backend/src/graphql/queries/Category.ts b/backend/src/graphql/queries/Category.ts index 202ba2165..52280c3cd 100644 --- a/backend/src/graphql/queries/Category.ts +++ b/backend/src/graphql/queries/Category.ts @@ -1,4 +1,4 @@ -import gql from 'graphql-tag' +import { gql } from 'graphql-tag' export const Category = gql` query { diff --git a/backend/src/graphql/queries/ChangeGroupMemberRole.ts b/backend/src/graphql/queries/ChangeGroupMemberRole.ts index 691853589..fbb6335e6 100644 --- a/backend/src/graphql/queries/ChangeGroupMemberRole.ts +++ b/backend/src/graphql/queries/ChangeGroupMemberRole.ts @@ -1,4 +1,4 @@ -import gql from 'graphql-tag' +import { gql } from 'graphql-tag' export const ChangeGroupMemberRole = gql` mutation ($groupId: ID!, $userId: ID!, $roleInGroup: GroupMemberRole!) { diff --git a/backend/src/graphql/queries/CreateComment.ts b/backend/src/graphql/queries/CreateComment.ts index c80678331..993943c98 100644 --- a/backend/src/graphql/queries/CreateComment.ts +++ b/backend/src/graphql/queries/CreateComment.ts @@ -1,4 +1,4 @@ -import gql from 'graphql-tag' +import { gql } from 'graphql-tag' export const CreateComment = gql` mutation ($id: ID, $postId: ID!, $content: String!) { diff --git a/backend/src/graphql/queries/CreateGroup.ts b/backend/src/graphql/queries/CreateGroup.ts index 3423b386e..ecfca4858 100644 --- a/backend/src/graphql/queries/CreateGroup.ts +++ b/backend/src/graphql/queries/CreateGroup.ts @@ -1,4 +1,4 @@ -import gql from 'graphql-tag' +import { gql } from 'graphql-tag' export const CreateGroup = gql` mutation ( diff --git a/backend/src/graphql/queries/CreateMessage.ts b/backend/src/graphql/queries/CreateMessage.ts index 1282c5d87..187bbfeee 100644 --- a/backend/src/graphql/queries/CreateMessage.ts +++ b/backend/src/graphql/queries/CreateMessage.ts @@ -1,4 +1,4 @@ -import gql from 'graphql-tag' +import { gql } from 'graphql-tag' export const CreateMessage = gql` mutation ($roomId: ID!, $content: String!, $files: [FileInput]) { diff --git a/backend/src/graphql/queries/CreatePost.ts b/backend/src/graphql/queries/CreatePost.ts index 3ddf35191..bdcfe52ec 100644 --- a/backend/src/graphql/queries/CreatePost.ts +++ b/backend/src/graphql/queries/CreatePost.ts @@ -1,4 +1,4 @@ -import gql from 'graphql-tag' +import { gql } from 'graphql-tag' export const CreatePost = gql` mutation ( diff --git a/backend/src/graphql/queries/CreateRoom.ts b/backend/src/graphql/queries/CreateRoom.ts index dd52e5ebe..47dbfd006 100644 --- a/backend/src/graphql/queries/CreateRoom.ts +++ b/backend/src/graphql/queries/CreateRoom.ts @@ -1,4 +1,4 @@ -import gql from 'graphql-tag' +import { gql } from 'graphql-tag' export const CreateRoom = gql` mutation ($userId: ID!) { diff --git a/backend/src/graphql/queries/CreateSocialMedia.ts b/backend/src/graphql/queries/CreateSocialMedia.ts index 3058415b4..f80ef059a 100644 --- a/backend/src/graphql/queries/CreateSocialMedia.ts +++ b/backend/src/graphql/queries/CreateSocialMedia.ts @@ -1,11 +1,10 @@ -import gql from 'graphql-tag' +import { gql } from 'graphql-tag' export const CreateSocialMedia = gql` mutation ($url: String!) { CreateSocialMedia(url: $url) { id url - url ownedBy { name } diff --git a/backend/src/graphql/queries/DeleteComment.ts b/backend/src/graphql/queries/DeleteComment.ts index 033357b79..4a6e0df54 100644 --- a/backend/src/graphql/queries/DeleteComment.ts +++ b/backend/src/graphql/queries/DeleteComment.ts @@ -1,4 +1,4 @@ -import gql from 'graphql-tag' +import { gql } from 'graphql-tag' export const DeleteComment = gql` mutation ($id: ID!) { diff --git a/backend/src/graphql/queries/DeletePost.ts b/backend/src/graphql/queries/DeletePost.ts index fc02f1747..76b430d7e 100644 --- a/backend/src/graphql/queries/DeletePost.ts +++ b/backend/src/graphql/queries/DeletePost.ts @@ -1,4 +1,4 @@ -import gql from 'graphql-tag' +import { gql } from 'graphql-tag' export const DeletePost = gql` mutation ($id: ID!) { diff --git a/backend/src/graphql/queries/DeleteSocialMedia.ts b/backend/src/graphql/queries/DeleteSocialMedia.ts index 1d2d17565..6a37d4add 100644 --- a/backend/src/graphql/queries/DeleteSocialMedia.ts +++ b/backend/src/graphql/queries/DeleteSocialMedia.ts @@ -1,4 +1,4 @@ -import gql from 'graphql-tag' +import { gql } from 'graphql-tag' export const DeleteSocialMedia = gql` mutation ($id: ID!) { diff --git a/backend/src/graphql/queries/DeleteUser.ts b/backend/src/graphql/queries/DeleteUser.ts index aa1176392..3a78c0ca0 100644 --- a/backend/src/graphql/queries/DeleteUser.ts +++ b/backend/src/graphql/queries/DeleteUser.ts @@ -1,4 +1,4 @@ -import gql from 'graphql-tag' +import { gql } from 'graphql-tag' export const DeleteUser = gql` mutation ($id: ID!, $resource: [Deletable]) { diff --git a/backend/src/graphql/queries/Donations.ts b/backend/src/graphql/queries/Donations.ts index eaee90af6..223673f84 100644 --- a/backend/src/graphql/queries/Donations.ts +++ b/backend/src/graphql/queries/Donations.ts @@ -1,4 +1,4 @@ -import gql from 'graphql-tag' +import { gql } from 'graphql-tag' export const Donations = gql` query { diff --git a/backend/src/graphql/queries/Group.ts b/backend/src/graphql/queries/Group.ts index b6009ddc1..fb93c3e99 100644 --- a/backend/src/graphql/queries/Group.ts +++ b/backend/src/graphql/queries/Group.ts @@ -1,4 +1,4 @@ -import gql from 'graphql-tag' +import { gql } from 'graphql-tag' export const Group = gql` query Group($isMember: Boolean, $id: ID, $slug: String) { diff --git a/backend/src/graphql/queries/GroupMembers.ts b/backend/src/graphql/queries/GroupMembers.ts index 74a78686a..1b87db85b 100644 --- a/backend/src/graphql/queries/GroupMembers.ts +++ b/backend/src/graphql/queries/GroupMembers.ts @@ -1,4 +1,4 @@ -import gql from 'graphql-tag' +import { gql } from 'graphql-tag' export const GroupMembers = gql` query GroupMembers($id: ID!) { diff --git a/backend/src/graphql/queries/JoinGroup.ts b/backend/src/graphql/queries/JoinGroup.ts index 7297423bb..55b4bba5d 100644 --- a/backend/src/graphql/queries/JoinGroup.ts +++ b/backend/src/graphql/queries/JoinGroup.ts @@ -1,4 +1,4 @@ -import gql from 'graphql-tag' +import { gql } from 'graphql-tag' export const JoinGroup = gql` mutation ($groupId: ID!, $userId: ID!) { diff --git a/backend/src/graphql/queries/LeaveGroup.ts b/backend/src/graphql/queries/LeaveGroup.ts index d7e17a040..59bc17683 100644 --- a/backend/src/graphql/queries/LeaveGroup.ts +++ b/backend/src/graphql/queries/LeaveGroup.ts @@ -1,4 +1,4 @@ -import gql from 'graphql-tag' +import { gql } from 'graphql-tag' export const LeaveGroup = gql` mutation ($groupId: ID!, $userId: ID!) { diff --git a/backend/src/graphql/queries/MarkMessagesAsSeen.ts b/backend/src/graphql/queries/MarkMessagesAsSeen.ts index f6a6418ba..a98258d95 100644 --- a/backend/src/graphql/queries/MarkMessagesAsSeen.ts +++ b/backend/src/graphql/queries/MarkMessagesAsSeen.ts @@ -1,4 +1,4 @@ -import gql from 'graphql-tag' +import { gql } from 'graphql-tag' export const MarkMessagesAsSeen = gql` mutation ($messageIds: [String!]) { diff --git a/backend/src/graphql/queries/Message.ts b/backend/src/graphql/queries/Message.ts index 459584b98..78c207fb5 100644 --- a/backend/src/graphql/queries/Message.ts +++ b/backend/src/graphql/queries/Message.ts @@ -1,4 +1,4 @@ -import gql from 'graphql-tag' +import { gql } from 'graphql-tag' export const Message = gql` query ($roomId: ID!, $first: Int, $offset: Int) { diff --git a/backend/src/graphql/queries/Post.ts b/backend/src/graphql/queries/Post.ts index e1bb7fe94..977c10cba 100644 --- a/backend/src/graphql/queries/Post.ts +++ b/backend/src/graphql/queries/Post.ts @@ -1,4 +1,4 @@ -import gql from 'graphql-tag' +import { gql } from 'graphql-tag' export const Post = gql` query ($id: ID, $filter: _PostFilter, $first: Int, $offset: Int, $orderBy: [_PostOrdering]) { diff --git a/backend/src/graphql/queries/PostsEmotionsByCurrentUser.ts b/backend/src/graphql/queries/PostsEmotionsByCurrentUser.ts index 8eeff6425..39902b7ba 100644 --- a/backend/src/graphql/queries/PostsEmotionsByCurrentUser.ts +++ b/backend/src/graphql/queries/PostsEmotionsByCurrentUser.ts @@ -1,4 +1,4 @@ -import gql from 'graphql-tag' +import { gql } from 'graphql-tag' export const PostsEmotionsByCurrentUser = gql` query ($postId: ID!) { diff --git a/backend/src/graphql/queries/PostsEmotionsCountByEmotion.ts b/backend/src/graphql/queries/PostsEmotionsCountByEmotion.ts index d97eaa66f..55759ce48 100644 --- a/backend/src/graphql/queries/PostsEmotionsCountByEmotion.ts +++ b/backend/src/graphql/queries/PostsEmotionsCountByEmotion.ts @@ -1,4 +1,4 @@ -import gql from 'graphql-tag' +import { gql } from 'graphql-tag' export const PostsEmotionsCountByEmotion = gql` query ($postId: ID!, $data: _EMOTEDInput!) { diff --git a/backend/src/graphql/queries/RemovePostEmotions.ts b/backend/src/graphql/queries/RemovePostEmotions.ts index 0b0906d79..b27f5bf45 100644 --- a/backend/src/graphql/queries/RemovePostEmotions.ts +++ b/backend/src/graphql/queries/RemovePostEmotions.ts @@ -1,4 +1,4 @@ -import gql from 'graphql-tag' +import { gql } from 'graphql-tag' export const RemovePostEmotions = gql` mutation ($to: _PostInput!, $data: _EMOTEDInput!) { diff --git a/backend/src/graphql/queries/RemoveUserFromGroup.ts b/backend/src/graphql/queries/RemoveUserFromGroup.ts index 0864d1e4f..f1ff69dd3 100644 --- a/backend/src/graphql/queries/RemoveUserFromGroup.ts +++ b/backend/src/graphql/queries/RemoveUserFromGroup.ts @@ -1,4 +1,4 @@ -import gql from 'graphql-tag' +import { gql } from 'graphql-tag' export const RemoveUserFromGroup = gql` mutation ($groupId: ID!, $userId: ID!) { diff --git a/backend/src/graphql/queries/Room.ts b/backend/src/graphql/queries/Room.ts index 32f53411d..b76fae1fe 100644 --- a/backend/src/graphql/queries/Room.ts +++ b/backend/src/graphql/queries/Room.ts @@ -1,4 +1,4 @@ -import gql from 'graphql-tag' +import { gql } from 'graphql-tag' export const Room = gql` query Room($first: Int, $offset: Int, $id: ID) { diff --git a/backend/src/graphql/queries/Signup.ts b/backend/src/graphql/queries/Signup.ts index 1d3319b31..5d60d9ba2 100644 --- a/backend/src/graphql/queries/Signup.ts +++ b/backend/src/graphql/queries/Signup.ts @@ -1,4 +1,4 @@ -import gql from 'graphql-tag' +import { gql } from 'graphql-tag' export const Signup = gql` mutation ($email: String!, $locale: String!, $inviteCode: String) { diff --git a/backend/src/graphql/queries/SignupVerification.ts b/backend/src/graphql/queries/SignupVerification.ts index 08ff8009f..5d395a2f1 100644 --- a/backend/src/graphql/queries/SignupVerification.ts +++ b/backend/src/graphql/queries/SignupVerification.ts @@ -1,4 +1,4 @@ -import gql from 'graphql-tag' +import { gql } from 'graphql-tag' export const SignupVerification = gql` mutation ( diff --git a/backend/src/graphql/queries/UnreadRooms.ts b/backend/src/graphql/queries/UnreadRooms.ts index 7cd0e8e1b..2f517384f 100644 --- a/backend/src/graphql/queries/UnreadRooms.ts +++ b/backend/src/graphql/queries/UnreadRooms.ts @@ -1,4 +1,4 @@ -import gql from 'graphql-tag' +import { gql } from 'graphql-tag' export const UnreadRooms = gql` query { diff --git a/backend/src/graphql/queries/UpdateComment.ts b/backend/src/graphql/queries/UpdateComment.ts index 27d04ae8e..e98e70ada 100644 --- a/backend/src/graphql/queries/UpdateComment.ts +++ b/backend/src/graphql/queries/UpdateComment.ts @@ -1,4 +1,4 @@ -import gql from 'graphql-tag' +import { gql } from 'graphql-tag' export const UpdateComment = gql` mutation ($content: String!, $id: ID!) { diff --git a/backend/src/graphql/queries/UpdateDonations.ts b/backend/src/graphql/queries/UpdateDonations.ts index bb5ccdc3d..5c28834bd 100644 --- a/backend/src/graphql/queries/UpdateDonations.ts +++ b/backend/src/graphql/queries/UpdateDonations.ts @@ -1,4 +1,4 @@ -import gql from 'graphql-tag' +import { gql } from 'graphql-tag' export const UpdateDonations = gql` mutation ($showDonations: Boolean, $goal: Int, $progress: Int) { diff --git a/backend/src/graphql/queries/UpdateGroup.ts b/backend/src/graphql/queries/UpdateGroup.ts index ccad22eec..ab071b76a 100644 --- a/backend/src/graphql/queries/UpdateGroup.ts +++ b/backend/src/graphql/queries/UpdateGroup.ts @@ -1,4 +1,4 @@ -import gql from 'graphql-tag' +import { gql } from 'graphql-tag' export const UpdateGroup = gql` mutation ( diff --git a/backend/src/graphql/queries/UpdatePost.ts b/backend/src/graphql/queries/UpdatePost.ts index 73f70fdeb..75f3c9324 100644 --- a/backend/src/graphql/queries/UpdatePost.ts +++ b/backend/src/graphql/queries/UpdatePost.ts @@ -1,4 +1,4 @@ -import gql from 'graphql-tag' +import { gql } from 'graphql-tag' export const UpdatePost = gql` mutation ( diff --git a/backend/src/graphql/queries/UpdateSocialMedia.ts b/backend/src/graphql/queries/UpdateSocialMedia.ts index dfbfeb22e..412d985fe 100644 --- a/backend/src/graphql/queries/UpdateSocialMedia.ts +++ b/backend/src/graphql/queries/UpdateSocialMedia.ts @@ -1,4 +1,4 @@ -import gql from 'graphql-tag' +import { gql } from 'graphql-tag' export const UpdateSocialMedia = gql` mutation ($id: ID!, $url: String!) { diff --git a/backend/src/graphql/queries/UpdateUser.ts b/backend/src/graphql/queries/UpdateUser.ts index 612feec21..4699390ca 100644 --- a/backend/src/graphql/queries/UpdateUser.ts +++ b/backend/src/graphql/queries/UpdateUser.ts @@ -1,4 +1,4 @@ -import gql from 'graphql-tag' +import { gql } from 'graphql-tag' export const UpdateUser = gql` mutation ( diff --git a/backend/src/graphql/queries/User.ts b/backend/src/graphql/queries/User.ts index 111b1fd74..5201bbf8f 100644 --- a/backend/src/graphql/queries/User.ts +++ b/backend/src/graphql/queries/User.ts @@ -1,4 +1,4 @@ -import gql from 'graphql-tag' +import { gql } from 'graphql-tag' export const User = gql` query ($id: ID, $name: String, $email: String) { diff --git a/backend/src/graphql/queries/VerifyEmailAddress.ts b/backend/src/graphql/queries/VerifyEmailAddress.ts index 48e7093e0..c6de3e828 100644 --- a/backend/src/graphql/queries/VerifyEmailAddress.ts +++ b/backend/src/graphql/queries/VerifyEmailAddress.ts @@ -1,4 +1,4 @@ -import gql from 'graphql-tag' +import { gql } from 'graphql-tag' export const VerifyEmailAddress = gql` mutation ($email: String!, $nonce: String!) { diff --git a/backend/src/graphql/queries/VerifyNonce.ts b/backend/src/graphql/queries/VerifyNonce.ts index 6511d1f29..8d77562a1 100644 --- a/backend/src/graphql/queries/VerifyNonce.ts +++ b/backend/src/graphql/queries/VerifyNonce.ts @@ -1,4 +1,4 @@ -import gql from 'graphql-tag' +import { gql } from 'graphql-tag' export const VerifyNonce = gql` query ($email: String!, $nonce: String!) { diff --git a/backend/src/graphql/queries/availableRoles.ts b/backend/src/graphql/queries/availableRoles.ts index d5a52e6a8..0fe823cda 100644 --- a/backend/src/graphql/queries/availableRoles.ts +++ b/backend/src/graphql/queries/availableRoles.ts @@ -1,4 +1,4 @@ -import gql from 'graphql-tag' +import { gql } from 'graphql-tag' export const availableRoles = gql` query { diff --git a/backend/src/graphql/queries/blockUser.ts b/backend/src/graphql/queries/blockUser.ts index 4bf878774..c85878a81 100644 --- a/backend/src/graphql/queries/blockUser.ts +++ b/backend/src/graphql/queries/blockUser.ts @@ -1,4 +1,4 @@ -import gql from 'graphql-tag' +import { gql } from 'graphql-tag' export const blockUser = gql` mutation ($id: ID!) { diff --git a/backend/src/graphql/queries/blockedUsers.ts b/backend/src/graphql/queries/blockedUsers.ts index d7f358f80..10c3fe861 100644 --- a/backend/src/graphql/queries/blockedUsers.ts +++ b/backend/src/graphql/queries/blockedUsers.ts @@ -1,4 +1,4 @@ -import gql from 'graphql-tag' +import { gql } from 'graphql-tag' export const blockedUsers = gql` query { diff --git a/backend/src/graphql/queries/changePassword.ts b/backend/src/graphql/queries/changePassword.ts index f53e701ef..2df09c79c 100644 --- a/backend/src/graphql/queries/changePassword.ts +++ b/backend/src/graphql/queries/changePassword.ts @@ -1,4 +1,4 @@ -import gql from 'graphql-tag' +import { gql } from 'graphql-tag' export const changePassword = gql` mutation ($oldPassword: String!, $newPassword: String!) { diff --git a/backend/src/graphql/queries/currentUser.ts b/backend/src/graphql/queries/currentUser.ts index 9cdaf64c7..3637a0c9d 100644 --- a/backend/src/graphql/queries/currentUser.ts +++ b/backend/src/graphql/queries/currentUser.ts @@ -1,4 +1,4 @@ -import gql from 'graphql-tag' +import { gql } from 'graphql-tag' export const currentUser = gql` query currentUser { diff --git a/backend/src/graphql/queries/embed.ts b/backend/src/graphql/queries/embed.ts index 12df35406..910383eb6 100644 --- a/backend/src/graphql/queries/embed.ts +++ b/backend/src/graphql/queries/embed.ts @@ -1,4 +1,4 @@ -import gql from 'graphql-tag' +import { gql } from 'graphql-tag' export const embed = gql` query ($url: String!) { diff --git a/backend/src/graphql/queries/fileReport.ts b/backend/src/graphql/queries/fileReport.ts index 87410c662..f362126c3 100644 --- a/backend/src/graphql/queries/fileReport.ts +++ b/backend/src/graphql/queries/fileReport.ts @@ -1,4 +1,4 @@ -import gql from 'graphql-tag' +import { gql } from 'graphql-tag' export const fileReport = gql` mutation ($resourceId: ID!, $reasonCategory: ReasonCategory!, $reasonDescription: String!) { diff --git a/backend/src/graphql/queries/followUser.ts b/backend/src/graphql/queries/followUser.ts index 9fb71b7d4..ff132c4db 100644 --- a/backend/src/graphql/queries/followUser.ts +++ b/backend/src/graphql/queries/followUser.ts @@ -1,4 +1,4 @@ -import gql from 'graphql-tag' +import { gql } from 'graphql-tag' export const followUser = gql` mutation ($id: ID!) { diff --git a/backend/src/graphql/queries/generateGroupInviteCode.ts b/backend/src/graphql/queries/generateGroupInviteCode.ts index 5633b41b7..53fae1001 100644 --- a/backend/src/graphql/queries/generateGroupInviteCode.ts +++ b/backend/src/graphql/queries/generateGroupInviteCode.ts @@ -1,4 +1,4 @@ -import gql from 'graphql-tag' +import { gql } from 'graphql-tag' export const generateGroupInviteCode = gql` mutation generateGroupInviteCode($groupId: ID!, $expiresAt: String, $comment: String) { diff --git a/backend/src/graphql/queries/generatePersonalInviteCode.ts b/backend/src/graphql/queries/generatePersonalInviteCode.ts index 429b25549..49bd08ada 100644 --- a/backend/src/graphql/queries/generatePersonalInviteCode.ts +++ b/backend/src/graphql/queries/generatePersonalInviteCode.ts @@ -1,4 +1,4 @@ -import gql from 'graphql-tag' +import { gql } from 'graphql-tag' export const generatePersonalInviteCode = gql` mutation generatePersonalInviteCode($expiresAt: String, $comment: String) { diff --git a/backend/src/graphql/queries/invalidateInviteCode.ts b/backend/src/graphql/queries/invalidateInviteCode.ts index 1b8581be3..dfbe96c1c 100644 --- a/backend/src/graphql/queries/invalidateInviteCode.ts +++ b/backend/src/graphql/queries/invalidateInviteCode.ts @@ -1,4 +1,4 @@ -import gql from 'graphql-tag' +import { gql } from 'graphql-tag' export const invalidateInviteCode = gql` mutation invalidateInviteCode($code: String!) { diff --git a/backend/src/graphql/queries/login.ts b/backend/src/graphql/queries/login.ts index c296d05e5..19c5472c9 100644 --- a/backend/src/graphql/queries/login.ts +++ b/backend/src/graphql/queries/login.ts @@ -1,4 +1,4 @@ -import gql from 'graphql-tag' +import { gql } from 'graphql-tag' export const login = gql` mutation ($email: String!, $password: String!) { diff --git a/backend/src/graphql/queries/markAllAsRead.ts b/backend/src/graphql/queries/markAllAsRead.ts index c86405941..60e08b4af 100644 --- a/backend/src/graphql/queries/markAllAsRead.ts +++ b/backend/src/graphql/queries/markAllAsRead.ts @@ -1,4 +1,4 @@ -import gql from 'graphql-tag' +import { gql } from 'graphql-tag' export const markAllAsRead = gql` mutation { diff --git a/backend/src/graphql/queries/markAsRead.ts b/backend/src/graphql/queries/markAsRead.ts index 23f8125fd..657d09395 100644 --- a/backend/src/graphql/queries/markAsRead.ts +++ b/backend/src/graphql/queries/markAsRead.ts @@ -1,4 +1,4 @@ -import gql from 'graphql-tag' +import { gql } from 'graphql-tag' export const markAsRead = gql` mutation ($id: ID!) { diff --git a/backend/src/graphql/queries/markTeaserAsViewed.ts b/backend/src/graphql/queries/markTeaserAsViewed.ts index 241ea168c..59922adea 100644 --- a/backend/src/graphql/queries/markTeaserAsViewed.ts +++ b/backend/src/graphql/queries/markTeaserAsViewed.ts @@ -1,4 +1,4 @@ -import gql from 'graphql-tag' +import { gql } from 'graphql-tag' export const markTeaserAsViewed = gql` mutation ($id: ID!) { diff --git a/backend/src/graphql/queries/muteGroup.ts b/backend/src/graphql/queries/muteGroup.ts index 269b39762..e10424c18 100644 --- a/backend/src/graphql/queries/muteGroup.ts +++ b/backend/src/graphql/queries/muteGroup.ts @@ -1,4 +1,4 @@ -import gql from 'graphql-tag' +import { gql } from 'graphql-tag' export const muteGroup = gql` mutation ($groupId: ID!) { diff --git a/backend/src/graphql/queries/muteUser.ts b/backend/src/graphql/queries/muteUser.ts index 0adb3469c..4e31ab1f3 100644 --- a/backend/src/graphql/queries/muteUser.ts +++ b/backend/src/graphql/queries/muteUser.ts @@ -1,4 +1,4 @@ -import gql from 'graphql-tag' +import { gql } from 'graphql-tag' export const muteUser = gql` mutation ($id: ID!) { diff --git a/backend/src/graphql/queries/mutedUsers.ts b/backend/src/graphql/queries/mutedUsers.ts index 5e00153c9..b80fab852 100644 --- a/backend/src/graphql/queries/mutedUsers.ts +++ b/backend/src/graphql/queries/mutedUsers.ts @@ -1,4 +1,4 @@ -import gql from 'graphql-tag' +import { gql } from 'graphql-tag' export const mutedUsers = gql` query { diff --git a/backend/src/graphql/queries/notifications.ts b/backend/src/graphql/queries/notifications.ts index 23ab65e9b..cd30a89c2 100644 --- a/backend/src/graphql/queries/notifications.ts +++ b/backend/src/graphql/queries/notifications.ts @@ -1,4 +1,4 @@ -import gql from 'graphql-tag' +import { gql } from 'graphql-tag' export const notifications = gql` query ($read: Boolean, $orderBy: NotificationOrdering) { diff --git a/backend/src/graphql/queries/pinGroupPost.ts b/backend/src/graphql/queries/pinGroupPost.ts index e22b42995..fbf95dc58 100644 --- a/backend/src/graphql/queries/pinGroupPost.ts +++ b/backend/src/graphql/queries/pinGroupPost.ts @@ -1,4 +1,4 @@ -import gql from 'graphql-tag' +import { gql } from 'graphql-tag' export const pinGroupPost = gql` mutation ($id: ID!) { diff --git a/backend/src/graphql/queries/pinPost.ts b/backend/src/graphql/queries/pinPost.ts index 6976bbc3d..6bd8faa98 100644 --- a/backend/src/graphql/queries/pinPost.ts +++ b/backend/src/graphql/queries/pinPost.ts @@ -1,4 +1,4 @@ -import gql from 'graphql-tag' +import { gql } from 'graphql-tag' export const pinPost = gql` mutation ($id: ID!) { diff --git a/backend/src/graphql/queries/profilePagePosts.ts b/backend/src/graphql/queries/profilePagePosts.ts index f54188d17..04029c9a6 100644 --- a/backend/src/graphql/queries/profilePagePosts.ts +++ b/backend/src/graphql/queries/profilePagePosts.ts @@ -1,4 +1,4 @@ -import gql from 'graphql-tag' +import { gql } from 'graphql-tag' export const profilePagePosts = gql` query profilePagePosts( diff --git a/backend/src/graphql/queries/pushPost.ts b/backend/src/graphql/queries/pushPost.ts index 56568188a..daab22c9b 100644 --- a/backend/src/graphql/queries/pushPost.ts +++ b/backend/src/graphql/queries/pushPost.ts @@ -1,4 +1,4 @@ -import gql from 'graphql-tag' +import { gql } from 'graphql-tag' export const pushPost = gql` mutation pushPost($id: ID!) { diff --git a/backend/src/graphql/queries/queryLocations.ts b/backend/src/graphql/queries/queryLocations.ts index fef21a9ad..0be730f25 100644 --- a/backend/src/graphql/queries/queryLocations.ts +++ b/backend/src/graphql/queries/queryLocations.ts @@ -1,4 +1,4 @@ -import gql from 'graphql-tag' +import { gql } from 'graphql-tag' export const queryLocations = gql` query ($place: String!, $lang: String!) { diff --git a/backend/src/graphql/queries/redeemInviteCode.ts b/backend/src/graphql/queries/redeemInviteCode.ts index 0852c564a..0e82642be 100644 --- a/backend/src/graphql/queries/redeemInviteCode.ts +++ b/backend/src/graphql/queries/redeemInviteCode.ts @@ -1,4 +1,4 @@ -import gql from 'graphql-tag' +import { gql } from 'graphql-tag' export const redeemInviteCode = gql` mutation redeemInviteCode($code: String!) { diff --git a/backend/src/graphql/queries/reports.ts b/backend/src/graphql/queries/reports.ts index f4549bb00..c1a5f0ad6 100644 --- a/backend/src/graphql/queries/reports.ts +++ b/backend/src/graphql/queries/reports.ts @@ -1,4 +1,4 @@ -import gql from 'graphql-tag' +import { gql } from 'graphql-tag' export const reports = gql` query ( diff --git a/backend/src/graphql/queries/requestPasswordReset.ts b/backend/src/graphql/queries/requestPasswordReset.ts index 6d6325131..b0c0c6eeb 100644 --- a/backend/src/graphql/queries/requestPasswordReset.ts +++ b/backend/src/graphql/queries/requestPasswordReset.ts @@ -1,4 +1,4 @@ -import gql from 'graphql-tag' +import { gql } from 'graphql-tag' export const requestPasswordReset = gql` mutation ($email: String!, $locale: String!) { diff --git a/backend/src/graphql/queries/resetPassword.ts b/backend/src/graphql/queries/resetPassword.ts index 280a059c7..e9f376aef 100644 --- a/backend/src/graphql/queries/resetPassword.ts +++ b/backend/src/graphql/queries/resetPassword.ts @@ -1,4 +1,4 @@ -import gql from 'graphql-tag' +import { gql } from 'graphql-tag' export const resetPassword = gql` mutation ($nonce: String!, $email: String!, $newPassword: String!) { diff --git a/backend/src/graphql/queries/resetTrophyBadgesSelected.ts b/backend/src/graphql/queries/resetTrophyBadgesSelected.ts index add29f17d..18314f6ed 100644 --- a/backend/src/graphql/queries/resetTrophyBadgesSelected.ts +++ b/backend/src/graphql/queries/resetTrophyBadgesSelected.ts @@ -1,4 +1,4 @@ -import gql from 'graphql-tag' +import { gql } from 'graphql-tag' export const resetTrophyBadgesSelected = gql` mutation { diff --git a/backend/src/graphql/queries/review.ts b/backend/src/graphql/queries/review.ts index dcb65c7ad..32a2953fa 100644 --- a/backend/src/graphql/queries/review.ts +++ b/backend/src/graphql/queries/review.ts @@ -1,4 +1,4 @@ -import gql from 'graphql-tag' +import { gql } from 'graphql-tag' export const review = gql` mutation ($resourceId: ID!, $disable: Boolean, $closed: Boolean) { diff --git a/backend/src/graphql/queries/revokeBadge.ts b/backend/src/graphql/queries/revokeBadge.ts index 809464b99..60786cc21 100644 --- a/backend/src/graphql/queries/revokeBadge.ts +++ b/backend/src/graphql/queries/revokeBadge.ts @@ -1,4 +1,4 @@ -import gql from 'graphql-tag' +import { gql } from 'graphql-tag' export const revokeBadge = gql` mutation ($badgeId: ID!, $userId: ID!) { diff --git a/backend/src/graphql/queries/rewardTrophyBadge.ts b/backend/src/graphql/queries/rewardTrophyBadge.ts index dda869d7f..5fb521296 100644 --- a/backend/src/graphql/queries/rewardTrophyBadge.ts +++ b/backend/src/graphql/queries/rewardTrophyBadge.ts @@ -1,4 +1,4 @@ -import gql from 'graphql-tag' +import { gql } from 'graphql-tag' export const rewardTrophyBadge = gql` mutation rewardTrophyBadge($badgeId: ID!, $userId: ID!) { diff --git a/backend/src/graphql/queries/saveCategorySettings.ts b/backend/src/graphql/queries/saveCategorySettings.ts index 8f5d72f04..0c0e8bf86 100644 --- a/backend/src/graphql/queries/saveCategorySettings.ts +++ b/backend/src/graphql/queries/saveCategorySettings.ts @@ -1,4 +1,4 @@ -import gql from 'graphql-tag' +import { gql } from 'graphql-tag' export const saveCategorySettings = gql` mutation ($activeCategories: [String]) { diff --git a/backend/src/graphql/queries/searchPosts.ts b/backend/src/graphql/queries/searchPosts.ts index 0bdea80ff..501043f70 100644 --- a/backend/src/graphql/queries/searchPosts.ts +++ b/backend/src/graphql/queries/searchPosts.ts @@ -1,4 +1,4 @@ -import gql from 'graphql-tag' +import { gql } from 'graphql-tag' export const searchPosts = gql` query ($query: String!, $firstPosts: Int, $postsOffset: Int) { diff --git a/backend/src/graphql/queries/searchResults.ts b/backend/src/graphql/queries/searchResults.ts index 0065a5347..b2d95da01 100644 --- a/backend/src/graphql/queries/searchResults.ts +++ b/backend/src/graphql/queries/searchResults.ts @@ -1,4 +1,4 @@ -import gql from 'graphql-tag' +import { gql } from 'graphql-tag' export const searchResults = gql` query ($query: String!) { diff --git a/backend/src/graphql/queries/setTrophyBadgeSelected.ts b/backend/src/graphql/queries/setTrophyBadgeSelected.ts index 62450809f..7b82626e0 100644 --- a/backend/src/graphql/queries/setTrophyBadgeSelected.ts +++ b/backend/src/graphql/queries/setTrophyBadgeSelected.ts @@ -1,4 +1,4 @@ -import gql from 'graphql-tag' +import { gql } from 'graphql-tag' export const setTrophyBadgeSelected = gql` mutation setTrophyBadgeSelected($slot: Int!, $badgeId: ID) { diff --git a/backend/src/graphql/queries/setVerificationBadge.ts b/backend/src/graphql/queries/setVerificationBadge.ts index b37ca5535..74ba2c2cb 100644 --- a/backend/src/graphql/queries/setVerificationBadge.ts +++ b/backend/src/graphql/queries/setVerificationBadge.ts @@ -1,4 +1,4 @@ -import gql from 'graphql-tag' +import { gql } from 'graphql-tag' export const setVerificationBadge = gql` mutation ($badgeId: ID!, $userId: ID!) { diff --git a/backend/src/graphql/queries/shout.ts b/backend/src/graphql/queries/shout.ts index 6861fffec..7ccc4d461 100644 --- a/backend/src/graphql/queries/shout.ts +++ b/backend/src/graphql/queries/shout.ts @@ -1,4 +1,4 @@ -import gql from 'graphql-tag' +import { gql } from 'graphql-tag' export const shout = gql` mutation ($id: ID!) { diff --git a/backend/src/graphql/queries/statistics.ts b/backend/src/graphql/queries/statistics.ts index 0463b63a4..c74d5f122 100644 --- a/backend/src/graphql/queries/statistics.ts +++ b/backend/src/graphql/queries/statistics.ts @@ -1,4 +1,4 @@ -import gql from 'graphql-tag' +import { gql } from 'graphql-tag' export const statistics = gql` query statistics { diff --git a/backend/src/graphql/queries/switchUserRole.ts b/backend/src/graphql/queries/switchUserRole.ts index 55d41abc0..5c6d087b0 100644 --- a/backend/src/graphql/queries/switchUserRole.ts +++ b/backend/src/graphql/queries/switchUserRole.ts @@ -1,4 +1,4 @@ -import gql from 'graphql-tag' +import { gql } from 'graphql-tag' export const switchUserRole = gql` mutation ($role: UserRole!, $id: ID!) { diff --git a/backend/src/graphql/queries/toggleObservePost.ts b/backend/src/graphql/queries/toggleObservePost.ts index a75950c63..41d506df3 100644 --- a/backend/src/graphql/queries/toggleObservePost.ts +++ b/backend/src/graphql/queries/toggleObservePost.ts @@ -1,4 +1,4 @@ -import gql from 'graphql-tag' +import { gql } from 'graphql-tag' export const toggleObservePost = gql` mutation ($id: ID!, $value: Boolean!) { diff --git a/backend/src/graphql/queries/unblockUser.ts b/backend/src/graphql/queries/unblockUser.ts index 7a65babdc..4b23f2ac1 100644 --- a/backend/src/graphql/queries/unblockUser.ts +++ b/backend/src/graphql/queries/unblockUser.ts @@ -1,4 +1,4 @@ -import gql from 'graphql-tag' +import { gql } from 'graphql-tag' export const unblockUser = gql` mutation ($id: ID!) { diff --git a/backend/src/graphql/queries/unfollowUser.ts b/backend/src/graphql/queries/unfollowUser.ts index aa2acb371..9f68012b6 100644 --- a/backend/src/graphql/queries/unfollowUser.ts +++ b/backend/src/graphql/queries/unfollowUser.ts @@ -1,4 +1,4 @@ -import gql from 'graphql-tag' +import { gql } from 'graphql-tag' export const unfollowUser = gql` mutation ($id: ID!) { diff --git a/backend/src/graphql/queries/unmuteGroup.ts b/backend/src/graphql/queries/unmuteGroup.ts index 53b335201..47eeb47dd 100644 --- a/backend/src/graphql/queries/unmuteGroup.ts +++ b/backend/src/graphql/queries/unmuteGroup.ts @@ -1,4 +1,4 @@ -import gql from 'graphql-tag' +import { gql } from 'graphql-tag' export const unmuteGroup = gql` mutation ($groupId: ID!) { diff --git a/backend/src/graphql/queries/unmuteUser.ts b/backend/src/graphql/queries/unmuteUser.ts index 0078b6091..fefa2ddf2 100644 --- a/backend/src/graphql/queries/unmuteUser.ts +++ b/backend/src/graphql/queries/unmuteUser.ts @@ -1,4 +1,4 @@ -import gql from 'graphql-tag' +import { gql } from 'graphql-tag' export const unmuteUser = gql` mutation ($id: ID!) { diff --git a/backend/src/graphql/queries/unpinGroupPost.ts b/backend/src/graphql/queries/unpinGroupPost.ts index 79f658d95..197db59fe 100644 --- a/backend/src/graphql/queries/unpinGroupPost.ts +++ b/backend/src/graphql/queries/unpinGroupPost.ts @@ -1,4 +1,4 @@ -import gql from 'graphql-tag' +import { gql } from 'graphql-tag' export const unpinGroupPost = gql` mutation ($id: ID!) { diff --git a/backend/src/graphql/queries/unpinPost.ts b/backend/src/graphql/queries/unpinPost.ts index 3130e1de7..bc64c18ea 100644 --- a/backend/src/graphql/queries/unpinPost.ts +++ b/backend/src/graphql/queries/unpinPost.ts @@ -1,4 +1,4 @@ -import gql from 'graphql-tag' +import { gql } from 'graphql-tag' export const unpinPost = gql` mutation ($id: ID!) { diff --git a/backend/src/graphql/queries/unpushPost.ts b/backend/src/graphql/queries/unpushPost.ts index dcf3ac0c8..9f60cd009 100644 --- a/backend/src/graphql/queries/unpushPost.ts +++ b/backend/src/graphql/queries/unpushPost.ts @@ -1,4 +1,4 @@ -import gql from 'graphql-tag' +import { gql } from 'graphql-tag' export const unpushPost = gql` mutation unpushPost($id: ID!) { diff --git a/backend/src/graphql/queries/unshout.ts b/backend/src/graphql/queries/unshout.ts index 6ad27180f..52d5e1369 100644 --- a/backend/src/graphql/queries/unshout.ts +++ b/backend/src/graphql/queries/unshout.ts @@ -1,4 +1,4 @@ -import gql from 'graphql-tag' +import { gql } from 'graphql-tag' export const unshout = gql` mutation ($id: ID!) { diff --git a/backend/src/graphql/queries/updateOnlineStatus.ts b/backend/src/graphql/queries/updateOnlineStatus.ts index ee39b0667..01eaa70bb 100644 --- a/backend/src/graphql/queries/updateOnlineStatus.ts +++ b/backend/src/graphql/queries/updateOnlineStatus.ts @@ -1,4 +1,4 @@ -import gql from 'graphql-tag' +import { gql } from 'graphql-tag' export const updateOnlineStatus = gql` mutation ($status: OnlineStatus!) { diff --git a/backend/src/graphql/queries/userData.ts b/backend/src/graphql/queries/userData.ts index 542c7edbb..4d2d5d455 100644 --- a/backend/src/graphql/queries/userData.ts +++ b/backend/src/graphql/queries/userData.ts @@ -1,4 +1,4 @@ -import gql from 'graphql-tag' +import { gql } from 'graphql-tag' export const userData = gql` query ($id: ID!) { diff --git a/backend/src/graphql/queries/validateInviteCode.ts b/backend/src/graphql/queries/validateInviteCode.ts index bcae09254..01aa918d8 100644 --- a/backend/src/graphql/queries/validateInviteCode.ts +++ b/backend/src/graphql/queries/validateInviteCode.ts @@ -1,4 +1,4 @@ -import gql from 'graphql-tag' +import { gql } from 'graphql-tag' export const unauthenticatedValidateInviteCode = gql` query validateInviteCode($code: String!) { diff --git a/backend/src/graphql/resolvers/attachments/attachments.spec.ts b/backend/src/graphql/resolvers/attachments/attachments.spec.ts index ab787cf8d..190301236 100644 --- a/backend/src/graphql/resolvers/attachments/attachments.spec.ts +++ b/backend/src/graphql/resolvers/attachments/attachments.spec.ts @@ -8,9 +8,9 @@ import { Readable } from 'node:stream' import { S3Client } from '@aws-sdk/client-s3' import { Upload } from '@aws-sdk/lib-storage' -import { UserInputError } from 'apollo-server' import Factory, { cleanDatabase } from '@db/factories' +import { UserInputError } from '@graphql/errors' import { CreateMessage } from '@graphql/queries/CreateMessage' import { CreateRoom } from '@graphql/queries/CreateRoom' import { createApolloTestSetup } from '@root/test/helpers' @@ -21,6 +21,7 @@ import type { FileInput } from './attachments' import type File from '@db/models/File' import type { ApolloTestSetup } from '@root/test/helpers' import type { S3Config } from '@src/config' +import type { Context } from '@src/context' import type { ReadStream } from 'node:fs' const s3SendMock = jest.fn() @@ -48,7 +49,7 @@ const config: S3Config = { IMAGOR_PUBLIC_URL: 'IMAGOR_PUBLIC_URL', } -let authenticatedUser +let authenticatedUser: Context['user'] const context = () => ({ authenticatedUser, config }) let mutate: ApolloTestSetup['mutate'] let database: ApolloTestSetup['database'] @@ -57,7 +58,7 @@ let server: ApolloTestSetup['server'] beforeAll(async () => { await cleanDatabase() - const apolloSetup = createApolloTestSetup({ context }) + const apolloSetup = await createApolloTestSetup({ context }) mutate = apolloSetup.mutate database = apolloSetup.database server = apolloSetup.server @@ -81,8 +82,8 @@ afterEach(async () => { describe('delete Attachment', () => { const { del: deleteAttachment } = attachments(config) describe('given a resource with an attachment', () => { - let user: { id: string } - let chatPartner: { id: string } + let user + let chatPartner let file: { id: string } let message: { id: string } beforeEach(async () => { @@ -115,7 +116,7 @@ describe('delete Attachment', () => { }, }) - message = (m.data as any).CreateMessage // eslint-disable-line @typescript-eslint/no-explicit-any + message = m.data.CreateMessage await database.write({ query: ` diff --git a/backend/src/graphql/resolvers/attachments/attachments.ts b/backend/src/graphql/resolvers/attachments/attachments.ts index 0a55752b5..37f381d5f 100644 --- a/backend/src/graphql/resolvers/attachments/attachments.ts +++ b/backend/src/graphql/resolvers/attachments/attachments.ts @@ -1,11 +1,11 @@ /* eslint-disable @typescript-eslint/no-shadow */ import path from 'node:path' -import { UserInputError } from 'apollo-server-express' import slug from 'slugify' import { v4 as uuid } from 'uuid' import { getDriver } from '@db/neo4j' +import { UserInputError } from '@graphql/errors' import { s3Service } from '@src/uploads/s3Service' import type { S3Config } from '@config/index' diff --git a/backend/src/graphql/resolvers/badges.spec.ts b/backend/src/graphql/resolvers/badges.spec.ts index 774ee904c..6e2fa06fd 100644 --- a/backend/src/graphql/resolvers/badges.spec.ts +++ b/backend/src/graphql/resolvers/badges.spec.ts @@ -25,7 +25,7 @@ let server: ApolloTestSetup['server'] beforeAll(async () => { await cleanDatabase() - const apolloSetup = createApolloTestSetup({ context }) + const apolloSetup = await createApolloTestSetup({ context }) mutate = apolloSetup.mutate query = apolloSetup.query database = apolloSetup.database diff --git a/backend/src/graphql/resolvers/comments.spec.ts b/backend/src/graphql/resolvers/comments.spec.ts index a85972966..a896879a6 100644 --- a/backend/src/graphql/resolvers/comments.spec.ts +++ b/backend/src/graphql/resolvers/comments.spec.ts @@ -20,7 +20,7 @@ let server: ApolloTestSetup['server'] beforeAll(async () => { await cleanDatabase() - const apolloSetup = createApolloTestSetup({ context }) + const apolloSetup = await createApolloTestSetup({ context }) mutate = apolloSetup.mutate database = apolloSetup.database server = apolloSetup.server diff --git a/backend/src/graphql/resolvers/donations.spec.ts b/backend/src/graphql/resolvers/donations.spec.ts index a9b8f0eba..ec150006e 100644 --- a/backend/src/graphql/resolvers/donations.spec.ts +++ b/backend/src/graphql/resolvers/donations.spec.ts @@ -2,17 +2,25 @@ /* eslint-disable @typescript-eslint/no-unsafe-call */ /* eslint-disable @typescript-eslint/no-unsafe-member-access */ /* eslint-disable @typescript-eslint/no-unsafe-assignment */ -import { createTestClient } from 'apollo-server-testing' import Factory, { cleanDatabase } from '@db/factories' -import { getNeode, getDriver } from '@db/neo4j' import { Donations } from '@graphql/queries/Donations' import { UpdateDonations as updateDonations } from '@graphql/queries/UpdateDonations' -import createServer from '@src/server' +import { createApolloTestSetup } from '@root/test/helpers' -let mutate, query, authenticatedUser, variables -const instance = getNeode() -const driver = getDriver() +import type { ApolloTestSetup } from '@root/test/helpers' +import type { Context } from '@src/context' + +let authenticatedUser: Context['user'] +let mutate: ApolloTestSetup['mutate'] +let query: ApolloTestSetup['query'] +let database: ApolloTestSetup['database'] +let server: ApolloTestSetup['server'] +let variables + +const contextFn = () => ({ + authenticatedUser, +}) beforeAll(async () => { await cleanDatabase() @@ -20,25 +28,21 @@ beforeAll(async () => { afterAll(async () => { await cleanDatabase() - await driver.close() + void server.stop() + void database.driver.close() + database.neode.close() }) describe('donations', () => { let currentUser, newlyCreatedDonations beforeAll(async () => { await cleanDatabase() - authenticatedUser = undefined - const { server } = createServer({ - context: () => { - return { - driver, - neode: instance, - user: authenticatedUser, - } - }, - }) - mutate = createTestClient(server).mutate - query = createTestClient(server).query + authenticatedUser = null + const apolloSetup = await createApolloTestSetup({ context: contextFn }) + query = apolloSetup.query + mutate = apolloSetup.mutate + database = apolloSetup.database + server = apolloSetup.server }) beforeEach(async () => { @@ -54,7 +58,7 @@ describe('donations', () => { describe('query for donations', () => { describe('unauthenticated', () => { it('throws authorization error', async () => { - authenticatedUser = undefined + authenticatedUser = null await expect(query({ query: Donations, variables })).resolves.toMatchObject({ errors: [{ message: 'Not Authorized!' }], }) @@ -86,7 +90,7 @@ describe('donations', () => { describe('unauthenticated', () => { it('throws authorization error', async () => { - authenticatedUser = undefined + authenticatedUser = null await expect(mutate({ mutation: updateDonations, variables })).resolves.toMatchObject({ errors: [{ message: 'Not Authorized!' }], }) diff --git a/backend/src/graphql/resolvers/emails.spec.ts b/backend/src/graphql/resolvers/emails.spec.ts index 54bebbcdf..da578f0df 100644 --- a/backend/src/graphql/resolvers/emails.spec.ts +++ b/backend/src/graphql/resolvers/emails.spec.ts @@ -1,48 +1,45 @@ -/* eslint-disable @typescript-eslint/await-thenable */ -/* eslint-disable @typescript-eslint/require-await */ /* eslint-disable @typescript-eslint/no-unsafe-call */ /* eslint-disable @typescript-eslint/no-unsafe-member-access */ /* eslint-disable @typescript-eslint/no-unsafe-assignment */ -/* eslint-disable @typescript-eslint/no-confusing-void-expression */ -import { createTestClient } from 'apollo-server-testing' import Factory, { cleanDatabase } from '@db/factories' -import { getDriver, getNeode } from '@db/neo4j' import { AddEmailAddress } from '@graphql/queries/AddEmailAddress' import { VerifyEmailAddress } from '@graphql/queries/VerifyEmailAddress' import { VerifyNonce } from '@graphql/queries/VerifyNonce' -import createServer from '@src/server' +import { createApolloTestSetup } from '@root/test/helpers' -const neode = getNeode() +import type { ApolloTestSetup } from '@root/test/helpers' +import type { Context } from '@src/context' -let mutate, query -let authenticatedUser +let authenticatedUser: Context['user'] +let mutate: ApolloTestSetup['mutate'] +let query: ApolloTestSetup['query'] +let database: ApolloTestSetup['database'] +let server: ApolloTestSetup['server'] let user let variables -const driver = getDriver() + +const contextFn = () => ({ + authenticatedUser, +}) beforeAll(async () => { await cleanDatabase() - - const { server } = createServer({ - context: () => { - return { - driver, - neode, - user: authenticatedUser, - } - }, - }) - mutate = createTestClient(server).mutate - query = createTestClient(server).query + const apolloSetup = await createApolloTestSetup({ context: contextFn }) + query = apolloSetup.query + mutate = apolloSetup.mutate + database = apolloSetup.database + server = apolloSetup.server }) afterAll(async () => { await cleanDatabase() - await driver.close() + void server.stop() + void database.driver.close() + database.neode.close() }) -beforeEach(async () => { +beforeEach(() => { variables = {} }) @@ -104,7 +101,7 @@ describe('AddEmailAddress', () => { it('connects `UnverifiedEmailAddress` to the authenticated user', async () => { await mutate({ mutation: AddEmailAddress, variables }) - const result = await neode.cypher( + const result = await database.neode.cypher( ` MATCH(u:User)-[:PRIMARY_EMAIL]->(:EmailAddress {email: "user@example.org"}) MATCH(u:User)<-[:BELONGS_TO]-(e:UnverifiedEmailAddress {email: "new-email@example.org"}) @@ -112,7 +109,11 @@ describe('AddEmailAddress', () => { `, {}, ) - const email = neode.hydrateFirst(result, 'e', neode.model('UnverifiedEmailAddress')) + const email = database.neode.hydrateFirst( + result, + 'e', + database.neode.model('UnverifiedEmailAddress'), + ) await expect(email.toJson()).resolves.toMatchObject({ email: 'new-email@example.org', nonce: expect.any(String), @@ -248,14 +249,18 @@ describe('VerifyEmailAddress', () => { it('connects the new `EmailAddress` as PRIMARY', async () => { await mutate({ mutation: VerifyEmailAddress, variables }) - const result = await neode.cypher( + const result = await database.neode.cypher( ` MATCH(u:User {id: "567"})-[:PRIMARY_EMAIL]->(e:EmailAddress {email: "to-be-verified@example.org"}) RETURN e `, {}, ) - const email = neode.hydrateFirst(result, 'e', neode.model('EmailAddress')) + const email = database.neode.hydrateFirst( + result, + 'e', + database.neode.model('EmailAddress'), + ) await expect(email.toJson()).resolves.toMatchObject({ email: 'to-be-verified@example.org', }) @@ -266,15 +271,19 @@ describe('VerifyEmailAddress', () => { MATCH(u:User {id: "567"})-[:PRIMARY_EMAIL]->(e:EmailAddress {email: "user@example.org"}) RETURN e ` - let result = await neode.cypher(cypherStatement, {}) - let email = neode.hydrateFirst(result, 'e', neode.model('EmailAddress')) + let result = await database.neode.cypher(cypherStatement, {}) + let email = database.neode.hydrateFirst( + result, + 'e', + database.neode.model('EmailAddress'), + ) await expect(email.toJson()).resolves.toMatchObject({ email: 'user@example.org', }) await mutate({ mutation: VerifyEmailAddress, variables }) - result = await neode.cypher(cypherStatement, {}) - email = neode.hydrateFirst(result, 'e', neode.model('EmailAddress')) - await expect(email).toBe(false) + result = await database.neode.cypher(cypherStatement, {}) + email = database.neode.hydrateFirst(result, 'e', database.neode.model('EmailAddress')) + expect(email).toBe(false) }) it('removes previous `EmailAddress` node', async () => { @@ -282,15 +291,19 @@ describe('VerifyEmailAddress', () => { MATCH(u:User {id: "567"})<-[:BELONGS_TO]-(e:EmailAddress {email: "user@example.org"}) RETURN e ` - let result = await neode.cypher(cypherStatement, {}) - let email = neode.hydrateFirst(result, 'e', neode.model('EmailAddress')) + let result = await database.neode.cypher(cypherStatement, {}) + let email = database.neode.hydrateFirst( + result, + 'e', + database.neode.model('EmailAddress'), + ) await expect(email.toJson()).resolves.toMatchObject({ email: 'user@example.org', }) await mutate({ mutation: VerifyEmailAddress, variables }) - result = await neode.cypher(cypherStatement, {}) - email = neode.hydrateFirst(result, 'e', neode.model('EmailAddress')) - await expect(email).toBe(false) + result = await database.neode.cypher(cypherStatement, {}) + email = database.neode.hydrateFirst(result, 'e', database.neode.model('EmailAddress')) + expect(email).toBe(false) }) describe('Edge case: In the meantime someone created an `EmailAddress` node with the given email belonging to a user', () => { @@ -315,14 +328,18 @@ describe('VerifyEmailAddress', () => { it('connects the new `EmailAddress` as PRIMARY', async () => { await mutate({ mutation: VerifyEmailAddress, variables }) - const result = await neode.cypher( + const result = await database.neode.cypher( ` MATCH(u:User {id: "567"})-[:PRIMARY_EMAIL]->(e:EmailAddress {email: "to-be-verified@example.org"}) RETURN e `, {}, ) - const email = neode.hydrateFirst(result, 'e', neode.model('EmailAddress')) + const email = database.neode.hydrateFirst( + result, + 'e', + database.neode.model('EmailAddress'), + ) await expect(email.toJson()).resolves.toMatchObject({ email: 'to-be-verified@example.org', }) diff --git a/backend/src/graphql/resolvers/emails.ts b/backend/src/graphql/resolvers/emails.ts index 3e3b976d7..841f635d5 100644 --- a/backend/src/graphql/resolvers/emails.ts +++ b/backend/src/graphql/resolvers/emails.ts @@ -2,10 +2,11 @@ /* eslint-disable @typescript-eslint/no-unsafe-call */ /* eslint-disable @typescript-eslint/no-unsafe-member-access */ /* eslint-disable @typescript-eslint/no-unsafe-assignment */ -import { UserInputError } from 'apollo-server' // eslint-disable-next-line import-x/extensions import Validator from 'neode/build/Services/Validator.js' +import { UserInputError } from '@graphql/errors' + import existingEmailAddress from './helpers/existingEmailAddress' import generateNonce from './helpers/generateNonce' import normalizeEmail from './helpers/normalizeEmail' diff --git a/backend/src/graphql/resolvers/embeds.spec.ts b/backend/src/graphql/resolvers/embeds.spec.ts index 762822b80..e2dfbfdcd 100644 --- a/backend/src/graphql/resolvers/embeds.spec.ts +++ b/backend/src/graphql/resolvers/embeds.spec.ts @@ -1,26 +1,44 @@ +/* eslint-disable @typescript-eslint/no-unsafe-argument */ /* eslint-disable @typescript-eslint/no-unsafe-assignment */ /* eslint-disable @typescript-eslint/no-unsafe-call */ -/* eslint-disable @typescript-eslint/no-unsafe-member-access */ + /* eslint-disable @typescript-eslint/no-shadow */ import fs from 'node:fs' import path from 'node:path' -import { createTestClient } from 'apollo-server-testing' import fetch from 'node-fetch' import { embed } from '@graphql/queries/embed' -import createServer from '@src/server' +import { createApolloTestSetup } from '@root/test/helpers' + +import type { ApolloTestSetup } from '@root/test/helpers' jest.mock('node-fetch') const mockedFetch = jest.mocked(fetch) const { Response } = jest.requireActual('node-fetch') +let query: ApolloTestSetup['query'] +let database: ApolloTestSetup['database'] +let server: ApolloTestSetup['server'] +let variables = {} + +beforeAll(async () => { + const apolloSetup = await createApolloTestSetup({ context: () => ({}) }) + query = apolloSetup.query + database = apolloSetup.database + server = apolloSetup.server +}) + +afterAll(() => { + void server.stop() + void database.driver.close() + database.neode.close() +}) + afterEach(() => { mockedFetch.mockRestore() }) -let variables = {} - // eslint-disable-next-line n/no-sync const HumanConnectionOrg = fs.readFileSync( path.join(__dirname, '../../../snapshots/embeds/HumanConnectionOrg.html'), @@ -61,10 +79,6 @@ describe('Query', () => { beforeEach(() => { embedAction = async (variables) => { - const { server } = createServer({ - context: () => {}, - }) - const { query } = createTestClient(server) return query({ query: embed, variables }) } }) diff --git a/backend/src/graphql/resolvers/embeds/scraper.ts b/backend/src/graphql/resolvers/embeds/scraper.ts index 24bc2b923..de9f9a2fd 100644 --- a/backend/src/graphql/resolvers/embeds/scraper.ts +++ b/backend/src/graphql/resolvers/embeds/scraper.ts @@ -11,7 +11,7 @@ /* eslint-disable import-x/no-commonjs */ /* eslint-disable import-x/no-named-as-default */ -import { ApolloError } from 'apollo-server' +import { GraphQLError } from 'graphql' import isArray from 'lodash/isArray' import isEmpty from 'lodash/isEmpty' import mergeWith from 'lodash/mergeWith' @@ -85,7 +85,7 @@ export default async function scrape(url) { }) if (isEmpty(output)) { - throw new ApolloError('Not found', 'NOT_FOUND') + throw new GraphQLError('Not found', { extensions: { code: 'NOT_FOUND' } }) } if (!output.type) { diff --git a/backend/src/graphql/resolvers/follow.spec.ts b/backend/src/graphql/resolvers/follow.spec.ts index d09ffc79f..f9214d7fe 100644 --- a/backend/src/graphql/resolvers/follow.spec.ts +++ b/backend/src/graphql/resolvers/follow.spec.ts @@ -24,7 +24,7 @@ let variables beforeAll(async () => { await cleanDatabase() - const apolloSetup = createApolloTestSetup({ context }) + const apolloSetup = await createApolloTestSetup({ context }) mutate = apolloSetup.mutate query = apolloSetup.query database = apolloSetup.database diff --git a/backend/src/graphql/resolvers/groups.spec.ts b/backend/src/graphql/resolvers/groups.spec.ts index 75dd41046..ee3f5a6f5 100644 --- a/backend/src/graphql/resolvers/groups.spec.ts +++ b/backend/src/graphql/resolvers/groups.spec.ts @@ -235,7 +235,7 @@ const seedComplexScenarioAndClearAuthentication = async () => { } beforeAll(async () => { - const apolloSetup = createApolloTestSetup({ context }) + const apolloSetup = await createApolloTestSetup({ context }) mutate = apolloSetup.mutate query = apolloSetup.query database = apolloSetup.database diff --git a/backend/src/graphql/resolvers/groups.ts b/backend/src/graphql/resolvers/groups.ts index 45572421d..219dfa126 100644 --- a/backend/src/graphql/resolvers/groups.ts +++ b/backend/src/graphql/resolvers/groups.ts @@ -7,11 +7,11 @@ /* eslint-disable @typescript-eslint/prefer-nullish-coalescing */ /* eslint-disable @typescript-eslint/no-shadow */ /* eslint-disable @typescript-eslint/no-use-before-define */ -import { UserInputError } from 'apollo-server' import { v4 as uuid } from 'uuid' import { CATEGORIES_MIN, CATEGORIES_MAX } from '@constants/categories' import { DESCRIPTION_WITHOUT_HTML_LENGTH_MIN } from '@constants/groups' +import { UserInputError } from '@graphql/errors' import { removeHtmlTags } from '@middleware/helpers/cleanHtml' import Resolver from './helpers/Resolver' diff --git a/backend/src/graphql/resolvers/helpers/events.ts b/backend/src/graphql/resolvers/helpers/events.ts index 6217398ce..15ee652b1 100644 --- a/backend/src/graphql/resolvers/helpers/events.ts +++ b/backend/src/graphql/resolvers/helpers/events.ts @@ -3,7 +3,7 @@ /* eslint-disable @typescript-eslint/no-unsafe-assignment */ /* eslint-disable @typescript-eslint/no-unsafe-member-access */ /* eslint-disable @typescript-eslint/no-use-before-define */ -import { UserInputError } from 'apollo-server' +import { UserInputError } from '@graphql/errors' export const validateEventParams = (params) => { let locationName = null diff --git a/backend/src/graphql/resolvers/images/imagesS3.spec.ts b/backend/src/graphql/resolvers/images/imagesS3.spec.ts index 73ba065ec..ba20250f9 100644 --- a/backend/src/graphql/resolvers/images/imagesS3.spec.ts +++ b/backend/src/graphql/resolvers/images/imagesS3.spec.ts @@ -8,10 +8,10 @@ /* eslint-disable @typescript-eslint/no-shadow */ import { DeleteObjectCommand } from '@aws-sdk/client-s3' import { Upload } from '@aws-sdk/lib-storage' -import { UserInputError } from 'apollo-server' import Factory, { cleanDatabase } from '@db/factories' import { getNeode, getDriver } from '@db/neo4j' +import { UserInputError } from '@graphql/errors' import { images } from './imagesS3' diff --git a/backend/src/graphql/resolvers/images/imagesS3.ts b/backend/src/graphql/resolvers/images/imagesS3.ts index c596b8aa2..61624f677 100644 --- a/backend/src/graphql/resolvers/images/imagesS3.ts +++ b/backend/src/graphql/resolvers/images/imagesS3.ts @@ -2,10 +2,10 @@ /* eslint-disable @typescript-eslint/no-shadow */ import path from 'node:path' -import { UserInputError } from 'apollo-server' import slug from 'slugify' import { v4 as uuid } from 'uuid' +import { UserInputError } from '@graphql/errors' import { s3Service } from '@src/uploads/s3Service' import { wrapTransactionDeleteImage, wrapTransactionMergeImage } from './wrapTransaction' diff --git a/backend/src/graphql/resolvers/index.ts b/backend/src/graphql/resolvers/index.ts index 9a21f9a9d..3a1c8cf87 100644 --- a/backend/src/graphql/resolvers/index.ts +++ b/backend/src/graphql/resolvers/index.ts @@ -1,7 +1,9 @@ import path from 'node:path' -import { fileLoader, mergeResolvers } from 'merge-graphql-schemas' +import { loadFilesSync } from '@graphql-tools/load-files' +import { mergeResolvers } from '@graphql-tools/merge' // the files must be correctly evaluated in built and dev state - therefore accept both js & ts files -const resolversArray = fileLoader(path.join(__dirname, './!(*.spec).(ts|js)')) +// eslint-disable-next-line n/no-sync +const resolversArray = loadFilesSync(path.join(__dirname, './!(*.spec).(ts|js)')) export default mergeResolvers(resolversArray) diff --git a/backend/src/graphql/resolvers/inviteCodes.spec.ts b/backend/src/graphql/resolvers/inviteCodes.spec.ts index 948802cde..92fea0a57 100644 --- a/backend/src/graphql/resolvers/inviteCodes.spec.ts +++ b/backend/src/graphql/resolvers/inviteCodes.spec.ts @@ -31,7 +31,7 @@ let server: ApolloTestSetup['server'] beforeAll(async () => { await cleanDatabase() - const apolloSetup = createApolloTestSetup({ context }) + const apolloSetup = await createApolloTestSetup({ context }) mutate = apolloSetup.mutate query = apolloSetup.query database = apolloSetup.database diff --git a/backend/src/graphql/resolvers/locations.spec.ts b/backend/src/graphql/resolvers/locations.spec.ts index b04d50635..bdb4a0e24 100644 --- a/backend/src/graphql/resolvers/locations.spec.ts +++ b/backend/src/graphql/resolvers/locations.spec.ts @@ -18,7 +18,7 @@ let server: ApolloTestSetup['server'] beforeAll(async () => { await cleanDatabase() - const apolloSetup = createApolloTestSetup({ context }) + const apolloSetup = await createApolloTestSetup({ context }) mutate = apolloSetup.mutate query = apolloSetup.query database = apolloSetup.database diff --git a/backend/src/graphql/resolvers/locations.ts b/backend/src/graphql/resolvers/locations.ts index 3341fba7a..3355a09bf 100644 --- a/backend/src/graphql/resolvers/locations.ts +++ b/backend/src/graphql/resolvers/locations.ts @@ -3,7 +3,7 @@ /* eslint-disable @typescript-eslint/no-unsafe-member-access */ /* eslint-disable @typescript-eslint/no-unsafe-argument */ /* eslint-disable @typescript-eslint/return-await */ -import { UserInputError } from 'apollo-server' +import { UserInputError } from '@graphql/errors' import Resolver from './helpers/Resolver' import { queryLocations } from './users/location' diff --git a/backend/src/graphql/resolvers/messages.spec.ts b/backend/src/graphql/resolvers/messages.spec.ts index f163bd4b3..c3f845d27 100644 --- a/backend/src/graphql/resolvers/messages.spec.ts +++ b/backend/src/graphql/resolvers/messages.spec.ts @@ -34,7 +34,7 @@ const pubsubSpy = jest.spyOn(pubsub, 'publish') beforeAll(async () => { await cleanDatabase() - const apolloSetup = createApolloTestSetup({ context }) + const apolloSetup = await createApolloTestSetup({ context }) mutate = apolloSetup.mutate query = apolloSetup.query database = apolloSetup.database @@ -131,7 +131,7 @@ describe('Message', () => { userId: 'other-chatting-user', }, }) - roomId = (room.data as any).CreateRoom.id // eslint-disable-line @typescript-eslint/no-explicit-any + roomId = room.data.CreateRoom.id }) describe('user chats in room', () => { @@ -413,7 +413,7 @@ describe('Message', () => { userId: 'other-chatting-user', }, }) - roomId = (room.data as any).CreateRoom.id // eslint-disable-line @typescript-eslint/no-explicit-any + roomId = room.data.CreateRoom.id await mutate({ mutation: CreateMessage, @@ -645,7 +645,7 @@ describe('Message', () => { userId: 'other-chatting-user', }, }) - roomId = (room.data as any).CreateRoom.id // eslint-disable-line @typescript-eslint/no-explicit-any + roomId = room.data.CreateRoom.id await mutate({ mutation: CreateMessage, variables: { diff --git a/backend/src/graphql/resolvers/moderation.spec.ts b/backend/src/graphql/resolvers/moderation.spec.ts index 805aba04b..1181c04a0 100644 --- a/backend/src/graphql/resolvers/moderation.spec.ts +++ b/backend/src/graphql/resolvers/moderation.spec.ts @@ -2,44 +2,40 @@ /* eslint-disable @typescript-eslint/no-unsafe-argument */ /* eslint-disable @typescript-eslint/no-unsafe-member-access */ /* eslint-disable @typescript-eslint/no-unsafe-assignment */ -import { createTestClient } from 'apollo-server-testing' import Factory, { cleanDatabase } from '@db/factories' -import { getNeode, getDriver } from '@db/neo4j' import { review } from '@graphql/queries/review' -import createServer from '@src/server' +import { createApolloTestSetup } from '@root/test/helpers' -const neode = getNeode() -const driver = getDriver() +import type { ApolloTestSetup } from '@root/test/helpers' +import type { Context } from '@src/context' -let mutate, +let authenticatedUser: Context['user'] +let mutate: ApolloTestSetup['mutate'] +let database: ApolloTestSetup['database'] +let server: ApolloTestSetup['server'] +let disableVariables, enableVariables, moderator, nonModerator, closeReportVariables + +const contextFn = () => ({ authenticatedUser, - disableVariables, - enableVariables, - moderator, - nonModerator, - closeReportVariables +}) describe('moderate resources', () => { beforeAll(async () => { await cleanDatabase() - authenticatedUser = undefined - const { server } = createServer({ - context: () => { - return { - driver, - neode, - user: authenticatedUser, - } - }, - }) - mutate = createTestClient(server).mutate + authenticatedUser = null + const apolloSetup = await createApolloTestSetup({ context: contextFn }) + mutate = apolloSetup.mutate + database = apolloSetup.database + server = apolloSetup.server }) afterAll(async () => { await cleanDatabase() - await driver.close() + void server.stop() + void database.driver.close() + database.neode.close() }) beforeEach(async () => { @@ -158,7 +154,7 @@ describe('moderate resources', () => { ]) const cypher = 'MATCH (:Report)<-[review:REVIEWED]-(moderator:User {id: "moderator-id"}) RETURN review' - const reviews = await neode.cypher(cypher, {}) + const reviews = await database.neode.cypher(cypher, {}) expect(reviews.records).toHaveLength(1) }) diff --git a/backend/src/graphql/resolvers/notifications.spec.ts b/backend/src/graphql/resolvers/notifications.spec.ts index 61529cf17..112679040 100644 --- a/backend/src/graphql/resolvers/notifications.spec.ts +++ b/backend/src/graphql/resolvers/notifications.spec.ts @@ -26,7 +26,7 @@ let server: ApolloTestSetup['server'] beforeAll(async () => { await cleanDatabase() - const apolloSetup = createApolloTestSetup({ context }) + const apolloSetup = await createApolloTestSetup({ context }) query = apolloSetup.query mutate = apolloSetup.mutate database = apolloSetup.database diff --git a/backend/src/graphql/resolvers/passwordReset.spec.ts b/backend/src/graphql/resolvers/passwordReset.spec.ts index e575747a3..1c5cf955e 100644 --- a/backend/src/graphql/resolvers/passwordReset.spec.ts +++ b/backend/src/graphql/resolvers/passwordReset.spec.ts @@ -31,7 +31,7 @@ const getAllPasswordResets = async () => { beforeAll(async () => { await cleanDatabase() - const apolloSetup = createApolloTestSetup() + const apolloSetup = await createApolloTestSetup() mutate = apolloSetup.mutate database = apolloSetup.database server = apolloSetup.server diff --git a/backend/src/graphql/resolvers/posts.filter.spec.ts b/backend/src/graphql/resolvers/posts.filter.spec.ts index d91da9b56..7d46d4f42 100644 --- a/backend/src/graphql/resolvers/posts.filter.spec.ts +++ b/backend/src/graphql/resolvers/posts.filter.spec.ts @@ -21,7 +21,7 @@ let server: ApolloTestSetup['server'] beforeAll(async () => { await cleanDatabase() - const apolloSetup = createApolloTestSetup({ context }) + const apolloSetup = await createApolloTestSetup({ context }) mutate = apolloSetup.mutate query = apolloSetup.query database = apolloSetup.database diff --git a/backend/src/graphql/resolvers/posts.group.pin.spec.ts b/backend/src/graphql/resolvers/posts.group.pin.spec.ts index bfd441c13..8cdb86c5d 100644 --- a/backend/src/graphql/resolvers/posts.group.pin.spec.ts +++ b/backend/src/graphql/resolvers/posts.group.pin.spec.ts @@ -31,7 +31,7 @@ let server: ApolloTestSetup['server'] beforeAll(async () => { await cleanDatabase() - const apolloSetup = createApolloTestSetup({ context }) + const apolloSetup = await createApolloTestSetup({ context }) mutate = apolloSetup.mutate query = apolloSetup.query database = apolloSetup.database diff --git a/backend/src/graphql/resolvers/posts.inGroups.spec.ts b/backend/src/graphql/resolvers/posts.inGroups.spec.ts index 29272410d..bcdfbe26c 100644 --- a/backend/src/graphql/resolvers/posts.inGroups.spec.ts +++ b/backend/src/graphql/resolvers/posts.inGroups.spec.ts @@ -41,7 +41,7 @@ let server: ApolloTestSetup['server'] beforeAll(async () => { await cleanDatabase() - const apolloSetup = createApolloTestSetup({ context }) + const apolloSetup = await createApolloTestSetup({ context }) mutate = apolloSetup.mutate query = apolloSetup.query database = apolloSetup.database diff --git a/backend/src/graphql/resolvers/posts.markTeaserAsViewed.spec.ts b/backend/src/graphql/resolvers/posts.markTeaserAsViewed.spec.ts index 124e16755..3791e76d0 100644 --- a/backend/src/graphql/resolvers/posts.markTeaserAsViewed.spec.ts +++ b/backend/src/graphql/resolvers/posts.markTeaserAsViewed.spec.ts @@ -1,45 +1,44 @@ /* eslint-disable @typescript-eslint/no-unsafe-member-access */ /* eslint-disable @typescript-eslint/no-unsafe-call */ /* eslint-disable @typescript-eslint/no-unsafe-assignment */ -import { createTestClient } from 'apollo-server-testing' import Factory, { cleanDatabase } from '@db/factories' -import { getNeode, getDriver } from '@db/neo4j' import { markTeaserAsViewed } from '@graphql/queries/markTeaserAsViewed' -import createServer from '@src/server' +import { createApolloTestSetup } from '@root/test/helpers' -const driver = getDriver() -const neode = getNeode() +import type { ApolloTestSetup } from '@root/test/helpers' +import type { Context } from '@src/context' -let mutate -let authenticatedUser +let authenticatedUser: Context['user'] +let mutate: ApolloTestSetup['mutate'] +let database: ApolloTestSetup['database'] +let server: ApolloTestSetup['server'] let variables +const contextFn = () => ({ + authenticatedUser, +}) + beforeAll(async () => { await cleanDatabase() - - const { server } = createServer({ - context: () => { - return { - driver, - neode, - user: authenticatedUser, - } - }, - }) - mutate = createTestClient(server).mutate + const apolloSetup = await createApolloTestSetup({ context: contextFn }) + mutate = apolloSetup.mutate + database = apolloSetup.database + server = apolloSetup.server }) afterAll(async () => { await cleanDatabase() - await driver.close() + void server.stop() + void database.driver.close() + database.neode.close() }) describe('count post teaser views', () => { let aUser, bUser beforeAll(async () => { - Factory.build('post', { id: 'post-to-be-viewed' }) + await Factory.build('post', { id: 'post-to-be-viewed' }) aUser = await Factory.build('user', { id: 'a-user' }) bUser = await Factory.build('user', { id: 'b-user' }) variables = { diff --git a/backend/src/graphql/resolvers/posts.observe.spec.ts b/backend/src/graphql/resolvers/posts.observe.spec.ts index b90af0d99..ab61cc22a 100644 --- a/backend/src/graphql/resolvers/posts.observe.spec.ts +++ b/backend/src/graphql/resolvers/posts.observe.spec.ts @@ -23,7 +23,7 @@ let server: ApolloTestSetup['server'] beforeAll(async () => { await cleanDatabase() - const apolloSetup = createApolloTestSetup({ context }) + const apolloSetup = await createApolloTestSetup({ context }) mutate = apolloSetup.mutate query = apolloSetup.query database = apolloSetup.database diff --git a/backend/src/graphql/resolvers/posts.spec.ts b/backend/src/graphql/resolvers/posts.spec.ts index b1f65a292..0b15fde55 100644 --- a/backend/src/graphql/resolvers/posts.spec.ts +++ b/backend/src/graphql/resolvers/posts.spec.ts @@ -41,7 +41,7 @@ let config: Partial beforeAll(async () => { await cleanDatabase() - const apolloSetup = createApolloTestSetup({ context }) + const apolloSetup = await createApolloTestSetup({ context }) mutate = apolloSetup.mutate query = apolloSetup.query database = apolloSetup.database @@ -299,8 +299,9 @@ describe('CreatePost', () => { ).resolves.toMatchObject({ errors: [ { - message: - 'Variable "$postType" got invalid value "not-valid"; Expected type PostType.', + message: expect.stringContaining( + 'Variable "$postType" got invalid value "not-valid"', + ), }, ], }) @@ -635,7 +636,7 @@ describe('UpdatePost', () => { categoryIds, }, }) - newlyCreatedPost = (data as any).CreatePost // eslint-disable-line @typescript-eslint/no-explicit-any + newlyCreatedPost = data.CreatePost variables = { id: newlyCreatedPost.id, title: 'New title', diff --git a/backend/src/graphql/resolvers/posts.ts b/backend/src/graphql/resolvers/posts.ts index 69b3aecf3..e8e908e91 100644 --- a/backend/src/graphql/resolvers/posts.ts +++ b/backend/src/graphql/resolvers/posts.ts @@ -5,11 +5,12 @@ /* eslint-disable @typescript-eslint/no-unsafe-member-access */ /* eslint-disable @typescript-eslint/no-unsafe-assignment */ /* eslint-disable @typescript-eslint/prefer-nullish-coalescing */ -import { UserInputError } from 'apollo-server' import { isEmpty } from 'lodash' import { neo4jgraphql } from 'neo4j-graphql-js' import { v4 as uuid } from 'uuid' +import { UserInputError } from '@graphql/errors' + import { validateEventParams } from './helpers/events' import { filterForMutedUsers } from './helpers/filterForMutedUsers' import { filterInvisiblePosts } from './helpers/filterInvisiblePosts' diff --git a/backend/src/graphql/resolvers/registration.spec.ts b/backend/src/graphql/resolvers/registration.spec.ts index b2de6ad10..d0ec06601 100644 --- a/backend/src/graphql/resolvers/registration.spec.ts +++ b/backend/src/graphql/resolvers/registration.spec.ts @@ -23,7 +23,7 @@ let config: Partial = {} beforeAll(async () => { await cleanDatabase() - const apolloSetup = createApolloTestSetup({ context }) + const apolloSetup = await createApolloTestSetup({ context }) mutate = apolloSetup.mutate database = apolloSetup.database server = apolloSetup.server diff --git a/backend/src/graphql/resolvers/registration.ts b/backend/src/graphql/resolvers/registration.ts index 32ab9a883..d82b8575f 100644 --- a/backend/src/graphql/resolvers/registration.ts +++ b/backend/src/graphql/resolvers/registration.ts @@ -3,10 +3,10 @@ /* eslint-disable @typescript-eslint/no-unsafe-return */ /* eslint-disable @typescript-eslint/no-unsafe-member-access */ /* eslint-disable @typescript-eslint/no-unsafe-assignment */ -import { UserInputError } from 'apollo-server' import { hash } from 'bcryptjs' import { getNeode } from '@db/neo4j' +import { UserInputError } from '@graphql/errors' import existingEmailAddress from './helpers/existingEmailAddress' import generateNonce from './helpers/generateNonce' diff --git a/backend/src/graphql/resolvers/reports.spec.ts b/backend/src/graphql/resolvers/reports.spec.ts index df86d451d..0a5be8e4f 100644 --- a/backend/src/graphql/resolvers/reports.spec.ts +++ b/backend/src/graphql/resolvers/reports.spec.ts @@ -1,21 +1,26 @@ +/* eslint-disable @typescript-eslint/no-non-null-assertion */ /* eslint-disable @typescript-eslint/no-unsafe-return */ /* eslint-disable @typescript-eslint/no-unsafe-call */ /* eslint-disable @typescript-eslint/no-unsafe-member-access */ /* eslint-disable @typescript-eslint/no-unsafe-assignment */ -import { createTestClient } from 'apollo-server-testing' import Factory, { cleanDatabase } from '@db/factories' -import { getDriver, getNeode } from '@db/neo4j' import { fileReport } from '@graphql/queries/fileReport' import { reports } from '@graphql/queries/reports' import { review } from '@graphql/queries/review' -import createServer from '@src/server' +import { createApolloTestSetup } from '@root/test/helpers' -const instance = getNeode() -const driver = getDriver() +import type { ApolloTestSetup } from '@root/test/helpers' +import type { Context } from '@src/context' + +let authenticatedUser: Context['user'] +let mutate: ApolloTestSetup['mutate'] +let query: ApolloTestSetup['query'] +let database: ApolloTestSetup['database'] +let server: ApolloTestSetup['server'] describe('reports', () => { - let authenticatedUser, currentUser, mutate, query, moderator, abusiveUser, otherReportingUser + let currentUser, moderator, abusiveUser, otherReportingUser const categoryIds = ['cat9'] const variables = { resourceId: 'invalid', @@ -23,25 +28,24 @@ describe('reports', () => { reasonDescription: 'Violates code of conduct !!!', } + const contextFn = () => ({ + authenticatedUser, + }) + beforeAll(async () => { await cleanDatabase() - - const { server } = createServer({ - context: () => { - return { - driver, - neode: instance, - user: authenticatedUser, - } - }, - }) - mutate = createTestClient(server).mutate - query = createTestClient(server).query + const apolloSetup = await createApolloTestSetup({ context: contextFn }) + query = apolloSetup.query + mutate = apolloSetup.mutate + database = apolloSetup.database + server = apolloSetup.server }) afterAll(async () => { await cleanDatabase() - await driver.close() + void server.stop() + void database.driver.close() + database.neode.close() }) // TODO: avoid database clean after each test in the future if possible for performance and flakyness reasons by filling the database step by step, see issue https://github.com/Ocelot-Social-Community/Ocelot-Social/issues/4543 @@ -106,7 +110,7 @@ describe('reports', () => { email: 'abusive-user@example.org', }, ) - await instance.create('Category', { + await database.neode.create('Category', { id: 'cat9', name: 'Democracy & Politics', icon: 'university', @@ -171,9 +175,9 @@ describe('reports', () => { variables: { ...variables, resourceId: 'abusive-user-id' }, }) - const reportsCypherQueryResponse = await instance.cypher(reportsCypherQuery, { + const reportsCypherQueryResponse = await database.neode.cypher(reportsCypherQuery, { resourceId: 'abusive-user-id', - currentUserId: authenticatedUser.id, + currentUserId: authenticatedUser!.id, }) expect(reportsCypherQueryResponse.records).toHaveLength(1) const [reportProperties] = reportsCypherQueryResponse.records.map( @@ -189,9 +193,9 @@ describe('reports', () => { variables: { ...variables, resourceId: 'abusive-user-id' }, }) - const reportsCypherQueryResponse = await instance.cypher(reportsCypherQuery, { + const reportsCypherQueryResponse = await database.neode.cypher(reportsCypherQuery, { resourceId: 'abusive-user-id', - currentUserId: authenticatedUser.id, + currentUserId: authenticatedUser!.id, }) expect(reportsCypherQueryResponse.records).toHaveLength(1) const [reportProperties] = reportsCypherQueryResponse.records.map( @@ -222,9 +226,9 @@ describe('reports', () => { variables: { ...variables, resourceId: 'abusive-user-id' }, }) - const reportsCypherQueryResponse = await instance.cypher(reportsCypherQuery, { + const reportsCypherQueryResponse = await database.neode.cypher(reportsCypherQuery, { resourceId: 'abusive-user-id', - currentUserId: authenticatedUser.id, + currentUserId: authenticatedUser!.id, }) expect(reportsCypherQueryResponse.records).toHaveLength(1) const [reportProperties] = reportsCypherQueryResponse.records.map( @@ -323,11 +327,12 @@ describe('reports', () => { }, }), ).resolves.toMatchObject({ - data: undefined, + data: null, errors: [ { - message: - 'Variable "$reasonCategory" got invalid value "category_missing_from_enum_reason_category"; Expected type ReasonCategory.', + message: expect.stringContaining( + 'Variable "$reasonCategory" got invalid value "category_missing_from_enum_reason_category"', + ), }, ], }) @@ -566,7 +571,7 @@ describe('reports', () => { email: 'abusive-user@example.org', }, ) - await instance.create('Category', { + await database.neode.create('Category', { id: 'cat9', name: 'Democracy & Politics', icon: 'university', diff --git a/backend/src/graphql/resolvers/roles.spec.ts b/backend/src/graphql/resolvers/roles.spec.ts index 7958dc0cf..ee449b542 100644 --- a/backend/src/graphql/resolvers/roles.spec.ts +++ b/backend/src/graphql/resolvers/roles.spec.ts @@ -1,40 +1,37 @@ /* eslint-disable @typescript-eslint/no-unsafe-call */ /* eslint-disable @typescript-eslint/no-unsafe-member-access */ /* eslint-disable @typescript-eslint/no-unsafe-assignment */ -import { createTestClient } from 'apollo-server-testing' import Factory, { cleanDatabase } from '@db/factories' -import { getDriver, getNeode } from '@db/neo4j' import { availableRoles } from '@graphql/queries/availableRoles' -import createServer from '@src/server' +import { createApolloTestSetup } from '@root/test/helpers' -import type { ApolloServerTestClient } from 'apollo-server-testing' +import type { ApolloTestSetup } from '@root/test/helpers' +import type { Context } from '@src/context' -const instance = getNeode() -const driver = getDriver() +let authenticatedUser: Context['user'] +let query: ApolloTestSetup['query'] +let database: ApolloTestSetup['database'] +let server: ApolloTestSetup['server'] + +const contextFn = () => ({ + authenticatedUser, +}) describe('availableRoles', () => { - let authenticatedUser - let query: ApolloServerTestClient['query'] - beforeAll(async () => { await cleanDatabase() - - const { server } = createServer({ - context: () => { - return { - driver, - neode: instance, - user: authenticatedUser, - } - }, - }) - query = createTestClient(server).query + const apolloSetup = await createApolloTestSetup({ context: contextFn }) + query = apolloSetup.query + database = apolloSetup.database + server = apolloSetup.server }) afterAll(async () => { await cleanDatabase() - await driver.close() + void server.stop() + void database.driver.close() + database.neode.close() }) afterEach(async () => { diff --git a/backend/src/graphql/resolvers/rooms.spec.ts b/backend/src/graphql/resolvers/rooms.spec.ts index a619f0651..d77220a97 100644 --- a/backend/src/graphql/resolvers/rooms.spec.ts +++ b/backend/src/graphql/resolvers/rooms.spec.ts @@ -22,7 +22,7 @@ let server: ApolloTestSetup['server'] beforeAll(async () => { await cleanDatabase() - const apolloSetup = createApolloTestSetup({ context }) + const apolloSetup = await createApolloTestSetup({ context }) mutate = apolloSetup.mutate query = apolloSetup.query database = apolloSetup.database @@ -130,13 +130,13 @@ describe('Room', () => { userId: 'other-chatting-user', }, }) - roomId = (result.data as any).CreateRoom.id + roomId = result.data.CreateRoom.id expect(result).toMatchObject({ errors: undefined, data: { CreateRoom: { id: expect.any(String), - roomId: (result.data as any).CreateRoom.id, + roomId: result.data.CreateRoom.id, roomName: 'Other Chatting User', unreadCount: 0, users: expect.arrayContaining([ @@ -212,7 +212,7 @@ describe('Room', () => { Room: [ { id: expect.any(String), - roomId: (result.data as any).Room[0].id, + roomId: result.data.Room[0].id, roomName: 'Other Chatting User', users: expect.arrayContaining([ { @@ -252,7 +252,7 @@ describe('Room', () => { Room: [ { id: expect.any(String), - roomId: (result.data as any).Room[0].id, + roomId: result.data.Room[0].id, roomName: 'Chatting User', unreadCount: 0, users: expect.arrayContaining([ @@ -322,7 +322,7 @@ describe('Room', () => { userId: 'not-chatting-user', }, }) - otherRoomId = (result.data as any).CreateRoom.roomId + otherRoomId = result.data.CreateRoom.roomId await mutate({ mutation: CreateMessage, variables: { @@ -351,7 +351,7 @@ describe('Room', () => { userId: 'not-chatting-user', }, }) - otherRoomId = (result2.data as any).CreateRoom.roomId + otherRoomId = result2.data.CreateRoom.roomId await mutate({ mutation: CreateMessage, variables: { diff --git a/backend/src/graphql/resolvers/searches.spec.ts b/backend/src/graphql/resolvers/searches.spec.ts index f42c7b1b2..d20f9f6eb 100644 --- a/backend/src/graphql/resolvers/searches.spec.ts +++ b/backend/src/graphql/resolvers/searches.spec.ts @@ -1,38 +1,38 @@ /* eslint-disable @typescript-eslint/no-unsafe-call */ /* eslint-disable @typescript-eslint/no-unsafe-member-access */ /* eslint-disable @typescript-eslint/no-unsafe-assignment */ -import { createTestClient } from 'apollo-server-testing' import Factory, { cleanDatabase } from '@db/factories' -import { getNeode, getDriver } from '@db/neo4j' import { searchPosts } from '@graphql/queries/searchPosts' import { searchResults } from '@graphql/queries/searchResults' -import createServer from '@src/server' +import { createApolloTestSetup } from '@root/test/helpers' -let query, authenticatedUser, user +import type { ApolloTestSetup } from '@root/test/helpers' +import type { Context } from '@src/context' -const driver = getDriver() -const neode = getNeode() +let authenticatedUser: Context['user'] +let query: ApolloTestSetup['query'] +let database: ApolloTestSetup['database'] +let server: ApolloTestSetup['server'] +let user + +const contextFn = () => ({ + authenticatedUser, +}) beforeAll(async () => { await cleanDatabase() - - const { server } = createServer({ - context: () => { - return { - driver, - neode, - user: authenticatedUser, - } - }, - }) - query = createTestClient(server).query + const apolloSetup = await createApolloTestSetup({ context: contextFn }) + query = apolloSetup.query + database = apolloSetup.database + server = apolloSetup.server }) afterAll(async () => { await cleanDatabase() - await driver.close() - neode.close() + void server.stop() + void database.driver.close() + database.neode.close() }) describe('resolvers/searches', () => { diff --git a/backend/src/graphql/resolvers/shout.spec.ts b/backend/src/graphql/resolvers/shout.spec.ts index d24cb9813..1fd1e17a2 100644 --- a/backend/src/graphql/resolvers/shout.spec.ts +++ b/backend/src/graphql/resolvers/shout.spec.ts @@ -2,18 +2,26 @@ /* eslint-disable @typescript-eslint/no-unsafe-call */ /* eslint-disable @typescript-eslint/no-unsafe-member-access */ /* eslint-disable @typescript-eslint/no-unsafe-assignment */ -import { createTestClient } from 'apollo-server-testing' import Factory, { cleanDatabase } from '@db/factories' -import { getNeode, getDriver } from '@db/neo4j' import { Post } from '@graphql/queries/Post' import { shout } from '@graphql/queries/shout' import { unshout } from '@graphql/queries/unshout' -import createServer from '@src/server' +import { createApolloTestSetup } from '@root/test/helpers' -let mutate, query, authenticatedUser, variables -const instance = getNeode() -const driver = getDriver() +import type { ApolloTestSetup } from '@root/test/helpers' +import type { Context } from '@src/context' + +let authenticatedUser: Context['user'] +let mutate: ApolloTestSetup['mutate'] +let query: ApolloTestSetup['query'] +let database: ApolloTestSetup['database'] +let server: ApolloTestSetup['server'] +let variables + +const contextFn = () => ({ + authenticatedUser, +}) describe('shout and unshout posts', () => { let currentUser, postAuthor @@ -21,26 +29,19 @@ describe('shout and unshout posts', () => { beforeAll(async () => { await cleanDatabase() - authenticatedUser = undefined - const { server } = createServer({ - context: () => { - return { - driver, - neode: instance, - user: authenticatedUser, - cypherParams: { - currentUserId: authenticatedUser ? authenticatedUser.id : null, - }, - } - }, - }) - mutate = createTestClient(server).mutate - query = createTestClient(server).query + authenticatedUser = null + const apolloSetup = await createApolloTestSetup({ context: contextFn }) + query = apolloSetup.query + mutate = apolloSetup.mutate + database = apolloSetup.database + server = apolloSetup.server }) afterAll(async () => { await cleanDatabase() - await driver.close() + void server.stop() + void database.driver.close() + database.neode.close() }) beforeEach(async () => { @@ -78,7 +79,7 @@ describe('shout and unshout posts', () => { describe('unauthenticated', () => { it('throws authorization error', async () => { variables = { id: 'post-to-shout-id' } - authenticatedUser = undefined + authenticatedUser = null await expect(mutate({ mutation: shout, variables })).resolves.toMatchObject({ errors: [{ message: 'Not Authorized!' }], }) @@ -124,7 +125,7 @@ describe('shout and unshout posts', () => { it('adds `createdAt` to `SHOUT` relationship', async () => { variables = { id: 'another-user-post-id' } await mutate({ mutation: shout, variables }) - const relation = await instance.cypher( + const relation = await database.neode.cypher( 'MATCH (user:User {id: $userId1})-[relationship:SHOUTED]->(node {id: $userId2}) WHERE relationship.createdAt IS NOT NULL RETURN relationship', { userId1: 'current-user-id', @@ -152,7 +153,7 @@ describe('shout and unshout posts', () => { describe('unshout', () => { describe('unauthenticated', () => { it('throws authorization error', async () => { - authenticatedUser = undefined + authenticatedUser = null variables = { id: 'post-to-shout-id' } await expect(mutate({ mutation: unshout, variables })).resolves.toMatchObject({ errors: [{ message: 'Not Authorized!' }], diff --git a/backend/src/graphql/resolvers/socialMedia.spec.ts b/backend/src/graphql/resolvers/socialMedia.spec.ts index ba75c6707..7dc62fb7f 100644 --- a/backend/src/graphql/resolvers/socialMedia.spec.ts +++ b/backend/src/graphql/resolvers/socialMedia.spec.ts @@ -1,30 +1,42 @@ -/* eslint-disable @typescript-eslint/require-await */ +/* eslint-disable @typescript-eslint/no-non-null-assertion */ /* eslint-disable @typescript-eslint/no-unsafe-return */ /* eslint-disable @typescript-eslint/no-unsafe-assignment */ /* eslint-disable @typescript-eslint/no-unsafe-member-access */ /* eslint-disable @typescript-eslint/no-unsafe-call */ -import { createTestClient } from 'apollo-server-testing' import Factory, { cleanDatabase } from '@db/factories' -import { getDriver } from '@db/neo4j' import { CreateSocialMedia } from '@graphql/queries/CreateSocialMedia' import { DeleteSocialMedia } from '@graphql/queries/DeleteSocialMedia' import { UpdateSocialMedia } from '@graphql/queries/UpdateSocialMedia' -import createServer from '@src/server' +import { createApolloTestSetup } from '@root/test/helpers' -const driver = getDriver() +import type { ApolloTestSetup } from '@root/test/helpers' +import type { Context } from '@src/context' + +let authenticatedUser: Context['user'] +let query: ApolloTestSetup['query'] +let database: ApolloTestSetup['database'] +let server: ApolloTestSetup['server'] + +const context = () => ({ authenticatedUser }) beforeAll(async () => { await cleanDatabase() + const apolloSetup = await createApolloTestSetup({ context }) + query = apolloSetup.query + database = apolloSetup.database + server = apolloSetup.server }) afterAll(async () => { await cleanDatabase() - await driver.close() + void server.stop() + void database.driver.close() + database.neode.close() }) describe('SocialMedia', () => { - let socialMediaAction, someUser, ownerNode, owner + let someUser, ownerNode, owner const url = 'https://twitter.com/pippi-langstrumpf' const newUrl = 'https://twitter.com/bullerby' @@ -35,6 +47,11 @@ describe('SocialMedia', () => { return socialMediaNode.toJson() } + const socialMediaAction = async (user, mutation, variables) => { + authenticatedUser = user + return query({ query: mutation, variables }) + } + beforeEach(async () => { const someUserNode = await Factory.build( 'user', @@ -59,23 +76,6 @@ describe('SocialMedia', () => { }, ) owner = await ownerNode.toJson() - - socialMediaAction = async (user, mutation, variables) => { - const { server } = createServer({ - context: () => { - return { - user, - driver, - } - }, - }) - const { mutate } = createTestClient(server) - - return mutate({ - mutation, - variables, - }) - } }) // TODO: avoid database clean after each test in the future if possible for performance and flakyness reasons by filling the database step by step, see issue https://github.com/Ocelot-Social-Community/Ocelot-Social/issues/4543 @@ -95,7 +95,7 @@ describe('SocialMedia', () => { const user = null const result = await socialMediaAction(user, CreateSocialMedia, variables) - expect(result.errors[0]).toHaveProperty('message', 'Not Authorized!') + expect(result.errors![0]).toHaveProperty('message', 'Not Authorized!') }) }) @@ -121,7 +121,7 @@ describe('SocialMedia', () => { variables = { url: '' } const result = await socialMediaAction(user, CreateSocialMedia, variables) - expect(result.errors[0].message).toEqual( + expect(result.errors![0].message).toEqual( expect.stringContaining('"url" is not allowed to be empty'), ) }) @@ -130,7 +130,7 @@ describe('SocialMedia', () => { variables = { url: 'not-a-url' } const result = await socialMediaAction(user, CreateSocialMedia, variables) - expect(result.errors[0].message).toEqual( + expect(result.errors![0].message).toEqual( expect.stringContaining('"url" must be a valid uri'), ) }) @@ -161,7 +161,7 @@ describe('SocialMedia', () => { const user = null const result = await socialMediaAction(user, UpdateSocialMedia, variables) - expect(result.errors[0]).toHaveProperty('message', 'Not Authorized!') + expect(result.errors![0]).toHaveProperty('message', 'Not Authorized!') }) }) @@ -170,7 +170,7 @@ describe('SocialMedia', () => { const user = someUser const result = await socialMediaAction(user, UpdateSocialMedia, variables) - expect(result.errors[0]).toHaveProperty('message', 'Not Authorized!') + expect(result.errors![0]).toHaveProperty('message', 'Not Authorized!') }) }) @@ -197,7 +197,7 @@ describe('SocialMedia', () => { variables.id = 'some-id' const result = await socialMediaAction(user, UpdateSocialMedia, variables) - expect(result.errors[0]).toHaveProperty('message', 'Not Authorized!') + expect(result.errors![0]).toHaveProperty('message', 'Not Authorized!') }) }) }) @@ -215,7 +215,7 @@ describe('SocialMedia', () => { const user = null const result = await socialMediaAction(user, DeleteSocialMedia, variables) - expect(result.errors[0]).toHaveProperty('message', 'Not Authorized!') + expect(result.errors![0]).toHaveProperty('message', 'Not Authorized!') }) }) @@ -224,14 +224,14 @@ describe('SocialMedia', () => { const user = someUser const result = await socialMediaAction(user, DeleteSocialMedia, variables) - expect(result.errors[0]).toHaveProperty('message', 'Not Authorized!') + expect(result.errors![0]).toHaveProperty('message', 'Not Authorized!') }) }) describe('authenticated as owner', () => { let user - beforeEach(async () => { + beforeEach(() => { user = owner }) diff --git a/backend/src/graphql/resolvers/statistics.spec.ts b/backend/src/graphql/resolvers/statistics.spec.ts index 53faffd11..fdf203c2f 100644 --- a/backend/src/graphql/resolvers/statistics.spec.ts +++ b/backend/src/graphql/resolvers/statistics.spec.ts @@ -19,7 +19,7 @@ let server: ApolloTestSetup['server'] beforeAll(async () => { await cleanDatabase() - const apolloSetup = createApolloTestSetup({ context }) + const apolloSetup = await createApolloTestSetup({ context }) query = apolloSetup.query database = apolloSetup.database server = apolloSetup.server diff --git a/backend/src/graphql/resolvers/userData.spec.ts b/backend/src/graphql/resolvers/userData.spec.ts index 8427dd964..3e0a7b993 100644 --- a/backend/src/graphql/resolvers/userData.spec.ts +++ b/backend/src/graphql/resolvers/userData.spec.ts @@ -1,17 +1,22 @@ /* eslint-disable @typescript-eslint/no-unsafe-call */ /* eslint-disable @typescript-eslint/no-unsafe-member-access */ /* eslint-disable @typescript-eslint/no-unsafe-assignment */ -import { createTestClient } from 'apollo-server-testing' import Factory, { cleanDatabase } from '@db/factories' -import { getNeode, getDriver } from '@db/neo4j' import { userData } from '@graphql/queries/userData' -import createServer from '@src/server' +import { createApolloTestSetup } from '@root/test/helpers' -let query, authenticatedUser +import type { ApolloTestSetup } from '@root/test/helpers' +import type { Context } from '@src/context' -const driver = getDriver() -const neode = getNeode() +let authenticatedUser: Context['user'] +let query: ApolloTestSetup['query'] +let database: ApolloTestSetup['database'] +let server: ApolloTestSetup['server'] + +const contextFn = () => ({ + authenticatedUser, +}) beforeAll(async () => { await cleanDatabase() @@ -27,21 +32,17 @@ beforeAll(async () => { slug: 'unauthenticated-user', }) authenticatedUser = await user.toJson() - const { server } = createServer({ - context: () => { - return { - driver, - neode, - user: authenticatedUser, - } - }, - }) - query = createTestClient(server).query + const apolloSetup = await createApolloTestSetup({ context: contextFn }) + query = apolloSetup.query + database = apolloSetup.database + server = apolloSetup.server }) afterAll(async () => { await cleanDatabase() - await driver.close() + void server.stop() + void database.driver.close() + database.neode.close() }) describe('resolvers/userData', () => { diff --git a/backend/src/graphql/resolvers/user_management.spec.ts b/backend/src/graphql/resolvers/user_management.spec.ts index 1568972fa..2741f1260 100644 --- a/backend/src/graphql/resolvers/user_management.spec.ts +++ b/backend/src/graphql/resolvers/user_management.spec.ts @@ -65,7 +65,7 @@ beforeAll(async () => { ) return { authenticatedUser, config } } - const apolloSetup = createApolloTestSetup({ context }) + const apolloSetup = await createApolloTestSetup({ context }) mutate = apolloSetup.mutate query = apolloSetup.query database = apolloSetup.database diff --git a/backend/src/graphql/resolvers/user_management.ts b/backend/src/graphql/resolvers/user_management.ts index 0e2604abc..122252816 100644 --- a/backend/src/graphql/resolvers/user_management.ts +++ b/backend/src/graphql/resolvers/user_management.ts @@ -2,10 +2,10 @@ /* eslint-disable @typescript-eslint/no-unsafe-assignment */ /* eslint-disable @typescript-eslint/no-unsafe-return */ /* eslint-disable @typescript-eslint/no-unsafe-member-access */ -import { AuthenticationError } from 'apollo-server' import bcrypt from 'bcryptjs' import { getNeode } from '@db/neo4j' +import { AuthenticationError } from '@graphql/errors' import { encode } from '@jwt/encode' import normalizeEmail from './helpers/normalizeEmail' diff --git a/backend/src/graphql/resolvers/users.spec.ts b/backend/src/graphql/resolvers/users.spec.ts index e5710841a..57e1977fd 100644 --- a/backend/src/graphql/resolvers/users.spec.ts +++ b/backend/src/graphql/resolvers/users.spec.ts @@ -41,7 +41,7 @@ let server: ApolloTestSetup['server'] beforeAll(async () => { await cleanDatabase() - const apolloSetup = createApolloTestSetup({ context }) + const apolloSetup = await createApolloTestSetup({ context }) mutate = apolloSetup.mutate query = apolloSetup.query database = apolloSetup.database diff --git a/backend/src/graphql/resolvers/users.ts b/backend/src/graphql/resolvers/users.ts index a74282986..25d122e34 100644 --- a/backend/src/graphql/resolvers/users.ts +++ b/backend/src/graphql/resolvers/users.ts @@ -5,11 +5,11 @@ /* eslint-disable @typescript-eslint/no-unsafe-return */ /* eslint-disable @typescript-eslint/no-unsafe-assignment */ /* eslint-disable @typescript-eslint/no-shadow */ -import { UserInputError, ForbiddenError } from 'apollo-server' import { neo4jgraphql } from 'neo4j-graphql-js' import { TROPHY_BADGES_SELECTED_MAX } from '@constants/badges' import { getNeode } from '@db/neo4j' +import { UserInputError, ForbiddenError } from '@graphql/errors' import { defaultTrophyBadge, defaultVerificationBadge } from './badges' import normalizeEmail from './helpers/normalizeEmail' diff --git a/backend/src/graphql/resolvers/users/blockedUsers.spec.ts b/backend/src/graphql/resolvers/users/blockedUsers.spec.ts index c66fddf5a..4550a4211 100644 --- a/backend/src/graphql/resolvers/users/blockedUsers.spec.ts +++ b/backend/src/graphql/resolvers/users/blockedUsers.spec.ts @@ -26,7 +26,7 @@ let server: ApolloTestSetup['server'] beforeAll(async () => { await cleanDatabase() - const apolloSetup = createApolloTestSetup({ context }) + const apolloSetup = await createApolloTestSetup({ context }) mutate = apolloSetup.mutate query = apolloSetup.query database = apolloSetup.database diff --git a/backend/src/graphql/resolvers/users/location.spec.ts b/backend/src/graphql/resolvers/users/location.spec.ts index bdd1b3c67..daa45c352 100644 --- a/backend/src/graphql/resolvers/users/location.spec.ts +++ b/backend/src/graphql/resolvers/users/location.spec.ts @@ -15,7 +15,7 @@ const context = () => ({ authenticatedUser, }) let mutate: ApolloTestSetup['mutate'] -let query: any // eslint-disable-line @typescript-eslint/no-explicit-any +let query: ApolloTestSetup['query'] let database: ApolloTestSetup['database'] let server: ApolloTestSetup['server'] @@ -70,7 +70,7 @@ const newlyCreatedNodesWithLocales = [ beforeAll(async () => { await cleanDatabase() - const apolloSetup = createApolloTestSetup({ + const apolloSetup = await createApolloTestSetup({ context, }) mutate = apolloSetup.mutate diff --git a/backend/src/graphql/resolvers/users/location.ts b/backend/src/graphql/resolvers/users/location.ts index 36861a93a..10a9497f1 100644 --- a/backend/src/graphql/resolvers/users/location.ts +++ b/backend/src/graphql/resolvers/users/location.ts @@ -9,7 +9,7 @@ /* eslint-disable @typescript-eslint/prefer-nullish-coalescing */ /* eslint-disable @typescript-eslint/no-loop-func */ -import { UserInputError } from 'apollo-server' +import { UserInputError } from '@graphql/errors' import type { Context } from '@src/context' @@ -74,80 +74,79 @@ export const createOrUpdateLocations = async ( let locationId - try { - if (locationName !== null) { - const response: any = await fetch( - `https://api.mapbox.com/geocoding/v5/mapbox.places/${encodeURIComponent( - locationName, - )}.json?access_token=${ - context.config.MAPBOX_TOKEN - }&types=region,place,country,address&language=${locales.join(',')}`, - { - signal: AbortSignal.timeout(REQUEST_TIMEOUT), - }, - ) + if (locationName !== null) { + const response: any = await fetch( + `https://api.mapbox.com/geocoding/v5/mapbox.places/${encodeURIComponent( + locationName, + )}.json?access_token=${ + context.config.MAPBOX_TOKEN + }&types=region,place,country,address&language=${locales.join(',')}`, + { + signal: AbortSignal.timeout(REQUEST_TIMEOUT), + }, + ) - const res = await response.json() + const res = await response.json() - if (!res?.features?.[0]) { - throw new UserInputError('locationName is invalid') + if (!res?.features?.[0]) { + throw new UserInputError('locationName is invalid') + } + + let data + + res.features.forEach((item) => { + if (item.matching_place_name === locationName) { + data = item } + }) + if (!data) { + data = res.features[0] + } - let data + if (!data?.place_type?.length) { + throw new UserInputError('locationName is invalid') + } - res.features.forEach((item) => { - if (item.matching_place_name === locationName) { - data = item - } - }) - if (!data) { - data = res.features[0] - } + if (data.place_type.length > 1) { + data.id = 'region.' + data.id.split('.')[1] + } + await createLocation(session, data) - if (!data?.place_type?.length) { - throw new UserInputError('locationName is invalid') - } + let parent = data - if (data.place_type.length > 1) { - data.id = 'region.' + data.id.split('.')[1] - } - await createLocation(session, data) + if (parent.address) { + parent.id += `-${parent.address}` + } - let parent = data - - if (parent.address) { - parent.id += `-${parent.address}` - } - - if (data.context) { - for await (const ctx of data.context) { - await createLocation(session, ctx) - await session.writeTransaction((transaction) => { - return transaction.run( - ` + if (data.context) { + for await (const ctx of data.context) { + await createLocation(session, ctx) + await session.writeTransaction((transaction) => { + return transaction.run( + ` MATCH (parent:Location {id: $parentId}), (child:Location {id: $childId}) MERGE (child)<-[:IS_IN]-(parent) RETURN child.id, parent.id `, - { - parentId: parent.id, - childId: ctx.id, - }, - ) - }) - parent = ctx - } + { + parentId: parent.id, + childId: ctx.id, + }, + ) + }) + parent = ctx } - - locationId = data.id - } else { - locationId = 'non-existent-id' } - // delete all current locations from node and add new location - await session.writeTransaction((transaction) => { - return transaction.run( - ` + locationId = data.id + } else { + locationId = 'non-existent-id' + } + + // delete all current locations from node and add new location + await session.writeTransaction((transaction) => { + return transaction.run( + ` MATCH (node:${nodeLabel} {id: $nodeId}) OPTIONAL MATCH (node)-[relationship:IS_IN]->(:Location) DELETE relationship @@ -156,29 +155,22 @@ export const createOrUpdateLocations = async ( MERGE (node)-[:IS_IN]->(location) RETURN location.id, node.id `, - { nodeId, locationId }, - ) - }) - } catch (error) { - throw new Error(error) - } + { nodeId, locationId }, + ) + }) } export const queryLocations = async ({ place, lang }, context: Context) => { - try { - const res: any = await fetch( - `https://api.mapbox.com/geocoding/v5/mapbox.places/${place}.json?access_token=${context.config.MAPBOX_TOKEN}&types=region,place,country&language=${lang}`, - { - signal: AbortSignal.timeout(REQUEST_TIMEOUT), - }, - ) - const response = await res.json() - // Return empty array if no location found or error occurred - if (!response?.features) { - return [] - } - return response.features - } catch (error) { - throw new Error(error) + const res: any = await fetch( + `https://api.mapbox.com/geocoding/v5/mapbox.places/${place}.json?access_token=${context.config.MAPBOX_TOKEN}&types=region,place,country&language=${lang}`, + { + signal: AbortSignal.timeout(REQUEST_TIMEOUT), + }, + ) + const response = await res.json() + // Return empty array if no location found or error occurred + if (!response?.features) { + return [] } + return response.features } diff --git a/backend/src/graphql/resolvers/users/mutedUsers.spec.ts b/backend/src/graphql/resolvers/users/mutedUsers.spec.ts index 641d20258..f94cf59fe 100644 --- a/backend/src/graphql/resolvers/users/mutedUsers.spec.ts +++ b/backend/src/graphql/resolvers/users/mutedUsers.spec.ts @@ -1,50 +1,44 @@ +/* eslint-disable @typescript-eslint/no-unsafe-return */ /* eslint-disable @typescript-eslint/no-unsafe-argument */ /* eslint-disable @typescript-eslint/no-unsafe-assignment */ /* eslint-disable @typescript-eslint/no-unsafe-member-access */ /* eslint-disable @typescript-eslint/no-unsafe-call */ -/* eslint-disable jest/expect-expect */ -import { createTestClient } from 'apollo-server-testing' import { cleanDatabase } from '@db/factories' -import { getNeode, getDriver } from '@db/neo4j' import { mutedUsers } from '@graphql/queries/mutedUsers' import { muteUser } from '@graphql/queries/muteUser' import { Post } from '@graphql/queries/Post' import { unmuteUser } from '@graphql/queries/unmuteUser' import { User } from '@graphql/queries/User' -import createServer from '@src/server' +import { createApolloTestSetup } from '@root/test/helpers' -const driver = getDriver() -const neode = getNeode() +import type { ApolloTestSetup } from '@root/test/helpers' +import type { Context } from '@src/context' let currentUser let mutedUser -let authenticatedUser -let server + +let authenticatedUser: Context['user'] +const context = () => ({ authenticatedUser }) +let mutate: ApolloTestSetup['mutate'] +let query: ApolloTestSetup['query'] +let database: ApolloTestSetup['database'] +let server: ApolloTestSetup['server'] beforeAll(async () => { await cleanDatabase() + const apolloSetup = await createApolloTestSetup({ context }) + mutate = apolloSetup.mutate + query = apolloSetup.query + database = apolloSetup.database + server = apolloSetup.server }) afterAll(async () => { await cleanDatabase() - await driver.close() -}) - -beforeEach(() => { - authenticatedUser = undefined - ;({ server } = createServer({ - context: () => { - return { - user: authenticatedUser, - driver, - neode, - cypherParams: { - currentUserId: authenticatedUser ? authenticatedUser.id : null, - }, - } - }, - })) + void server.stop() + void database.driver.close() + database.neode.close() }) // TODO: avoid database clean after each test in the future if possible for performance and flakyness reasons by filling the database step by step, see issue https://github.com/Ocelot-Social-Community/Ocelot-Social/issues/4543 @@ -53,20 +47,25 @@ afterEach(async () => { }) describe('mutedUsers', () => { - it('throws permission error', async () => { - const { query } = createTestClient(server) - const result = await query({ query: mutedUsers }) - // eslint-disable-next-line @typescript-eslint/no-non-null-assertion - expect(result.errors![0]).toHaveProperty('message', 'Not Authorized!') + describe('unauthenticated', () => { + beforeEach(() => { + authenticatedUser = null + }) + + it('throws permission error', async () => { + const result = await query({ query: mutedUsers }) + // eslint-disable-next-line @typescript-eslint/no-non-null-assertion + expect(result.errors![0]).toHaveProperty('message', 'Not Authorized!') + }) }) describe('authenticated and given a muted user', () => { beforeEach(async () => { - currentUser = await neode.create('User', { + currentUser = await database.neode.create('User', { name: 'Current User', id: 'u1', }) - mutedUser = await neode.create('User', { + mutedUser = await database.neode.create('User', { name: 'Muted User', id: 'u2', }) @@ -75,7 +74,6 @@ describe('mutedUsers', () => { }) it('returns a list of muted users', async () => { - const { query } = createTestClient(server) await expect(query({ query: mutedUsers })).resolves.toEqual( expect.objectContaining({ data: { @@ -96,26 +94,30 @@ describe('mutedUsers', () => { describe('muteUser', () => { let muteAction - beforeEach(() => { - currentUser = undefined - muteAction = async (variables) => { - const { mutate } = createTestClient(server) - return mutate({ mutation: muteUser, variables }) - } - }) + describe('unauthenticated', () => { + beforeEach(() => { + authenticatedUser = null + muteAction = async (variables) => { + return mutate({ mutation: muteUser, variables }) + } + }) - it('throws permission error', async () => { - const result = await muteAction({ id: 'u2' }) - expect(result.errors[0]).toHaveProperty('message', 'Not Authorized!') + it('throws permission error', async () => { + const result = await muteAction({ id: 'u2' }) + expect(result.errors[0]).toHaveProperty('message', 'Not Authorized!') + }) }) describe('authenticated', () => { beforeEach(async () => { - currentUser = await neode.create('User', { + currentUser = await database.neode.create('User', { name: 'Current User', id: 'u1', }) authenticatedUser = await currentUser.toJson() + muteAction = async (variables) => { + return mutate({ mutation: muteUser, variables }) + } }) describe('mute yourself', () => { @@ -136,7 +138,7 @@ describe('muteUser', () => { describe('given a to-be-muted user', () => { beforeEach(async () => { - mutedUser = await neode.create('User', { + mutedUser = await database.neode.create('User', { name: 'Muted User', id: 'u2', }) @@ -154,7 +156,6 @@ describe('muteUser', () => { it('unfollows the user', async () => { await currentUser.relateTo(mutedUser, 'following') - const { query } = createTestClient(server) await expect(query({ query: User, variables: { id: 'u2' } })).resolves.toMatchObject({ data: { User: expect.arrayContaining([ @@ -174,12 +175,12 @@ describe('muteUser', () => { describe('given both the current user and the to-be-muted user write a post', () => { beforeEach(async () => { - const post1 = await neode.create('Post', { + const post1 = await database.neode.create('Post', { id: 'p12', title: 'A post written by the current user', content: 'content', }) - const post2 = await neode.create('Post', { + const post2 = await database.neode.create('Post', { id: 'p23', title: 'A post written by the muted user', content: 'content', @@ -191,7 +192,6 @@ describe('muteUser', () => { }) const bothPostsAreInTheNewsfeed = async () => { - const { query } = createTestClient(server) await expect( query({ query: Post, variables: { orderBy: 'createdAt_asc' } }), ).resolves.toMatchObject({ @@ -219,6 +219,7 @@ describe('muteUser', () => { } describe('from the perspective of the current user', () => { + // eslint-disable-next-line jest/expect-expect it('both posts are in the newsfeed', bothPostsAreInTheNewsfeed) describe('but if the current user mutes the other user', () => { @@ -227,7 +228,6 @@ describe('muteUser', () => { }) it("the muted user's post won't show up in the newsfeed of the current user", async () => { - const { query } = createTestClient(server) await expect( query({ query: Post, variables: { orderBy: 'createdAt_asc' } }), ).resolves.toMatchObject({ @@ -244,7 +244,6 @@ describe('muteUser', () => { }) it("the muted user's post is still accessible by direct id lookup", async () => { - const { query } = createTestClient(server) await expect(query({ query: Post, variables: { id: 'p23' } })).resolves.toMatchObject( { data: { @@ -261,7 +260,7 @@ describe('muteUser', () => { describe('but the muted user has a pinned post', () => { beforeEach(async () => { - const pinnedPost = await neode.create('Post', { + const pinnedPost = await database.neode.create('Post', { id: 'p-pinned', title: 'A pinned post by the muted user', content: 'pinned content', @@ -271,7 +270,6 @@ describe('muteUser', () => { }) it('the pinned post still shows up in the post list', async () => { - const { query } = createTestClient(server) await expect( query({ query: Post, variables: { orderBy: 'createdAt_asc' } }), ).resolves.toMatchObject({ @@ -288,7 +286,6 @@ describe('muteUser', () => { }) it('the pinned post is accessible by id', async () => { - const { query } = createTestClient(server) await expect( query({ query: Post, variables: { id: 'p-pinned' } }), ).resolves.toMatchObject({ @@ -305,12 +302,10 @@ describe('muteUser', () => { }) it('the non-pinned post from the muted user is still hidden in the feed', async () => { - const { query } = createTestClient(server) const result = await query({ query: Post, variables: { orderBy: 'createdAt_asc' }, }) - // eslint-disable-next-line @typescript-eslint/no-unsafe-return const postIds = result.data?.Post.map((p) => p.id) expect(postIds).not.toContain('p23') }) @@ -323,6 +318,7 @@ describe('muteUser', () => { authenticatedUser = await mutedUser.toJson() }) + // eslint-disable-next-line jest/expect-expect it('both posts are in the newsfeed', bothPostsAreInTheNewsfeed) describe('but if the current user mutes the other user', () => { beforeEach(async () => { @@ -330,7 +326,6 @@ describe('muteUser', () => { }) it("the current user's post will show up in the newsfeed of the muted user", async () => { - const { query } = createTestClient(server) await expect( query({ query: Post, variables: { orderBy: 'createdAt_asc' } }), ).resolves.toMatchObject({ @@ -360,26 +355,30 @@ describe('muteUser', () => { describe('unmuteUser', () => { let unmuteAction - beforeEach(() => { - currentUser = undefined - unmuteAction = async (variables) => { - const { mutate } = createTestClient(server) - return mutate({ mutation: unmuteUser, variables }) - } - }) + describe('unauthenticated', () => { + beforeEach(() => { + authenticatedUser = null + unmuteAction = async (variables) => { + return mutate({ mutation: unmuteUser, variables }) + } + }) - it('throws permission error', async () => { - const result = await unmuteAction({ id: 'u2' }) - expect(result.errors[0]).toHaveProperty('message', 'Not Authorized!') + it('throws permission error', async () => { + const result = await unmuteAction({ id: 'u2' }) + expect(result.errors[0]).toHaveProperty('message', 'Not Authorized!') + }) }) describe('authenticated', () => { beforeEach(async () => { - currentUser = await neode.create('User', { + currentUser = await database.neode.create('User', { name: 'Current User', id: 'u1', }) authenticatedUser = await currentUser.toJson() + unmuteAction = async (variables) => { + return mutate({ mutation: unmuteUser, variables }) + } }) describe('unmute yourself', () => { @@ -400,7 +399,7 @@ describe('unmuteUser', () => { describe('given another user', () => { beforeEach(async () => { - mutedUser = await neode.create('User', { + mutedUser = await database.neode.create('User', { name: 'Muted User', id: 'u2', }) diff --git a/backend/src/graphql/schema.ts b/backend/src/graphql/schema.ts index b010084c3..ce756691c 100644 --- a/backend/src/graphql/schema.ts +++ b/backend/src/graphql/schema.ts @@ -1,5 +1,5 @@ -/* eslint-disable @typescript-eslint/no-unsafe-assignment */ /* eslint-disable @typescript-eslint/no-unsafe-call */ +import { print } from 'graphql' import { makeAugmentedSchema } from 'neo4j-graphql-js' import typeDefs from '@graphql/types/index' @@ -7,7 +7,7 @@ import typeDefs from '@graphql/types/index' import resolvers from './resolvers' export default makeAugmentedSchema({ - typeDefs, + typeDefs: print(typeDefs), resolvers, config: { query: { diff --git a/backend/src/graphql/types/index.ts b/backend/src/graphql/types/index.ts index 42d813ae4..a998f19a1 100644 --- a/backend/src/graphql/types/index.ts +++ b/backend/src/graphql/types/index.ts @@ -1,6 +1,8 @@ import path from 'node:path' -import { mergeTypes, fileLoader } from 'merge-graphql-schemas' +import { loadFilesSync } from '@graphql-tools/load-files' +import { mergeTypeDefs } from '@graphql-tools/merge' -const typeDefs = fileLoader(path.join(__dirname, './**/*.gql')) -export default mergeTypes(typeDefs, { all: true }) +// eslint-disable-next-line n/no-sync +const typeDefs = loadFilesSync(path.join(__dirname, './**/*.gql')) +export default mergeTypeDefs(typeDefs) diff --git a/backend/src/index.ts b/backend/src/index.ts index f1b3827fe..519e6fc51 100644 --- a/backend/src/index.ts +++ b/backend/src/index.ts @@ -1,34 +1,41 @@ -/* eslint-disable @typescript-eslint/restrict-template-expressions */ - import CONFIG from './config' import { loggerPlugin } from './plugins/apolloLogger' import createProxy from './proxy' import createServer from './server' -const { server, httpServer } = createServer({ - plugins: [loggerPlugin], -}) -const url = new URL(CONFIG.GRAPHQL_URI) -httpServer.listen({ port: url.port }, () => { - /* eslint-disable-next-line no-console */ - console.log(`🚀 Server ready at http://localhost:${url.port}${server.graphqlPath}`) - /* eslint-disable-next-line no-console */ - console.log(`🚀 Subscriptions ready at ws://localhost:${url.port}${server.subscriptionsPath}`) -}) - -if (CONFIG.PROXY_S3) { - /* - In a Docker environment, the `AWS_ENDPOINT` of the backend container would be `http://minio:9000` but this domain is not reachable from the Docker host. - Therefore, we forward the local port 9000 to "http://minio:9000." The backend can upload files to its own proxy `http://localhost:9000` and the returned file location is going to be accessible from the web frontend. - This behavior is only required in local development, not in production. Therefore, we put it behind a `CONFIG.PROXY_S3` feature flag. - */ - const target = new URL(CONFIG.PROXY_S3) - const proxy = createProxy(target) - const forwardedPort = target.port // target port and forwarded port must be the same - proxy.listen(forwardedPort, () => { - /* eslint-disable-next-line no-console */ - console.log(`Simple HTTP proxy listening on port ${forwardedPort}`) - /* eslint-disable-next-line no-console */ - console.log(`Proxying requests to ${target}`) +async function main() { + const { httpServer } = await createServer({ + plugins: [loggerPlugin], }) + const url = new URL(CONFIG.GRAPHQL_URI) + httpServer.listen({ port: url.port }, () => { + /* eslint-disable-next-line no-console */ + console.log(`🚀 Server ready at http://localhost:${url.port}/`) + /* eslint-disable-next-line no-console */ + console.log(`🚀 Subscriptions ready at ws://localhost:${url.port}/`) + }) + + if (CONFIG.PROXY_S3) { + /* + In a Docker environment, the `AWS_ENDPOINT` of the backend container would be `http://minio:9000` but this domain is not reachable from the Docker host. + Therefore, we forward the local port 9000 to "http://minio:9000." The backend can upload files to its own proxy `http://localhost:9000` and the returned file location is going to be accessible from the web frontend. + This behavior is only required in local development, not in production. Therefore, we put it behind a `CONFIG.PROXY_S3` feature flag. + */ + const target = new URL(CONFIG.PROXY_S3) + const proxy = createProxy(target) + const forwardedPort = target.port // target port and forwarded port must be the same + proxy.listen(forwardedPort, () => { + /* eslint-disable-next-line no-console */ + console.log(`Simple HTTP proxy listening on port ${forwardedPort}`) + /* eslint-disable-next-line no-console */ + console.log(`Proxying requests to ${target}`) + }) + } } + +// eslint-disable-next-line promise/prefer-await-to-callbacks, @typescript-eslint/use-unknown-in-catch-callback-variable +main().catch((err) => { + /* eslint-disable-next-line no-console */ + console.error('Failed to start server:', err) + process.exit(1) +}) diff --git a/backend/src/middleware/categories.spec.ts b/backend/src/middleware/categories.spec.ts index 6199da30e..3fef0d1fe 100644 --- a/backend/src/middleware/categories.spec.ts +++ b/backend/src/middleware/categories.spec.ts @@ -20,7 +20,7 @@ beforeEach(() => { beforeAll(async () => { await cleanDatabase() const context = () => ({ config, authenticatedUser: null }) - const apolloSetup = createApolloTestSetup({ context }) + const apolloSetup = await createApolloTestSetup({ context }) query = apolloSetup.query database = apolloSetup.database server = apolloSetup.server diff --git a/backend/src/middleware/hashtags/hashtagsMiddleware.spec.ts b/backend/src/middleware/hashtags/hashtagsMiddleware.spec.ts index c60c34b25..62f33c701 100644 --- a/backend/src/middleware/hashtags/hashtagsMiddleware.spec.ts +++ b/backend/src/middleware/hashtags/hashtagsMiddleware.spec.ts @@ -22,7 +22,7 @@ const categoryIds = ['cat9'] beforeAll(async () => { await cleanDatabase() - const apolloSetup = createApolloTestSetup({ context }) + const apolloSetup = await createApolloTestSetup({ context }) mutate = apolloSetup.mutate query = apolloSetup.query database = apolloSetup.database diff --git a/backend/src/middleware/languages/languages.spec.ts b/backend/src/middleware/languages/languages.spec.ts index 90c950c3b..7c2c2b89a 100644 --- a/backend/src/middleware/languages/languages.spec.ts +++ b/backend/src/middleware/languages/languages.spec.ts @@ -17,7 +17,7 @@ let server: ApolloTestSetup['server'] beforeAll(async () => { await cleanDatabase() - const apolloSetup = createApolloTestSetup({ context }) + const apolloSetup = await createApolloTestSetup({ context }) mutate = apolloSetup.mutate database = apolloSetup.database server = apolloSetup.server diff --git a/backend/src/middleware/notifications/notificationsMiddleware.emails.spec.ts b/backend/src/middleware/notifications/notificationsMiddleware.emails.spec.ts index 8dce92a4e..f9ca50605 100644 --- a/backend/src/middleware/notifications/notificationsMiddleware.emails.spec.ts +++ b/backend/src/middleware/notifications/notificationsMiddleware.emails.spec.ts @@ -38,7 +38,7 @@ const mentionString = ` beforeAll(async () => { await cleanDatabase() - const apolloSetup = createApolloTestSetup({ context }) + const apolloSetup = await createApolloTestSetup({ context }) mutate = apolloSetup.mutate query = apolloSetup.query database = apolloSetup.database diff --git a/backend/src/middleware/notifications/notificationsMiddleware.followed-users.spec.ts b/backend/src/middleware/notifications/notificationsMiddleware.followed-users.spec.ts index 35bce3b1a..cc47ba678 100644 --- a/backend/src/middleware/notifications/notificationsMiddleware.followed-users.spec.ts +++ b/backend/src/middleware/notifications/notificationsMiddleware.followed-users.spec.ts @@ -30,7 +30,7 @@ let postAuthor, firstFollower, secondFollower, thirdFollower, emaillessFollower beforeAll(async () => { await cleanDatabase() - const apolloSetup = createApolloTestSetup({ context }) + const apolloSetup = await createApolloTestSetup({ context }) mutate = apolloSetup.mutate query = apolloSetup.query database = apolloSetup.database diff --git a/backend/src/middleware/notifications/notificationsMiddleware.mentions-in-groups.spec.ts b/backend/src/middleware/notifications/notificationsMiddleware.mentions-in-groups.spec.ts index 5410f3e0c..55e2e0ac9 100644 --- a/backend/src/middleware/notifications/notificationsMiddleware.mentions-in-groups.spec.ts +++ b/backend/src/middleware/notifications/notificationsMiddleware.mentions-in-groups.spec.ts @@ -40,7 +40,7 @@ const mentionString = ` beforeAll(async () => { await cleanDatabase() - const apolloSetup = createApolloTestSetup({ context }) + const apolloSetup = await createApolloTestSetup({ context }) mutate = apolloSetup.mutate query = apolloSetup.query database = apolloSetup.database diff --git a/backend/src/middleware/notifications/notificationsMiddleware.observing-posts.spec.ts b/backend/src/middleware/notifications/notificationsMiddleware.observing-posts.spec.ts index 5de65d0fe..094a04b69 100644 --- a/backend/src/middleware/notifications/notificationsMiddleware.observing-posts.spec.ts +++ b/backend/src/middleware/notifications/notificationsMiddleware.observing-posts.spec.ts @@ -30,7 +30,7 @@ let postAuthor, firstCommenter, secondCommenter, emaillessObserver beforeAll(async () => { await cleanDatabase() - const apolloSetup = createApolloTestSetup({ context }) + const apolloSetup = await createApolloTestSetup({ context }) mutate = apolloSetup.mutate query = apolloSetup.query database = apolloSetup.database diff --git a/backend/src/middleware/notifications/notificationsMiddleware.online-status.spec.ts b/backend/src/middleware/notifications/notificationsMiddleware.online-status.spec.ts index aba5c68c1..a0201f377 100644 --- a/backend/src/middleware/notifications/notificationsMiddleware.online-status.spec.ts +++ b/backend/src/middleware/notifications/notificationsMiddleware.online-status.spec.ts @@ -32,7 +32,7 @@ let postAuthor beforeAll(async () => { await cleanDatabase() - const apolloSetup = createApolloTestSetup({ context }) + const apolloSetup = await createApolloTestSetup({ context }) mutate = apolloSetup.mutate database = apolloSetup.database server = apolloSetup.server @@ -41,7 +41,8 @@ beforeAll(async () => { afterAll(async () => { await cleanDatabase() void server.stop() - await database.driver.close() + void database.driver.close() + database.neode.close() }) afterEach(async () => { diff --git a/backend/src/middleware/notifications/notificationsMiddleware.posts-in-groups.spec.ts b/backend/src/middleware/notifications/notificationsMiddleware.posts-in-groups.spec.ts index ecd0ebb9e..1bf90d576 100644 --- a/backend/src/middleware/notifications/notificationsMiddleware.posts-in-groups.spec.ts +++ b/backend/src/middleware/notifications/notificationsMiddleware.posts-in-groups.spec.ts @@ -34,7 +34,7 @@ let postAuthor, groupMember, pendingMember, emaillessMember beforeAll(async () => { await cleanDatabase() - const apolloSetup = createApolloTestSetup({ context }) + const apolloSetup = await createApolloTestSetup({ context }) mutate = apolloSetup.mutate query = apolloSetup.query database = apolloSetup.database diff --git a/backend/src/middleware/notifications/notificationsMiddleware.spec.ts b/backend/src/middleware/notifications/notificationsMiddleware.spec.ts index 6e8d7a7ee..9b21ab8a0 100644 --- a/backend/src/middleware/notifications/notificationsMiddleware.spec.ts +++ b/backend/src/middleware/notifications/notificationsMiddleware.spec.ts @@ -56,7 +56,7 @@ const categoryIds = ['cat9'] beforeAll(async () => { await cleanDatabase() - const apolloSetup = createApolloTestSetup({ context }) + const apolloSetup = await createApolloTestSetup({ context }) mutate = apolloSetup.mutate query = apolloSetup.query database = apolloSetup.database @@ -883,7 +883,7 @@ describe('notifications', () => { userId: 'chatReceiver', }, }) - roomId = (room.data as any).CreateRoom.id // eslint-disable-line @typescript-eslint/no-explicit-any + roomId = room.data.CreateRoom.id }) describe('if the chatReceiver is online', () => { diff --git a/backend/src/middleware/orderByMiddleware.spec.ts b/backend/src/middleware/orderByMiddleware.spec.ts index 78f5a1988..c5687c428 100644 --- a/backend/src/middleware/orderByMiddleware.spec.ts +++ b/backend/src/middleware/orderByMiddleware.spec.ts @@ -1,41 +1,37 @@ -import { createTestClient } from 'apollo-server-testing' - import { cleanDatabase } from '@db/factories' -import { getNeode, getDriver } from '@db/neo4j' import { Post } from '@graphql/queries/Post' -import createServer from '@src/server' +import { createApolloTestSetup } from '@root/test/helpers' -const neode = getNeode() -const driver = getDriver() +import type { ApolloTestSetup } from '@root/test/helpers' -const { server } = createServer({ - context: () => { - return { - user: null, - neode, - driver, - cypherParams: { - currentUserId: null, - }, - } - }, +let query: ApolloTestSetup['query'] +let database: ApolloTestSetup['database'] +let server: ApolloTestSetup['server'] + +const contextFn = () => ({ + authenticatedUser: null, }) -const { query } = createTestClient(server) beforeAll(async () => { await cleanDatabase() + const apolloSetup = await createApolloTestSetup({ context: contextFn }) + query = apolloSetup.query + database = apolloSetup.database + server = apolloSetup.server }) afterAll(async () => { await cleanDatabase() - await driver.close() + void server.stop() + void database.driver.close() + database.neode.close() }) beforeEach(async () => { - await neode.create('Post', { title: 'first', content: 'content' }) - await neode.create('Post', { title: 'second', content: 'content' }) - await neode.create('Post', { title: 'third', content: 'content' }) - await neode.create('Post', { title: 'last', content: 'content' }) + await database.neode.create('Post', { title: 'first', content: 'content' }) + await database.neode.create('Post', { title: 'second', content: 'content' }) + await database.neode.create('Post', { title: 'third', content: 'content' }) + await database.neode.create('Post', { title: 'last', content: 'content' }) }) // TODO: avoid database clean after each test in the future if possible for performance and flakyness reasons by filling the database step by step, see issue https://github.com/Ocelot-Social-Community/Ocelot-Social/issues/4543 diff --git a/backend/src/middleware/permissionsMiddleware.spec.ts b/backend/src/middleware/permissionsMiddleware.spec.ts index 0eb9754e2..ecd07538d 100644 --- a/backend/src/middleware/permissionsMiddleware.spec.ts +++ b/backend/src/middleware/permissionsMiddleware.spec.ts @@ -26,7 +26,7 @@ beforeEach(() => { beforeAll(async () => { await cleanDatabase() - const apolloSetup = createApolloTestSetup({ context }) + const apolloSetup = await createApolloTestSetup({ context }) mutate = apolloSetup.mutate query = apolloSetup.query database = apolloSetup.database diff --git a/backend/src/middleware/sentryMiddleware.ts b/backend/src/middleware/sentryMiddleware.ts index f8e52eca5..7207a654c 100644 --- a/backend/src/middleware/sentryMiddleware.ts +++ b/backend/src/middleware/sentryMiddleware.ts @@ -2,7 +2,7 @@ /* eslint-disable @typescript-eslint/no-unsafe-assignment */ /* eslint-disable @typescript-eslint/no-unsafe-call */ /* eslint-disable @typescript-eslint/no-unsafe-return */ -import { sentry } from 'graphql-middleware-sentry' +import { init, withScope, captureException } from '@sentry/node' import CONFIG from '@config/index' @@ -11,23 +11,29 @@ let sentryMiddleware: any = (resolve, root, args, context, resolveInfo) => resolve(root, args, context, resolveInfo) if (CONFIG.SENTRY_DSN_BACKEND) { - sentryMiddleware = sentry({ - forwardErrors: true, - config: { - dsn: CONFIG.SENTRY_DSN_BACKEND, - release: CONFIG.COMMIT, - environment: CONFIG.NODE_ENV, - }, - // eslint-disable-next-line @typescript-eslint/no-explicit-any - withScope: (scope, error, context: any) => { - scope.setUser({ - id: context.user?.id, - }) - scope.setExtra('body', context.req.body) - scope.setExtra('origin', context.req.headers.origin) - scope.setExtra('user-agent', context.req.headers['user-agent']) - }, + init({ + dsn: CONFIG.SENTRY_DSN_BACKEND, + release: CONFIG.COMMIT, + environment: CONFIG.NODE_ENV, }) + + // eslint-disable-next-line @typescript-eslint/no-explicit-any + sentryMiddleware = async (resolve, root, args, context: any, resolveInfo) => { + try { + return await resolve(root, args, context, resolveInfo) + } catch (error) { + withScope((scope) => { + scope.setUser({ + id: context.user?.id, + }) + scope.setExtra('body', context.req?.body) + scope.setExtra('origin', context.req?.headers?.origin) + scope.setExtra('user-agent', context.req?.headers?.['user-agent']) + captureException(error) + }) + throw error + } + } } else { // eslint-disable-next-line no-console if (!CONFIG.TEST) console.log('Warning: Sentry middleware inactive.') diff --git a/backend/src/middleware/slugifyMiddleware.spec.ts b/backend/src/middleware/slugifyMiddleware.spec.ts index 4be9fb1a6..1424d206a 100644 --- a/backend/src/middleware/slugifyMiddleware.spec.ts +++ b/backend/src/middleware/slugifyMiddleware.spec.ts @@ -26,7 +26,7 @@ let server: ApolloTestSetup['server'] beforeAll(async () => { await cleanDatabase() - const testServer = createApolloTestSetup({ context }) + const testServer = await createApolloTestSetup({ context }) mutate = testServer.mutate database = testServer.database server = testServer.server diff --git a/backend/src/middleware/softDelete/softDeleteMiddleware.spec.ts b/backend/src/middleware/softDelete/softDeleteMiddleware.spec.ts index ef87a5cc6..79a06398b 100644 --- a/backend/src/middleware/softDelete/softDeleteMiddleware.spec.ts +++ b/backend/src/middleware/softDelete/softDeleteMiddleware.spec.ts @@ -1,7 +1,7 @@ /* eslint-disable @typescript-eslint/require-await */ /* eslint-disable @typescript-eslint/no-unsafe-member-access */ /* eslint-disable @typescript-eslint/no-unsafe-call */ -/* eslint-disable @typescript-eslint/no-explicit-any */ + /* eslint-disable @typescript-eslint/no-unsafe-assignment */ import Factory, { cleanDatabase } from '@db/factories' import { Post } from '@graphql/queries/Post' @@ -23,7 +23,7 @@ let server: ApolloTestSetup['server'] beforeAll(async () => { await cleanDatabase() - const apolloSetup = createApolloTestSetup({ context }) + const apolloSetup = await createApolloTestSetup({ context }) query = apolloSetup.query database = apolloSetup.database server = apolloSetup.server @@ -205,15 +205,15 @@ describe('softDeleteMiddleware', () => { let subject const beforeComment = async () => { const { data } = await query({ query: User, variables: { id: 'u1' } }) - subject = (data as any).User[0].following[0].comments[0] + subject = data.User[0].following[0].comments[0] } const beforeUser = async () => { const { data } = await query({ query: User, variables: { id: 'u1' } }) - subject = (data as any).User[0].following[0] + subject = data.User[0].following[0] } const beforePost = async () => { const { data } = await query({ query: User, variables: { id: 'u1' } }) - subject = (data as any).User[0].following[0].contributions[0] + subject = data.User[0].following[0].contributions[0] } describe('as moderator', () => { @@ -349,7 +349,7 @@ describe('softDeleteMiddleware', () => { it('shows disabled but hides deleted posts', async () => { const { data } = await query({ query: Post }) - const { Post: PostData } = data as any + const { Post: PostData } = data expect(PostData).toEqual( expect.arrayContaining([ expect.objectContaining({ title: 'Disabled post' }), @@ -373,7 +373,7 @@ describe('softDeleteMiddleware', () => { const { data } = await query({ query: Post, variables: { id: 'p3' } }) const { Post: [{ comments }], - } = data as any + } = data expect(comments).toEqual(expect.arrayContaining(expected)) }) }) @@ -391,7 +391,7 @@ describe('softDeleteMiddleware', () => { const { data } = await query({ query: Post, variables: { id: 'p3' } }) const { Post: [{ comments }], - } = data as any + } = data expect(comments).toEqual(expect.arrayContaining(expected)) }) }) diff --git a/backend/src/middleware/userInteractions.spec.ts b/backend/src/middleware/userInteractions.spec.ts index 3b3bccbe7..70ecb49b0 100644 --- a/backend/src/middleware/userInteractions.spec.ts +++ b/backend/src/middleware/userInteractions.spec.ts @@ -1,17 +1,23 @@ /* eslint-disable @typescript-eslint/no-unsafe-call */ /* eslint-disable @typescript-eslint/no-unsafe-member-access */ /* eslint-disable @typescript-eslint/no-unsafe-assignment */ -import { createTestClient } from 'apollo-server-testing' import Factory, { cleanDatabase } from '@db/factories' -import { getNeode, getDriver } from '@db/neo4j' import { Post } from '@graphql/queries/Post' -import createServer from '@src/server' +import { createApolloTestSetup } from '@root/test/helpers' -let query, aUser, bUser, post, authenticatedUser, variables +import type { ApolloTestSetup } from '@root/test/helpers' +import type { Context } from '@src/context' -const driver = getDriver() -const neode = getNeode() +let query: ApolloTestSetup['query'] +let database: ApolloTestSetup['database'] +let server: ApolloTestSetup['server'] +let authenticatedUser: Context['user'] +let aUser, bUser, post, variables + +const contextFn = () => ({ + authenticatedUser, +}) beforeAll(async () => { await cleanDatabase() @@ -24,24 +30,17 @@ beforeAll(async () => { }) post = await Factory.build('post') authenticatedUser = await aUser.toJson() - const { server } = createServer({ - context: () => { - return { - driver, - neode, - user: authenticatedUser, - cypherParams: { - currentUserId: authenticatedUser ? authenticatedUser.id : null, - }, - } - }, - }) - query = createTestClient(server).query + const apolloSetup = await createApolloTestSetup({ context: contextFn }) + query = apolloSetup.query + database = apolloSetup.database + server = apolloSetup.server }) afterAll(async () => { await cleanDatabase() - await driver.close() + void server.stop() + void database.driver.close() + database.neode.close() }) describe('middleware/userInteractions', () => { diff --git a/backend/src/middleware/validation/validationMiddleware.spec.ts b/backend/src/middleware/validation/validationMiddleware.spec.ts index a5271af41..3b469f930 100644 --- a/backend/src/middleware/validation/validationMiddleware.spec.ts +++ b/backend/src/middleware/validation/validationMiddleware.spec.ts @@ -1,22 +1,22 @@ /* eslint-disable @typescript-eslint/no-unsafe-call */ /* eslint-disable @typescript-eslint/no-unsafe-member-access */ /* eslint-disable @typescript-eslint/no-unsafe-assignment */ -import { createTestClient } from 'apollo-server-testing' - import Factory, { cleanDatabase } from '@db/factories' -import { getNeode, getDriver } from '@db/neo4j' import { CreateComment } from '@graphql/queries/CreateComment' import { fileReport } from '@graphql/queries/fileReport' import { review } from '@graphql/queries/review' import { UpdateComment } from '@graphql/queries/UpdateComment' import { UpdateUser } from '@graphql/queries/UpdateUser' -import createServer from '@src/server' +import { createApolloTestSetup } from '@root/test/helpers' -const neode = getNeode() -const driver = getDriver() -let authenticatedUser, - mutate, - users, +import type { ApolloTestSetup } from '@root/test/helpers' +import type { Context } from '@src/context' + +let authenticatedUser: Context['user'] +let mutate: ApolloTestSetup['mutate'] +let database: ApolloTestSetup['database'] +let server: ApolloTestSetup['server'] +let users, offensivePost, reportVariables, disableVariables, @@ -24,24 +24,23 @@ let authenticatedUser, moderatingUser, commentingUser +const contextFn = () => ({ + authenticatedUser, +}) + beforeAll(async () => { await cleanDatabase() - - const { server } = createServer({ - context: () => { - return { - user: authenticatedUser, - neode, - driver, - } - }, - }) - mutate = createTestClient(server).mutate + const apolloSetup = await createApolloTestSetup({ context: contextFn }) + mutate = apolloSetup.mutate + database = apolloSetup.database + server = apolloSetup.server }) afterAll(async () => { await cleanDatabase() - await driver.close() + void server.stop() + void database.driver.close() + database.neode.close() }) beforeEach(async () => { diff --git a/backend/src/middleware/validation/validationMiddleware.ts b/backend/src/middleware/validation/validationMiddleware.ts index c70236ae1..331c8414c 100644 --- a/backend/src/middleware/validation/validationMiddleware.ts +++ b/backend/src/middleware/validation/validationMiddleware.ts @@ -4,7 +4,7 @@ /* eslint-disable @typescript-eslint/no-unsafe-call */ /* eslint-disable @typescript-eslint/no-unsafe-member-access */ /* eslint-disable @typescript-eslint/no-unsafe-assignment */ -import { UserInputError } from 'apollo-server' +import { UserInputError } from '@graphql/errors' import type { IMiddlewareResolver } from 'graphql-middleware/dist/types' diff --git a/backend/src/plugins/apolloLogger.spec.ts b/backend/src/plugins/apolloLogger.spec.ts index 1f40820dd..42341c0f3 100644 --- a/backend/src/plugins/apolloLogger.spec.ts +++ b/backend/src/plugins/apolloLogger.spec.ts @@ -7,11 +7,10 @@ import { login } from '@src/graphql/queries/login' import ocelotLogger from '@src/logger' import { loggerPlugin } from '@src/plugins/apolloLogger' +import type { Context } from '@context/index' import type { ApolloTestSetup } from '@root/test/helpers' -import type { Context } from '@src/context' -import type { ApolloServer } from 'apollo-server-express' -let server: ApolloServer +let server: ApolloTestSetup['server'] const authenticatedUser: Context['user'] = null let mutate: ApolloTestSetup['mutate'] @@ -20,7 +19,7 @@ const context = () => ({ authenticatedUser }) beforeAll(async () => { await cleanDatabase() - const apolloSetup = createApolloTestSetup({ context, plugins: [loggerPlugin] }) + const apolloSetup = await createApolloTestSetup({ context, plugins: [loggerPlugin] }) mutate = apolloSetup.mutate database = apolloSetup.database server = apolloSetup.server @@ -70,7 +69,7 @@ describe('apollo logger', () => { expect(loggerSpy).toHaveBeenCalledWith( 'Apollo Request', expect.any(String), - '"mutation ($email: String!, $password: String!) {\\n login(email: $email, password: $password)\\n}\\n"', + '"mutation ($email: String!, $password: String!) {\\n login(email: $email, password: $password)\\n}"', JSON.stringify({ email: 'test@example.org', password: '***', diff --git a/backend/src/plugins/apolloLogger.ts b/backend/src/plugins/apolloLogger.ts index e04562b5d..4f13ac0db 100644 --- a/backend/src/plugins/apolloLogger.ts +++ b/backend/src/plugins/apolloLogger.ts @@ -9,7 +9,8 @@ import cloneDeep from 'lodash/cloneDeep' import ocelotLogger from '@src/logger' export const loggerPlugin = { - requestDidStart(requestContext) { + // eslint-disable-next-line @typescript-eslint/require-await + async requestDidStart(requestContext) { const isIntrospectionQuery = requestContext.request.operationName === 'IntrospectionQuery' const qID = randomBytes(4).toString('hex') if (!isIntrospectionQuery) { @@ -27,17 +28,18 @@ export const loggerPlugin = { async willSendResponse(requestContext) { if (!isIntrospectionQuery) { const logResponse = ['Apollo Response', qID] - if (requestContext.errors) { - ocelotLogger.error(...logResponse, JSON.stringify(requestContext.errors)) + const errors = requestContext.response.body?.singleResult?.errors + if (errors?.length) { + ocelotLogger.error(...logResponse, JSON.stringify(errors)) return } - if (requestContext.response.data.login) { + if (requestContext.response.body?.singleResult?.data?.login) { // mask the token - const data = cloneDeep(requestContext.response.data) + const data = cloneDeep(requestContext.response.body.singleResult.data) data.login = 'token' logResponse.push(JSON.stringify(data)) - } else { - logResponse.push(JSON.stringify(requestContext.response.data)) + } else if (requestContext.response.body?.singleResult?.data) { + logResponse.push(JSON.stringify(requestContext.response.body.singleResult.data)) } ocelotLogger.debug(...logResponse) } diff --git a/backend/src/server.ts b/backend/src/server.ts index 0b9e63647..9909da75e 100644 --- a/backend/src/server.ts +++ b/backend/src/server.ts @@ -8,46 +8,115 @@ /* eslint-disable @typescript-eslint/prefer-nullish-coalescing */ import http from 'node:http' -import { ApolloServer } from 'apollo-server-express' +import { ApolloServer } from '@apollo/server' +import { expressMiddleware } from '@apollo/server/express4' +import { ApolloServerPluginDrainHttpServer } from '@apollo/server/plugin/drainHttpServer' import bodyParser from 'body-parser' import express from 'express' +import { execute, subscribe } from 'graphql' import { graphqlUploadExpress } from 'graphql-upload' +import { useServer } from 'graphql-ws/lib/use/ws' import helmet from 'helmet' +import { SubscriptionServer } from 'subscriptions-transport-ws' +import { WebSocketServer } from 'ws' import CONFIG from './config' -import { context, getContext } from './context' +import { getContext } from './context' import schema from './graphql/schema' import logger from './logger' import middleware from './middleware' -import type { ApolloServerExpressConfig } from 'apollo-server-express' +import type { ApolloServerPlugin } from '@apollo/server' -const createServer = (options?: ApolloServerExpressConfig) => { - const defaults: ApolloServerExpressConfig = { - context, - schema: middleware(schema), - subscriptions: { - keepAlive: 10000, - onConnect: async (connectionParams) => - getContext()(connectionParams as { headers: { authorization?: string } }), +interface CreateServerOptions { + context?: (req: { headers: { authorization?: string } }) => Promise + plugins?: ApolloServerPlugin[] +} + +const createServer = async (options?: CreateServerOptions) => { + const app = express() + const httpServer = http.createServer(app) + const appliedSchema = middleware(schema) + + // Two WebSocket servers for dual protocol support (noServer mode) + const wsServer = new WebSocketServer({ noServer: true }) + const legacyWsServer = new WebSocketServer({ noServer: true }) + + // New protocol: graphql-ws (subprotocol: graphql-transport-ws) + const serverCleanup = useServer( + { + schema: appliedSchema, + context: async (ctx) => + getContext()(ctx.connectionParams as { headers: { authorization?: string } }), onDisconnect: () => { logger.debug('WebSocket client disconnected') }, }, - debug: !!CONFIG.DEBUG, - uploads: false, - tracing: !!CONFIG.DEBUG, - formatError: (error) => { - // console.log(error.originalError) - if (error.message === 'ERROR_VALIDATION') { - return new Error((error.originalError as any).details.map((d) => d.message)) - } - return error - }, - } - const server = new ApolloServer(Object.assign(defaults, options)) + wsServer, + ) - const app = express() + // Legacy protocol: subscriptions-transport-ws (subprotocol: graphql-ws) + const legacyServerCleanup = SubscriptionServer.create( + { + schema: appliedSchema, + execute, + subscribe, + onConnect: async (connectionParams: Record) => { + return getContext()(connectionParams as { headers: { authorization?: string } }) + }, + onDisconnect: () => { + logger.debug('Legacy WebSocket client disconnected') + }, + }, + legacyWsServer, + ) + + // Route WebSocket upgrade requests based on subprotocol + httpServer.on('upgrade', (req, socket, head) => { + const protocol = req.headers['sec-websocket-protocol'] + const isLegacy = protocol === 'graphql-ws' || !protocol + const targetServer = isLegacy ? legacyWsServer : wsServer + targetServer.handleUpgrade(req, socket, head, (ws) => { + targetServer.emit('connection', ws, req) + }) + }) + + const server = new ApolloServer({ + schema: appliedSchema, + // TODO: Re-enable CSRF prevention once the webapp sends the 'apollo-require-preflight' header. + // Currently disabled because the Nuxt 2 webapp uses apollo-upload-client for multipart/form-data + // file uploads, which Apollo Server 4 blocks by default as a CSRF vector. The webapp relies on + // JWT/cookie authentication and CORS configuration for request validation instead. + csrfPrevention: false, + formatError: (formattedError, error) => { + if (formattedError.message === 'ERROR_VALIDATION') { + return { + ...formattedError, + message: String( + (error as any).originalError?.details?.map((d) => d.message) ?? formattedError.message, + ), + } + } + return formattedError + }, + plugins: [ + ApolloServerPluginDrainHttpServer({ httpServer }), + { + // eslint-disable-next-line @typescript-eslint/require-await + async serverWillStart() { + return { + async drainServer() { + await serverCleanup.dispose() + legacyServerCleanup.close() + }, + } + }, + }, + ...(options?.plugins ?? []), + ], + }) + + await server.start() // TODO: this exception is required for the graphql playground, since the playground loads external resources // See: https://github.com/graphql/graphql-playground/issues/1283 @@ -57,12 +126,20 @@ const createServer = (options?: ApolloServerExpressConfig) => { ) as any, ) app.use(express.static('public')) - app.use(bodyParser.json({ limit: '10mb' }) as any) - app.use(bodyParser.urlencoded({ limit: '10mb', extended: true }) as any) app.use(graphqlUploadExpress()) - server.applyMiddleware({ app, path: '/' }) - const httpServer = http.createServer(app) - server.installSubscriptionHandlers(httpServer) + app.use( + '/', + bodyParser.json({ limit: '10mb' }) as any, + bodyParser.urlencoded({ limit: '10mb', extended: true }) as any, + expressMiddleware(server, { + context: async ({ req }) => { + if (options?.context) { + return options.context(req) + } + return getContext()(req) + }, + }), + ) return { server, httpServer, app } } diff --git a/backend/test/helpers.ts b/backend/test/helpers.ts index d9d140cc2..fc718b394 100644 --- a/backend/test/helpers.ts +++ b/backend/test/helpers.ts @@ -1,13 +1,13 @@ -/* eslint-disable n/no-unpublished-import */ -import { createTestClient } from 'apollo-server-testing' - +/* eslint-disable @typescript-eslint/no-unsafe-assignment */ +/* eslint-disable @typescript-eslint/no-explicit-any */ import databaseContext from '@context/database' import { getContext } from '@src/context' import createServer from '@src/server' -import type CONFIG from '@src/config' +import type { ApolloServerPlugin } from '@apollo/server' +import type CONFIG from '@config/index' import type { Context } from '@src/context' -import type { ApolloServerExpressConfig } from 'apollo-server-express' +import type { DocumentNode } from 'graphql' export const TEST_CONFIG = { NODE_ENV: 'test', @@ -71,14 +71,14 @@ interface OverwritableContextParams { } interface CreateTestServerOptions { context: () => OverwritableContextParams | Promise - plugins?: ApolloServerExpressConfig['plugins'] + plugins?: ApolloServerPlugin[] } -export const createApolloTestSetup = (opts?: CreateTestServerOptions) => { +export const createApolloTestSetup = async (opts?: CreateTestServerOptions) => { const defaultOpts: CreateTestServerOptions = { context: () => ({ authenticatedUser: null }) } const { context: testContext, plugins } = opts ?? defaultOpts const database = databaseContext() - const context = async (req: { headers: { authorization?: string } }) => { + const contextFn = async (req: { headers: { authorization?: string } }) => { const { authenticatedUser, config = {}, pubsub } = await testContext() return getContext({ authenticatedUser, @@ -88,11 +88,30 @@ export const createApolloTestSetup = (opts?: CreateTestServerOptions) => { })(req) } - const server = createServer({ - context, + const { server } = await createServer({ + context: contextFn, plugins, - }).server - const { mutate, query } = createTestClient(server) + }) + + const query = async (queryOpts: { query: DocumentNode | string; variables?: any }) => { + const result = await server.executeOperation( + { query: queryOpts.query, variables: queryOpts.variables }, + { contextValue: await contextFn({ headers: {} }) }, + ) + if (result.body.kind !== 'single') { + throw new Error( + `Unexpected incremental response (kind: "${result.body.kind}"). Test helper only supports single responses.`, + ) + } + return { + data: (result.body.singleResult.data ?? null) as any, + errors: result.body.singleResult.errors, + } + } + + const mutate = async (mutateOpts: { mutation: DocumentNode | string; variables?: any }) => + query({ query: mutateOpts.mutation, variables: mutateOpts.variables }) + return { server, query, @@ -101,4 +120,4 @@ export const createApolloTestSetup = (opts?: CreateTestServerOptions) => { } } -export type ApolloTestSetup = ReturnType +export type ApolloTestSetup = Awaited> diff --git a/backend/yarn.lock b/backend/yarn.lock index 11592ffcd..bc2e5d051 100644 --- a/backend/yarn.lock +++ b/backend/yarn.lock @@ -15,10 +15,15 @@ "@jridgewell/gen-mapping" "^0.3.5" "@jridgewell/trace-mapping" "^0.3.24" -"@apollo/protobufjs@1.2.2": - version "1.2.2" - resolved "https://registry.yarnpkg.com/@apollo/protobufjs/-/protobufjs-1.2.2.tgz#4bd92cd7701ccaef6d517cdb75af2755f049f87c" - integrity sha512-vF+zxhPiLtkwxONs6YanSt1EpwpGilThpneExUN5K3tCymuxNnVq2yojTvnpRjv2QfsEIt/n7ozPIIzBLwGIDQ== +"@apollo/cache-control-types@^1.0.3": + version "1.0.3" + resolved "https://registry.yarnpkg.com/@apollo/cache-control-types/-/cache-control-types-1.0.3.tgz#5da62cf64c3b4419dabfef4536b57a40c8ff0b47" + integrity sha512-F17/vCp7QVwom9eG7ToauIKdAxpSoadsJnqIfyryLFSkLSOEqu+eC5Z3N8OXcUVStuOMcNHlyraRsA6rRICu4g== + +"@apollo/protobufjs@1.2.7": + version "1.2.7" + resolved "https://registry.yarnpkg.com/@apollo/protobufjs/-/protobufjs-1.2.7.tgz#3a8675512817e4a046a897e5f4f16415f16a7d8a" + integrity sha512-Lahx5zntHPZia35myYDBRuF58tlwPskwHc5CWBZC/4bMKB6siTBWwtMrkqXcsNwQiFSzSx5hKdRPUmemrEp3Gg== dependencies: "@protobufjs/aspromise" "^1.1.2" "@protobufjs/base64" "^1.1.2" @@ -31,33 +36,130 @@ "@protobufjs/pool" "^1.1.0" "@protobufjs/utf8" "^1.1.0" "@types/long" "^4.0.0" - "@types/node" "^10.1.0" long "^4.0.0" -"@apollographql/apollo-tools@^0.5.0": - version "0.5.4" - resolved "https://registry.yarnpkg.com/@apollographql/apollo-tools/-/apollo-tools-0.5.4.tgz#cb3998c6cf12e494b90c733f44dd9935e2d8196c" - integrity sha512-shM3q7rUbNyXVVRkQJQseXv6bnYM3BUma/eZhwXR4xsuM+bqWnJKvW7SAfRjP7LuSCocrexa5AXhjjawNHrIlw== - -"@apollographql/graphql-playground-html@1.6.27": - version "1.6.27" - resolved "https://registry.yarnpkg.com/@apollographql/graphql-playground-html/-/graphql-playground-html-1.6.27.tgz#bc9ab60e9445aa2a8813b4e94f152fa72b756335" - integrity sha512-tea2LweZvn6y6xFV11K0KC8ETjmm52mQrW+ezgB2O/aTQf8JGyFmMcRPFgUaQZeHbWdm8iisDC6EjOKsXu0nfw== +"@apollo/server-gateway-interface@^1.1.1": + version "1.1.1" + resolved "https://registry.yarnpkg.com/@apollo/server-gateway-interface/-/server-gateway-interface-1.1.1.tgz#a79632aa921edefcd532589943f6b97c96fa4d3c" + integrity sha512-pGwCl/po6+rxRmDMFgozKQo2pbsSwE91TpsDBAOgf74CRDPXHHtM88wbwjab0wMMZh95QfR45GGyDIdhY24bkQ== dependencies: - xss "^1.0.8" + "@apollo/usage-reporting-protobuf" "^4.1.1" + "@apollo/utils.fetcher" "^2.0.0" + "@apollo/utils.keyvaluecache" "^2.1.0" + "@apollo/utils.logger" "^2.0.0" -"@apollographql/graphql-upload-8-fork@^8.1.4": - version "8.1.4" - resolved "https://registry.yarnpkg.com/@apollographql/graphql-upload-8-fork/-/graphql-upload-8-fork-8.1.4.tgz#898a6826cf53b13e42161884b0090d3bb8c8b2f3" - integrity sha512-lHAj/PUegYu02zza9Pg0bQQYH5I0ah1nyIzu2YIqOv41P0vu3GCBISAmQCfFHThK7N3dy7dLFPhoKcXlXRLPoQ== +"@apollo/server@^4.11.3": + version "4.13.0" + resolved "https://registry.yarnpkg.com/@apollo/server/-/server-4.13.0.tgz#765e5ad6aaf3c901a678c3d9d63e354a12075e7c" + integrity sha512-t4GzaRiYIcPwYy40db6QjZzgvTr9ztDKBddykUXmBb2SVjswMKXbkaJ5nPeHqmT3awr9PAaZdCZdZhRj55I/8A== dependencies: - "@types/express" "*" - "@types/fs-capacitor" "^2.0.0" - "@types/koa" "*" - busboy "^0.3.1" - fs-capacitor "^2.0.4" - http-errors "^1.7.3" - object-path "^0.11.4" + "@apollo/cache-control-types" "^1.0.3" + "@apollo/server-gateway-interface" "^1.1.1" + "@apollo/usage-reporting-protobuf" "^4.1.1" + "@apollo/utils.createhash" "^2.0.2" + "@apollo/utils.fetcher" "^2.0.0" + "@apollo/utils.isnodelike" "^2.0.0" + "@apollo/utils.keyvaluecache" "^2.1.0" + "@apollo/utils.logger" "^2.0.0" + "@apollo/utils.usagereporting" "^2.1.0" + "@apollo/utils.withrequired" "^2.0.0" + "@graphql-tools/schema" "^9.0.0" + "@types/express" "^4.17.13" + "@types/express-serve-static-core" "^4.17.30" + "@types/node-fetch" "^2.6.1" + async-retry "^1.2.1" + content-type "^1.0.5" + cors "^2.8.5" + express "^4.21.1" + loglevel "^1.6.8" + lru-cache "^7.10.1" + negotiator "^0.6.3" + node-abort-controller "^3.1.1" + node-fetch "^2.6.7" + uuid "^9.0.0" + whatwg-mimetype "^3.0.0" + +"@apollo/usage-reporting-protobuf@^4.1.0", "@apollo/usage-reporting-protobuf@^4.1.1": + version "4.1.1" + resolved "https://registry.yarnpkg.com/@apollo/usage-reporting-protobuf/-/usage-reporting-protobuf-4.1.1.tgz#407c3d18c7fbed7a264f3b9a3812620b93499de1" + integrity sha512-u40dIUePHaSKVshcedO7Wp+mPiZsaU6xjv9J+VyxpoU/zL6Jle+9zWeG98tr/+SZ0nZ4OXhrbb8SNr0rAPpIDA== + dependencies: + "@apollo/protobufjs" "1.2.7" + +"@apollo/utils.createhash@^2.0.2": + version "2.0.2" + resolved "https://registry.yarnpkg.com/@apollo/utils.createhash/-/utils.createhash-2.0.2.tgz#838767c83714354ab36892196b209e45d29745e6" + integrity sha512-UkS3xqnVFLZ3JFpEmU/2cM2iKJotQXMoSTgxXsfQgXLC5gR1WaepoXagmYnPSA7Q/2cmnyTYK5OgAgoC4RULPg== + dependencies: + "@apollo/utils.isnodelike" "^2.0.1" + sha.js "^2.4.11" + +"@apollo/utils.dropunuseddefinitions@^2.0.1": + version "2.0.1" + resolved "https://registry.yarnpkg.com/@apollo/utils.dropunuseddefinitions/-/utils.dropunuseddefinitions-2.0.1.tgz#916cd912cbd88769d3b0eab2d24f4674eeda8124" + integrity sha512-EsPIBqsSt2BwDsv8Wu76LK5R1KtsVkNoO4b0M5aK0hx+dGg9xJXuqlr7Fo34Dl+y83jmzn+UvEW+t1/GP2melA== + +"@apollo/utils.fetcher@^2.0.0": + version "2.0.1" + resolved "https://registry.yarnpkg.com/@apollo/utils.fetcher/-/utils.fetcher-2.0.1.tgz#2f6e3edc8ce79fbe916110d9baaddad7e13d955f" + integrity sha512-jvvon885hEyWXd4H6zpWeN3tl88QcWnHp5gWF5OPF34uhvoR+DFqcNxs9vrRaBBSY3qda3Qe0bdud7tz2zGx1A== + +"@apollo/utils.isnodelike@^2.0.0", "@apollo/utils.isnodelike@^2.0.1": + version "2.0.1" + resolved "https://registry.yarnpkg.com/@apollo/utils.isnodelike/-/utils.isnodelike-2.0.1.tgz#08a7e50f08d2031122efa25af089d1c6ee609f31" + integrity sha512-w41XyepR+jBEuVpoRM715N2ZD0xMD413UiJx8w5xnAZD2ZkSJnMJBoIzauK83kJpSgNuR6ywbV29jG9NmxjK0Q== + +"@apollo/utils.keyvaluecache@^2.1.0": + version "2.1.1" + resolved "https://registry.yarnpkg.com/@apollo/utils.keyvaluecache/-/utils.keyvaluecache-2.1.1.tgz#f3f79a2f00520c6ab7a77a680a4e1fec4d19e1a6" + integrity sha512-qVo5PvUUMD8oB9oYvq4ViCjYAMWnZ5zZwEjNF37L2m1u528x5mueMlU+Cr1UinupCgdB78g+egA1G98rbJ03Vw== + dependencies: + "@apollo/utils.logger" "^2.0.1" + lru-cache "^7.14.1" + +"@apollo/utils.logger@^2.0.0", "@apollo/utils.logger@^2.0.1": + version "2.0.1" + resolved "https://registry.yarnpkg.com/@apollo/utils.logger/-/utils.logger-2.0.1.tgz#74faeb97d7ad9f22282dfb465bcb2e6873b8a625" + integrity sha512-YuplwLHaHf1oviidB7MxnCXAdHp3IqYV8n0momZ3JfLniae92eYqMIx+j5qJFX6WKJPs6q7bczmV4lXIsTu5Pg== + +"@apollo/utils.printwithreducedwhitespace@^2.0.1": + version "2.0.1" + resolved "https://registry.yarnpkg.com/@apollo/utils.printwithreducedwhitespace/-/utils.printwithreducedwhitespace-2.0.1.tgz#f4fadea0ae849af2c19c339cc5420d1ddfaa905e" + integrity sha512-9M4LUXV/fQBh8vZWlLvb/HyyhjJ77/I5ZKu+NBWV/BmYGyRmoEP9EVAy7LCVoY3t8BDcyCAGfxJaLFCSuQkPUg== + +"@apollo/utils.removealiases@2.0.1": + version "2.0.1" + resolved "https://registry.yarnpkg.com/@apollo/utils.removealiases/-/utils.removealiases-2.0.1.tgz#2873c93d72d086c60fc0d77e23d0f75e66a2598f" + integrity sha512-0joRc2HBO4u594Op1nev+mUF6yRnxoUH64xw8x3bX7n8QBDYdeYgY4tF0vJReTy+zdn2xv6fMsquATSgC722FA== + +"@apollo/utils.sortast@^2.0.1": + version "2.0.1" + resolved "https://registry.yarnpkg.com/@apollo/utils.sortast/-/utils.sortast-2.0.1.tgz#58c90bb8bd24726346b61fa51ba7fcf06e922ef7" + integrity sha512-eciIavsWpJ09za1pn37wpsCGrQNXUhM0TktnZmHwO+Zy9O4fu/WdB4+5BvVhFiZYOXvfjzJUcc+hsIV8RUOtMw== + dependencies: + lodash.sortby "^4.7.0" + +"@apollo/utils.stripsensitiveliterals@^2.0.1": + version "2.0.1" + resolved "https://registry.yarnpkg.com/@apollo/utils.stripsensitiveliterals/-/utils.stripsensitiveliterals-2.0.1.tgz#2f3350483be376a98229f90185eaf19888323132" + integrity sha512-QJs7HtzXS/JIPMKWimFnUMK7VjkGQTzqD9bKD1h3iuPAqLsxd0mUNVbkYOPTsDhUKgcvUOfOqOJWYohAKMvcSA== + +"@apollo/utils.usagereporting@^2.1.0": + version "2.1.0" + resolved "https://registry.yarnpkg.com/@apollo/utils.usagereporting/-/utils.usagereporting-2.1.0.tgz#11bca6a61fcbc6e6d812004503b38916e74313f4" + integrity sha512-LPSlBrn+S17oBy5eWkrRSGb98sWmnEzo3DPTZgp8IQc8sJe0prDgDuppGq4NeQlpoqEHz0hQeYHAOA0Z3aQsxQ== + dependencies: + "@apollo/usage-reporting-protobuf" "^4.1.0" + "@apollo/utils.dropunuseddefinitions" "^2.0.1" + "@apollo/utils.printwithreducedwhitespace" "^2.0.1" + "@apollo/utils.removealiases" "2.0.1" + "@apollo/utils.sortast" "^2.0.1" + "@apollo/utils.stripsensitiveliterals" "^2.0.1" + +"@apollo/utils.withrequired@^2.0.0": + version "2.0.1" + resolved "https://registry.yarnpkg.com/@apollo/utils.withrequired/-/utils.withrequired-2.0.1.tgz#e72bc512582a6f26af150439f7eb7473b46ba874" + integrity sha512-YBDiuAX9i1lLc6GeTy1m7DGLFn/gMnvXqlalOIMjM7DeOgIacEjjfwPqb0M1CQ2v11HhR15d1NmxJoRCfrNqcA== "@asamuzakjp/css-color@^4.1.1": version "4.1.1" @@ -1059,7 +1161,7 @@ dependencies: core-js-pure "^3.43.0" -"@babel/runtime@^7.5.5", "@babel/runtime@^7.9.2", "@babel/runtime@^7.9.6": +"@babel/runtime@^7.15.4", "@babel/runtime@^7.5.5": version "7.28.6" resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.28.6.tgz#d267a43cb1836dc4d182cce93ae75ba954ef6d2b" integrity sha512-05WQkdpL9COIMz4LjTxGpPNCdlpyimKppYNoJ5Di5EUObifl8t4tuLuUBBZEpoLYOmfvIWrsp9fCl0HoPRVTdA== @@ -1371,34 +1473,6 @@ resolved "https://registry.yarnpkg.com/@graphql-hive/signal/-/signal-1.0.0.tgz#6e2193660a47c925abadbe72293dfc9430e24f8f" integrity sha512-RiwLMc89lTjvyLEivZ/qxAC5nBHoS2CtsWFSOsN35sxG9zoo5Z+JsFHM8MlvmO9yt+MJNIyC5MLE1rsbOphlag== -"@graphql-toolkit/common@0.10.4": - version "0.10.4" - resolved "https://registry.yarnpkg.com/@graphql-toolkit/common/-/common-0.10.4.tgz#7785f2a3f14559d0778859c49f4442078c196695" - integrity sha512-HQ3HaxCqX+UE8y/0h7LMDBBGSIKJxY/gaQesaksvE2Y+N4NpSWdiW6HpOcgXfC2HGf9yM0hEdsERzzL8z3mbHQ== - dependencies: - aggregate-error "3.0.1" - camel-case "4.1.1" - graphql-tools "5.0.0" - lodash "4.17.15" - -"@graphql-toolkit/file-loading@0.10.4": - version "0.10.4" - resolved "https://registry.yarnpkg.com/@graphql-toolkit/file-loading/-/file-loading-0.10.4.tgz#50e8933e44b17853544c1fe63350df93f33a5e80" - integrity sha512-oUmy/sO3BJfax85pVKI7FZ6TWrViNuWXoJkRM293YV9bKGuYU9TgqZoHyM+oEqWO5ruXCL/nCdw3cIBau+rSNA== - dependencies: - globby "11.0.0" - unixify "1.0.0" - -"@graphql-toolkit/schema-merging@0.10.4": - version "0.10.4" - resolved "https://registry.yarnpkg.com/@graphql-toolkit/schema-merging/-/schema-merging-0.10.4.tgz#2428590a531a33e9fe03be27cce9030f1c4c044b" - integrity sha512-naL6reYBuILLMrkMfKz0lOLL0kl6gGYnaaywnO/Dgp9F4NeAxDdAs5CV6Fy9NO5OzePFP58Dnc4sh2RyYrrFJg== - dependencies: - "@graphql-toolkit/common" "0.10.4" - deepmerge "4.2.2" - graphql-tools "5.0.0" - tslib "1.11.1" - "@graphql-tools/batch-execute@8.5.1": version "8.5.1" resolved "https://registry.yarnpkg.com/@graphql-tools/batch-execute/-/batch-execute-8.5.1.tgz#fa3321d58c64041650be44250b1ebc3aab0ba7a9" @@ -1568,6 +1642,15 @@ tslib "^2.4.0" unixify "^1.0.0" +"@graphql-tools/load-files@^7.0.0": + version "7.0.1" + resolved "https://registry.yarnpkg.com/@graphql-tools/load-files/-/load-files-7.0.1.tgz#f161332bacb4687fff7c3802510ab0a3268dea04" + integrity sha512-oTNIENc9To9u8Gc3kY82C74caW6kXa8ya2GyxWRXp8gP4zK/7PmvlWJK0/GFCUH0cU3t9jM7k59zXz1+ZfP3Mw== + dependencies: + globby "11.1.0" + tslib "^2.4.0" + unixify "^1.0.0" + "@graphql-tools/load@^8.1.0": version "8.1.8" resolved "https://registry.yarnpkg.com/@graphql-tools/load/-/load-8.1.8.tgz#977fdf0005078283942e0e4a028ff97c78dd6f0b" @@ -1586,6 +1669,14 @@ "@graphql-tools/utils" "8.9.0" tslib "^2.4.0" +"@graphql-tools/merge@^8.4.1": + version "8.4.2" + resolved "https://registry.yarnpkg.com/@graphql-tools/merge/-/merge-8.4.2.tgz#95778bbe26b635e8d2f60ce9856b388f11fe8288" + integrity sha512-XbrHAaj8yDuINph+sAfuq3QCZ/tKblrTLOpirK0+CAgNlZUCHs0Fa+xtMUURgwCVThLle1AF7svJCxFizygLsw== + dependencies: + "@graphql-tools/utils" "^9.2.1" + tslib "^2.4.0" + "@graphql-tools/merge@^9.0.0", "@graphql-tools/merge@^9.1.7": version "9.1.7" resolved "https://registry.yarnpkg.com/@graphql-tools/merge/-/merge-9.1.7.tgz#8040553c19aeadf6df41060b811e9c5df8716be1" @@ -1613,6 +1704,16 @@ "@graphql-tools/utils" "^11.0.0" tslib "^2.4.0" +"@graphql-tools/schema@^9.0.0": + version "9.0.19" + resolved "https://registry.yarnpkg.com/@graphql-tools/schema/-/schema-9.0.19.tgz#c4ad373b5e1b8a0cf365163435b7d236ebdd06e7" + integrity sha512-oBRPoNBtCkk0zbUsyP4GaIzCt8C0aCI4ycIRUL67KK5pOHljKLBBtGT+Jr6hkzA74C8Gco8bpZPe7aWFjiaK2w== + 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/url-loader@^8.0.0": version "8.0.33" resolved "https://registry.yarnpkg.com/@graphql-tools/url-loader/-/url-loader-8.0.33.tgz#1e5ebfa6a840e3bdc25336c231df2889028f7e0c" @@ -1658,6 +1759,14 @@ cross-inspect "1.0.1" tslib "^2.4.0" +"@graphql-tools/utils@^9.2.1": + version "9.2.1" + resolved "https://registry.yarnpkg.com/@graphql-tools/utils/-/utils-9.2.1.tgz#1b3df0ef166cfa3eae706e3518b17d5922721c57" + integrity sha512-WUw506Ql6xzmOORlriNrD6Ugx+HjVgYxt9KCXD9mHAak+eaXSwuGGPyE60hy9xaDEoXKBsG7SkG69ybitaVl6A== + dependencies: + "@graphql-typed-document-node/core" "^3.1.1" + tslib "^2.4.0" + "@graphql-tools/wrap@^10.0.16": version "10.1.4" resolved "https://registry.yarnpkg.com/@graphql-tools/wrap/-/wrap-10.1.4.tgz#46f94b00113693d4d4eccddcf262494164234ba6" @@ -1999,11 +2108,6 @@ "@types/yargs" "^17.0.33" chalk "^4.1.2" -"@josephg/resolvable@^1.0.0": - version "1.0.1" - resolved "https://registry.yarnpkg.com/@josephg/resolvable/-/resolvable-1.0.1.tgz#69bc4db754d79e1a2f17a650d3466e038d94a5eb" - integrity sha512-CtzORUwWTTOTqfVtHaKRJ0I1kNQd1bpn3sUh8I3nJDVY+5/M/Oe1DnEWzPQvqq/xPIIkzzzIP7mfCoAjFRvDhg== - "@jridgewell/gen-mapping@^0.3.12", "@jridgewell/gen-mapping@^0.3.5": version "0.3.13" resolved "https://registry.yarnpkg.com/@jridgewell/gen-mapping/-/gen-mapping-0.3.13.tgz#6342a19f44347518c93e43b1ac69deb3c4656a1f" @@ -2976,13 +3080,6 @@ dependencies: tslib "^2.4.0" -"@types/accepts@*", "@types/accepts@^1.3.5": - version "1.3.7" - resolved "https://registry.yarnpkg.com/@types/accepts/-/accepts-1.3.7.tgz#3b98b1889d2b2386604c2bbbe62e4fb51e95b265" - integrity sha512-Pay9fq2lM2wXPWbteBsRAGiWH2hig4ZE2asK+mm7kUzlxRTfL961rj89I6zV/E3PcIkDqyuBEcMxFT7rccugeQ== - dependencies: - "@types/node" "*" - "@types/babel__core@^7.20.5": version "7.20.5" resolved "https://registry.yarnpkg.com/@types/babel__core/-/babel__core-7.20.5.tgz#3df15f27ba85319caa07ba08d0721889bb39c017" @@ -3016,7 +3113,7 @@ dependencies: "@babel/types" "^7.28.2" -"@types/body-parser@*", "@types/body-parser@1.19.0": +"@types/body-parser@*": version "1.19.0" resolved "https://registry.yarnpkg.com/@types/body-parser/-/body-parser-1.19.0.tgz#0685b3c47eb3006ffed117cdd55164b61f80538f" integrity sha512-W98JrE0j2K78swW4ukqMleo8R7h/pFETjM2DQ90MF6XK2i4LO4W3gQ71Lt4w3bfm2EvVSyWHplECvB5sK22yFQ== @@ -3046,26 +3143,6 @@ dependencies: "@types/node" "*" -"@types/content-disposition@*": - version "0.5.9" - resolved "https://registry.yarnpkg.com/@types/content-disposition/-/content-disposition-0.5.9.tgz#00ca14939432869de829a4ccf6fd380fa9181750" - integrity sha512-8uYXI3Gw35MhiVYhG3s295oihrxRyytcRHjSjqnqZVDDy/xcGBRny7+Xj1Wgfhv5QzRtN2hB2dVRBUX9XW3UcQ== - -"@types/cookies@*": - version "0.9.2" - resolved "https://registry.yarnpkg.com/@types/cookies/-/cookies-0.9.2.tgz#ccdf86d782f2dea34531dd32733a25be48177cd4" - integrity sha512-1AvkDdZM2dbyFybL4fxpuNCaWyv//0AwsuUk2DWeXyM1/5ZKm6W3z6mQi24RZ4l2ucY+bkSHzbDVpySqPGuV8A== - dependencies: - "@types/connect" "*" - "@types/express" "*" - "@types/keygrip" "*" - "@types/node" "*" - -"@types/cors@2.8.10": - version "2.8.10" - resolved "https://registry.yarnpkg.com/@types/cors/-/cors-2.8.10.tgz#61cc8469849e5bcdd0c7044122265c39cec10cf4" - integrity sha512-C7srjHiVG3Ey1nR6d511dtDkCEjxuN9W1HWAEjGq8kpcwmNM6JJkpC0xvabM7BXTG2wDq8Eu33iH9aQKa7IvLQ== - "@types/email-templates@^10.0.4": version "10.0.4" resolved "https://registry.yarnpkg.com/@types/email-templates/-/email-templates-10.0.4.tgz#3181fd540e76e6b90b8b3e0a5a1afbc803ef7797" @@ -3085,7 +3162,7 @@ resolved "https://registry.yarnpkg.com/@types/estree/-/estree-1.0.8.tgz#958b91c991b1867ced318bedea0e215ee050726e" integrity sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w== -"@types/express-serve-static-core@^4.17.21", "@types/express-serve-static-core@^4.17.33": +"@types/express-serve-static-core@^4.17.30", "@types/express-serve-static-core@^4.17.33": version "4.19.8" resolved "https://registry.yarnpkg.com/@types/express-serve-static-core/-/express-serve-static-core-4.19.8.tgz#99b960322a4d576b239a640ab52ef191989b036f" integrity sha512-02S5fmqeoKzVZCHPZid4b8JH2eM5HzQLZWN2FohQEy/0eXTq8VXZfSN6Pcr3F6N9R/vNrj7cpgbhjie6m/1tCA== @@ -3095,7 +3172,7 @@ "@types/range-parser" "*" "@types/send" "*" -"@types/express@*", "@types/express@4.17.25", "@types/express@^4.17.12": +"@types/express@4.17.25", "@types/express@^4.17.13": version "4.17.25" resolved "https://registry.yarnpkg.com/@types/express/-/express-4.17.25.tgz#070c8c73a6fee6936d65c195dbbfb7da5026649b" integrity sha512-dVd04UKsfpINUnK0yBoYHDF3xu7xVH4BuDotC/xGuycx4CgbP48X/KF/586bcObxT0HENHXEU8Nqtu6NR+eKhw== @@ -3105,29 +3182,17 @@ "@types/qs" "*" "@types/serve-static" "^1" -"@types/fs-capacitor@^2.0.0": - version "2.0.0" - resolved "https://registry.yarnpkg.com/@types/fs-capacitor/-/fs-capacitor-2.0.0.tgz#17113e25817f584f58100fb7a08eed288b81956e" - integrity sha512-FKVPOCFbhCvZxpVAMhdBdTfVfXUpsh15wFHgqOKxh9N9vzWZVuWCSijZ5T4U34XYNnuj2oduh6xcs1i+LPI+BQ== - dependencies: - "@types/node" "*" - "@types/html-to-text@*": version "9.0.4" resolved "https://registry.yarnpkg.com/@types/html-to-text/-/html-to-text-9.0.4.tgz#4a83dd8ae8bfa91457d0b1ffc26f4d0537eff58c" integrity sha512-pUY3cKH/Nm2yYrEmDlPR1mR7yszjGx4DrwPjQ702C4/D5CwHuZTgZdIdwPkRbcuhs7BAh2L5rg3CL5cbRiGTCQ== -"@types/http-assert@*": - version "1.5.6" - resolved "https://registry.yarnpkg.com/@types/http-assert/-/http-assert-1.5.6.tgz#b6b657c38a2350d21ce213139f33b03b2b5fa431" - integrity sha512-TTEwmtjgVbYAzZYWyeHPrrtWnfVkm8tQkP8P21uQifPgMRgjrow3XDEYqucuC8SKZJT7pUnhU/JymvjggxO9vw== - "@types/http-cache-semantics@*": version "4.2.0" resolved "https://registry.yarnpkg.com/@types/http-cache-semantics/-/http-cache-semantics-4.2.0.tgz#f6a7788f438cbfde15f29acad46512b4c01913b3" integrity sha512-L3LgimLHXtGkWikKnsPg0/VFx9OGZaC+eN1u4r+OB1XRqH3meBIAVC2zr1WdMH+RHmnRkqliQAOHNJ/E0j/e0Q== -"@types/http-errors@*", "@types/http-errors@^2": +"@types/http-errors@*": version "2.0.5" resolved "https://registry.yarnpkg.com/@types/http-errors/-/http-errors-2.0.5.tgz#5b749ab2b16ba113423feb1a64a95dcd30398472" integrity sha512-r8Tayk8HJnX0FztbZN7oVqGccWgw98T/0neJphO91KkmOzug1KkofZURD4UaD5uH8AqcFLfdPErnBod0u71/qg== @@ -3171,11 +3236,6 @@ dependencies: "@types/node" "*" -"@types/keygrip@*": - version "1.0.6" - resolved "https://registry.yarnpkg.com/@types/keygrip/-/keygrip-1.0.6.tgz#1749535181a2a9b02ac04a797550a8787345b740" - integrity sha512-lZuNAY9xeJt7Bx4t4dx0rYCDqGPW8RXhQZK1td7d4H6E9zYbLoOtjBvfwdTKpsyxQI/2jv+armjX/RW+ZNpXOQ== - "@types/keyv@^3.1.4": version "3.1.4" resolved "https://registry.yarnpkg.com/@types/keyv/-/keyv-3.1.4.tgz#3ccdb1c6751b0c7e52300bcdacd5bcbf8faa75b6" @@ -3183,28 +3243,7 @@ dependencies: "@types/node" "*" -"@types/koa-compose@*": - version "3.2.9" - resolved "https://registry.yarnpkg.com/@types/koa-compose/-/koa-compose-3.2.9.tgz#6efb945ee5573be0f4eddb728a2f6826f7a3f395" - integrity sha512-BroAZ9FTvPiCy0Pi8tjD1OfJ7bgU1gQf0eR6e1Vm+JJATy9eKOG3hQMFtMciMawiSOVnLMdmUOC46s7HBhSTsA== - dependencies: - "@types/koa" "*" - -"@types/koa@*": - version "3.0.1" - resolved "https://registry.yarnpkg.com/@types/koa/-/koa-3.0.1.tgz#2c9ace20ecb33d0cf84d63492af231185eb2aefa" - integrity sha512-VkB6WJUQSe0zBpR+Q7/YIUESGp5wPHcaXr0xueU5W0EOUWtlSbblsl+Kl31lyRQ63nIILh0e/7gXjQ09JXJIHw== - dependencies: - "@types/accepts" "*" - "@types/content-disposition" "*" - "@types/cookies" "*" - "@types/http-assert" "*" - "@types/http-errors" "^2" - "@types/keygrip" "*" - "@types/koa-compose" "*" - "@types/node" "*" - -"@types/lodash@^4.17.23": +"@types/lodash@^4.14.175", "@types/lodash@^4.17.23": version "4.17.23" resolved "https://registry.yarnpkg.com/@types/lodash/-/lodash-4.17.23.tgz#c1bb06db218acc8fc232da0447473fc2fb9d9841" integrity sha512-RDvF6wTulMPjrNdCoYRC8gNR880JNGT8uB+REUpC2Ns4pRqQJhGz90wh7rgdXDPpCczF3VGktDuFGVnz8zP7HA== @@ -3229,6 +3268,14 @@ resolved "https://registry.yarnpkg.com/@types/minimatch/-/minimatch-3.0.5.tgz#1001cc5e6a3704b83c236027e77f2f58ea010f40" integrity sha512-Klz949h02Gz2uZCMGwDUSDS1YBlTdDDgbWHi+81l29tQALUtvz4rAYi5uoVhE5Lagoq6DeqAUlbrHvW/mXDgdQ== +"@types/node-fetch@^2.6.1": + version "2.6.13" + resolved "https://registry.yarnpkg.com/@types/node-fetch/-/node-fetch-2.6.13.tgz#e0c9b7b5edbdb1b50ce32c127e85e880872d56ee" + integrity sha512-QGpRVpzSaUs30JBSGPjOg4Uveu384erbHBoT1zeONvyCfwQxIkUshLAOqN/k9EjGviPRmWTTe6aH2qySWKTVSw== + dependencies: + "@types/node" "*" + form-data "^4.0.4" + "@types/node@*", "@types/node@^25.3.0": version "25.3.0" resolved "https://registry.yarnpkg.com/@types/node/-/node-25.3.0.tgz#749b1bd4058e51b72e22bd41e9eab6ebd0180470" @@ -3236,11 +3283,6 @@ dependencies: undici-types "~7.18.0" -"@types/node@^10.1.0": - version "10.17.60" - resolved "https://registry.yarnpkg.com/@types/node/-/node-10.17.60.tgz#35f3d6213daed95da7f0f73e75bcc6980e90597b" - integrity sha512-F0KIgDJfy2nA3zMLmWGKxcH2ZVEtCZXHHdOQs2gSaQ27+lNeEfGxzkIw90aXswATX7AZ33tahPbzy6KAfUreVw== - "@types/nodemailer@*": version "7.0.9" resolved "https://registry.yarnpkg.com/@types/nodemailer/-/nodemailer-7.0.9.tgz#a19e3fa222b21213b481cdbdbc70a06787ea49e8" @@ -3319,14 +3361,7 @@ resolved "https://registry.yarnpkg.com/@types/uuid/-/uuid-9.0.8.tgz#7545ba4fc3c003d6c756f651f3bf163d8f0f29ba" integrity sha512-jg+97EGIcY9AGHJJRaaPVgetKDsrTgbRjQ5Msgjh/DQKEFl0DtyRr/VCOyD1T2R1MNeWPK/u7JoGhlDZnKBAfA== -"@types/ws@^7.0.0": - version "7.4.7" - resolved "https://registry.yarnpkg.com/@types/ws/-/ws-7.4.7.tgz#f7c390a36f7a0679aa69de2d501319f4f8d9b702" - integrity sha512-JQbbmxZTZehdc2iszGKs5oC3NFnjeay7mtAWrdt7qNtAVK0g19muApzAy4bm9byz79xa2ZnO/BOBC2R8RC5Lww== - dependencies: - "@types/node" "*" - -"@types/ws@^8.0.0": +"@types/ws@^8.0.0", "@types/ws@^8.18.1": version "8.18.1" resolved "https://registry.yarnpkg.com/@types/ws/-/ws-8.18.1.tgz#48464e4bf2ddfd17db13d845467f6070ffea4aa9" integrity sha512-ThVF6DCVhA8kUGy+aazFQ4kXQ7E1Ty7A3ypFOe0IcJV8O/M511G99AW24irKrW56Wt44yG9+ij8FaqoBGkuBXg== @@ -3345,10 +3380,10 @@ dependencies: "@types/yargs-parser" "*" -"@types/yup@0.26.37": - version "0.26.37" - resolved "https://registry.yarnpkg.com/@types/yup/-/yup-0.26.37.tgz#7a52854ac602ba0dc969bebc960559f7464a1686" - integrity sha512-cDqR/ez4+iAVQYOwadXjKX4Dq1frtnDGV2GNVKj3aUVKVCKRvsr8esFk66j+LgeeJGmrMcBkkfCf3zk13MjV7A== +"@types/yup@0.29.13": + version "0.29.13" + resolved "https://registry.yarnpkg.com/@types/yup/-/yup-0.29.13.tgz#21b137ba60841307a3c8a1050d3bf4e63ad561e9" + integrity sha512-qRyuv+P/1t1JK1rA+elmK1MmCL1BapEzKKfbEhDBV/LMMse4lmhZ/XbgETI39JveDJRpLjmToOI6uFtMW/WR2g== "@typescript-eslint/eslint-plugin@8.56.0": version "8.56.0" @@ -3680,7 +3715,7 @@ abbrev@^4.0.0: resolved "https://registry.yarnpkg.com/abbrev/-/abbrev-4.0.0.tgz#ec933f0e27b6cd60e89b5c6b2a304af42209bb05" integrity sha512-a1wflyaL0tHtJSmLSOVybYhy22vRih4eduhhrkcjgrWGnRfrZtovJ2FRjxuTtkkj47O/baf0R86QU5OuYpz8fA== -accepts@^1.3.5, accepts@~1.3.8: +accepts@~1.3.8: version "1.3.8" resolved "https://registry.yarnpkg.com/accepts/-/accepts-1.3.8.tgz#0bf0be125b67014adcb0b0921e62db7bffe16b2e" integrity sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw== @@ -3727,14 +3762,6 @@ agent-base@^7.1.0, agent-base@^7.1.2: resolved "https://registry.yarnpkg.com/agent-base/-/agent-base-7.1.4.tgz#e3cd76d4c548ee895d3c3fd8dc1f6c5b9032e7a8" integrity sha512-MnA+YT8fwfJPgBx3m60MNqakm30XOkyIoH1y6huTQvC0PwZG7ki8NacLBcrPbNoo8vEZy7Jpuk7+jMO+CUovTQ== -aggregate-error@3.0.1: - version "3.0.1" - resolved "https://registry.yarnpkg.com/aggregate-error/-/aggregate-error-3.0.1.tgz#db2fe7246e536f40d9b5442a39e117d7dd6a24e0" - integrity sha512-quoaXsZ9/BLNae5yiNoUz+Nhkwz83GhWwtYFglcjEQB2NDHCIpApbqXxIFnm4Pq/Nvhrsq5sYJFyohrrxnTGAA== - dependencies: - clean-stack "^2.0.0" - indent-string "^4.0.0" - ajv@^6.12.4: version "6.12.6" resolved "https://registry.yarnpkg.com/ajv/-/ajv-6.12.6.tgz#baf5a62e802b07d977034586f8c3baf5adf26df4" @@ -3797,22 +3824,6 @@ anymatch@^3.1.3, anymatch@~3.1.2: normalize-path "^3.0.0" picomatch "^2.0.4" -apollo-cache-control@^0.15.0: - version "0.15.0" - resolved "https://registry.yarnpkg.com/apollo-cache-control/-/apollo-cache-control-0.15.0.tgz#45897ed318b883bf964960e6fcd7516a50b4e4d4" - integrity sha512-U2uYvHZsWmR6s6CD5zlq3PepfbUAM8953CeVM2Y2QYMtJ8i4CYplEPbIWb3zTIXSPbIPeWGddM56pChI6Iz3zA== - dependencies: - apollo-server-env "^3.2.0" - apollo-server-plugin-base "^0.14.0" - -apollo-datasource@^0.10.0: - version "0.10.0" - resolved "https://registry.yarnpkg.com/apollo-datasource/-/apollo-datasource-0.10.0.tgz#5450fc88f23f73b36ba04b4f7a6d00ef2f5364a9" - integrity sha512-wrLhuoM2MtA0KA0+3qyioe0H2FjAxjTvuFOlNCk6WberA887m0MQlWULZImCWTkKuN+zEAMerHfxN+F+W8+lBA== - dependencies: - apollo-server-caching "^0.7.0" - apollo-server-env "^3.2.0" - apollo-errors@^1.9.0: version "1.9.0" resolved "https://registry.yarnpkg.com/apollo-errors/-/apollo-errors-1.9.0.tgz#f1ed0ca0a6be5cd2f24e2eaa7b0860a10146ff51" @@ -3821,25 +3832,7 @@ apollo-errors@^1.9.0: assert "^1.4.1" extendable-error "^0.1.5" -apollo-graphql@^0.9.0: - version "0.9.7" - resolved "https://registry.yarnpkg.com/apollo-graphql/-/apollo-graphql-0.9.7.tgz#33185093b497a578f2df61ab8ecc6447d700ae64" - integrity sha512-bezL9ItUWUGHTm1bI/XzIgiiZbhXpsC7uxk4UxFPmcVJwJsDc3ayZ99oXxAaK+3Rbg/IoqrHckA6CwmkCsbaSA== - dependencies: - core-js-pure "^3.10.2" - lodash.sortby "^4.7.0" - sha.js "^2.4.11" - -apollo-link-http-common@^0.2.14: - version "0.2.16" - resolved "https://registry.yarnpkg.com/apollo-link-http-common/-/apollo-link-http-common-0.2.16.tgz#756749dafc732792c8ca0923f9a40564b7c59ecc" - integrity sha512-2tIhOIrnaF4UbQHf7kjeQA/EmSorB7+HyJIIrUjJOKBgnXwuexi8aMecRlqTIDWcyVXCeqLhUnztMa6bOH/jTg== - dependencies: - apollo-link "^1.2.14" - ts-invariant "^0.4.0" - tslib "^1.9.3" - -apollo-link@^1.2.12, apollo-link@^1.2.14: +apollo-link@^1.2.14: version "1.2.14" resolved "https://registry.yarnpkg.com/apollo-link/-/apollo-link-1.2.14.tgz#3feda4b47f9ebba7f4160bef8b977ba725b684d9" integrity sha512-p67CMEFP7kOG1JZ0ZkYZwRDa369w5PIjtMjvrQd/HnIV8FRsHRqLqK+oAZQnFa1DDdZtOtHTi+aMIW6EatC2jg== @@ -3849,139 +3842,6 @@ apollo-link@^1.2.12, apollo-link@^1.2.14: tslib "^1.9.3" zen-observable-ts "^0.8.21" -apollo-reporting-protobuf@^0.8.0: - version "0.8.0" - resolved "https://registry.yarnpkg.com/apollo-reporting-protobuf/-/apollo-reporting-protobuf-0.8.0.tgz#ae9d967934d3d8ed816fc85a0d8068ef45c371b9" - integrity sha512-B3XmnkH6Y458iV6OsA7AhfwvTgeZnFq9nPVjbxmLKnvfkEl8hYADtz724uPa0WeBiD7DSFcnLtqg9yGmCkBohg== - dependencies: - "@apollo/protobufjs" "1.2.2" - -apollo-server-caching@^0.7.0: - version "0.7.0" - resolved "https://registry.yarnpkg.com/apollo-server-caching/-/apollo-server-caching-0.7.0.tgz#e6d1e68e3bb571cba63a61f60b434fb771c6ff39" - integrity sha512-MsVCuf/2FxuTFVhGLK13B+TZH9tBd2qkyoXKKILIiGcZ5CDUEBO14vIV63aNkMkS1xxvK2U4wBcuuNj/VH2Mkw== - dependencies: - lru-cache "^6.0.0" - -apollo-server-core@^2.11.0, apollo-server-core@^2.14.5, apollo-server-core@^2.26.2: - version "2.26.2" - resolved "https://registry.yarnpkg.com/apollo-server-core/-/apollo-server-core-2.26.2.tgz#5391bb93654194a5d6b83cf1855f229c94d5b3b1" - integrity sha512-r8jOhf1jElaxsNsALFMy/MLiJCqSa1ZiwxkerVYbsEkyWrpD1Khy0extDkTBrfa6uK8CatX7xK9U413bYNhJFA== - dependencies: - "@apollographql/apollo-tools" "^0.5.0" - "@apollographql/graphql-playground-html" "1.6.27" - "@apollographql/graphql-upload-8-fork" "^8.1.4" - "@josephg/resolvable" "^1.0.0" - "@types/ws" "^7.0.0" - apollo-cache-control "^0.15.0" - apollo-datasource "^0.10.0" - apollo-graphql "^0.9.0" - apollo-reporting-protobuf "^0.8.0" - apollo-server-caching "^0.7.0" - apollo-server-env "^3.2.0" - apollo-server-errors "^2.5.0" - apollo-server-plugin-base "^0.14.0" - apollo-server-types "^0.10.0" - apollo-tracing "^0.16.0" - async-retry "^1.2.1" - fast-json-stable-stringify "^2.0.0" - graphql-extensions "^0.16.0" - graphql-tag "^2.11.0" - graphql-tools "^4.0.8" - loglevel "^1.6.7" - lru-cache "^6.0.0" - sha.js "^2.4.11" - subscriptions-transport-ws "^0.9.19" - uuid "^8.0.0" - -apollo-server-env@^3.2.0: - version "3.2.0" - resolved "https://registry.yarnpkg.com/apollo-server-env/-/apollo-server-env-3.2.0.tgz#0572e307da4784c5d7633a0ade1f45e231da28e3" - integrity sha512-V+kO5e6vUo2JwqV1/Ng71ZE3J6x1hCOC+nID2/++bCYl0/fPY9iLChbBNSgN/uoFcjhgmBchOv+m4o0Nie/TFQ== - dependencies: - node-fetch "^2.6.1" - util.promisify "^1.0.0" - -apollo-server-errors@^2.5.0: - version "2.5.0" - resolved "https://registry.yarnpkg.com/apollo-server-errors/-/apollo-server-errors-2.5.0.tgz#5d1024117c7496a2979e3e34908b5685fe112b68" - integrity sha512-lO5oTjgiC3vlVg2RKr3RiXIIQ5pGXBFxYGGUkKDhTud3jMIhs+gel8L8zsEjKaKxkjHhCQAA/bcEfYiKkGQIvA== - -apollo-server-express@^2.14.2, apollo-server-express@^2.14.5: - version "2.26.2" - resolved "https://registry.yarnpkg.com/apollo-server-express/-/apollo-server-express-2.26.2.tgz#e1df5cc88e3214b4301e754f1f03addfeb0b33ce" - integrity sha512-8KaDwc6/DMK6e5KmP4AGH/NNY7OhEOFxusz3JZ/Du08a+PN8c/JmaEAwQ0aTNpySb5PWpv6xeXRPPwNfaPK9IQ== - dependencies: - "@apollographql/graphql-playground-html" "1.6.27" - "@types/accepts" "^1.3.5" - "@types/body-parser" "1.19.0" - "@types/cors" "2.8.10" - "@types/express" "^4.17.12" - "@types/express-serve-static-core" "^4.17.21" - accepts "^1.3.5" - apollo-server-core "^2.26.2" - apollo-server-types "^0.10.0" - body-parser "^1.18.3" - cors "^2.8.5" - express "^4.17.1" - graphql-subscriptions "^1.0.0" - graphql-tools "^4.0.8" - parseurl "^1.3.2" - subscriptions-transport-ws "^0.9.19" - type-is "^1.6.16" - -apollo-server-plugin-base@^0.14.0: - version "0.14.0" - resolved "https://registry.yarnpkg.com/apollo-server-plugin-base/-/apollo-server-plugin-base-0.14.0.tgz#f59b6ab7780304162d2e4fd9ee29ed0696b174ef" - integrity sha512-nTNSFuBhZURGjtWptdVqwemYUOdsvABj/GSKzeNvepiEubiv4N0rt4Gvy1inHDiMbo98wQTdF/7XohNcB9A77g== - dependencies: - apollo-server-types "^0.10.0" - -apollo-server-testing@~2.11.0: - version "2.11.0" - resolved "https://registry.yarnpkg.com/apollo-server-testing/-/apollo-server-testing-2.11.0.tgz#3f6e25a6f04a60b0c839aa776a85e886209d1832" - integrity sha512-iqb20FYmkM6VJ9s4M78J8lXabZSDZCt8V2/As1x2zvgZ8bOdX77fR5UxrkkV/zR6bwd7252wIiHp/m9FF9O2zA== - dependencies: - apollo-server-core "^2.11.0" - -apollo-server-types@^0.10.0: - version "0.10.0" - resolved "https://registry.yarnpkg.com/apollo-server-types/-/apollo-server-types-0.10.0.tgz#af578bf507151a0e86fbdf188f9673ece3f8f164" - integrity sha512-LsB3epw1X3Co/HGiKHCGtzWG35J59gG8Ypx0p22+wgdM9AVDm1ylsNGZy+osNIVJc1lUJf3nF5kZ90vA866K/w== - dependencies: - apollo-reporting-protobuf "^0.8.0" - apollo-server-caching "^0.7.0" - apollo-server-env "^3.2.0" - -apollo-server@~2.14.2: - version "2.14.5" - resolved "https://registry.yarnpkg.com/apollo-server/-/apollo-server-2.14.5.tgz#75bf35b930d1383515316f567b00aa87ee5159da" - integrity sha512-mnGVlkd/suniMvboVs//wHfJYK6WXhLEX6hW40JJB2keQgNkAjSjldhCRLbK92hNS2D1N+Oyx2xZzooPFjGIig== - dependencies: - apollo-server-core "^2.14.5" - apollo-server-express "^2.14.5" - express "^4.0.0" - graphql-subscriptions "^1.0.0" - graphql-tools "^4.0.0" - -apollo-tracing@^0.16.0: - version "0.16.0" - resolved "https://registry.yarnpkg.com/apollo-tracing/-/apollo-tracing-0.16.0.tgz#8542ca40ae4a3f84f899e749631b65833557ceb1" - integrity sha512-Oy8kTggB+fJ/hHXwHyMpuTl5KW7u1XetKFDErZVOobUKc2zjc/NgWiC/s7SGYZCgfLodBjvwfa6rMcvLkz7c0w== - dependencies: - apollo-server-env "^3.2.0" - apollo-server-plugin-base "^0.14.0" - -apollo-upload-client@^13.0.0: - version "13.0.0" - resolved "https://registry.yarnpkg.com/apollo-upload-client/-/apollo-upload-client-13.0.0.tgz#146d1ddd85d711fcac8ca97a72d3ca6787f2b71b" - integrity sha512-lJ9/bk1BH1lD15WhWRha2J3+LrXrPIX5LP5EwiOUHv8PCORp4EUrcujrA3rI5hZeZygrTX8bshcuMdpqpSrvtA== - dependencies: - "@babel/runtime" "^7.9.2" - apollo-link "^1.2.12" - apollo-link-http-common "^0.2.14" - extract-files "^8.0.0" - apollo-utilities@^1.0.1, apollo-utilities@^1.3.0: version "1.3.4" resolved "https://registry.yarnpkg.com/apollo-utilities/-/apollo-utilities-1.3.4.tgz#6129e438e8be201b6c55b0f13ce49d2c7175c9cf" @@ -4088,20 +3948,6 @@ array.prototype.flatmap@^1.3.3: es-abstract "^1.23.5" es-shim-unscopables "^1.0.2" -array.prototype.reduce@^1.0.8: - version "1.0.8" - resolved "https://registry.yarnpkg.com/array.prototype.reduce/-/array.prototype.reduce-1.0.8.tgz#42f97f5078daedca687d4463fd3c05cbfd83da57" - integrity sha512-DwuEqgXFBwbmZSRqt3BpQigWNUoqw9Ml2dTWdF3B2zQlQX4OeUE0zyuzX0fX0IbTvjdkZbcBTU3idgpO78qkTw== - dependencies: - call-bind "^1.0.8" - call-bound "^1.0.4" - define-properties "^1.2.1" - es-abstract "^1.23.9" - es-array-method-boxes-properly "^1.0.0" - es-errors "^1.3.0" - es-object-atoms "^1.1.1" - is-string "^1.1.1" - array.prototype.tosorted@^1.1.4: version "1.1.4" resolved "https://registry.yarnpkg.com/array.prototype.tosorted/-/array.prototype.tosorted-1.1.4.tgz#fe954678ff53034e717ea3352a03f0b0b86f7ffc" @@ -4304,7 +4150,7 @@ binary-extensions@^2.0.0: resolved "https://registry.yarnpkg.com/binary-extensions/-/binary-extensions-2.3.0.tgz#f6e14a97858d327252200242d4ccfe522c445522" integrity sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw== -body-parser@^1.18.3, body-parser@^1.20.3, body-parser@~1.20.3: +body-parser@^1.20.3, body-parser@~1.20.3: version "1.20.4" resolved "https://registry.yarnpkg.com/body-parser/-/body-parser-1.20.4.tgz#f8e20f4d06ca8a50a71ed329c15dccad1cdc547f" integrity sha512-ZTgYYLMOXY9qKU/57FAo8F+HA2dGX7bqGc71txDRC1rS4frdFI5R7NhluHxH6M0YItAP0sHB4uqAOcYKxO6uGA== @@ -4490,14 +4336,6 @@ callsites@^3.0.0, callsites@^3.1.0: resolved "https://registry.yarnpkg.com/callsites/-/callsites-3.1.0.tgz#b3630abd8943432f54b3f0519238e33cd7df2f73" integrity sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ== -camel-case@4.1.1: - version "4.1.1" - resolved "https://registry.yarnpkg.com/camel-case/-/camel-case-4.1.1.tgz#1fc41c854f00e2f7d0139dfeba1542d6896fe547" - integrity sha512-7fa2WcG4fYFkclIvEmxBbTvmibwF2/agfEBc6q3lOpVu0A13ltLsA+Hr/8Hp6kp5f+G7hKi6t8lys6XxP+1K6Q== - dependencies: - pascal-case "^3.1.1" - tslib "^1.10.0" - camelcase@^5.3.1: version "5.3.1" resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-5.3.1.tgz#e3c9b31569e106811df242f715725a1f4c494320" @@ -4684,11 +4522,6 @@ cjs-module-lexer@^2.1.0: resolved "https://registry.yarnpkg.com/cjs-module-lexer/-/cjs-module-lexer-2.2.0.tgz#b3ca5101843389259ade7d88c77bd06ce55849ca" integrity sha512-4bHTS2YuzUvtoLjdy+98ykbNB5jS0+07EvFNXerqZQJ89F7DI6ET7OQo/HJuW6K0aVsKA9hj9/RVb2kQVOrPDQ== -clean-stack@^2.0.0: - version "2.2.0" - resolved "https://registry.yarnpkg.com/clean-stack/-/clean-stack-2.2.0.tgz#ee8472dbb129e727b31e8a10a427dee9dfe4008b" - integrity sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A== - clipboardy@1.2.2: version "1.2.2" resolved "https://registry.yarnpkg.com/clipboardy/-/clipboardy-1.2.2.tgz#2ce320b9ed9be1514f79878b53ff9765420903e2" @@ -4828,7 +4661,7 @@ content-disposition@~0.5.4: dependencies: safe-buffer "5.2.1" -content-type@~1.0.4, content-type@~1.0.5: +content-type@^1.0.5, content-type@~1.0.4, content-type@~1.0.5: version "1.0.5" resolved "https://registry.yarnpkg.com/content-type/-/content-type-1.0.5.tgz#8b773162656d1d1086784c8f23a54ce6d73d7918" integrity sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA== @@ -4853,7 +4686,7 @@ cookie@~0.7.1: resolved "https://registry.yarnpkg.com/cookie/-/cookie-0.7.2.tgz#556369c472a2ba910f2979891b526b3436237ed7" integrity sha512-yki5XnKuf750l50uGTllt6kKILY4nQ1eNIQatoXEByZ5dWgnKqbnqmTrBE5B4N7lrMJKQ2ytWMiTO2o0v6Ew/w== -core-js-pure@^3.10.2, core-js-pure@^3.43.0: +core-js-pure@^3.43.0: version "3.48.0" resolved "https://registry.yarnpkg.com/core-js-pure/-/core-js-pure-3.48.0.tgz#7d5a3fe1ec3631b9aa76a81c843ac2ce918e5023" integrity sha512-1slJgk89tWC51HQ1AEqG+s2VuwpTRr8ocu4n20QUcH1v9lAN0RXen0Q0AABa/DK1I7RrNWLucplOHMx8hfTGTw== @@ -4970,11 +4803,6 @@ cssesc@^3.0.0: resolved "https://registry.yarnpkg.com/cssesc/-/cssesc-3.0.0.tgz#37741919903b868565e1c09ea747445cd18983ee" integrity sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg== -cssfilter@0.0.10: - version "0.0.10" - resolved "https://registry.yarnpkg.com/cssfilter/-/cssfilter-0.0.10.tgz#c6d2672632a2e5c83e013e6864a42ce8defd20ae" - integrity sha512-FAaLDaplstoRsDR8XGYH51znUN0UY7nMc6Z9/fvE8EXGwvJE9hu7W2vHwx1+bd6gCYnln9nLbzxFTrcO9YQDZw== - cssstyle@^5.3.4: version "5.3.7" resolved "https://registry.yarnpkg.com/cssstyle/-/cssstyle-5.3.7.tgz#2202e56abcecf97ae81dd7783fc8abc5f044305d" @@ -5102,11 +4930,6 @@ deep-is@^0.1.3: resolved "https://registry.yarnpkg.com/deep-is/-/deep-is-0.1.4.tgz#a6f2dce612fadd2ef1f519b73551f17e85199831" integrity sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ== -deepmerge@4.2.2: - version "4.2.2" - resolved "https://registry.yarnpkg.com/deepmerge/-/deepmerge-4.2.2.tgz#44d2ea3679b8f4d4ffba33f03d865fc1e7bf4955" - integrity sha512-FJ3UgI4gIl+PHZm53knsuSFpE+nESMr7M4v9QcgB7S63Kj/6WqMiFQJpBBYz1Pt+66bZpP3Q7Lye0Oo9MPKEdg== - deepmerge@^4.2.2, deepmerge@^4.3.1: version "4.3.1" resolved "https://registry.yarnpkg.com/deepmerge/-/deepmerge-4.3.1.tgz#44b5f2147cd3b00d4b56137685966f26fd25dd4a" @@ -5489,11 +5312,6 @@ es-abstract@^1.17.5, es-abstract@^1.23.2, es-abstract@^1.23.3, es-abstract@^1.23 unbox-primitive "^1.1.0" which-typed-array "^1.1.19" -es-array-method-boxes-properly@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/es-array-method-boxes-properly/-/es-array-method-boxes-properly-1.0.0.tgz#873f3e84418de4ee19c5be752990b2e44718d09e" - integrity sha512-wd6JXUmyHmt8T5a2xreUwKcGPq6f1f+WwIJkijUqiGcJz1qqnZgP6XIK+QyIWU5lT7imeNxUll48bziG+TSYcA== - es-define-property@^1.0.0, es-define-property@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/es-define-property/-/es-define-property-1.0.1.tgz#983eb2f9a6724e9303f61addf011c72e09e0b0fa" @@ -6022,7 +5840,7 @@ exponential-backoff@^3.1.1: resolved "https://registry.yarnpkg.com/exponential-backoff/-/exponential-backoff-3.1.3.tgz#51cf92c1c0493c766053f9d3abee4434c244d2f6" integrity sha512-ZgEeZXj30q+I0EN+CbSSpIyPaJ5HVQD18Z1m+u1FXbAeT94mr1zw50q4q6jiiC447Nl/YTcIYSAftiGqetwXCA== -express@^4.0.0, express@^4.17.1, express@^4.22.1: +express@^4.21.1, express@^4.22.1: version "4.22.1" resolved "https://registry.yarnpkg.com/express/-/express-4.22.1.tgz#1de23a09745a4fffdb39247b344bb5eaff382069" integrity sha512-F2X8g9P1X7uCPZMA3MVf9wcTqlyNp7IhH5qPCI0izhaOIYXaW9L535tGA3qmjRzpH+bZczqq7hVKxTR4NWnu+g== @@ -6069,11 +5887,6 @@ extendable-error@^0.1.5: resolved "https://registry.yarnpkg.com/extendable-error/-/extendable-error-0.1.7.tgz#60b9adf206264ac920058a7395685ae4670c2b96" integrity sha512-UOiS2in6/Q0FK0R0q6UY9vYpQ21mr/Qn1KOnte7vsACuNJf514WvCCUHSRCPcgjPT2bAhNIJdlE6bVap1GKmeg== -extract-files@^8.0.0: - version "8.1.0" - resolved "https://registry.yarnpkg.com/extract-files/-/extract-files-8.1.0.tgz#46a0690d0fe77411a2e3804852adeaa65cd59288" - integrity sha512-PTGtfthZK79WUMk+avLmwx3NGdU8+iVFXC2NMGxKsn0MnihOG2lvumj+AZo8CTwTrwjXDgZ5tztbRlEdRjBonQ== - fast-deep-equal@^3.1.1, fast-deep-equal@^3.1.3: version "3.1.3" resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz#3a7d56b559d6cbc3eb512325244e619a65c6c525" @@ -6084,7 +5897,7 @@ fast-diff@^1.1.2: resolved "https://registry.yarnpkg.com/fast-diff/-/fast-diff-1.3.0.tgz#ece407fa550a64d638536cd727e129c61616e0f0" integrity sha512-VxPP4NqbUjj6MaAOafWeUn2cXWLcCtljklUtZf0Ind4XQ+QPtmA0b18zZy0jIQx+ExRVCR/ZQpBmik5lXshNsw== -fast-glob@^3.1.1, fast-glob@^3.2.12, fast-glob@^3.2.9, fast-glob@^3.3.3: +fast-glob@^3.2.12, fast-glob@^3.2.9, fast-glob@^3.3.3: version "3.3.3" resolved "https://registry.yarnpkg.com/fast-glob/-/fast-glob-3.3.3.tgz#d06d585ce8dba90a16b0505c543c3ccfb3aeb818" integrity sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg== @@ -6217,11 +6030,6 @@ flatted@^3.2.9: resolved "https://registry.yarnpkg.com/flatted/-/flatted-3.3.3.tgz#67c8fad95454a7c7abebf74bb78ee74a44023358" integrity sha512-GX+ysw4PBCz0PzosHDepZGANEuFCMLrnRTiEy9McGjmkCQYwRq4A/X786G/fjM/+OjsWSU1ZrY5qyARZmO/uwg== -fn-name@~3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/fn-name/-/fn-name-3.0.0.tgz#0596707f635929634d791f452309ab41558e3c5c" - integrity sha512-eNMNr5exLoavuAMhIUVsOKF79SWd/zG104ef6sxBTSw+cZc6BXdQXDvYcGvp0VbxVVSp1XDUNoz7mg1xMtSznA== - for-each@^0.3.3, for-each@^0.3.5: version "0.3.5" resolved "https://registry.yarnpkg.com/for-each/-/for-each-0.3.5.tgz#d650688027826920feeb0af747ee7b9421a41d47" @@ -6249,16 +6057,16 @@ form-data@^2.5.5: mime-types "^2.1.35" safe-buffer "^5.2.1" -form-data@^3.0.0: - version "3.0.4" - resolved "https://registry.yarnpkg.com/form-data/-/form-data-3.0.4.tgz#938273171d3f999286a4557528ce022dc2c98df1" - integrity sha512-f0cRzm6dkyVYV3nPoooP8XlccPQukegwhAnpoLcXy+X+A8KfpGOoXwDr9FLZd3wzgLaBGQBE3lY93Zm/i1JvIQ== +form-data@^4.0.4: + version "4.0.5" + resolved "https://registry.yarnpkg.com/form-data/-/form-data-4.0.5.tgz#b49e48858045ff4cbf6b03e1805cebcad3679053" + integrity sha512-8RipRLol37bNs2bhoV67fiTEvdTrbMUYcFTiy3+wuuOnUog2QBHCZWXDRijWQfAkhBj2Uf5UnVaiWwA5vdd82w== dependencies: asynckit "^0.4.0" combined-stream "^1.0.8" es-set-tostringtag "^2.1.0" hasown "^2.0.2" - mime-types "^2.1.35" + mime-types "^2.1.12" formdata-polyfill@^4.0.10: version "4.0.10" @@ -6284,7 +6092,7 @@ fresh@~0.5.2: resolved "https://registry.yarnpkg.com/fresh/-/fresh-0.5.2.tgz#3d8cadd90d976569fa835ab1f8e4b23a105605a7" integrity sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q== -fs-capacitor@^2.0.4, fs-capacitor@^6.1.0, fs-capacitor@^6.2.0: +fs-capacitor@^6.1.0, fs-capacitor@^6.2.0: version "6.2.0" resolved "https://registry.yarnpkg.com/fs-capacitor/-/fs-capacitor-6.2.0.tgz#fa79ac6576629163cb84561995602d8999afb7f5" integrity sha512-nKcE1UduoSKX27NSZlg879LdQc94OtbOsEmKMN2MBNudXREvijRKx2GEBsTMTfws+BrbkJoEuynbGSVRSpauvw== @@ -6487,19 +6295,7 @@ globalthis@^1.0.4: define-properties "^1.2.1" gopd "^1.0.1" -globby@11.0.0: - version "11.0.0" - resolved "https://registry.yarnpkg.com/globby/-/globby-11.0.0.tgz#56fd0e9f0d4f8fb0c456f1ab0dee96e1380bc154" - integrity sha512-iuehFnR3xu5wBBtm4xi0dMe92Ob87ufyu/dHwpDYfbcpYpIbrO5OnS8M1vWvrBhSGEJ3/Ecj7gnX76P8YxpPEg== - dependencies: - array-union "^2.1.0" - dir-glob "^3.0.1" - fast-glob "^3.1.1" - ignore "^5.1.4" - merge2 "^1.3.0" - slash "^3.0.0" - -globby@^11.0.3, globby@^11.0.4: +globby@11.1.0, globby@^11.0.3, globby@^11.0.4: version "11.1.0" resolved "https://registry.yarnpkg.com/globby/-/globby-11.1.0.tgz#bd4be98bb042f83d796f7e3811991fbe82a0d34b" integrity sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g== @@ -6576,20 +6372,6 @@ graphql-depth-limit@^1.1.0: dependencies: arrify "^1.0.1" -graphql-extensions@^0.16.0: - version "0.16.0" - resolved "https://registry.yarnpkg.com/graphql-extensions/-/graphql-extensions-0.16.0.tgz#32669fde0a2f115de60e5dda818ae457c1d71bb8" - integrity sha512-rZQc/USoEIw437BGRUwoHoLPR1LA791Ltj6axONqgKIyyx2sqIO3YT9kTbB/eIUdJBrCozp4KuUeZ09xKeQDxg== - dependencies: - "@apollographql/apollo-tools" "^0.5.0" - apollo-server-env "^3.2.0" - apollo-server-types "^0.10.0" - -graphql-middleware-sentry@^3.2.1: - version "3.2.1" - resolved "https://registry.yarnpkg.com/graphql-middleware-sentry/-/graphql-middleware-sentry-3.2.1.tgz#b5653d78903d655cf4212a602cfa6e26689cda07" - integrity sha512-lAwmHwsyey1db6scQg32javmqAFifabhqPIr0SUzx46O4kvjQlLZZn7KrRT12XDwgW7i6goAotdSPl9Fq+TBrQ== - graphql-middleware@~6.1.35: version "6.1.35" resolved "https://registry.yarnpkg.com/graphql-middleware/-/graphql-middleware-6.1.35.tgz#7297d41ceb35742b80640cca5cd85d1e47e8ab24" @@ -6605,49 +6387,31 @@ graphql-redis-subscriptions@^2.7.0: optionalDependencies: ioredis "^5.3.2" -graphql-shield@~7.2.2: - version "7.2.6" - resolved "https://registry.yarnpkg.com/graphql-shield/-/graphql-shield-7.2.6.tgz#f11107ed122c1882cb8062d55ed3c3acffcdbc17" - integrity sha512-XTGd+l0Ah3JzJp/jBFpluGZTmlcM8y09WxVR0w74DuQoFdr7W58j9cNvFudJIET5uBSaCVd7pUPYtep26SltsQ== +graphql-shield@^7.6.5: + version "7.6.5" + resolved "https://registry.yarnpkg.com/graphql-shield/-/graphql-shield-7.6.5.tgz#91683254e498e120ce58d560b8b4f118e10530ea" + integrity sha512-etbzf7UIhQW6vadn/UR+ds0LJOceO8ITDXwbUkQMlP2KqPgSKTZRE2zci+AUfqP+cpV9zDQdbTJfPfW5OCEamg== dependencies: - "@types/yup" "0.26.37" - object-hash "^2.0.3" - yup "^0.28.4" + "@types/yup" "0.29.13" + object-hash "^3.0.0" + tslib "^2.4.0" + yup "^0.32.0" -graphql-subscriptions@^1.0.0, graphql-subscriptions@^1.1.0: - version "1.2.1" - resolved "https://registry.yarnpkg.com/graphql-subscriptions/-/graphql-subscriptions-1.2.1.tgz#2142b2d729661ddf967b7388f7cf1dd4cf2e061d" - integrity sha512-95yD/tKi24q8xYa7Q9rhQN16AYj5wPbrb8tmHGM3WRc9EBmWrG/0kkMl+tQG8wcEuE9ibR4zyOM31p5Sdr2v4g== +graphql-subscriptions@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/graphql-subscriptions/-/graphql-subscriptions-2.0.0.tgz#11ec181d475852d8aec879183e8e1eb94f2eb79a" + integrity sha512-s6k2b8mmt9gF9pEfkxsaO1lTxaySfKoEJzEfmwguBbQ//Oq23hIXCfR1hm4kdh5hnR20RdwB+s3BCb+0duHSZA== dependencies: iterall "^1.3.0" -graphql-tag@^2.11.0: +graphql-tag@^2.12.6: version "2.12.6" resolved "https://registry.yarnpkg.com/graphql-tag/-/graphql-tag-2.12.6.tgz#d441a569c1d2537ef10ca3d1633b48725329b5f1" integrity sha512-FdSNcu2QQcWnM2VNvSCCDCVS5PpPqpzgFT8+GXzqJuoDd0CBncxCY278u4mhRO7tMgo2JjgJA5aZ+nWSQ/Z+xg== dependencies: tslib "^2.1.0" -graphql-tag@~2.10.3: - version "2.10.4" - resolved "https://registry.yarnpkg.com/graphql-tag/-/graphql-tag-2.10.4.tgz#2f301a98219be8b178a6453bb7e33b79b66d8f83" - integrity sha512-O7vG5BT3w6Sotc26ybcvLKNTdfr4GfsIVMD+LdYqXCeJIYPRyp8BIsDOUtxw7S1PYvRw5vH3278J2EDezR6mfA== - -graphql-tools@5.0.0: - version "5.0.0" - resolved "https://registry.yarnpkg.com/graphql-tools/-/graphql-tools-5.0.0.tgz#67281c834a0e29f458adba8018f424816fa627e9" - integrity sha512-5zn3vtn//382b7G3Wzz3d5q/sh+f7tVrnxeuhTMTJ7pWJijNqLxH7VEzv8VwXCq19zAzHYEosFHfXiK7qzvk7w== - dependencies: - apollo-link "^1.2.14" - apollo-upload-client "^13.0.0" - deprecated-decorator "^0.1.6" - form-data "^3.0.0" - iterall "^1.3.0" - node-fetch "^2.6.0" - tslib "^1.11.1" - uuid "^7.0.3" - -graphql-tools@^4.0.0, graphql-tools@^4.0.7, graphql-tools@^4.0.8: +graphql-tools@^4.0.7: version "4.0.8" resolved "https://registry.yarnpkg.com/graphql-tools/-/graphql-tools-4.0.8.tgz#e7fb9f0d43408fb0878ba66b522ce871bafe9d30" integrity sha512-MW+ioleBrwhRjalKjYaLQbr+920pHBgy9vM/n47sswtns8+96sRn5M/G+J1eu7IMeKWiN/9p6tmwCHU7552VJg== @@ -6679,17 +6443,20 @@ graphql-upload@^13.0.0: http-errors "^1.8.1" object-path "^0.11.8" +graphql-ws@^5.16.2: + version "5.16.2" + resolved "https://registry.yarnpkg.com/graphql-ws/-/graphql-ws-5.16.2.tgz#7b0306c1bdb0e97a05e800ccd523f46fb212e37c" + integrity sha512-E1uccsZxt/96jH/OwmLPuXMACILs76pKF2i3W861LpKBCYtGIyPQGtWLuBLkND4ox1KHns70e83PS4te50nvPQ== + graphql-ws@^6.0.6: version "6.0.7" resolved "https://registry.yarnpkg.com/graphql-ws/-/graphql-ws-6.0.7.tgz#140307a513f0ba659ecec618d6cf15354a842f96" integrity sha512-yoLRW+KRlDmnnROdAu7sX77VNLC0bsFoZyGQJLy1cF+X/SkLg/fWkRGrEEYQK8o2cafJ2wmEaMqMEZB3U3DYDg== -graphql@^14.2.1, graphql@^14.6.0: - version "14.6.0" - resolved "https://registry.yarnpkg.com/graphql/-/graphql-14.6.0.tgz#57822297111e874ea12f5cd4419616930cd83e49" - integrity sha512-VKzfvHEKybTKjQVpTFrA5yUq2S9ihcZvfJAtsDBBCuV6wauPu1xl/f9ehgVf0FcEJJs4vz6ysb/ZMkGigQZseg== - dependencies: - iterall "^1.2.2" +graphql@^14.2.1, graphql@^16.11.0: + version "16.12.0" + resolved "https://registry.yarnpkg.com/graphql/-/graphql-16.12.0.tgz#28cc2462435b1ac3fdc6976d030cef83a0c13ac7" + integrity sha512-DKKrynuQRne0PNpEbzuEdHlYOMksHSUI8Zc9Unei5gTsMNA2/vMpoMz/yKba50pejK56qj98qM0SjYxAKi13gQ== handlebars@^4.7.8: version "4.7.8" @@ -6975,7 +6742,7 @@ ignore-by-default@^1.0.1: resolved "https://registry.yarnpkg.com/ignore-by-default/-/ignore-by-default-1.0.1.tgz#48ca6d72f6c6a3af00a9ad4ae6876be3889e2b09" integrity sha512-Ius2VYcGNk7T90CppJqcIkS5ooHUZyIQK+ClZfMfMNFEF9VSE73Fq+906u/CWu92x4gzZMWOwfFYckPObzdEbA== -ignore@^5.1.4, ignore@^5.2.0, ignore@^5.3.2: +ignore@^5.2.0, ignore@^5.3.2: version "5.3.2" resolved "https://registry.yarnpkg.com/ignore/-/ignore-5.3.2.tgz#3cd40e729f3643fd87cb04e50bf0eb722bc596f5" integrity sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g== @@ -7011,11 +6778,6 @@ imurmurhash@^0.1.4: resolved "https://registry.yarnpkg.com/imurmurhash/-/imurmurhash-0.1.4.tgz#9218b9b2b928a238b13dc4fb6b6d576f231453ea" integrity sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA== -indent-string@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/indent-string/-/indent-string-4.0.0.tgz#624f8f4497d619b2d9768531d58f4122854d7251" - integrity sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg== - inflight@^1.0.4: version "1.0.6" resolved "https://registry.yarnpkg.com/inflight/-/inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9" @@ -7478,7 +7240,7 @@ istanbul-reports@^3.1.3: html-escaper "^2.0.0" istanbul-lib-report "^3.0.0" -iterall@^1.1.3, iterall@^1.2.1, iterall@^1.2.2, iterall@^1.3.0: +iterall@^1.1.3, iterall@^1.2.1, iterall@^1.3.0: version "1.3.0" resolved "https://registry.yarnpkg.com/iterall/-/iterall-1.3.0.tgz#afcb08492e2915cbd8a0884eb93a8c94d0d72fea" integrity sha512-QZ9qOMdF+QLHxy1QIpUHUU1D5pS2CG2P69LF6L6CPjPYA/XMOmKV3PZpawHoAjHNyB0swdVTRxdYT4tbBbxqwg== @@ -8132,7 +7894,7 @@ locate-path@^6.0.0: dependencies: p-locate "^5.0.0" -lodash-es@^4.17.11: +lodash-es@^4.17.21: version "4.17.23" resolved "https://registry.yarnpkg.com/lodash-es/-/lodash-es-4.17.23.tgz#58c4360fd1b5d33afc6c0bbd3d1149349b1138e0" integrity sha512-kVI48u3PZr38HdYz98UmfPnXl2DXrpdctLrFLCd3kOx1xUkOmpFPx7gCWWM5MPkL/fD8zb+Ph0QzjGFs4+hHWg== @@ -8202,17 +7964,12 @@ lodash.sortby@^4.7.0: resolved "https://registry.yarnpkg.com/lodash.sortby/-/lodash.sortby-4.7.0.tgz#edd14c824e2cc9c1e0b0a1b42bb5210516a42438" integrity sha512-HDWXG8isMntAyRF5vZ7xKuEvOhT4AhlRt/3czTSjvGUxjYCBVRQY48ViDHyfYz9VIoBkW4TMGQNapx+l3RUwdA== -lodash@4.17.15: - version "4.17.15" - resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.15.tgz#b447f6670a0455bbfeedd11392eff330ea097548" - integrity sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A== - lodash@^4.17.15, lodash@^4.17.21, lodash@~4.17.11, lodash@~4.17.23: version "4.17.23" resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.23.tgz#f113b0378386103be4f6893388c73d0bde7f2c5a" integrity sha512-LgVTMpQtIopCi79SJeDiP0TfWi5CNEc/L/aRdTh3yIvmZXTnheWpKjSZhnvMl8iXbC1tFg9gdHHDMLoV7CnG+w== -loglevel@^1.6.7: +loglevel@^1.6.8: version "1.9.2" resolved "https://registry.yarnpkg.com/loglevel/-/loglevel-1.9.2.tgz#c2e028d6c757720107df4e64508530db6621ba08" integrity sha512-HgMmCqIJSAKqo68l0rS2AanEWfkxaZ5wNiEFb5ggm08lDs9Xl2KxBlX3PTcaD2chBM1gXAYf491/M2Rv8Jwayg== @@ -8266,12 +8023,10 @@ lru-cache@^5.1.1: dependencies: yallist "^3.0.2" -lru-cache@^6.0.0: - version "6.0.0" - resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-6.0.0.tgz#6d6fe6570ebd96aaf90fcad1dafa3b2566db3a94" - integrity sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA== - dependencies: - yallist "^4.0.0" +lru-cache@^7.10.1, lru-cache@^7.14.1: + version "7.18.3" + resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-7.18.3.tgz#f793896e0fd0e954a59dfdd82f0773808df6aa89" + integrity sha512-jumlc0BIUrS3qJGgIkWZsyfAM7NCWiBcCDhnd+3NNM5KbBmLTgHVfWBcg6W+rLUsIpzpERPsvwUP7CckAQSOoA== lru_map@^0.3.3: version "0.3.3" @@ -8375,15 +8130,6 @@ merge-descriptors@1.0.3: resolved "https://registry.yarnpkg.com/merge-descriptors/-/merge-descriptors-1.0.3.tgz#d80319a65f3c7935351e5cfdac8f9318504dbed5" integrity sha512-gaNvAS7TZ897/rVaZ0nMtAyxNyi/pdbjbAwUpFQpN70GqnVfOiXpeUUMKRBmzXaSQ8DdTX4/0ms62r2K+hE6mQ== -merge-graphql-schemas@^1.7.8: - version "1.7.8" - resolved "https://registry.yarnpkg.com/merge-graphql-schemas/-/merge-graphql-schemas-1.7.8.tgz#11a0a672a38a61d988c09ffdebe1bd4f8418de48" - integrity sha512-C3EJ1i86OjmbcCT524wVPRl17M5VZzgyh9kIGYAlYnAILX+7xfh8cCbMKfehh9n4opZg6CtcPogCiVZ6PB2NyQ== - dependencies: - "@graphql-toolkit/file-loading" "0.10.4" - "@graphql-toolkit/schema-merging" "0.10.4" - tslib "1.11.1" - merge-stream@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/merge-stream/-/merge-stream-2.0.0.tgz#52823629a14dd00c9770fb6ad47dc6310f2c1f60" @@ -8550,7 +8296,7 @@ mime-db@^1.54.0: resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.54.0.tgz#cddb3ee4f9c64530dff640236661d42cb6a314f5" integrity sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ== -mime-types@^2.1.35, mime-types@~2.1.22, mime-types@~2.1.24, mime-types@~2.1.34: +mime-types@^2.1.12, mime-types@^2.1.35, mime-types@~2.1.22, mime-types@~2.1.24, mime-types@~2.1.34: version "2.1.35" resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.35.tgz#381a871b62a734450660ae3deee44813f70d959a" integrity sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw== @@ -8734,6 +8480,11 @@ nan@^2.24.0: resolved "https://registry.yarnpkg.com/nan/-/nan-2.25.0.tgz#937ed345e63d9481362a7942d49c4860d27eeabd" integrity sha512-0M90Ag7Xn5KMLLZ7zliPWP3rT90P6PN+IzVFS0VqmnPktBk3700xUVv8Ikm9EUaUE5SDWdp/BIxdENzVznpm1g== +nanoclone@^0.2.1: + version "0.2.1" + resolved "https://registry.yarnpkg.com/nanoclone/-/nanoclone-0.2.1.tgz#dd4090f8f1a110d26bb32c49ed2f5b9235209ed4" + integrity sha512-wynEP02LmIbLpcYw8uBKpcfF6dmg2vcpKqxeH5UcoKEYdExslsdUA4ugFauuaeYdTB76ez6gJW8XAZ6CgkXYxA== + nanoid@^3.3.11: version "3.3.11" resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-3.3.11.tgz#4f4f112cefbe303202f2199838128936266d185b" @@ -8754,6 +8505,11 @@ negotiator@0.6.3: resolved "https://registry.yarnpkg.com/negotiator/-/negotiator-0.6.3.tgz#58e323a72fedc0d6f9cd4d31fe49f51479590ccd" integrity sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg== +negotiator@^0.6.3: + version "0.6.4" + resolved "https://registry.yarnpkg.com/negotiator/-/negotiator-0.6.4.tgz#777948e2452651c570b712dd01c23e262713fff7" + integrity sha512-myRT3DiWPHqho5PrJaIRyaMv2kgYf0mUVgBNOYMuCH5Ki1yEiQaf/ZJuQ62nvpc44wL5WDbTX7yGJi1Neevw8w== + negotiator@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/negotiator/-/negotiator-1.0.0.tgz#b6c91bb47172d69f93cfd7c357bbb529019b5f6a" @@ -8841,6 +8597,11 @@ no-case@^3.0.4: lower-case "^2.0.2" tslib "^2.0.3" +node-abort-controller@^3.1.1: + version "3.1.1" + resolved "https://registry.yarnpkg.com/node-abort-controller/-/node-abort-controller-3.1.1.tgz#a94377e964a9a37ac3976d848cb5c765833b8548" + integrity sha512-AGK2yQKIjRuqnc6VkX2Xj5d+QW8xZ87pa1UK6yA6ouUyuxfHuMP6umE5QK7UmTeOAymo+Zx1Fxiuw9rVx8taHQ== + node-domexception@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/node-domexception/-/node-domexception-1.0.0.tgz#6888db46a1f71c0b76b3f7555016b63fe64766e5" @@ -8856,7 +8617,7 @@ node-exports-info@^1.6.0: object.entries "^1.1.9" semver "^6.3.1" -node-fetch@^2.6.0, node-fetch@^2.6.1, node-fetch@^2.7.0: +node-fetch@^2.6.0, node-fetch@^2.6.7, node-fetch@^2.7.0: version "2.7.0" resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.7.0.tgz#d0f0fa6e3e2dc1d27efcd8ad99d550bda94d187d" integrity sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A== @@ -8996,10 +8757,10 @@ object-assign@^4, object-assign@^4.1.1: resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863" integrity sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg== -object-hash@^2.0.3: - version "2.2.0" - resolved "https://registry.yarnpkg.com/object-hash/-/object-hash-2.2.0.tgz#5ad518581eefc443bd763472b8ff2e9c2c0d54a5" - integrity sha512-gScRMn0bS5fH+IuwyIFgnh9zBdo4DV+6GhygmWM9HyNJSgS0hScp1f5vjtm7oIIOiT9trXrShAkLFSc2IqKNgw== +object-hash@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/object-hash/-/object-hash-3.0.0.tgz#73f97f753e7baffc0e2cc9d6e079079744ac82e9" + integrity sha512-RSn9F68PjH9HqtltsSnqYC1XXoWe9Bju5+213R98cNGttag9q9yAOTzdbsqvIa7aNm5WffBZFpWYr2aWrklWAw== object-inspect@^1.13.3, object-inspect@^1.13.4: version "1.13.4" @@ -9048,19 +8809,6 @@ object.fromentries@^2.0.8: es-abstract "^1.23.2" es-object-atoms "^1.0.0" -object.getownpropertydescriptors@^2.1.8: - version "2.1.9" - resolved "https://registry.yarnpkg.com/object.getownpropertydescriptors/-/object.getownpropertydescriptors-2.1.9.tgz#bf9e7520f14d50de88dee2b9c9eca841166322dc" - integrity sha512-mt8YM6XwsTTovI+kdZdHSxoyF2DI59up034orlC9NfweclcWOt7CVascNNLp6U+bjFVCVCIh9PwS76tDM/rH8g== - dependencies: - array.prototype.reduce "^1.0.8" - call-bind "^1.0.8" - define-properties "^1.2.1" - es-abstract "^1.24.0" - es-object-atoms "^1.1.1" - gopd "^1.2.0" - safe-array-concat "^1.1.3" - object.values@^1.1.6, object.values@^1.2.1: version "1.2.1" resolved "https://registry.yarnpkg.com/object.values/-/object.values-1.2.1.tgz#deed520a50809ff7f75a7cfd4bc64c7a038c6216" @@ -9281,19 +9029,11 @@ parseley@^0.12.0: leac "^0.6.0" peberminta "^0.9.0" -parseurl@^1.3.2, parseurl@~1.3.3: +parseurl@~1.3.3: version "1.3.3" resolved "https://registry.yarnpkg.com/parseurl/-/parseurl-1.3.3.tgz#9da19e7bee8d12dff0513ed5b76957793bc2e8d4" integrity sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ== -pascal-case@^3.1.1: - version "3.1.2" - resolved "https://registry.yarnpkg.com/pascal-case/-/pascal-case-3.1.2.tgz#b48e0ef2b98e205e7c1dae747d0b1508237660eb" - integrity sha512-uWlGT3YSnK9x3BQJaOdcZwrnV6hPpd8jFH1/ucpiLRPh/2zCVJKS19E4GvYHvaCcACn3foXZ0cLB9Wrx1KGe5g== - dependencies: - no-case "^3.0.4" - tslib "^2.0.3" - path-exists@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-4.0.0.tgz#513bdbe2d3b95d7762e8c1137efa195c6c61b5b3" @@ -9504,7 +9244,7 @@ prop-types@^15.8.1: object-assign "^4.1.1" react-is "^16.13.1" -property-expr@^2.0.2: +property-expr@^2.0.4: version "2.0.6" resolved "https://registry.yarnpkg.com/property-expr/-/property-expr-2.0.6.tgz#f77bc00d5928a6c748414ad12882e83f24aec1e8" integrity sha512-SVtmxhRE/CGkn3eZY1T6pC8Nln6Fr/lu1mKSgRud0eC73whjGfoAogbn78LkD8aFL0zz3bAFerKSnOl7NlErBA== @@ -10436,10 +10176,10 @@ strnum@^2.1.2: resolved "https://registry.yarnpkg.com/strnum/-/strnum-2.1.2.tgz#a5e00ba66ab25f9cafa3726b567ce7a49170937a" integrity sha512-l63NF9y/cLROq/yqKXSLtcMeeyOfnSQlfMSlzFt/K73oIaD8DGaQWd7Z34X9GPiKqP5rbSh84Hl4bOlLcjiSrQ== -subscriptions-transport-ws@^0.9.19: - version "0.9.19" - resolved "https://registry.yarnpkg.com/subscriptions-transport-ws/-/subscriptions-transport-ws-0.9.19.tgz#10ca32f7e291d5ee8eb728b9c02e43c52606cdcf" - integrity sha512-dxdemxFFB0ppCLg10FTtRqH/31FNRL1y1BQv8209MK5I4CwALb7iihQg+7p65lFcIl8MHatINWBLOqpgU4Kyyw== +subscriptions-transport-ws@^0.11.0: + version "0.11.0" + resolved "https://registry.yarnpkg.com/subscriptions-transport-ws/-/subscriptions-transport-ws-0.11.0.tgz#baf88f050cba51d52afe781de5e81b3c31f89883" + integrity sha512-8D4C6DIH5tGiAIpp5I0wD/xRlNiZAPGHygzCe7VzyzUoxHtawzjNAY9SUTXU05/EY2NMY9/9GF0ycizkXr1CWQ== dependencies: backo2 "^1.0.2" eventemitter3 "^3.1.0" @@ -10499,11 +10239,6 @@ sync-fetch@0.6.0-2: timeout-signal "^2.0.0" whatwg-mimetype "^4.0.0" -synchronous-promise@^2.0.10: - version "2.0.17" - resolved "https://registry.yarnpkg.com/synchronous-promise/-/synchronous-promise-2.0.17.tgz#38901319632f946c982152586f2caf8ddc25c032" - integrity sha512-AsS729u2RHUfEra9xJrE39peJcc2stq2+poBXX8bcM08Y6g9j/i/PUzwNQqkaJde7Ntg1TO7bSREbR5sdosQ+g== - synckit@^0.11.12, synckit@^0.11.8: version "0.11.12" resolved "https://registry.yarnpkg.com/synckit/-/synckit-0.11.12.tgz#abe74124264fbc00a48011b0d98bdc1cffb64a7b" @@ -10754,12 +10489,7 @@ tsconfig-paths@^4.2.0: minimist "^1.2.6" strip-bom "^3.0.0" -tslib@1.11.1: - version "1.11.1" - resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.11.1.tgz#eb15d128827fbee2841549e171f45ed338ac7e35" - integrity sha512-aZW88SY8kQbU7gpV19lN24LtXh/yD4ZZg6qieAJDDg+YBsJcSmLGK9QpnUjAKVG/xefmvJGd1WUmfpT/g6AJGA== - -tslib@^1.10.0, tslib@^1.11.1, tslib@^1.9.0, tslib@^1.9.3: +tslib@^1.10.0, tslib@^1.9.0, tslib@^1.9.3: version "1.14.1" resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.14.1.tgz#cf2d38bdc34a134bcaf1091c41f6619e2f672d00" integrity sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg== @@ -10801,7 +10531,7 @@ type-fest@^4.41.0: resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-4.41.0.tgz#6ae1c8e5731273c2bf1f58ad39cbae2c91a46c58" integrity sha512-TeTSQ6H5YHvpqVwBRcnLDCBnDOHWYu7IvGbHT6N8AOymcr9PJGjc1GTtiWZTYg0NCgYwvnYWEkVChQAr9bjfwA== -type-is@^1.6.16, type-is@~1.6.18: +type-is@~1.6.18: version "1.6.18" resolved "https://registry.yarnpkg.com/type-is/-/type-is-1.6.18.tgz#4e552cd05df09467dcbc4ef739de89f2cf37c131" integrity sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g== @@ -10933,7 +10663,7 @@ unique-slug@^6.0.0: dependencies: imurmurhash "^0.1.4" -unixify@1.0.0, unixify@^1.0.0: +unixify@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/unixify/-/unixify-1.0.0.tgz#3a641c8c2ffbce4da683a5c70f03a462940c2090" integrity sha512-6bc58dPYhCMHHuwxldQxO3RRNZ4eCogZ/st++0+fcC1nr0jiGUtAdBJ2qzmLQWSxbtz42pWt4QQMiZ9HvZf5cg== @@ -11020,24 +10750,6 @@ util-deprecate@^1.0.1, util-deprecate@^1.0.2: resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf" integrity sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw== -util.promisify@^1.0.0: - version "1.1.3" - resolved "https://registry.yarnpkg.com/util.promisify/-/util.promisify-1.1.3.tgz#3d77cf56628b4aad743e5acde8e5c44cea7dbf1c" - integrity sha512-GIEaZ6o86fj09Wtf0VfZ5XP7tmd4t3jM5aZCgmBi231D0DB1AEBa3Aa6MP48DMsAIi96WkpWLimIWVwOjbDMOw== - dependencies: - call-bind "^1.0.8" - call-bound "^1.0.3" - define-data-property "^1.1.4" - define-properties "^1.2.1" - es-errors "^1.3.0" - es-object-atoms "^1.0.0" - for-each "^0.3.3" - get-intrinsic "^1.2.6" - has-proto "^1.2.0" - has-symbols "^1.1.0" - object.getownpropertydescriptors "^2.1.8" - safe-array-concat "^1.1.3" - util@^0.10.4: version "0.10.4" resolved "https://registry.yarnpkg.com/util/-/util-0.10.4.tgz#3aa0125bfe668a4672de58857d3ace27ecb76901" @@ -11055,17 +10767,7 @@ uuid@^3.1.0, uuid@^3.4.0: resolved "https://registry.yarnpkg.com/uuid/-/uuid-3.4.0.tgz#b23e4358afa8a202fe7a100af1f5f883f02007ee" integrity sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A== -uuid@^7.0.3: - version "7.0.3" - resolved "https://registry.yarnpkg.com/uuid/-/uuid-7.0.3.tgz#c5c9f2c8cf25dc0a372c4df1441c41f5bd0c680b" - integrity sha512-DPSke0pXhTZgoF/d+WSt2QaKMCFSfx7QegxEWT+JOuHF5aWrKEn0G+ztjuJg/gG8/ItK+rbPCD/yNv8yyih6Cg== - -uuid@^8.0.0: - version "8.3.2" - resolved "https://registry.yarnpkg.com/uuid/-/uuid-8.3.2.tgz#80d5b5ced271bb9af6c445f21a1a04c606cefbe2" - integrity sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg== - -uuid@^9.0.1, uuid@~9.0.1: +uuid@^9.0.0, uuid@^9.0.1, uuid@~9.0.1: version "9.0.1" resolved "https://registry.yarnpkg.com/uuid/-/uuid-9.0.1.tgz#e188d4c8853cc722220392c424cd637f32293f30" integrity sha512-b+1eJOlsR9K8HJpow9Ok3fiWOWSIcIzXodvv0rQjVoOVNpWMpxf1wZNpt4y9h10odCNrqnYp1OBzRktckBe3sA== @@ -11099,6 +10801,11 @@ value-or-promise@1.0.11: resolved "https://registry.yarnpkg.com/value-or-promise/-/value-or-promise-1.0.11.tgz#3e90299af31dd014fe843fe309cefa7c1d94b140" integrity sha512-41BrgH+dIbCFXClcSapVs5M6GkENd3gQOJpEfPDNa71LsUGMXDL0jMWpI/Rh7WhX+Aalfz2TTS3Zt5pUsbnhLg== +value-or-promise@^1.0.12: + version "1.0.12" + resolved "https://registry.yarnpkg.com/value-or-promise/-/value-or-promise-1.0.12.tgz#0e5abfeec70148c78460a849f6b003ea7986f15c" + integrity sha512-Z6Uz+TYwEqE7ZN50gwn+1LCVo9ZVrpxRPOhOLnncYkY1ZzOYtrX8Fwf/rFktZ8R5mJms6EZf5TqNOMeZmnPq9Q== + vary@^1, vary@~1.1.2: version "1.1.2" resolved "https://registry.yarnpkg.com/vary/-/vary-1.1.2.tgz#2299f02c6ded30d4a5961b0b9f74524a18f634fc" @@ -11190,6 +10897,11 @@ whatwg-encoding@^3.1.1: dependencies: iconv-lite "0.6.3" +whatwg-mimetype@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/whatwg-mimetype/-/whatwg-mimetype-3.0.0.tgz#5fa1a7623867ff1af6ca3dc72ad6b8a4208beba7" + integrity sha512-nt+N2dzIutVRxARx1nghPKGv1xHikU7HKdfafKkLNLindmPU/ch3U31NOCGGA/dmPcmb1VlofO0vnKAcsm0o/Q== + whatwg-mimetype@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/whatwg-mimetype/-/whatwg-mimetype-4.0.0.tgz#bc1bf94a985dc50388d54a9258ac405c3ca2fc0a" @@ -11351,7 +11063,7 @@ write-file-atomic@^5.0.1: resolved "https://registry.yarnpkg.com/ws/-/ws-7.5.10.tgz#58b5c20dc281633f6c19113f39b349bd8bd558d9" integrity sha512-+dbF1tHwZpXcbOJdVOkzLDxZP1ailvSxM6ZweXTegylPny803bFhA+vqBYw4s31NSAk4S2Qz+AKXK9a4wkdjcQ== -ws@^8.17.1, ws@^8.18.3, ws@^8.19.0: +ws@^8.17.1, ws@^8.18.2, ws@^8.18.3, ws@^8.19.0: version "8.19.0" resolved "https://registry.yarnpkg.com/ws/-/ws-8.19.0.tgz#ddc2bdfa5b9ad860204f5a72a4863a8895fd8c8b" integrity sha512-blAT2mjOEIi0ZzruJfIhb3nps74PRWTCz1IjglWEEpQl5XS/UNama6u2/rjFkDDouqr4L67ry+1aGIALViWjDg== @@ -11378,14 +11090,6 @@ xregexp@^5.1.2: dependencies: "@babel/runtime-corejs3" "^7.26.9" -xss@^1.0.8: - version "1.0.15" - resolved "https://registry.yarnpkg.com/xss/-/xss-1.0.15.tgz#96a0e13886f0661063028b410ed1b18670f4e59a" - integrity sha512-FVdlVVC67WOIPvfOwhoMETV72f6GbW7aOabBC3WxN/oUdoEMDyLz4OgRv5/gck2ZeNqEQu+Tb0kloovXOfpYVg== - dependencies: - commander "^2.20.3" - cssfilter "0.0.10" - y18n@^5.0.5: version "5.0.8" resolved "https://registry.yarnpkg.com/y18n/-/y18n-5.0.8.tgz#7f4934d0f7ca8c56f95314939ddcd2dd91ce1d55" @@ -11452,17 +11156,17 @@ yocto-queue@^0.1.0: resolved "https://registry.yarnpkg.com/yocto-queue/-/yocto-queue-0.1.0.tgz#0294eb3dee05028d31ee1a5fa2c556a6aaf10a1b" integrity sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q== -yup@^0.28.4: - version "0.28.5" - resolved "https://registry.yarnpkg.com/yup/-/yup-0.28.5.tgz#85cabb4000d3623ef69be81551190692e631a8a5" - integrity sha512-7JZcvpUGUxMKoaEtcoMEM8lCWRaueGNH/A3EhL/UWqfbFm3uloiI+x59Yq4nzhbbYWUTwAsCteaZOJ+VbqI1uw== +yup@^0.32.0: + version "0.32.11" + resolved "https://registry.yarnpkg.com/yup/-/yup-0.32.11.tgz#d67fb83eefa4698607982e63f7ca4c5ed3cf18c5" + integrity sha512-Z2Fe1bn+eLstG8DRR6FTavGD+MeAwyfmouhHsIUgaADz8jvFKbO/fXc2trJKZg+5EBjh4gGm3iU/t3onKlXHIg== dependencies: - "@babel/runtime" "^7.9.6" - fn-name "~3.0.0" - lodash "^4.17.15" - lodash-es "^4.17.11" - property-expr "^2.0.2" - synchronous-promise "^2.0.10" + "@babel/runtime" "^7.15.4" + "@types/lodash" "^4.14.175" + lodash "^4.17.21" + lodash-es "^4.17.21" + nanoclone "^0.2.1" + property-expr "^2.0.4" toposort "^2.0.2" zen-observable-ts@^0.8.21: