2
0

⬆️ Upgrade sentry and improve its reliability

This commit is contained in:
Baptiste Arnaud
2023-10-07 12:03:42 +02:00
parent 15823df6bd
commit 3e7b9b3afd
23 changed files with 1931 additions and 1726 deletions

View File

@ -54,20 +54,32 @@ const nextConfig = {
}, },
} }
const sentryWebpackPluginOptions = { export default withSentryConfig(
silent: true, nextConfig,
release: process.env.NEXT_PUBLIC_VERCEL_GIT_COMMIT_SHA + '-builder', {
} // For all available options, see:
// https://github.com/getsentry/sentry-webpack-plugin#options
export default process.env.NEXT_PUBLIC_SENTRY_DSN // Suppresses source map uploading logs during build
? withSentryConfig( silent: true,
{ release: process.env.NEXT_PUBLIC_VERCEL_GIT_COMMIT_SHA + '-builder',
...nextConfig, org: process.env.SENTRY_ORG,
sentry: { project: process.env.SENTRY_PROJECT,
hideSourceMaps: true, },
widenClientFileUpload: true, {
}, // For all available options, see:
}, // https://docs.sentry.io/platforms/javascript/guides/nextjs/manual-setup/
sentryWebpackPluginOptions
) // Upload a larger set of source maps for prettier stack traces (increases build time)
: nextConfig widenClientFileUpload: true,
// Routes browser requests to Sentry through a Next.js rewrite to circumvent ad-blockers (increases server load)
tunnelRoute: '/monitoring',
// Hides source maps from generated client bundles
hideSourceMaps: true,
// Automatically tree-shake Sentry logger statements to reduce bundle size
disableLogger: true,
}
)

View File

@ -26,13 +26,13 @@
"@giphy/react-components": "7.1.0", "@giphy/react-components": "7.1.0",
"@googleapis/drive": "8.0.0", "@googleapis/drive": "8.0.0",
"@paralleldrive/cuid2": "2.2.1", "@paralleldrive/cuid2": "2.2.1",
"@sentry/nextjs": "7.66.0", "@sentry/nextjs": "7.73.0",
"@tanstack/react-query": "^4.29.19", "@tanstack/react-query": "^4.29.19",
"@tanstack/react-table": "8.9.3", "@tanstack/react-table": "8.9.3",
"@trpc/client": "10.34.0", "@trpc/client": "10.40.0",
"@trpc/next": "10.34.0", "@trpc/next": "10.40.0",
"@trpc/react-query": "10.34.0", "@trpc/react-query": "10.40.0",
"@trpc/server": "10.34.0", "@trpc/server": "10.40.0",
"@typebot.io/bot-engine": "workspace:*", "@typebot.io/bot-engine": "workspace:*",
"@typebot.io/emails": "workspace:*", "@typebot.io/emails": "workspace:*",
"@typebot.io/env": "workspace:*", "@typebot.io/env": "workspace:*",

View File

@ -1,6 +1,12 @@
import * as Sentry from '@sentry/nextjs' import * as Sentry from '@sentry/nextjs'
import prisma from '@typebot.io/lib/prisma'
Sentry.init({ Sentry.init({
dsn: process.env.NEXT_PUBLIC_SENTRY_DSN, dsn: process.env.NEXT_PUBLIC_SENTRY_DSN,
release: process.env.NEXT_PUBLIC_VERCEL_GIT_COMMIT_SHA + '-builder', release: process.env.NEXT_PUBLIC_VERCEL_GIT_COMMIT_SHA + '-builder',
integrations: [
new Sentry.Integrations.Prisma({
client: prisma,
}),
],
}) })

View File

