2
0

build: 🏗️ Add Sentry to builder

This commit is contained in:
Baptiste Arnaud
2022-02-14 10:57:57 +01:00
parent 5a060c7f7e
commit 8501d39234
31 changed files with 474 additions and 52 deletions

View File

@ -44,3 +44,6 @@ STRIPE_WEBHOOK_SECRET=
NEXT_PUBLIC_GIPHY_API_KEY=
NEXT_PUBLIC_VIEWER_HOST=http://localhost:3001
# (Optional) Error tracking with Sentry
NEXT_PUBLIC_SENTRY_DSN=

View File

@ -1,4 +1,4 @@
import { OrderedList, ListItem, Tag, Text, Stack } from '@chakra-ui/react'
import { OrderedList, ListItem, Tag } from '@chakra-ui/react'
import { ChatEmbedCode } from 'components/share/codeSnippets/Chat/EmbedCode'
import { ChatEmbedSettings } from 'components/share/codeSnippets/Chat/EmbedSettings'
import { ContainerEmbedCode } from 'components/share/codeSnippets/Container/EmbedCode'

View File

@ -0,0 +1,14 @@
// eslint-disable-next-line @typescript-eslint/no-var-requires
const { withSentryConfig } = require('@sentry/nextjs')
const moduleExports = {
// Your existing module.exports
}
const sentryWebpackPluginOptions = {
silent: true,
// For all available options, see:
// https://github.com/getsentry/sentry-webpack-plugin#options.
}
module.exports = withSentryConfig(moduleExports, sentryWebpackPluginOptions)

View File

@ -29,6 +29,7 @@
"@giphy/react-components": "^5.4.0",
"@googleapis/drive": "^2.1.0",
"@next-auth/prisma-adapter": "1.0.1",
"@sentry/nextjs": "^6.17.7",
"@stripe/stripe-js": "^1.22.0",
"@udecode/plate-basic-marks": "^10.0.0",
"@udecode/plate-common": "^7.0.2",
@ -99,9 +100,9 @@
"eslint-config-prettier": "^8.3.0",
"eslint-plugin-cypress": "^2.12.1",
"eslint-plugin-prettier": "^4.0.0",
"firebase-admin": "^10.0.2",
"next-transpile-modules": "^9.0.0",
"prettier": "^2.5.1",
"firebase-admin": "^10.0.2",
"typescript": "^4.5.5"
}
}

View File

@ -0,0 +1,65 @@
import NextErrorComponent from 'next/error'
import * as Sentry from '@sentry/nextjs'
const MyError = ({ statusCode, hasGetInitialPropsRun, err }) => {
if (!hasGetInitialPropsRun && err) {
// getInitialProps is not called in case of
// https://github.com/vercel/next.js/issues/8592. As a workaround, we pass
// err via _app.js so it can be captured
Sentry.captureException(err)
// Flushing is not required in this case as it only happens on the client
}
return <NextErrorComponent statusCode={statusCode} />
}
MyError.getInitialProps = async (context) => {
const errorInitialProps = await NextErrorComponent.getInitialProps(context)
const { res, err, asPath } = context
// Workaround for https://github.com/vercel/next.js/issues/8592, mark when
// getInitialProps has run
errorInitialProps.hasGetInitialPropsRun = true
// Returning early because we don't want to log 404 errors to Sentry.
if (res?.statusCode === 404) {
return errorInitialProps
}
// Running on the server, the response object (`res`) is available.
//
// Next.js will pass an err on the server if a page's data fetching methods
// threw or returned a Promise that rejected
//
// Running on the client (browser), Next.js will provide an err if:
//
// - a page's `getInitialProps` threw or returned a Promise that rejected
// - an exception was thrown somewhere in the React lifecycle (render,
// componentDidMount, etc) that was caught by Next.js's React Error
// Boundary. Read more about what types of exceptions are caught by Error
// Boundaries: https://reactjs.org/docs/error-boundaries.html
if (err) {
Sentry.captureException(err)
// Flushing before returning is necessary if deploying to Vercel, see
// https://vercel.com/docs/platform/limits#streaming-responses
await Sentry.flush(2000)
return errorInitialProps
}
// If this point is reached, getInitialProps was called without any
// information about what the error might be. This is unexpected and may
// indicate a bug introduced in Next.js, so record it in Sentry
Sentry.captureException(
new Error(`_error.js getInitialProps missing data at path: ${asPath}`)
)
await Sentry.flush(2000)
return errorInitialProps
}
export default MyError

