mirror of
https://github.com/omnivore-app/omnivore.git
synced 2026-03-11 08:54:26 +00:00
Remove subscriptions, comment out the sanitize directive
This commit is contained in:
parent
df2b36b33a
commit
fb224d60c4
4 changed files with 32 additions and 191 deletions
|
|
@ -15,12 +15,12 @@ import { tracer } from './tracing'
|
|||
import { env } from './env'
|
||||
import { promisify } from 'util'
|
||||
import { buildLogger } from './utils/logger'
|
||||
import { ApolloServer, makeExecutableSchema } from 'apollo-server-express'
|
||||
import { ApolloServer } from 'apollo-server-express'
|
||||
import { makeExecutableSchema } from '@graphql-tools/schema'
|
||||
import { applyMiddleware } from 'graphql-middleware'
|
||||
import * as cookie from 'cookie'
|
||||
import typeDefs from './schema'
|
||||
import { gqlTracingPlugin, traceResolvers } from './graphql_tracing'
|
||||
import { SanitizeDirective } from './directives'
|
||||
// import { SanitizeDirective } from './directives'
|
||||
import { functionResolvers } from './resolvers/function_resolvers'
|
||||
import ScalarResolvers from './scalars'
|
||||
import * as Sentry from '@sentry/node'
|
||||
|
|
@ -38,10 +38,6 @@ const resolvers = {
|
|||
...ScalarResolvers,
|
||||
}
|
||||
|
||||
const schemaDirectives = {
|
||||
sanitize: SanitizeDirective,
|
||||
}
|
||||
|
||||
const contextFunc: ContextFunction<ExpressContext, ResolverContext> = async ({
|
||||
req,
|
||||
res,
|
||||
|
|
@ -112,53 +108,16 @@ const contextFunc: ContextFunction<ExpressContext, ResolverContext> = async ({
|
|||
}
|
||||
|
||||
export function makeApolloServer(app: Express): ApolloServer {
|
||||
traceResolvers(functionResolvers)
|
||||
|
||||
let schema = makeExecutableSchema({ typeDefs, resolvers })
|
||||
const apollo = new ApolloServer({
|
||||
schema: applyMiddleware(
|
||||
makeExecutableSchema({ typeDefs, resolvers, schemaDirectives })
|
||||
),
|
||||
schema: schema,
|
||||
context: contextFunc,
|
||||
plugins: [
|
||||
gqlTracingPlugin,
|
||||
{
|
||||
requestDidStart: () => ({
|
||||
didEncounterErrors: (ctx) => {
|
||||
const error = ctx.errors[0]
|
||||
const trxId = ctx.request.http?.headers.get('X-Transaction-ID')
|
||||
const userId = ctx.context?.claims?.uid
|
||||
const consoleMessage = `Transaction ID: ${trxId}. user: ${userId}.\n`
|
||||
console.error(consoleMessage, error)
|
||||
},
|
||||
}),
|
||||
},
|
||||
],
|
||||
formatError: (err) => {
|
||||
Sentry.captureException(err)
|
||||
// hide error messages from frontend on prod
|
||||
return new Error('Unexpected server error')
|
||||
},
|
||||
subscriptions: {
|
||||
path: '/api/graphql',
|
||||
keepAlive: 4000,
|
||||
onConnect: (connectionParams, webSocket, context) => {
|
||||
const extraContext: { [key: string]: Record<string, unknown> } = {}
|
||||
if (
|
||||
context.request &&
|
||||
context.request.headers &&
|
||||
context.request.headers.cookie
|
||||
) {
|
||||
extraContext.cookies = cookie.parse(context.request.headers.cookie)
|
||||
}
|
||||
return {
|
||||
...extraContext,
|
||||
...context,
|
||||
}
|
||||
},
|
||||
},
|
||||
})
|
||||
|
||||
apollo.applyMiddleware({ app, path: '/api/graphql', cors: corsConfig })
|
||||
|
||||
return apollo
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,25 +1,25 @@
|
|||
/* eslint-disable @typescript-eslint/restrict-template-expressions */
|
||||
import { SchemaDirectiveVisitor } from 'apollo-server-express'
|
||||
import { GraphQLInputField, GraphQLScalarType } from 'graphql'
|
||||
import { SanitizedString } from './scalars'
|
||||
import { GraphQLNonNull } from 'graphql/type/definition'
|
||||
// import { SchemaDirectiveVisitor } from 'apollo-server-express'
|
||||
// import { GraphQLInputField, GraphQLScalarType } from 'graphql'
|
||||
// import { SanitizedString } from './scalars'
|
||||
// import { GraphQLNonNull } from 'graphql/type/definition'
|
||||
|
||||
export class SanitizeDirective extends SchemaDirectiveVisitor {
|
||||
visitInputFieldDefinition(
|
||||
field: GraphQLInputField
|
||||
): GraphQLInputField | void | null {
|
||||
const { allowedTags, maxLength } = this.args
|
||||
if (
|
||||
field.type instanceof GraphQLNonNull &&
|
||||
field.type.ofType instanceof GraphQLScalarType
|
||||
) {
|
||||
field.type = new GraphQLNonNull(
|
||||
new SanitizedString(field.type.ofType, allowedTags, maxLength)
|
||||
)
|
||||
} else if (field.type instanceof GraphQLScalarType) {
|
||||
field.type = new SanitizedString(field.type, allowedTags, maxLength)
|
||||
} else {
|
||||
throw new Error(`Not a scalar type: ${field.type}`)
|
||||
}
|
||||
}
|
||||
}
|
||||
// export class SanitizeDirective extends SchemaDirectiveVisitor {
|
||||
// visitInputFieldDefinition(
|
||||
// field: GraphQLInputField
|
||||
// ): GraphQLInputField | void | null {
|
||||
// const { allowedTags, maxLength } = this.args
|
||||
// if (
|
||||
// field.type instanceof GraphQLNonNull &&
|
||||
// field.type.ofType instanceof GraphQLScalarType
|
||||
// ) {
|
||||
// field.type = new GraphQLNonNull(
|
||||
// new SanitizedString(field.type.ofType, allowedTags, maxLength)
|
||||
// )
|
||||
// } else if (field.type instanceof GraphQLScalarType) {
|
||||
// field.type = new SanitizedString(field.type, allowedTags, maxLength)
|
||||
// } else {
|
||||
// throw new Error(`Not a scalar type: ${field.type}`)
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
|
|
|||
|
|
@ -1,122 +0,0 @@
|
|||
/* eslint-disable @typescript-eslint/require-await */
|
||||
/* eslint-disable @typescript-eslint/no-unused-vars */
|
||||
/* eslint-disable prefer-const */
|
||||
/* eslint-disable @typescript-eslint/no-unsafe-member-access */
|
||||
/* eslint-disable @typescript-eslint/no-unsafe-return */
|
||||
/* eslint-disable @typescript-eslint/no-unsafe-assignment */
|
||||
/* eslint-disable @typescript-eslint/no-explicit-any */
|
||||
import {
|
||||
ApolloServerPlugin,
|
||||
GraphQLRequestListener,
|
||||
ValueOrPromise,
|
||||
WithRequired,
|
||||
} from 'apollo-server-plugin-base'
|
||||
import { GraphQLRequestContext } from 'apollo-server-core'
|
||||
import { GraphQLResolveInfo } from 'graphql'
|
||||
import { ResolverContext } from './resolvers/types'
|
||||
import { ResolverFn, SubscriptionResolverObject } from './generated/graphql'
|
||||
import { traceAs } from './tracing'
|
||||
|
||||
/**
|
||||
* Replaces resolver functions with tracing-wrapped functions.
|
||||
*/
|
||||
export function traceResolvers(resolvers: {
|
||||
[rootKey: string]: {
|
||||
[fieldKey: string]:
|
||||
| ResolverFn<any, any, any, any>
|
||||
| SubscriptionResolverObject<any, any, any, any>
|
||||
}
|
||||
}): void {
|
||||
for (const typeKey in resolvers) {
|
||||
const rootType = resolvers[typeKey]
|
||||
for (const fieldKey in rootType) {
|
||||
const resolver = rootType[fieldKey]
|
||||
const resolveFn =
|
||||
typeof resolver === 'function' ? resolver : resolver.resolve
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/explicit-function-return-type
|
||||
const wrappedResolveFn = async (
|
||||
...resolverArgs: [any, any, ResolverContext, GraphQLResolveInfo]
|
||||
) => {
|
||||
let info, ctx, args
|
||||
if (resolverArgs.length === 4) {
|
||||
;[, args, ctx, info] = resolverArgs
|
||||
}
|
||||
if (!info?.path) {
|
||||
return resolveFn(...resolverArgs)
|
||||
}
|
||||
|
||||
const spanName = `${typeKey}.${info.path.key}`
|
||||
return traceAs(
|
||||
{
|
||||
spanName,
|
||||
attributes: {
|
||||
'resolver.args': JSON.stringify(args),
|
||||
},
|
||||
},
|
||||
async () => {
|
||||
return resolveFn(...resolverArgs)
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
if (typeof resolver === 'function') {
|
||||
rootType[fieldKey] = wrappedResolveFn
|
||||
} else {
|
||||
;(rootType[fieldKey] as any).resolve = wrappedResolveFn
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class GQLTracingPlugin implements GraphQLRequestListener<ResolverContext> {
|
||||
[key: string]: import('apollo-server-types').AnyFunction | undefined
|
||||
willSendResponse({
|
||||
context,
|
||||
}: WithRequired<
|
||||
GraphQLRequestContext<ResolverContext>,
|
||||
'metrics' | 'response'
|
||||
>): ValueOrPromise<void> {
|
||||
context.tracingSpan.end()
|
||||
}
|
||||
|
||||
didEncounterErrors(
|
||||
ctx: WithRequired<
|
||||
GraphQLRequestContext<ResolverContext>,
|
||||
'metrics' | 'source' | 'errors'
|
||||
>
|
||||
): ValueOrPromise<void> {
|
||||
const error = ctx.errors[0]
|
||||
const trxId = ctx.request.http?.headers.get('X-Transaction-ID')
|
||||
const userId = ctx.context?.claims?.uid
|
||||
ctx.context.tracingSpan.setAttributes({
|
||||
'graphql.error': true,
|
||||
'graphql.error.message': error.message,
|
||||
'request.transaction_id': trxId || '',
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
export const gqlTracingPlugin: ApolloServerPlugin<ResolverContext> = {
|
||||
requestDidStart({
|
||||
context: { tracingSpan, claims },
|
||||
request,
|
||||
}: GraphQLRequestContext<ResolverContext>): GraphQLRequestListener<ResolverContext> | void {
|
||||
if (request.query) {
|
||||
tracingSpan.setAttribute('graphql.query', request.query)
|
||||
}
|
||||
if (claims?.uid) {
|
||||
tracingSpan.setAttribute('user.id', claims.uid)
|
||||
}
|
||||
if (request.operationName) {
|
||||
tracingSpan.setAttribute('graphql.operationName', request.operationName)
|
||||
}
|
||||
if (request.variables) {
|
||||
tracingSpan.setAttribute(
|
||||
'graphql.variables',
|
||||
JSON.stringify(request.variables)
|
||||
)
|
||||
}
|
||||
return new GQLTracingPlugin()
|
||||
},
|
||||
}
|
||||
|
|
@ -38,6 +38,7 @@ import ReminderModel from './datalayer/reminders'
|
|||
import { remindersServiceRouter } from './routers/svc/reminders'
|
||||
import { ApolloServer } from 'apollo-server-express'
|
||||
import { pdfAttachmentsRouter } from './routers/svc/pdf_attachments'
|
||||
import { corsConfig } from './utils/corsConfig'
|
||||
|
||||
const PORT = process.env.PORT || 4000
|
||||
|
||||
|
|
@ -125,6 +126,9 @@ const main = async (): Promise<void> => {
|
|||
|
||||
const { app, apollo, httpServer } = createApp()
|
||||
|
||||
await apollo.start()
|
||||
apollo.applyMiddleware({ app, path: '/api/graphql', cors: corsConfig })
|
||||
|
||||
if (!env.dev.isLocal) {
|
||||
const mwLogger = loggers.get('express', { levels: config.syslog.levels })
|
||||
const transport = buildLoggerTransport('express')
|
||||
|
|
|
|||
Loading…
Reference in a new issue