@ -1,6 +1,6 @@
import prisma from '@typebot.io/lib/prisma' import prisma from '@typebot.io/lib/prisma'
import { authOptions } from '@/pages/api/auth/[...nextauth]' import { authOptions } from '@/pages/api/auth/[...nextauth]'
import { setUser } from '@sentry/nextjs' import * as Sentry from '@sentry/nextjs'
import { User } from '@typebot.io/prisma' import { User } from '@typebot.io/prisma'
import { NextApiRequest, NextApiResponse } from 'next' import { NextApiRequest, NextApiResponse } from 'next'
import { getServerSession } from 'next-auth' import { getServerSession } from 'next-auth'
@ -19,7 +19,7 @@ export const getAuthenticatedUser = async (
| User | User
| undefined) | undefined)
if (!user || !('id' in user)) return if (!user || !('id' in user)) return
setUser({ id: user.id }) Sentry.setUser({ id: user.id })
return user return user
} }
@ -30,7 +30,7 @@ const authenticateByToken = async (
const user = (await prisma.user.findFirst({ const user = (await prisma.user.findFirst({
where: { apiTokens: { some: { token: apiToken } } }, where: { apiTokens: { some: { token: apiToken } } },
})) as User })) as User
setUser({ id: user.id }) Sentry.setUser({ id: user.id })
return user return user
} }

View File