View File

@ -1,3 +1,4 @@
import { withSentry } from '@sentry/nextjs'
import { Prisma, User } from 'db'
import prisma from 'libs/prisma'
import { NextApiRequest, NextApiResponse } from 'next'
@ -28,4 +29,4 @@ const handler = async (req: NextApiRequest, res: NextApiResponse) => {
}
}
export default handler
export default withSentry(handler)

View File

@ -7,6 +7,7 @@ import { stringify } from 'querystring'
import { CredentialsType } from 'models'
import { encrypt } from 'utils'
import { oauth2Client } from 'libs/google-sheets'
import { withSentry } from '@sentry/nextjs'
const handler = async (req: NextApiRequest, res: NextApiResponse) => {
const session = await getSession({ req })
@ -57,10 +58,10 @@ const handler = async (req: NextApiRequest, res: NextApiResponse) => {
},
})
const queryParams = stringify({ stepId, credentialsId })
return res.redirect(
res.redirect(
`${redirectUrl}?${queryParams}` ?? `${process.env.NEXTAUTH_URL}`
)
}
}
export default handler
export default withSentry(handler)

View File

@ -1,3 +1,4 @@
import { withSentry } from '@sentry/nextjs'
import { oauth2Client } from 'libs/google-sheets'
import { NextApiRequest, NextApiResponse } from 'next'
@ -15,8 +16,8 @@ const handler = (req: NextApiRequest, res: NextApiResponse) => {
prompt: 'consent',
state: Buffer.from(JSON.stringify(req.query)).toString('base64'),
})
return res.status(301).redirect(url)
res.status(301).redirect(url)
}
}
export default handler
export default withSentry(handler)

View File

@ -1,3 +1,4 @@
import { withSentry } from '@sentry/nextjs'
import { DashboardFolder, User } from 'db'
import prisma from 'libs/prisma'
import { NextApiRequest, NextApiResponse } from 'next'
@ -34,4 +35,4 @@ const handler = async (req: NextApiRequest, res: NextApiResponse) => {
return methodNotAllowed(res)
}
export default handler
export default withSentry(handler)

View File

@ -1,3 +1,4 @@
import { withSentry } from '@sentry/nextjs'
import { DashboardFolder } from 'db'
import prisma from 'libs/prisma'
import { NextApiRequest, NextApiResponse } from 'next'
@ -34,4 +35,4 @@ const handler = async (req: NextApiRequest, res: NextApiResponse) => {
return methodNotAllowed(res)
}
export default handler
export default withSentry(handler)

View File

