Add sentry to template. Got a small error but we are gonna fix it soon!
This commit is contained in:
29
.env.example
29
.env.example
@ -1,11 +1,3 @@
|
|||||||
# Since the ".env" file is gitignored, you can use the ".env.example" file to
|
|
||||||
# build a new ".env" file when you clone the repo. Keep this file up-to-date
|
|
||||||
# when you add new variables to `.env`.
|
|
||||||
|
|
||||||
# This file will be committed to version control, so make sure not to have any
|
|
||||||
# secrets in it. If you are cloning this repo, create a copy of this file named
|
|
||||||
# ".env" and populate it with your secrets.
|
|
||||||
|
|
||||||
# When adding additional environment variables, the schema in "/src/env.js"
|
# When adding additional environment variables, the schema in "/src/env.js"
|
||||||
# should be updated accordingly.
|
# should be updated accordingly.
|
||||||
|
|
||||||
@ -13,14 +5,27 @@
|
|||||||
# SERVERVAR="foo"
|
# SERVERVAR="foo"
|
||||||
# NEXT_PUBLIC_CLIENTVAR="bar"
|
# NEXT_PUBLIC_CLIENTVAR="bar"
|
||||||
|
|
||||||
# Server Variables
|
### Server Variables ###
|
||||||
NODE_ENV=
|
# Next Variables # Default Values:
|
||||||
|
#NODE_ENV= # development
|
||||||
|
#SKIP_ENV_VALIDATION= # false
|
||||||
|
#NEXT_RUNTIME= # nodejs
|
||||||
|
# Sentry Variables # Default Values:
|
||||||
|
#SENTRY_URL= # https://sentry.gbrown.org
|
||||||
|
SENTRY_AUTH_TOKEN=
|
||||||
|
#CI= # true
|
||||||
|
|
||||||
# Client Variables
|
### Client Variables ###
|
||||||
|
# Next Variables # Default Values:
|
||||||
|
#NEXT_PUBLIC_SITE_URL= # http://localhost:3000
|
||||||
|
# Supabase Variables
|
||||||
NEXT_PUBLIC_SUPABASE_URL=
|
NEXT_PUBLIC_SUPABASE_URL=
|
||||||
NEXT_PUBLIC_SUPABASE_ANON_KEY=
|
NEXT_PUBLIC_SUPABASE_ANON_KEY=
|
||||||
|
# Sentry Variables
|
||||||
|
NEXT_PUBLIC_SENTRY_DSN=
|
||||||
|
|
||||||
# Script Variables # Default Values
|
### Script Variables ### These variables are only needed for our scripts, so do not add these to env.js! ###
|
||||||
|
# generateTypes # Default Values:
|
||||||
SUPABASE_DB_PASSWORD=
|
SUPABASE_DB_PASSWORD=
|
||||||
#SUPABASE_DB_PORT= # 5432
|
#SUPABASE_DB_PORT= # 5432
|
||||||
#SUPABASE_DB_USER= # postgres
|
#SUPABASE_DB_USER= # postgres
|
||||||
|
35
instrumentation-client.ts
Normal file
35
instrumentation-client.ts
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
// https://docs.sentry.io/platforms/javascript/guides/nextjs/manual-setup/
|
||||||
|
import * as Sentry from '@sentry/nextjs';
|
||||||
|
import './src/env.js';
|
||||||
|
|
||||||
|
Sentry.init({
|
||||||
|
dsn: process.env.NEXT_PUBLIC_SENTRY_DSN!,
|
||||||
|
|
||||||
|
// Adds request headers and IP for users, for more info visit:
|
||||||
|
// https://docs.sentry.io/platforms/javascript/guides/nextjs/configuration/options/#sendDefaultPii
|
||||||
|
sendDefaultPii: true,
|
||||||
|
|
||||||
|
// Set tracesSampleRate to 1.0 to capture 100%
|
||||||
|
// of transactions for tracing.
|
||||||
|
// We recommend adjusting this value in production
|
||||||
|
// Learn more at
|
||||||
|
// https://docs.sentry.io/platforms/javascript/configuration/options/#traces-sample-rate
|
||||||
|
tracesSampleRate: 1.0,
|
||||||
|
// Replay may only be enabled for the client-side
|
||||||
|
integrations: [Sentry.replayIntegration()],
|
||||||
|
|
||||||
|
// Capture Replay for 10% of all sessions,
|
||||||
|
// plus for 100% of sessions with an error
|
||||||
|
// Learn more at
|
||||||
|
// https://docs.sentry.io/platforms/javascript/session-replay/configuration/#general-integration-configuration
|
||||||
|
replaysSessionSampleRate: 0.1,
|
||||||
|
replaysOnErrorSampleRate: 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
|
||||||
|
});
|
||||||
|
|
||||||
|
// This export will instrument router navigations, and is only relevant if you enable tracing.
|
||||||
|
// `captureRouterTransitionStart` is available from SDK version 9.12.0 onwards
|
||||||
|
export const onRouterTransitionStart = Sentry.captureRouterTransitionStart;
|
@ -3,9 +3,18 @@
|
|||||||
* for Docker builds.
|
* for Docker builds.
|
||||||
*/
|
*/
|
||||||
import './src/env.js';
|
import './src/env.js';
|
||||||
|
import { withSentryConfig } from '@sentry/nextjs';
|
||||||
|
|
||||||
/** @type {import("next").NextConfig} */
|
/** @type {import("next").NextConfig} */
|
||||||
const config = {
|
const config = {
|
||||||
|
turbopack: {
|
||||||
|
rules: {
|
||||||
|
'*.svg': {
|
||||||
|
loaders: ['@svgr/webpack'],
|
||||||
|
as: '*.js',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
output: 'standalone',
|
output: 'standalone',
|
||||||
images: {
|
images: {
|
||||||
remotePatterns: [
|
remotePatterns: [
|
||||||
@ -22,4 +31,30 @@ const config = {
|
|||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
export default config;
|
const sentryConfig = {
|
||||||
|
// For all available options, see:
|
||||||
|
// https://www.npmjs.com/package/@sentry/webpack-plugin#options
|
||||||
|
org: 'gib',
|
||||||
|
project: 't3-supabase-template',
|
||||||
|
sentryUrl: process.env.SENTRY_URL,
|
||||||
|
authToken: process.env.SENTRY_AUTH_TOKEN,
|
||||||
|
// Only print logs for uploading source maps in CI
|
||||||
|
silent: !process.env.CI,
|
||||||
|
// For all available options, see:
|
||||||
|
// https://docs.sentry.io/platforms/javascript/guides/nextjs/manual-setup/
|
||||||
|
// Upload a larger set of source maps for prettier stack traces (increases build time)
|
||||||
|
widenClientFileUpload: true,
|
||||||
|
// Route browser requests to Sentry through a Next.js rewrite to circumvent ad-blockers.
|
||||||
|
// This can increase your server load as well as your hosting bill.
|
||||||
|
// Note: Check that the configured route will not match with your Next.js middleware, otherwise reporting of client-
|
||||||
|
// side errors will fail.
|
||||||
|
tunnelRoute: '/monitoring',
|
||||||
|
// Automatically tree-shake Sentry logger statements to reduce bundle size
|
||||||
|
disableLogger: true,
|
||||||
|
// Capture React Component Names
|
||||||
|
reactComponentAnnotation: {
|
||||||
|
enabled: true,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
export default withSentryConfig(config, sentryConfig);
|
||||||
|
@ -23,6 +23,7 @@
|
|||||||
"@radix-ui/react-label": "^2.1.7",
|
"@radix-ui/react-label": "^2.1.7",
|
||||||
"@radix-ui/react-separator": "^1.1.7",
|
"@radix-ui/react-separator": "^1.1.7",
|
||||||
"@radix-ui/react-slot": "^1.2.3",
|
"@radix-ui/react-slot": "^1.2.3",
|
||||||
|
"@sentry/nextjs": "^9.27.0",
|
||||||
"@supabase/ssr": "^0.6.1",
|
"@supabase/ssr": "^0.6.1",
|
||||||
"@supabase/supabase-js": "^2.50.0",
|
"@supabase/supabase-js": "^2.50.0",
|
||||||
"@t3-oss/env-nextjs": "^0.12.0",
|
"@t3-oss/env-nextjs": "^0.12.0",
|
||||||
@ -34,8 +35,9 @@
|
|||||||
"react": "^19.1.0",
|
"react": "^19.1.0",
|
||||||
"react-dom": "^19.1.0",
|
"react-dom": "^19.1.0",
|
||||||
"react-hook-form": "^7.57.0",
|
"react-hook-form": "^7.57.0",
|
||||||
|
"require-in-the-middle": "^7.5.2",
|
||||||
"sonner": "^2.0.5",
|
"sonner": "^2.0.5",
|
||||||
"zod": "^3.25.55"
|
"zod": "^3.25.56"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@eslint/eslintrc": "^3.3.1",
|
"@eslint/eslintrc": "^3.3.1",
|
||||||
|
2070
pnpm-lock.yaml
generated
2070
pnpm-lock.yaml
generated
File diff suppressed because it is too large
Load Diff
@ -1,4 +1,5 @@
|
|||||||
onlyBuiltDependencies:
|
onlyBuiltDependencies:
|
||||||
|
- '@sentry/cli'
|
||||||
- '@tailwindcss/oxide'
|
- '@tailwindcss/oxide'
|
||||||
- sharp
|
- sharp
|
||||||
- unrs-resolver
|
- unrs-resolver
|
||||||
|
23
sentry.edge.config.ts
Normal file
23
sentry.edge.config.ts
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
|
||||||
|
import * as Sentry from "@sentry/nextjs";
|
||||||
|
|
||||||
|
Sentry.init({
|
||||||
|
dsn: process.env.NEXT_PUBLIC_SENTRY_DSN!,
|
||||||
|
|
||||||
|
// Adds request headers and IP for users, for more info visit:
|
||||||
|
// https://docs.sentry.io/platforms/javascript/guides/nextjs/configuration/options/#sendDefaultPii
|
||||||
|
sendDefaultPii: true,
|
||||||
|
|
||||||
|
// Set tracesSampleRate to 1.0 to capture 100%
|
||||||
|
// of transactions for tracing.
|
||||||
|
// We recommend adjusting this value in production
|
||||||
|
// Learn more at
|
||||||
|
// https://docs.sentry.io/platforms/javascript/configuration/options/#traces-sample-rate
|
||||||
|
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
|
||||||
|
});
|
23
sentry.server.config.ts
Normal file
23
sentry.server.config.ts
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
// https://docs.sentry.io/platforms/javascript/guides/nextjs/manual-setup/
|
||||||
|
import * as Sentry from '@sentry/nextjs';
|
||||||
|
|
||||||
|
Sentry.init({
|
||||||
|
dsn: process.env.NEXT_PUBLIC_SENTRY_DSN!,
|
||||||
|
|
||||||
|
// Adds request headers and IP for users, for more info visit:
|
||||||
|
// https://docs.sentry.io/platforms/javascript/guides/nextjs/configuration/options/#sendDefaultPii
|
||||||
|
sendDefaultPii: true,
|
||||||
|
|
||||||
|
// Set tracesSampleRate to 1.0 to capture 100%
|
||||||
|
// of transactions for tracing.
|
||||||
|
// We recommend adjusting this value in production
|
||||||
|
// Learn more at
|
||||||
|
// https://docs.sentry.io/platforms/javascript/configuration/options/#traces-sample-rate
|
||||||
|
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
|
||||||
|
});
|
80
src/app/global-error.tsx
Normal file
80
src/app/global-error.tsx
Normal file
@ -0,0 +1,80 @@
|
|||||||
|
'use client';
|
||||||
|
|
||||||
|
import '@/styles/globals.css';
|
||||||
|
import { cn } from '@/lib/utils';
|
||||||
|
import { ThemeProvider } from '@/components/context/theme';
|
||||||
|
import { AuthProvider } from '@/components/context/auth';
|
||||||
|
import Navigation from '@/components/default/navigation';
|
||||||
|
import Footer from '@/components/default/footer';
|
||||||
|
import { Button, Toaster } from '@/components/ui';
|
||||||
|
import * as Sentry from '@sentry/nextjs';
|
||||||
|
import NextError from 'next/error';
|
||||||
|
import { useEffect } from 'react';
|
||||||
|
import { Geist } from 'next/font/google';
|
||||||
|
|
||||||
|
const geist = Geist({
|
||||||
|
subsets: ['latin'],
|
||||||
|
variable: '--font-geist-sans',
|
||||||
|
});
|
||||||
|
|
||||||
|
type GlobalErrorProps = {
|
||||||
|
error: Error & { digest?: string };
|
||||||
|
reset?: () => void;
|
||||||
|
};
|
||||||
|
|
||||||
|
const GlobalError = ({ error, reset = undefined }: GlobalErrorProps) => {
|
||||||
|
useEffect(() => {
|
||||||
|
Sentry.captureException(error);
|
||||||
|
}, [error]);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<html lang='en' className={`${geist.variable}`} suppressHydrationWarning>
|
||||||
|
<body
|
||||||
|
className={cn('bg-background text-foreground font-sans antialiased')}
|
||||||
|
>
|
||||||
|
<ThemeProvider
|
||||||
|
attribute='class'
|
||||||
|
defaultTheme='system'
|
||||||
|
enableSystem
|
||||||
|
disableTransitionOnChange
|
||||||
|
>
|
||||||
|
<AuthProvider>
|
||||||
|
<main className='min-h-screen flex flex-col items-center'>
|
||||||
|
<div className='flex-1 w-full flex flex-col gap-20 items-center'>
|
||||||
|
<Navigation />
|
||||||
|
<div
|
||||||
|
className='flex flex-col gap-20 max-w-5xl
|
||||||
|
p-5 w-full items-center'
|
||||||
|
>
|
||||||
|
<NextError statusCode={0} />
|
||||||
|
{reset !== undefined && (
|
||||||
|
<Button onClick={() => reset()}>Try again</Button>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<Footer />
|
||||||
|
</main>
|
||||||
|
<Toaster />
|
||||||
|
</AuthProvider>
|
||||||
|
</ThemeProvider>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<html lang='en'>
|
||||||
|
<body>
|
||||||
|
{/* `NextError` is the default Next.js error page component. Its type
|
||||||
|
definition requires a `statusCode` prop. However, since the App Router
|
||||||
|
does not expose status codes for errors, we simply pass 0 to render a
|
||||||
|
generic error message. */}
|
||||||
|
<NextError statusCode={0} />
|
||||||
|
{reset !== undefined && (
|
||||||
|
<Button onClick={() => reset()}>Try again</Button>
|
||||||
|
)}
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default GlobalError;
|
@ -1,4 +1,4 @@
|
|||||||
import { type Metadata } from 'next';
|
import type { Metadata } from 'next';
|
||||||
import '@/styles/globals.css';
|
import '@/styles/globals.css';
|
||||||
import { Geist } from 'next/font/google';
|
import { Geist } from 'next/font/google';
|
||||||
import { cn } from '@/lib/utils';
|
import { cn } from '@/lib/utils';
|
||||||
@ -7,8 +7,10 @@ import { AuthProvider } from '@/components/context/auth';
|
|||||||
import Navigation from '@/components/default/navigation';
|
import Navigation from '@/components/default/navigation';
|
||||||
import Footer from '@/components/default/footer';
|
import Footer from '@/components/default/footer';
|
||||||
import { Toaster } from '@/components/ui';
|
import { Toaster } from '@/components/ui';
|
||||||
|
import * as Sentry from '@sentry/nextjs';
|
||||||
|
|
||||||
export const metadata: Metadata = {
|
export const generateMetadata = (): Metadata => {
|
||||||
|
return {
|
||||||
title: {
|
title: {
|
||||||
template: '%s | T3 Template',
|
template: '%s | T3 Template',
|
||||||
default: 'T3 Template with Supabase',
|
default: 'T3 Template with Supabase',
|
||||||
@ -73,7 +75,11 @@ export const metadata: Metadata = {
|
|||||||
{ url: '/appicon/icon-48x48.png', type: 'image/png', sizes: '48x48' },
|
{ url: '/appicon/icon-48x48.png', type: 'image/png', sizes: '48x48' },
|
||||||
{ url: '/appicon/icon-72x72.png', type: 'image/png', sizes: '72x72' },
|
{ url: '/appicon/icon-72x72.png', type: 'image/png', sizes: '72x72' },
|
||||||
{ url: '/appicon/icon-96x96.png', type: 'image/png', sizes: '96x96' },
|
{ url: '/appicon/icon-96x96.png', type: 'image/png', sizes: '96x96' },
|
||||||
{ url: '/appicon/icon-144x144.png', type: 'image/png', sizes: '144x144' },
|
{
|
||||||
|
url: '/appicon/icon-144x144.png',
|
||||||
|
type: 'image/png',
|
||||||
|
sizes: '144x144',
|
||||||
|
},
|
||||||
{ url: '/appicon/icon.png', type: 'image/png', sizes: '192x192' },
|
{ url: '/appicon/icon.png', type: 'image/png', sizes: '192x192' },
|
||||||
{
|
{
|
||||||
url: '/appicon/icon-36x36.png',
|
url: '/appicon/icon-36x36.png',
|
||||||
@ -117,7 +123,11 @@ export const metadata: Metadata = {
|
|||||||
{ url: '/appicon/icon-48x48.png', type: 'image/png', sizes: '48x48' },
|
{ url: '/appicon/icon-48x48.png', type: 'image/png', sizes: '48x48' },
|
||||||
{ url: '/appicon/icon-72x72.png', type: 'image/png', sizes: '72x72' },
|
{ url: '/appicon/icon-72x72.png', type: 'image/png', sizes: '72x72' },
|
||||||
{ url: '/appicon/icon-96x96.png', type: 'image/png', sizes: '96x96' },
|
{ url: '/appicon/icon-96x96.png', type: 'image/png', sizes: '96x96' },
|
||||||
{ url: '/appicon/icon-144x144.png', type: 'image/png', sizes: '144x144' },
|
{
|
||||||
|
url: '/appicon/icon-144x144.png',
|
||||||
|
type: 'image/png',
|
||||||
|
sizes: '144x144',
|
||||||
|
},
|
||||||
{ url: '/appicon/icon.png', type: 'image/png', sizes: '192x192' },
|
{ url: '/appicon/icon.png', type: 'image/png', sizes: '192x192' },
|
||||||
{
|
{
|
||||||
url: '/appicon/icon-36x36.png',
|
url: '/appicon/icon-36x36.png',
|
||||||
@ -161,11 +171,31 @@ export const metadata: Metadata = {
|
|||||||
{ url: 'appicon/icon-60x60.png', type: 'image/png', sizes: '60x60' },
|
{ url: 'appicon/icon-60x60.png', type: 'image/png', sizes: '60x60' },
|
||||||
{ url: 'appicon/icon-72x72.png', type: 'image/png', sizes: '72x72' },
|
{ url: 'appicon/icon-72x72.png', type: 'image/png', sizes: '72x72' },
|
||||||
{ url: 'appicon/icon-76x76.png', type: 'image/png', sizes: '76x76' },
|
{ url: 'appicon/icon-76x76.png', type: 'image/png', sizes: '76x76' },
|
||||||
{ url: 'appicon/icon-114x114.png', type: 'image/png', sizes: '114x114' },
|
{
|
||||||
{ url: 'appicon/icon-120x120.png', type: 'image/png', sizes: '120x120' },
|
url: 'appicon/icon-114x114.png',
|
||||||
{ url: 'appicon/icon-144x144.png', type: 'image/png', sizes: '144x144' },
|
type: 'image/png',
|
||||||
{ url: 'appicon/icon-152x152.png', type: 'image/png', sizes: '152x152' },
|
sizes: '114x114',
|
||||||
{ url: 'appicon/icon-180x180.png', type: 'image/png', sizes: '180x180' },
|
},
|
||||||
|
{
|
||||||
|
url: 'appicon/icon-120x120.png',
|
||||||
|
type: 'image/png',
|
||||||
|
sizes: '120x120',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
url: 'appicon/icon-144x144.png',
|
||||||
|
type: 'image/png',
|
||||||
|
sizes: '144x144',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
url: 'appicon/icon-152x152.png',
|
||||||
|
type: 'image/png',
|
||||||
|
sizes: '152x152',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
url: 'appicon/icon-180x180.png',
|
||||||
|
type: 'image/png',
|
||||||
|
sizes: '180x180',
|
||||||
|
},
|
||||||
{ url: 'appicon/icon.png', type: 'image/png', sizes: '192x192' },
|
{ url: 'appicon/icon.png', type: 'image/png', sizes: '192x192' },
|
||||||
{
|
{
|
||||||
url: 'appicon/icon-57x57.png',
|
url: 'appicon/icon-57x57.png',
|
||||||
@ -237,6 +267,9 @@ export const metadata: Metadata = {
|
|||||||
},
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
|
other: {
|
||||||
|
...Sentry.getTraceData(),
|
||||||
|
},
|
||||||
twitter: {
|
twitter: {
|
||||||
card: 'app',
|
card: 'app',
|
||||||
title: 'T3 Template',
|
title: 'T3 Template',
|
||||||
@ -304,6 +337,7 @@ export const metadata: Metadata = {
|
|||||||
},
|
},
|
||||||
category: 'technology',
|
category: 'technology',
|
||||||
};
|
};
|
||||||
|
};
|
||||||
|
|
||||||
const geist = Geist({
|
const geist = Geist({
|
||||||
subsets: ['latin'],
|
subsets: ['latin'],
|
||||||
|
14
src/env.js
14
src/env.js
@ -7,7 +7,11 @@ export const env = createEnv({
|
|||||||
* This way you can ensure the app isn't built with invalid env vars.
|
* This way you can ensure the app isn't built with invalid env vars.
|
||||||
*/
|
*/
|
||||||
server: {
|
server: {
|
||||||
NODE_ENV: z.enum(['development', 'test', 'production']),
|
NODE_ENV: z.enum(['development', 'test', 'production']).default('development'),
|
||||||
|
NEXT_RUNTIME: z.enum(['nodejs', 'edge']).default('nodejs'),
|
||||||
|
SENTRY_URL: z.string().url().default('https://sentry.gbrown.org'),
|
||||||
|
SENTRY_AUTH_TOKEN: z.string().min(1),
|
||||||
|
CI: z.enum(['true', 'false']).default('true'),
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -18,7 +22,8 @@ export const env = createEnv({
|
|||||||
client: {
|
client: {
|
||||||
NEXT_PUBLIC_SUPABASE_URL: z.string().url(),
|
NEXT_PUBLIC_SUPABASE_URL: z.string().url(),
|
||||||
NEXT_PUBLIC_SUPABASE_ANON_KEY: z.string().min(1),
|
NEXT_PUBLIC_SUPABASE_ANON_KEY: z.string().min(1),
|
||||||
NEXT_PUBLIC_SITE_URL: z.string().url(),
|
NEXT_PUBLIC_SITE_URL: z.string().url().default('http://localhost:3000'),
|
||||||
|
NEXT_PUBLIC_SENTRY_DSN: z.string().min(1),
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -27,10 +32,15 @@ export const env = createEnv({
|
|||||||
*/
|
*/
|
||||||
runtimeEnv: {
|
runtimeEnv: {
|
||||||
NODE_ENV: process.env.NODE_ENV,
|
NODE_ENV: process.env.NODE_ENV,
|
||||||
|
NEXT_RUNTIME: process.env.NEXT_RUNTIME,
|
||||||
|
SENTRY_URL: process.env.SENTRY_URL,
|
||||||
|
SENTRY_AUTH_TOKEN: process.env.SENTRY_AUTH_TOKEN,
|
||||||
|
CI: process.env.CI,
|
||||||
|
|
||||||
NEXT_PUBLIC_SUPABASE_URL: process.env.NEXT_PUBLIC_SUPABASE_URL,
|
NEXT_PUBLIC_SUPABASE_URL: process.env.NEXT_PUBLIC_SUPABASE_URL,
|
||||||
NEXT_PUBLIC_SUPABASE_ANON_KEY: process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY,
|
NEXT_PUBLIC_SUPABASE_ANON_KEY: process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY,
|
||||||
NEXT_PUBLIC_SITE_URL: process.env.NEXT_PUBLIC_SITE_URL,
|
NEXT_PUBLIC_SITE_URL: process.env.NEXT_PUBLIC_SITE_URL,
|
||||||
|
NEXT_PUBLIC_SENTRY_DSN: process.env.NEXT_PUBLIC_SENTRY_DSN,
|
||||||
},
|
},
|
||||||
/**
|
/**
|
||||||
* Run `build` or `dev` with `SKIP_ENV_VALIDATION` to skip env validation. This is especially
|
* Run `build` or `dev` with `SKIP_ENV_VALIDATION` to skip env validation. This is especially
|
||||||
|
13
src/instrumentation.ts
Normal file
13
src/instrumentation.ts
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
import * as Sentry from '@sentry/nextjs';
|
||||||
|
import type { Instrumentation } from 'next';
|
||||||
|
|
||||||
|
|
||||||
|
export const register = async () => {
|
||||||
|
if (process.env.NEXT_RUNTIME === 'edge') {
|
||||||
|
await import('../sentry.edge.config');
|
||||||
|
} else await import('../sentry.server.config');
|
||||||
|
};
|
||||||
|
|
||||||
|
export const onRequestError: Instrumentation.onRequestError = (...args) => {
|
||||||
|
Sentry.captureRequestError(...args);
|
||||||
|
};
|
@ -12,9 +12,10 @@ export const config = {
|
|||||||
* - _next/static (static files)
|
* - _next/static (static files)
|
||||||
* - _next/image (image optimization files)
|
* - _next/image (image optimization files)
|
||||||
* - favicon.ico (favicon file)
|
* - favicon.ico (favicon file)
|
||||||
|
* - /monitoring-tunnel (Sentry monitoring)
|
||||||
* - images - .svg, .png, .jpg, .jpeg, .gif, .webp
|
* - images - .svg, .png, .jpg, .jpeg, .gif, .webp
|
||||||
* Feel free to modify this pattern to include more paths.
|
* Feel free to modify this pattern to include more paths.
|
||||||
*/
|
*/
|
||||||
'/((?!_next/static|_next/image|favicon.ico|.*\\.(?:svg|png|jpg|jpeg|gif|webp)$).*)',
|
'/((?!_next/static|_next/image|favicon.ico|monitoring-tunnel|.*\\.(?:svg|png|jpg|jpeg|gif|webp)$).*)',
|
||||||
],
|
],
|
||||||
};
|
};
|
||||||
|
Reference in New Issue
Block a user