@ -2,11 +2,18 @@ import { TRPCError, initTRPC } from '@trpc/server'
import { Context } from './context' import { Context } from './context'
import { OpenApiMeta } from 'trpc-openapi' import { OpenApiMeta } from 'trpc-openapi'
import superjson from 'superjson' import superjson from 'superjson'
import * as Sentry from '@sentry/nextjs'
const t = initTRPC.context<Context>().meta<OpenApiMeta>().create({ const t = initTRPC.context<Context>().meta<OpenApiMeta>().create({
transformer: superjson, transformer: superjson,
}) })
const sentryMiddleware = t.middleware(
Sentry.Handlers.trpcMiddleware({
attachRpcInput: true,
})
)
const isAuthed = t.middleware(({ next, ctx }) => { const isAuthed = t.middleware(({ next, ctx }) => {
if (!ctx.user?.id) { if (!ctx.user?.id) {
throw new TRPCError({ throw new TRPCError({
@ -20,10 +27,12 @@ const isAuthed = t.middleware(({ next, ctx }) => {
}) })
}) })
const finalMiddleware = sentryMiddleware.unstable_pipe(isAuthed)
export const middleware = t.middleware export const middleware = t.middleware
export const router = t.router export const router = t.router
export const publicProcedure = t.procedure export const publicProcedure = t.procedure.use(sentryMiddleware)
export const authenticatedProcedure = t.procedure.use(isAuthed) export const authenticatedProcedure = t.procedure.use(finalMiddleware)

View File

@ -18,6 +18,7 @@ import { Ratelimit } from '@upstash/ratelimit'
import { Redis } from '@upstash/redis/nodejs' import { Redis } from '@upstash/redis/nodejs'
import got from 'got' import got from 'got'
import { env } from '@typebot.io/env' import { env } from '@typebot.io/env'
import * as Sentry from '@sentry/nextjs'
const providers: Provider[] = [] const providers: Provider[] = []
@ -134,6 +135,14 @@ export const authOptions: AuthOptions = {
signIn: '/signin', signIn: '/signin',
newUser: env.NEXT_PUBLIC_ONBOARDING_TYPEBOT_ID ? '/onboarding' : undefined, newUser: env.NEXT_PUBLIC_ONBOARDING_TYPEBOT_ID ? '/onboarding' : undefined,
}, },
events: {
signIn({ user }) {
Sentry.setUser({ id: user.id })
},
signOut() {
Sentry.setUser(null)
},
},
callbacks: { callbacks: {
session: async ({ session, user }) => { session: async ({ session, user }) => {
const userFromDb = user as User const userFromDb = user as User

View File

@ -1,6 +1,6 @@
import { createContext } from '@/helpers/server/context' import { createContext } from '@/helpers/server/context'
import { trpcRouter } from '@/helpers/server/routers/v1/trpcRouter' import { trpcRouter } from '@/helpers/server/routers/v1/trpcRouter'
import { captureException } from '@sentry/nextjs' import * as Sentry from '@sentry/nextjs'
import { createNextApiHandler } from '@trpc/server/adapters/next' import { createNextApiHandler } from '@trpc/server/adapters/next'
export default createNextApiHandler({ export default createNextApiHandler({
@ -8,7 +8,7 @@ export default createNextApiHandler({
createContext, createContext,
onError({ error }) { onError({ error }) {
if (error.code === 'INTERNAL_SERVER_ERROR') { if (error.code === 'INTERNAL_SERVER_ERROR') {
captureException(error) Sentry.captureException(error)
console.error('Something went wrong', error) console.error('Something went wrong', error)
} }
return error return error

View File

@ -1,6 +1,6 @@
import { createContext } from '@/helpers/server/context' import { createContext } from '@/helpers/server/context'
import { trpcRouter } from '@/helpers/server/routers/v1/trpcRouter' import { trpcRouter } from '@/helpers/server/routers/v1/trpcRouter'
import { captureException } from '@sentry/nextjs' import * as Sentry from '@sentry/nextjs'
import { NextApiRequest, NextApiResponse } from 'next' import { NextApiRequest, NextApiResponse } from 'next'
import { createOpenApiNextHandler } from 'trpc-openapi' import { createOpenApiNextHandler } from 'trpc-openapi'
import cors from 'nextjs-cors' import cors from 'nextjs-cors'
@ -15,7 +15,7 @@ const handler = async (req: NextApiRequest, res: NextApiResponse) => {
createContext, createContext,
onError({ error }) { onError({ error }) {
if (error.code === 'INTERNAL_SERVER_ERROR') { if (error.code === 'INTERNAL_SERVER_ERROR') {
captureException(error) Sentry.captureException(error)
console.error('Something went wrong', error) console.error('Something went wrong', error)
} }
}, },

View File

@ -134,20 +134,32 @@ const nextConfig = {
}, },
} }
const sentryWebpackPluginOptions = { export default withSentryConfig(
silent: true, nextConfig,
release: process.env.NEXT_PUBLIC_VERCEL_GIT_COMMIT_SHA + '-viewer', {
} // For all available options, see:
// https://github.com/getsentry/sentry-webpack-plugin#options
export default process.env.NEXT_PUBLIC_SENTRY_DSN // Suppresses source map uploading logs during build
? withSentryConfig( silent: true,
{ release: process.env.NEXT_PUBLIC_VERCEL_GIT_COMMIT_SHA + '-viewer',
...nextConfig, org: process.env.SENTRY_ORG,
sentry: { project: process.env.SENTRY_PROJECT,
hideSourceMaps: true, },
widenClientFileUpload: true, {
}, // For all available options, see:
}, // https://docs.sentry.io/platforms/javascript/guides/nextjs/manual-setup/
sentryWebpackPluginOptions
) // Upload a larger set of source maps for prettier stack traces (increases build time)
: nextConfig widenClientFileUpload: true,
// Routes browser requests to Sentry through a Next.js rewrite to circumvent ad-blockers (increases server load)
tunnelRoute: '/monitoring',
// Hides source maps from generated client bundles
hideSourceMaps: true,
// Automatically tree-shake Sentry logger statements to reduce bundle size
disableLogger: true,
}
)

View File

@ -12,8 +12,8 @@
}, },
"dependencies": { "dependencies": {
"@planetscale/database": "^1.8.0", "@planetscale/database": "^1.8.0",
"@sentry/nextjs": "7.66.0", "@sentry/nextjs": "7.73.0",
"@trpc/server": "10.34.0", "@trpc/server": "10.40.0",
"@typebot.io/bot-engine": "workspace:*", "@typebot.io/bot-engine": "workspace:*",
"@typebot.io/nextjs": "workspace:*", "@typebot.io/nextjs": "workspace:*",
"@typebot.io/prisma": "workspace:*", "@typebot.io/prisma": "workspace:*",

View File

@ -1,6 +1,12 @@
import * as Sentry from '@sentry/nextjs' import * as Sentry from '@sentry/nextjs'
import prisma from '@typebot.io/lib/prisma'
Sentry.init({ Sentry.init({
dsn: process.env.NEXT_PUBLIC_SENTRY_DSN, dsn: process.env.NEXT_PUBLIC_SENTRY_DSN,
release: process.env.NEXT_PUBLIC_VERCEL_GIT_COMMIT_SHA + '-viewer', release: process.env.NEXT_PUBLIC_VERCEL_GIT_COMMIT_SHA + '-viewer',
integrations: [
new Sentry.Integrations.Prisma({
client: prisma,
}),
],
}) })

View File

@ -2,11 +2,18 @@ import { initTRPC } from '@trpc/server'
import { OpenApiMeta } from 'trpc-openapi' import { OpenApiMeta } from 'trpc-openapi'
import superjson from 'superjson' import superjson from 'superjson'
import { Context } from './context' import { Context } from './context'
import * as Sentry from '@sentry/nextjs'
const t = initTRPC.context<Context>().meta<OpenApiMeta>().create({ const t = initTRPC.context<Context>().meta<OpenApiMeta>().create({
transformer: superjson, transformer: superjson,
}) })
const sentryMiddleware = t.middleware(
Sentry.Handlers.trpcMiddleware({
attachRpcInput: true,
})
)
const injectUser = t.middleware(({ next, ctx }) => { const injectUser = t.middleware(({ next, ctx }) => {
return next({ return next({
ctx: { ctx: {
@ -15,8 +22,10 @@ const injectUser = t.middleware(({ next, ctx }) => {
}) })
}) })
const finalMiddleware = sentryMiddleware.unstable_pipe(injectUser)
export const middleware = t.middleware export const middleware = t.middleware
export const router = t.router export const router = t.router
export const publicProcedure = t.procedure.use(injectUser) export const publicProcedure = t.procedure.use(finalMiddleware)

View File

@ -1,5 +1,5 @@
import { appRouter } from '@/helpers/server/routers/appRouterV1' import { appRouter } from '@/helpers/server/routers/appRouterV1'
import { captureException } from '@sentry/nextjs' import * as Sentry from '@sentry/nextjs'
import { createOpenApiNextHandler } from 'trpc-openapi' import { createOpenApiNextHandler } from 'trpc-openapi'
import cors from 'nextjs-cors' import cors from 'nextjs-cors'
import { NextApiRequest, NextApiResponse } from 'next' import { NextApiRequest, NextApiResponse } from 'next'
@ -13,7 +13,7 @@ const handler = async (req: NextApiRequest, res: NextApiResponse) => {
createContext, createContext,
onError({ error }) { onError({ error }) {
if (error.code === 'INTERNAL_SERVER_ERROR') { if (error.code === 'INTERNAL_SERVER_ERROR') {
captureException(error) Sentry.captureException(error)
console.error('Something went wrong', error) console.error('Something went wrong', error)
} }
}, },

View File

@ -1,5 +1,5 @@
import { appRouter } from '@/helpers/server/routers/appRouterV2' import { appRouter } from '@/helpers/server/routers/appRouterV2'
import { captureException } from '@sentry/nextjs' import * as Sentry from '@sentry/nextjs'
import { createOpenApiNextHandler } from 'trpc-openapi' import { createOpenApiNextHandler } from 'trpc-openapi'
import cors from 'nextjs-cors' import cors from 'nextjs-cors'
import { NextApiRequest, NextApiResponse } from 'next' import { NextApiRequest, NextApiResponse } from 'next'
@ -13,7 +13,7 @@ const handler = async (req: NextApiRequest, res: NextApiResponse) => {
createContext, createContext,
onError({ error }) { onError({ error }) {
if (error.code === 'INTERNAL_SERVER_ERROR') { if (error.code === 'INTERNAL_SERVER_ERROR') {
captureException(error) Sentry.captureException(error)
console.error('Something went wrong', error) console.error('Something went wrong', error)
} }
}, },

View File

@ -3,9 +3,7 @@
"compilerOptions": { "compilerOptions": {
"baseUrl": ".", "baseUrl": ".",
"paths": { "paths": {
"@/*": [ "@/*": ["src/*"]
"src/*"
]
}, },
"plugins": [ "plugins": [
{ {
@ -14,10 +12,5 @@
], ],
"strictNullChecks": true "strictNullChecks": true
}, },
"include": [ "include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", ".next/types/**/*.ts"]
"next-env.d.ts",
"**/*.ts",
"**/*.tsx",
".next/types/**/*.ts"
]
} }

View File

@ -8,8 +8,8 @@
"dependencies": { "dependencies": {
"@paralleldrive/cuid2": "2.2.1", "@paralleldrive/cuid2": "2.2.1",
"@planetscale/database": "^1.8.0", "@planetscale/database": "^1.8.0",
"@sentry/nextjs": "7.66.0", "@sentry/nextjs": "7.73.0",
"@trpc/server": "10.34.0", "@trpc/server": "10.40.0",
"@typebot.io/emails": "workspace:*", "@typebot.io/emails": "workspace:*",
"@typebot.io/env": "workspace:*", "@typebot.io/env": "workspace:*",
"@typebot.io/lib": "workspace:*", "@typebot.io/lib": "workspace:*",

View File

@ -10,7 +10,7 @@ import {
} from '@typebot.io/schemas/features/whatsapp' } from '@typebot.io/schemas/features/whatsapp'
import { convertMessageToWhatsAppMessage } from './convertMessageToWhatsAppMessage' import { convertMessageToWhatsAppMessage } from './convertMessageToWhatsAppMessage'
import { sendWhatsAppMessage } from './sendWhatsAppMessage' import { sendWhatsAppMessage } from './sendWhatsAppMessage'
import { captureException } from '@sentry/nextjs' import * as Sentry from '@sentry/nextjs'
import { HTTPError } from 'got' import { HTTPError } from 'got'
import { convertInputToWhatsAppMessages } from './convertInputToWhatsAppMessage' import { convertInputToWhatsAppMessages } from './convertInputToWhatsAppMessage'
import { isNotDefined } from '@typebot.io/lib/utils' import { isNotDefined } from '@typebot.io/lib/utils'
@ -108,7 +108,7 @@ export const sendChatReplyToWhatsApp = async ({
}) })
} }
} catch (err) { } catch (err) {
captureException(err, { extra: { message } }) Sentry.captureException(err, { extra: { message } })
console.log('Failed to send message:', JSON.stringify(message, null, 2)) console.log('Failed to send message:', JSON.stringify(message, null, 2))
if (err instanceof HTTPError) if (err instanceof HTTPError)
console.log('HTTPError', err.response.statusCode, err.response.body) console.log('HTTPError', err.response.statusCode, err.response.body)
@ -139,7 +139,7 @@ export const sendChatReplyToWhatsApp = async ({
credentials, credentials,
}) })
} catch (err) { } catch (err) {
captureException(err, { extra: { message } }) Sentry.captureException(err, { extra: { message } })
console.log('Failed to send message:', JSON.stringify(message, null, 2)) console.log('Failed to send message:', JSON.stringify(message, null, 2))
if (err instanceof HTTPError) if (err instanceof HTTPError)
console.log('HTTPError', err.response.statusCode, err.response.body) console.log('HTTPError', err.response.statusCode, err.response.body)
@ -209,7 +209,7 @@ const executeClientSideAction =
credentials: context.credentials, credentials: context.credentials,
}) })
} catch (err) { } catch (err) {
captureException(err, { extra: { message } }) Sentry.captureException(err, { extra: { message } })
console.log('Failed to send message:', JSON.stringify(message, null, 2)) console.log('Failed to send message:', JSON.stringify(message, null, 2))
if (err instanceof HTTPError) if (err instanceof HTTPError)
console.log('HTTPError', err.response.statusCode, err.response.body) console.log('HTTPError', err.response.statusCode, err.response.body)

View File

@ -58,7 +58,8 @@ export const startWhatsAppSession = async ({
const publicTypebotWithMatchedCondition = botsWithWhatsAppEnabled.find( const publicTypebotWithMatchedCondition = botsWithWhatsAppEnabled.find(
(publicTypebot) => (publicTypebot) =>
publicTypebot.settings.whatsApp?.startCondition && (publicTypebot.settings.whatsApp?.startCondition?.comparisons.length ??
0) > 0 &&
messageMatchStartCondition( messageMatchStartCondition(
incomingMessage ?? '', incomingMessage ?? '',
publicTypebot.settings.whatsApp?.startCondition publicTypebot.settings.whatsApp?.startCondition

View File

@ -22,8 +22,8 @@
"nodemailer": "6.7.8" "nodemailer": "6.7.8"
}, },
"dependencies": { "dependencies": {
"@sentry/nextjs": "7.66.0", "@sentry/nextjs": "7.73.0",
"@trpc/server": "10.34.0", "@trpc/server": "10.40.0",
"@udecode/plate-common": "^21.1.5", "@udecode/plate-common": "^21.1.5",
"got": "12.6.0", "got": "12.6.0",
"minio": "7.1.3", "minio": "7.1.3",

3458
pnpm-lock.yaml generated

File diff suppressed because it is too large Load Diff