diff --git a/packages/test-server/bin.mjs b/packages/test-server/bin.mjs index 92b9118..7a27e27 100755 --- a/packages/test-server/bin.mjs +++ b/packages/test-server/bin.mjs @@ -1,4 +1,4 @@ #!/usr/bin/env node 'use strict' -import './src/index.mjs' +import './dist/index.js' diff --git a/packages/test-server/package.json b/packages/test-server/package.json index 3260f87..4a01b3b 100644 --- a/packages/test-server/package.json +++ b/packages/test-server/package.json @@ -5,6 +5,11 @@ "bin": { "test-server": "./bin.mjs" }, + "type": "module", + "scripts": { + "build": "tsc -d", + "prepare": "pnpm run build" + }, "dependencies": { "@apollo/server": "^4.7.3", "@graphql-tools/schema": "^10.0.0", @@ -19,6 +24,11 @@ "ws": "^8.13.0" }, "devDependencies": { - "@types/shortid": "^0.0.29" + "@types/body-parser": "^1.19.2", + "@types/cors": "^2.8.13", + "@types/express": "^4.17.17", + "@types/shortid": "^0.0.29", + "@types/ws": "^8.5.5", + "typescript": "^4.7.4" } } diff --git a/packages/test-server/src/data.mjs b/packages/test-server/src/data.mjs deleted file mode 100644 index d286f69..0000000 --- a/packages/test-server/src/data.mjs +++ /dev/null @@ -1,18 +0,0 @@ -export let channels = [] - -export function resetDatabase () { - channels = [ - { - id: 'general', - label: 'General', - messages: [], - }, - { - id: 'random', - label: 'Random', - messages: [], - }, - ] -} - -resetDatabase() diff --git a/packages/test-server/src/data.ts b/packages/test-server/src/data.ts new file mode 100644 index 0000000..711ead1 --- /dev/null +++ b/packages/test-server/src/data.ts @@ -0,0 +1,30 @@ +export interface Channel { + id: string + label: string + messages: Message[] +} + +export interface Message { + id: string + channel: Channel + text: string +} + +export let channels: Channel[] = [] + +export function resetDatabase (): void { + channels = [ + { + id: 'general', + label: 'General', + messages: [], + }, + { + id: 'random', + label: 'Random', + messages: [], + }, + ] +} + +resetDatabase() diff --git a/packages/test-server/src/index.mjs b/packages/test-server/src/index.ts similarity index 79% rename from packages/test-server/src/index.mjs rename to packages/test-server/src/index.ts index de31e56..d4ec961 100644 --- a/packages/test-server/src/index.mjs +++ b/packages/test-server/src/index.ts @@ -6,12 +6,15 @@ import { ApolloServer } from '@apollo/server' import { expressMiddleware } from '@apollo/server/express4' import { WebSocketServer } from 'ws' import { useServer } from 'graphql-ws/lib/use/ws' -import { schema } from './schema.mjs' -import { resetDatabase } from './data.mjs' +import { schema } from './schema.js' +import { resetDatabase } from './data.js' +import { simulateLatency } from './util.js' const app = express() -app.use(cors('*')) +app.use(cors({ + origin: '*', +})) app.use(bodyParser.json()) @@ -22,9 +25,6 @@ app.get('/_reset', (req, res) => { const server = new ApolloServer({ schema, - context: () => new Promise(resolve => { - setTimeout(() => resolve({}), 50) - }), plugins: [ // Proper shutdown for the WebSocket server. { @@ -42,7 +42,12 @@ const server = new ApolloServer({ await server.start() -app.use('/graphql', expressMiddleware(server)) +app.use('/graphql', expressMiddleware(server, { + context: async () => { + await simulateLatency() + return {} + }, +})) const httpServer = createServer(app) diff --git a/packages/test-server/src/schema.mjs b/packages/test-server/src/schema.ts similarity index 76% rename from packages/test-server/src/schema.mjs rename to packages/test-server/src/schema.ts index bd84801..912aa76 100644 --- a/packages/test-server/src/schema.mjs +++ b/packages/test-server/src/schema.ts @@ -2,8 +2,8 @@ import { makeExecutableSchema } from '@graphql-tools/schema' import { PubSub, withFilter } from 'graphql-subscriptions' import shortid from 'shortid' import gql from 'graphql-tag' -import { channels } from './data.mjs' -import { simulateLatency, GraphQLErrorWithCode } from './util.mjs' +import { channels } from './data.js' +import { GraphQLErrorWithCode } from './util.js' const pubsub = new PubSub() @@ -51,21 +51,31 @@ type Subscription { } ` +interface AddMessageInput { + channelId: string + text: string +} + +interface UpdateMessageInput { + id: string + channelId: string + text: string +} + const resolvers = { Query: { - hello: () => simulateLatency().then(() => 'Hello world!'), - channels: () => simulateLatency().then(() => channels), - channel: (root, { id }) => simulateLatency().then(() => channels.find(c => c.id === id)), - list: () => simulateLatency().then(() => ['a', 'b', 'c']), - good: () => simulateLatency().then(() => 'good'), + hello: () => 'Hello world!', + channels: () => channels, + channel: (root: any, { id }: { id: string }) => channels.find(c => c.id === id), + list: () => ['a', 'b', 'c'], + good: () => 'good', bad: async () => { - await simulateLatency() throw new Error('An error') }, }, Mutation: { - addMessage: (root, { input }) => { + addMessage: (root: any, { input }: { input: AddMessageInput }) => { const channel = channels.find(c => c.id === input.channelId) if (!channel) { throw new GraphQLErrorWithCode(`Channel ${input.channelId} not found`, 'not-found') @@ -80,12 +90,15 @@ const resolvers = { return message }, - updateMessage: (root, { input }) => { + updateMessage: (root: any, { input }: { input: UpdateMessageInput }) => { const channel = channels.find(c => c.id === input.channelId) if (!channel) { throw new GraphQLErrorWithCode(`Channel ${input.channelId} not found`, 'not-found') } const message = channel.messages.find(m => m.id === input.id) + if (!message) { + throw new GraphQLErrorWithCode(`Message ${input.id} not found`, 'not-found') + } Object.assign(message, { text: input.text, }) diff --git a/packages/test-server/src/util.mjs b/packages/test-server/src/util.ts similarity index 70% rename from packages/test-server/src/util.mjs rename to packages/test-server/src/util.ts index 86ae9cb..e8c77a8 100644 --- a/packages/test-server/src/util.mjs +++ b/packages/test-server/src/util.ts @@ -1,4 +1,4 @@ -import { GraphQLError } from 'graphql' +import { GraphQLError, GraphQLErrorExtensions } from 'graphql' const shouldSimulateLatency = process.argv.includes('--simulate-latency') @@ -11,7 +11,7 @@ if (shouldSimulateLatency) { } export function simulateLatency () { - return new Promise(resolve => { + return new Promise(resolve => { if (shouldSimulateLatency) { setTimeout(resolve, latency) } else { @@ -21,8 +21,8 @@ export function simulateLatency () { } export class GraphQLErrorWithCode extends GraphQLError { - constructor (message, code, extensions) { - super(message, { + constructor (message: string, code: string, extensions?: GraphQLErrorExtensions) { + super(message, null, null, null, null, null, { extensions: { code, ...extensions, diff --git a/packages/test-server/tsconfig.json b/packages/test-server/tsconfig.json new file mode 100644 index 0000000..cb8a87a --- /dev/null +++ b/packages/test-server/tsconfig.json @@ -0,0 +1,23 @@ +{ + "compilerOptions": { + "target": "esnext", + "module": "esnext", + "strict": true, + "importHelpers": true, + "moduleResolution": "node", + "skipLibCheck": true, + "esModuleInterop": true, + "allowSyntheticDefaultImports": true, + "sourceMap": true, + "lib": [ + "esnext" + ], + "outDir": "dist", + }, + "include": [ + "src/**/*.ts", + ], + "exclude": [ + "node_modules" + ] +} diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 7e162eb..550db27 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -279,9 +279,24 @@ importers: specifier: ^8.13.0 version: 8.13.0 devDependencies: + '@types/body-parser': + specifier: ^1.19.2 + version: 1.19.2 + '@types/cors': + specifier: ^2.8.13 + version: 2.8.13 + '@types/express': + specifier: ^4.17.17 + version: 4.17.17 '@types/shortid': specifier: ^0.0.29 version: 0.0.29 + '@types/ws': + specifier: ^8.5.5 + version: 8.5.5 + typescript: + specifier: ^4.7.4 + version: 4.9.5 packages/vue-apollo-components: dependencies: @@ -2800,6 +2815,13 @@ packages: dependencies: '@types/connect': 3.4.35 '@types/node': 18.14.0 + dev: false + + /@types/body-parser@1.19.2: + resolution: {integrity: sha512-ALYone6pm6QmwZoAgeyNksccT9Q4AWZQ6PvfwR37GT6r6FWUPguq6sUmNGSMV2Wr761oQoBxwGGa6DR5o1DC9g==} + dependencies: + '@types/connect': 3.4.35 + '@types/node': 18.14.0 /@types/bonjour@3.5.10: resolution: {integrity: sha512-p7ienRMiS41Nu2/igbJxxLDWrSZ0WxM8UQgCeO9KhoVF7cOVFkrKsiDr1EsJIla8vV3oEEjGcz11jc5yimhzZw==} @@ -2836,6 +2858,12 @@ packages: resolution: {integrity: sha512-C7srjHiVG3Ey1nR6d511dtDkCEjxuN9W1HWAEjGq8kpcwmNM6JJkpC0xvabM7BXTG2wDq8Eu33iH9aQKa7IvLQ==} dev: false + /@types/cors@2.8.13: + resolution: {integrity: sha512-RG8AStHlUiV5ysZQKq97copd2UmVYw3/pRMLefISZ3S1hK104Cwm7iLQ3fTKx+lsUH2CE8FlLaYeEA2LSeqYUA==} + dependencies: + '@types/node': 18.14.0 + dev: true + /@types/eslint-scope@3.7.4: resolution: {integrity: sha512-9K4zoImiZc3HlIp6AVUDE4CWYx22a+lhSZMYNpbjW04+YF0KWj4pJXnEMjdnFTiQibFFmElcsasJXDbdI/EPhA==} dependencies: @@ -2868,7 +2896,7 @@ packages: /@types/express@4.17.17: resolution: {integrity: sha512-Q4FmmuLGBG58btUnfS1c1r/NQdlp3DMfGDGig8WhfpA2YRUtEkxAjkZb0yvplJGYdF1fsQ81iMDcH24sSCNC/Q==} dependencies: - '@types/body-parser': 1.19.0 + '@types/body-parser': 1.19.2 '@types/express-serve-static-core': 4.17.33 '@types/qs': 6.9.7 '@types/serve-static': 1.15.0 @@ -3069,8 +3097,8 @@ packages: '@types/node': 18.14.0 dev: false - /@types/ws@8.5.4: - resolution: {integrity: sha512-zdQDHKUgcX/zBc4GrwsE/7dVdAD8JR4EuiAXiiUhhfyIJXXb2+PrGshFyeXWQPMmmZ2XxgaqclgpIC7eTXc1mg==} + /@types/ws@8.5.5: + resolution: {integrity: sha512-lwhs8hktwxSjf9UaZ9tG5M03PGogvFaH8gUgLNbN9HKIg0dvv6q+gkSuJ8HN4/VbyxkuLzCjlN7GquQ0gUJfIg==} dependencies: '@types/node': 18.14.0 dev: true @@ -14036,7 +14064,7 @@ packages: '@types/serve-index': 1.9.1 '@types/serve-static': 1.15.0 '@types/sockjs': 0.3.33 - '@types/ws': 8.5.4 + '@types/ws': 8.5.5 ansi-html-community: 0.0.8 bonjour-service: 1.1.0 chokidar: 3.5.3