deploy #1

Merged
smueller merged 30 commits from deploy into main 2026-07-24 08:41:09 +00:00
5 changed files with 35 additions and 14 deletions
Showing only changes of commit c14c2ddaa2 - Show all commits

View File

@@ -4,7 +4,10 @@ import type { NextConfig } from 'next';
const nextConfig: NextConfig = {
output: 'standalone',
transpilePackages: ['@nexumi/shared'],
outputFileTracingRoot: path.join(__dirname, '../..')
outputFileTracingRoot: path.join(__dirname, '../..'),
// Keep Node-only packages out of the Next server webpack bundle so they
// cannot break React's RSC/client boundary during page-data collection.
serverExternalPackages: ['@sentry/node', '@prisma/client', 'ioredis', 'bullmq']
};
export default nextConfig;

View File

@@ -1,9 +1,9 @@
import type { Metadata } from 'next';
import { Inter } from 'next/font/google';
import type { ReactNode } from 'react';
import { Toaster } from 'sonner';
import { LocaleProvider } from '@/components/locale-provider';
import { ThemeProvider } from '@/components/layout/theme-provider';
import { Toaster } from '@/components/ui/toaster';
import { getLocale, MESSAGES } from '@/lib/i18n';
import './globals.css';
@@ -23,7 +23,7 @@ export default async function RootLayout({ children }: { children: ReactNode })
<ThemeProvider>
<LocaleProvider locale={locale} messages={MESSAGES[locale]}>
{children}
<Toaster richColors position="top-right" />
<Toaster />
</LocaleProvider>
</ThemeProvider>
</body>

View File

@@ -0,0 +1,7 @@
'use client';
import { Toaster as SonnerToaster } from 'sonner';
export function Toaster() {
return <SonnerToaster richColors position="top-right" />;
}

View File

@@ -1,6 +1,6 @@
export async function register(): Promise<void> {
if (process.env.NEXT_RUNTIME === 'nodejs') {
const { initWebuiSentry } = await import('./lib/sentry');
initWebuiSentry();
await initWebuiSentry();
}
}

View File

@@ -1,17 +1,23 @@
import * as Sentry from '@sentry/node';
import { env } from './env';
let initialized = false;
export function initWebuiSentry(): void {
if (initialized || !env.SENTRY_DSN) {
export async function initWebuiSentry(): Promise<void> {
if (initialized) {
return;
}
const dsn = process.env.SENTRY_DSN?.trim();
if (!dsn) {
return;
}
// Import only when a DSN is configured. Loading `@sentry/node` at module
// scope patches Node builtins and can break Next.js page-data collection
// (`createContext is not a function`) during `next build`.
const Sentry = await import('@sentry/node');
Sentry.init({
dsn: env.SENTRY_DSN,
environment: env.NODE_ENV,
dsn,
environment: process.env.NODE_ENV ?? 'production',
release: 'nexumi-webui@0.1.0',
tracesSampleRate: env.NODE_ENV === 'production' ? 0.1 : 1.0,
tracesSampleRate: process.env.NODE_ENV === 'production' ? 0.1 : 1.0,
initialScope: {
tags: { service: 'webui' }
}
@@ -19,10 +25,15 @@ export function initWebuiSentry(): void {
initialized = true;
}
export function captureWebuiException(error: unknown, context?: Record<string, unknown>): void {
if (!env.SENTRY_DSN) {
export async function captureWebuiException(
error: unknown,
context?: Record<string, unknown>
): Promise<void> {
const dsn = process.env.SENTRY_DSN?.trim();
if (!dsn) {
return;
}
const Sentry = await import('@sentry/node');
Sentry.withScope((scope) => {
if (context) {
scope.setExtras(context);