Files
vibn-frontend/next.config.ts
Mark Henderson 9eab86f8c2 feat(observability): wire Sentry for runtime error capture
Adds @sentry/nextjs v10 with the Next.js 16 instrumentation pattern:
- instrumentation.ts        — server + edge runtime init
- instrumentation-client.ts — browser init with Session Replay
                              (free tier, mask all text/inputs by
                              default since chat content is sensitive)
- app/global-error.tsx      — catches root-layout crashes that escape
                              every other error boundary
- app/sentry-example-page   — verification page; click both buttons
- next.config.ts            — wrapped with withSentryConfig, source
                              maps upload to Sentry on every build,
                              client error events tunneled through
                              /monitoring to bypass ad-blockers

Runtime capture works as soon as NEXT_PUBLIC_SENTRY_DSN is in Coolify
env (already added). Full source-map de-minification of prod stack
traces requires SENTRY_AUTH_TOKEN in Coolify env — pending user.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-01 11:24:10 -07:00

114 lines
4.1 KiB
TypeScript

import type { NextConfig } from "next";
import path from "path";
import { fileURLToPath } from "url";
import { withSentryConfig } from "@sentry/nextjs";
// This app lives in vibn-frontend; a lockfile under $HOME can make Turbopack pick the wrong root
// and hydrate with a mismatched client bundle (e.g. different JustineNav markup).
const turbopackRoot = path.dirname(fileURLToPath(import.meta.url));
// Google OAuth on localhost: NextAuth must build the same callback URL Google expects.
// If NEXTAUTH_URL is unset in dev, default it (set explicitly if you use 127.0.0.1 or another port).
if (process.env.NODE_ENV === "development" && !process.env.NEXTAUTH_URL?.trim()) {
process.env.NEXTAUTH_URL = "http://localhost:3000";
}
const nextConfig: NextConfig = {
turbopack: {
root: turbopackRoot,
},
output: "standalone",
// ssh2 ships native .node binaries; turbopack can't bundle them
// ("non-ecmascript placeable asset"). Externalize so they're loaded
// at runtime via Node's require, the same way @prisma/client works.
serverExternalPackages: ["@prisma/client", "prisma", "ssh2", "cpu-features"],
// react-markdown and its entire unified/remark/rehype ecosystem are
// ESM-only (type:"module", no CJS fallback). Next.js webpack can't
// resolve them without explicit transpilation — manifests as
// "TypeError: Cannot read properties of undefined (reading 'z')" in
// the minified production bundle.
transpilePackages: [
"react-markdown",
"remark-gfm",
"remark-parse",
"remark-rehype",
"unified",
"vfile",
"vfile-message",
"mdast-util-from-markdown",
"mdast-util-to-markdown",
"mdast-util-gfm",
"mdast-util-gfm-table",
"mdast-util-gfm-task-list-item",
"mdast-util-gfm-strikethrough",
"mdast-util-gfm-autolink-literal",
"mdast-util-gfm-footnote",
"micromark",
"micromark-core-commonmark",
"micromark-extension-gfm",
"micromark-util-combine-extensions",
"micromark-util-character",
"micromark-util-chunked",
"micromark-util-classify-character",
"micromark-util-decode-string",
"micromark-util-encode",
"micromark-util-html-tag-name",
"micromark-util-normalize-identifier",
"micromark-util-resolve-all",
"micromark-util-sanitize-uri",
"micromark-util-subtokenize",
"micromark-util-types",
"micromark-util-symbol",
"micromark-util-decode-numeric-character-reference",
"hast-util-to-jsx-runtime",
"hast-util-whitespace",
"hast-util-from-parse5",
"property-information",
"space-separated-tokens",
"comma-separated-tokens",
"decode-named-character-reference",
"character-entities",
"unist-util-position",
"unist-util-stringify-position",
"unist-util-visit",
"unist-util-is",
],
typescript: {
ignoreBuildErrors: true,
},
};
// Wrap with Sentry: uploads source maps on every Coolify build so the
// minified prod stack traces (TypeError: reading 'z' / 'j' / 'aa' etc.)
// arrive in the dashboard already de-minified. Auth token is set in
// Coolify env (SENTRY_AUTH_TOKEN); without it the wrapper still works
// at runtime but skips source map upload at build time.
export default withSentryConfig(nextConfig, {
org: "vibnai",
project: "vibn-ai",
// Quiet build output unless something is actually wrong.
silent: !process.env.CI,
// Upload source maps for every client chunk (incl. those in
// unrelated dirs like node_modules); we want full coverage so
// production stack traces are de-minified end to end. SDK v10
// deletes the public source maps after upload by default, so
// they're only readable inside Sentry.
widenClientFileUpload: true,
// Prevents ad-blockers from killing client error events. Routes
// them through /monitoring on our domain instead of sentry.io.
tunnelRoute: "/monitoring",
// Disable telemetry pings from the build wrapper itself.
telemetry: false,
// Don't fail the build if source map upload fails (e.g. token
// missing in a preview build); errors will still capture, they
// just won't be de-minified.
errorHandler: (err) => {
console.warn("Sentry source map upload skipped:", err.message);
},
});