import { ApolloServer } from '@apollo/server' import { startServerAndCreateNextHandler } from '@as-integrations/next' import resolvers from '@/api/resolvers' import models from '@/api/models' import lnd from '@/api/lnd' import typeDefs from '@/api/typeDefs' import { getServerSession } from 'next-auth/next' import { getAuthOptions } from './auth/[...nextauth]' import search from '@/api/search' import { ApolloServerPluginLandingPageLocalDefault, ApolloServerPluginLandingPageProductionDefault } from '@apollo/server/plugin/landingPage/default' const apolloServer = new ApolloServer({ typeDefs, resolvers, introspection: true, allowBatchedHttpRequests: true, plugins: [{ requestDidStart (initialRequestContext) { return { executionDidStart () { return { willResolveField ({ source, args, context, info }) { const start = process.hrtime.bigint() return (error, result) => { const end = process.hrtime.bigint() const ms = (end - start) / 1000000n if (process.env.GRAPHQL_SLOW_LOGS_MS && ms > process.env.GRAPHQL_SLOW_LOGS_MS) { console.log(`Field ${info.parentType.name}.${info.fieldName} took ${ms}ms`) } if (error) { console.log(`Field ${info.parentType.name}.${info.fieldName} failed with ${error}`) } } }, async executionDidEnd (err) { if (err) { console.error('hey bud', err) } } } } } } }, process.env.NODE_ENV === 'production' ? ApolloServerPluginLandingPageProductionDefault( { embed: { endpointIsEditable: false, persistExplorerState: true, displayOptions: { theme: 'dark' } }, footer: false }) : ApolloServerPluginLandingPageLocalDefault( { embed: { endpointIsEditable: false, persistExplorerState: true, displayOptions: { theme: 'dark' } }, footer: false })] }) export default startServerAndCreateNextHandler(apolloServer, { context: async (req, res) => { const apiKey = req.headers['x-api-key'] let session if (apiKey) { const [user] = await models.$queryRaw` SELECT id, name, "apiKeyEnabled" FROM users WHERE "apiKeyHash" = encode(digest(${apiKey}, 'sha256'), 'hex') LIMIT 1` if (user?.apiKeyEnabled) { const { apiKeyEnabled, ...sessionFields } = user session = { user: { ...sessionFields, apiKey: true } } } } else { req = multiAuthMiddleware(req) session = await getServerSession(req, res, getAuthOptions(req)) } return { models, headers: req.headers, lnd, me: session ? session.user : null, search } } }) function multiAuthMiddleware (request) { // switch next-auth session cookie with multi_auth cookie if cookie pointer present // is there a cookie pointer? const cookiePointerName = 'multi_auth.user-id' const hasCookiePointer = !!request.cookies[cookiePointerName] const secure = process.env.NODE_ENV === 'production' // is there a session? const sessionCookieName = secure ? '__Secure-next-auth.session-token' : 'next-auth.session-token' const hasSession = !!request.cookies[sessionCookieName] if (!hasCookiePointer || !hasSession) { // no session or no cookie pointer. do nothing. return request } const userId = request.cookies[cookiePointerName] if (userId === 'anonymous') { // user switched to anon. only delete session cookie. delete request.cookies[sessionCookieName] return request } const userJWT = request.cookies[`multi_auth.${userId}`] if (!userJWT) { // no JWT for account switching found return request } if (userJWT) { // use JWT found in cookie pointed to by cookie pointer request.cookies[sessionCookieName] = userJWT return request } return request }