@ -4,6 +4,7 @@ import { getAuthenticatedGoogleClient } from 'libs/google-sheets'
import { methodNotAllowed } from 'utils'
import { getSession } from 'next-auth/react'
import { User } from 'db'
import { withSentry } from '@sentry/nextjs'
const handler = async (req: NextApiRequest, res: NextApiResponse) => {
const session = await getSession({ req })
@ -27,4 +28,4 @@ const handler = async (req: NextApiRequest, res: NextApiResponse) => {
return methodNotAllowed(res)
}
export default handler
export default withSentry(handler)

View File

@ -4,6 +4,7 @@ import { getAuthenticatedGoogleClient } from 'libs/google-sheets'
import { methodNotAllowed } from 'utils'
import { getSession } from 'next-auth/react'
import { User } from 'db'
import { withSentry } from '@sentry/nextjs'
const handler = async (req: NextApiRequest, res: NextApiResponse) => {
const session = await getSession({ req })
@ -38,4 +39,4 @@ const handler = async (req: NextApiRequest, res: NextApiResponse) => {
return methodNotAllowed(res)
}
export default handler
export default withSentry(handler)

View File

@ -1,3 +1,4 @@
import { withSentry } from '@sentry/nextjs'
import { NextApiRequest, NextApiResponse } from 'next'
import { methodNotAllowed } from 'utils'
@ -23,4 +24,4 @@ const handler = (req: NextApiRequest, res: NextApiResponse) => {
return methodNotAllowed(res)
}
export default handler
export default withSentry(handler)

View File

@ -1,3 +1,4 @@
import { withSentry } from '@sentry/nextjs'
import prisma from 'libs/prisma'
import { NextApiRequest, NextApiResponse } from 'next'
import { getSession } from 'next-auth/react'
@ -27,4 +28,4 @@ const handler = async (req: NextApiRequest, res: NextApiResponse) => {
}
}
export default handler
export default withSentry(handler)

View File

@ -1,3 +1,4 @@
import { withSentry } from '@sentry/nextjs'
import prisma from 'libs/prisma'
import { NextApiRequest, NextApiResponse } from 'next'
import { getSession } from 'next-auth/react'
@ -21,4 +22,4 @@ const handler = async (req: NextApiRequest, res: NextApiResponse) => {
return methodNotAllowed(res)
}
export default handler
export default withSentry(handler)

View File

@ -1,3 +1,4 @@
import { withSentry } from '@sentry/nextjs'
import aws from 'aws-sdk'
import { NextApiRequest, NextApiResponse } from 'next'
import { getSession } from 'next-auth/react'
@ -39,4 +40,4 @@ const handler = async (
return methodNotAllowed(res)
}
export default handler
export default withSentry(handler)

View File

@ -1,12 +1,10 @@
import { NextApiRequest, NextApiResponse } from 'next'
import { methodNotAllowed } from 'utils'
import Stripe from 'stripe'
import { withSentry } from '@sentry/nextjs'
const usdPriceIdTest = 'price_1Jc4TQKexUFvKTWyGvsH4Ff5'
const createCheckoutSession = async (
req: NextApiRequest,
res: NextApiResponse
) => {
const handler = async (req: NextApiRequest, res: NextApiResponse) => {
if (req.method === 'POST') {
if (!process.env.STRIPE_SECRET_KEY)
throw Error('STRIPE_SECRET_KEY var is missing')
@ -32,4 +30,4 @@ const createCheckoutSession = async (
return methodNotAllowed(res)
}
export default createCheckoutSession
export default withSentry(handler)

View File

@ -3,11 +3,9 @@ import { NextApiRequest, NextApiResponse } from 'next'
import { getSession } from 'next-auth/react'
import { methodNotAllowed } from 'utils'
import Stripe from 'stripe'
import { withSentry } from '@sentry/nextjs'
const createCheckoutSession = async (
req: NextApiRequest,
res: NextApiResponse
) => {
const handler = async (req: NextApiRequest, res: NextApiResponse) => {
const session = await getSession({ req })
if (!session?.user)
return res.status(401).json({ message: 'Not authenticated' })
@ -29,4 +27,4 @@ const createCheckoutSession = async (
return methodNotAllowed(res)
}
export default createCheckoutSession
export default withSentry(handler)

View File

@ -5,6 +5,7 @@ import Cors from 'micro-cors'
import { buffer } from 'micro'
import prisma from 'libs/prisma'
import { Plan } from 'db'
import { withSentry } from '@sentry/nextjs'
if (!process.env.STRIPE_SECRET_KEY || !process.env.STRIPE_WEBHOOK_SECRET)
throw new Error('STRIPE_SECRET_KEY or STRIPE_WEBHOOK_SECRET missing')
@ -70,4 +71,4 @@ const webhookHandler = async (req: NextApiRequest, res: NextApiResponse) => {
}
// eslint-disable-next-line @typescript-eslint/no-explicit-any
export default cors(webhookHandler as any)
export default withSentry(cors(webhookHandler as any))

View File

@ -1,3 +1,4 @@
import { withSentry } from '@sentry/nextjs'
import { Prisma, User } from 'db'
import prisma from 'libs/prisma'
import { NextApiRequest, NextApiResponse } from 'next'
@ -46,4 +47,4 @@ const handler = async (req: NextApiRequest, res: NextApiResponse) => {
}
}
export default handler
export default withSentry(handler)

View File

@ -1,3 +1,4 @@
import { withSentry } from '@sentry/nextjs'
import prisma from 'libs/prisma'
import { NextApiRequest, NextApiResponse } from 'next'
import { getSession } from 'next-auth/react'
@ -50,4 +51,4 @@ const handler = async (req: NextApiRequest, res: NextApiResponse) => {
return methodNotAllowed(res)
}
export default handler
export default withSentry(handler)

View File

@ -5,6 +5,7 @@ import { NextApiRequest, NextApiResponse } from 'next'
import got, { Method, Headers, HTTPError } from 'got'
import { methodNotAllowed } from 'utils'
import { stringify } from 'qs'
import { withSentry } from '@sentry/nextjs'
const handler = async (req: NextApiRequest, res: NextApiResponse) => {
if (req.method === 'POST') {
@ -19,10 +20,9 @@ const handler = async (req: NextApiRequest, res: NextApiResponse) => {
stepIndex
]
if (!('webhook' in step))
return {
statusCode: 400,
data: { message: `Couldn't find webhook` },
}
return res
.status(404)
.send({ statusCode: 404, data: { message: `Couldn't find webhook` } })
const result = await executeWebhook(step.webhook, variables)
return res.status(200).send(result)
}
@ -101,4 +101,4 @@ const convertKeyValueTableToObject = (
}, {})
}
export default handler
export default withSentry(handler)

View File

@ -1,3 +1,4 @@
import { withSentry } from '@sentry/nextjs'
import { User } from 'db'
import prisma from 'libs/prisma'
import { NextApiRequest, NextApiResponse } from 'next'
@ -48,4 +49,4 @@ const handler = async (req: NextApiRequest, res: NextApiResponse) => {
return methodNotAllowed(res)
}
export default handler
export default withSentry(handler)

View File

@ -4,6 +4,7 @@ import prisma from 'libs/prisma'
import { NextApiRequest, NextApiResponse } from 'next'
import { getSession } from 'next-auth/react'
import { methodNotAllowed } from 'utils'
import { withSentry } from '@sentry/nextjs'
const handler = async (req: NextApiRequest, res: NextApiResponse) => {
const session = await getSession({ req })
@ -38,4 +39,4 @@ const handler = async (req: NextApiRequest, res: NextApiResponse) => {
return methodNotAllowed(res)
}
export default handler
export default withSentry(handler)

View File

@ -1,3 +1,4 @@
import { withSentry } from '@sentry/nextjs'
import { User } from 'db'
import prisma from 'libs/prisma'
import { Stats } from 'models'
@ -45,4 +46,4 @@ const handler = async (req: NextApiRequest, res: NextApiResponse) => {
return methodNotAllowed(res)
}
export default handler
export default withSentry(handler)

View File

@ -1,3 +1,4 @@
import { withSentry } from '@sentry/nextjs'
import prisma from 'libs/prisma'
import { NextApiRequest, NextApiResponse } from 'next'
import { getSession } from 'next-auth/react'
@ -21,4 +22,4 @@ const handler = async (req: NextApiRequest, res: NextApiResponse) => {
return methodNotAllowed(res)
}
export default handler
export default withSentry(handler)

View File

@ -1,3 +1,4 @@
import { withSentry } from '@sentry/nextjs'
import { Prisma, User } from 'db'
import prisma from 'libs/prisma'
import { Credentials } from 'models'
@ -37,4 +38,4 @@ const handler = async (req: NextApiRequest, res: NextApiResponse) => {
return methodNotAllowed(res)
}
export default handler
export default withSentry(handler)

View File

@ -0,0 +1,15 @@
// This file configures the initialization of Sentry on the browser.
// The config you add here will be used whenever a page is visited.
// https://docs.sentry.io/platforms/javascript/guides/nextjs/
import * as Sentry from '@sentry/nextjs'
Sentry.init({
dsn: process.env.NEXT_PUBLIC_SENTRY_DSN,
// Adjust this value in production, or use tracesSampler for greater control
tracesSampleRate: 1.0,
// ...
// Note: if you want to override the automatic release value, do not set a
// `release` value here - use the environment variable `SENTRY_RELEASE`, so
// that it will also get attached to your source maps
})

View File

@ -0,0 +1,15 @@
// This file configures the initialization of Sentry on the browser.
// The config you add here will be used whenever a page is visited.
// https://docs.sentry.io/platforms/javascript/guides/nextjs/
import * as Sentry from '@sentry/nextjs'
Sentry.init({
dsn: process.env.NEXT_PUBLIC_SENTRY_DSN,
// Adjust this value in production, or use tracesSampler for greater control
tracesSampleRate: 1.0,
// ...
// Note: if you want to override the automatic release value, do not set a
// `release` value here - use the environment variable `SENTRY_RELEASE`, so
// that it will also get attached to your source maps
})