Add sentry to template. Got a small error but we are gonna fix it soon!

This commit is contained in:
2025-06-07 11:44:54 -05:00
parent 930dc0867d
commit eebc022928
14 changed files with 2619 additions and 317 deletions

View File

@ -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
View 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;

View File

@ -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);

View File

@ -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

File diff suppressed because it is too large Load Diff

View File

@ -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
View 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
View 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
View 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;

View File

@ -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,302 +7,336 @@ 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 => {
title: { return {
template: '%s | T3 Template', title: {
default: 'T3 Template with Supabase', template: '%s | T3 Template',
}, default: 'T3 Template with Supabase',
description: 'Created by Gib with T3!', },
applicationName: 'T3 Template', description: 'Created by Gib with T3!',
keywords: applicationName: 'T3 Template',
'T3 Template, Next.js, Supabase, Tailwind, TypeScript, React, T3, Gib, Theo', keywords:
authors: [{ name: 'Gib', url: 'https://gbrown.org' }], 'T3 Template, Next.js, Supabase, Tailwind, TypeScript, React, T3, Gib, Theo',
creator: 'Gib Brown', authors: [{ name: 'Gib', url: 'https://gbrown.org' }],
publisher: 'Gib Brown', creator: 'Gib Brown',
formatDetection: { publisher: 'Gib Brown',
email: false, formatDetection: {
address: false, email: false,
telephone: false, address: false,
}, telephone: false,
robots: { },
index: true, robots: {
follow: true,
nocache: false,
googleBot: {
index: true, index: true,
follow: true, follow: true,
noimageindex: false, nocache: false,
'max-video-preview': -1, googleBot: {
'max-image-preview': 'large', index: true,
'max-snippet': -1, follow: true,
noimageindex: false,
'max-video-preview': -1,
'max-image-preview': 'large',
'max-snippet': -1,
},
}, },
}, icons: {
icons: { icon: [
icon: [ { url: '/favicon.ico', type: 'image/x-icon', sizes: 'any' },
{ url: '/favicon.ico', type: 'image/x-icon', sizes: 'any' }, { url: '/favicon-16x16.png', type: 'image/png', sizes: '16x16' },
{ url: '/favicon-16x16.png', type: 'image/png', sizes: '16x16' }, { url: '/favicon-32x32.png', type: 'image/png', sizes: '32x32' },
{ url: '/favicon-32x32.png', type: 'image/png', sizes: '32x32' }, { url: '/favicon.png', type: 'image/png', sizes: '96x96' },
{ url: '/favicon.png', type: 'image/png', sizes: '96x96' }, {
{ url: '/favicon.ico',
url: '/favicon.ico', type: 'image/x-icon',
type: 'image/x-icon', sizes: 'any',
sizes: 'any', media: '(prefers-color-scheme: dark)',
media: '(prefers-color-scheme: dark)', },
}, {
{ url: '/favicon-16x16.png',
url: '/favicon-16x16.png', type: 'image/png',
type: 'image/png', sizes: '16x16',
sizes: '16x16', media: '(prefers-color-scheme: dark)',
media: '(prefers-color-scheme: dark)', },
}, {
{ url: '/favicon-32x32.png',
url: '/favicon-32x32.png', type: 'image/png',
type: 'image/png', sizes: '32x32',
sizes: '32x32', media: '(prefers-color-scheme: dark)',
media: '(prefers-color-scheme: dark)', },
}, {
{ url: '/favicon-96x96.png',
url: '/favicon-96x96.png', type: 'image/png',
type: 'image/png', sizes: '96x96',
sizes: '96x96', media: '(prefers-color-scheme: dark)',
media: '(prefers-color-scheme: dark)', },
},
{ url: '/appicon/icon-36x36.png', type: 'image/png', sizes: '36x36' }, { url: '/appicon/icon-36x36.png', type: 'image/png', sizes: '36x36' },
{ 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.png', type: 'image/png', sizes: '192x192' }, url: '/appicon/icon-144x144.png',
{ type: 'image/png',
url: '/appicon/icon-36x36.png', sizes: '144x144',
type: 'image/png', },
sizes: '36x36', { url: '/appicon/icon.png', type: 'image/png', sizes: '192x192' },
media: '(prefers-color-scheme: dark)', {
}, url: '/appicon/icon-36x36.png',
{ type: 'image/png',
url: '/appicon/icon-48x48.png', sizes: '36x36',
type: 'image/png', media: '(prefers-color-scheme: dark)',
sizes: '48x48', },
media: '(prefers-color-scheme: dark)', {
}, url: '/appicon/icon-48x48.png',
{ type: 'image/png',
url: '/appicon/icon-72x72.png', sizes: '48x48',
type: 'image/png', media: '(prefers-color-scheme: dark)',
sizes: '72x72', },
media: '(prefers-color-scheme: dark)', {
}, url: '/appicon/icon-72x72.png',
{ type: 'image/png',
url: '/appicon/icon-96x96.png', sizes: '72x72',
type: 'image/png', media: '(prefers-color-scheme: dark)',
sizes: '96x96', },
media: '(prefers-color-scheme: dark)', {
}, url: '/appicon/icon-96x96.png',
{ type: 'image/png',
url: '/appicon/icon-144x144.png', sizes: '96x96',
type: 'image/png', media: '(prefers-color-scheme: dark)',
sizes: '144x144', },
media: '(prefers-color-scheme: dark)', {
}, url: '/appicon/icon-144x144.png',
{ type: 'image/png',
url: '/appicon/icon.png', sizes: '144x144',
type: 'image/png', media: '(prefers-color-scheme: dark)',
sizes: '192x192', },
media: '(prefers-color-scheme: dark)', {
}, url: '/appicon/icon.png',
], type: 'image/png',
shortcut: [ sizes: '192x192',
{ url: '/appicon/icon-36x36.png', type: 'image/png', sizes: '36x36' }, media: '(prefers-color-scheme: dark)',
{ url: '/appicon/icon-48x48.png', type: 'image/png', sizes: '48x48' }, },
{ url: '/appicon/icon-72x72.png', type: 'image/png', sizes: '72x72' }, ],
{ url: '/appicon/icon-96x96.png', type: 'image/png', sizes: '96x96' }, shortcut: [
{ url: '/appicon/icon-144x144.png', type: 'image/png', sizes: '144x144' }, { url: '/appicon/icon-36x36.png', type: 'image/png', sizes: '36x36' },
{ url: '/appicon/icon.png', type: 'image/png', sizes: '192x192' }, { url: '/appicon/icon-48x48.png', type: 'image/png', sizes: '48x48' },
{ { url: '/appicon/icon-72x72.png', type: 'image/png', sizes: '72x72' },
url: '/appicon/icon-36x36.png', { url: '/appicon/icon-96x96.png', type: 'image/png', sizes: '96x96' },
type: 'image/png', {
sizes: '36x36', url: '/appicon/icon-144x144.png',
media: '(prefers-color-scheme: dark)', type: 'image/png',
}, sizes: '144x144',
{ },
url: '/appicon/icon-48x48.png', { url: '/appicon/icon.png', type: 'image/png', sizes: '192x192' },
type: 'image/png', {
sizes: '48x48', url: '/appicon/icon-36x36.png',
media: '(prefers-color-scheme: dark)', type: 'image/png',
}, sizes: '36x36',
{ media: '(prefers-color-scheme: dark)',
url: '/appicon/icon-72x72.png', },
type: 'image/png', {
sizes: '72x72', url: '/appicon/icon-48x48.png',
media: '(prefers-color-scheme: dark)', type: 'image/png',
}, sizes: '48x48',
{ media: '(prefers-color-scheme: dark)',
url: '/appicon/icon-96x96.png', },
type: 'image/png', {
sizes: '96x96', url: '/appicon/icon-72x72.png',
media: '(prefers-color-scheme: dark)', type: 'image/png',
}, sizes: '72x72',
{ media: '(prefers-color-scheme: dark)',
url: '/appicon/icon-144x144.png', },
type: 'image/png', {
sizes: '144x144', url: '/appicon/icon-96x96.png',
media: '(prefers-color-scheme: dark)', type: 'image/png',
}, sizes: '96x96',
{ media: '(prefers-color-scheme: dark)',
url: '/appicon/icon.png', },
type: 'image/png', {
sizes: '192x192', url: '/appicon/icon-144x144.png',
media: '(prefers-color-scheme: dark)', type: 'image/png',
}, sizes: '144x144',
], media: '(prefers-color-scheme: dark)',
apple: [ },
{ url: 'appicon/icon-57x57.png', type: 'image/png', sizes: '57x57' }, {
{ url: 'appicon/icon-60x60.png', type: 'image/png', sizes: '60x60' }, url: '/appicon/icon.png',
{ url: 'appicon/icon-72x72.png', type: 'image/png', sizes: '72x72' }, type: 'image/png',
{ url: 'appicon/icon-76x76.png', type: 'image/png', sizes: '76x76' }, sizes: '192x192',
{ url: 'appicon/icon-114x114.png', type: 'image/png', sizes: '114x114' }, media: '(prefers-color-scheme: dark)',
{ 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' }, apple: [
{ url: 'appicon/icon-180x180.png', type: 'image/png', sizes: '180x180' }, { url: 'appicon/icon-57x57.png', type: 'image/png', sizes: '57x57' },
{ url: 'appicon/icon.png', type: 'image/png', sizes: '192x192' }, { url: 'appicon/icon-60x60.png', type: 'image/png', sizes: '60x60' },
{ { url: 'appicon/icon-72x72.png', type: 'image/png', sizes: '72x72' },
url: 'appicon/icon-57x57.png', { url: 'appicon/icon-76x76.png', type: 'image/png', sizes: '76x76' },
type: 'image/png', {
sizes: '57x57', url: 'appicon/icon-114x114.png',
media: '(prefers-color-scheme: dark)', type: 'image/png',
}, sizes: '114x114',
{ },
url: 'appicon/icon-60x60.png', {
type: 'image/png', url: 'appicon/icon-120x120.png',
sizes: '60x60', type: 'image/png',
media: '(prefers-color-scheme: dark)', sizes: '120x120',
}, },
{ {
url: 'appicon/icon-72x72.png', url: 'appicon/icon-144x144.png',
type: 'image/png', type: 'image/png',
sizes: '72x72', sizes: '144x144',
media: '(prefers-color-scheme: dark)', },
}, {
{ url: 'appicon/icon-152x152.png',
url: 'appicon/icon-76x76.png', type: 'image/png',
type: 'image/png', sizes: '152x152',
sizes: '76x76', },
media: '(prefers-color-scheme: dark)', {
}, url: 'appicon/icon-180x180.png',
{ type: 'image/png',
url: 'appicon/icon-114x114.png', sizes: '180x180',
type: 'image/png', },
sizes: '114x114', { url: 'appicon/icon.png', type: 'image/png', sizes: '192x192' },
media: '(prefers-color-scheme: dark)', {
}, url: 'appicon/icon-57x57.png',
{ type: 'image/png',
url: 'appicon/icon-120x120.png', sizes: '57x57',
type: 'image/png', media: '(prefers-color-scheme: dark)',
sizes: '120x120', },
media: '(prefers-color-scheme: dark)', {
}, url: 'appicon/icon-60x60.png',
{ type: 'image/png',
url: 'appicon/icon-144x144.png', sizes: '60x60',
type: 'image/png', media: '(prefers-color-scheme: dark)',
sizes: '144x144', },
media: '(prefers-color-scheme: dark)', {
}, url: 'appicon/icon-72x72.png',
{ type: 'image/png',
url: 'appicon/icon-152x152.png', sizes: '72x72',
type: 'image/png', media: '(prefers-color-scheme: dark)',
sizes: '152x152', },
media: '(prefers-color-scheme: dark)', {
}, url: 'appicon/icon-76x76.png',
{ type: 'image/png',
url: 'appicon/icon-180x180.png', sizes: '76x76',
type: 'image/png', media: '(prefers-color-scheme: dark)',
sizes: '180x180', },
media: '(prefers-color-scheme: dark)', {
}, url: 'appicon/icon-114x114.png',
{ type: 'image/png',
url: 'appicon/icon.png', sizes: '114x114',
type: 'image/png', media: '(prefers-color-scheme: dark)',
sizes: '192x192', },
media: '(prefers-color-scheme: dark)', {
}, url: 'appicon/icon-120x120.png',
], type: 'image/png',
other: [ sizes: '120x120',
{ media: '(prefers-color-scheme: dark)',
rel: 'apple-touch-icon-precomposed', },
url: '/appicon/icon-precomposed.png', {
type: 'image/png', url: 'appicon/icon-144x144.png',
sizes: '180x180', type: 'image/png',
}, sizes: '144x144',
], media: '(prefers-color-scheme: dark)',
}, },
twitter: { {
card: 'app', url: 'appicon/icon-152x152.png',
title: 'T3 Template', type: 'image/png',
description: 'Created by Gib with T3!', sizes: '152x152',
siteId: '', media: '(prefers-color-scheme: dark)',
creator: '@cs_gib', },
creatorId: '', {
images: { url: 'appicon/icon-180x180.png',
url: 'https://git.gbrown.org/gib/T3-Template/raw/main/public/icons/apple/icon.png', type: 'image/png',
alt: 'T3 Template', sizes: '180x180',
media: '(prefers-color-scheme: dark)',
},
{
url: 'appicon/icon.png',
type: 'image/png',
sizes: '192x192',
media: '(prefers-color-scheme: dark)',
},
],
other: [
{
rel: 'apple-touch-icon-precomposed',
url: '/appicon/icon-precomposed.png',
type: 'image/png',
sizes: '180x180',
},
],
}, },
app: { other: {
name: 'T3 Template', ...Sentry.getTraceData(),
id: { },
iphone: '', twitter: {
ipad: '', card: 'app',
googleplay: '', title: 'T3 Template',
description: 'Created by Gib with T3!',
siteId: '',
creator: '@cs_gib',
creatorId: '',
images: {
url: 'https://git.gbrown.org/gib/T3-Template/raw/main/public/icons/apple/icon.png',
alt: 'T3 Template',
}, },
url: { app: {
iphone: '', name: 'T3 Template',
ipad: '', id: {
googleplay: '', iphone: '',
ipad: '',
googleplay: '',
},
url: {
iphone: '',
ipad: '',
googleplay: '',
},
}, },
}, },
}, verification: {
verification: { google: 'google',
google: 'google', yandex: 'yandex',
yandex: 'yandex', yahoo: 'yahoo',
yahoo: 'yahoo', },
}, itunes: {
itunes: { appId: '',
appId: '', appArgument: '',
appArgument: '', },
}, appleWebApp: {
appleWebApp: { title: 'T3 Template',
title: 'T3 Template', statusBarStyle: 'black-translucent',
statusBarStyle: 'black-translucent', startupImage: [
startupImage: [ '/icons/apple/splash-768x1004.png',
'/icons/apple/splash-768x1004.png', {
{ url: '/icons/apple/splash-1536x2008.png',
url: '/icons/apple/splash-1536x2008.png', media: '(device-width: 768px) and (device-height: 1024px)',
media: '(device-width: 768px) and (device-height: 1024px)', },
],
},
appLinks: {
ios: {
url: 'https://t3-template.gbrown.org/ios',
app_store_id: 't3_template',
},
android: {
package: 'org.gbrown.android/t3-template',
app_name: 'app_t3_template',
},
web: {
url: 'https://t3-template.gbrown.org/web',
should_fallback: true,
}, },
],
},
appLinks: {
ios: {
url: 'https://t3-template.gbrown.org/ios',
app_store_id: 't3_template',
}, },
android: { facebook: {
package: 'org.gbrown.android/t3-template', appId: '',
app_name: 'app_t3_template',
}, },
web: { pinterest: {
url: 'https://t3-template.gbrown.org/web', richPin: true,
should_fallback: true,
}, },
}, category: 'technology',
facebook: { };
appId: '',
},
pinterest: {
richPin: true,
},
category: 'technology',
}; };
const geist = Geist({ const geist = Geist({

View File

@ -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
View 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);
};

View File

@ -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)$).*)',
], ],
}; };