Closes checklist items F-01..F-06, D-01..D-28, S-01..S-10, C-01..C-07, B-01..B-07, R-01..R-02, O-03. Security (28 deletions + 10 auth gates): - Delete 28 unauthenticated debug/cursor/firebase/test routes - Gate ai/chat, ai/conversation, context/summarize, work-completed with withTenantProject/withAuth - Add HMAC-SHA256 signature verification to webhooks/coolify - Switch all admin secret comparisons to timingSafeStringEq Foundations (lib/server/*): - api-handler.ts: withAuth, withTenantProject, withWorkspace, withAdminSecret, withRateLimit - logger.ts: structured request-scoped logging with turnId - audit-log.ts: writeAuditLog helper + audit_log table - rate-limit.ts: Postgres sliding window rate limiter - coolify-webhook.ts: verifyCoolifySignature - timing-safe.ts: timingSafeStringEq Chat hardening (chat/route.ts): - MAX_TOOL_ROUNDS 15 → 8 (C-01) - Loop detection: hard-break at 3 identical fingerprints (was 5) (C-02) - Add 6-consecutive-tool-call hard-break (C-02) - Mode: respond first, act second prompt block (C-03) - SSE heartbeat every 25s via setInterval (C-04) - Per-tool 45s timeout via Promise.race (C-05) - turnId per-turn UUID for log correlation (C-06) - Recovery fires when roundsSinceText >= 4 (C-07) - SSE plan event on plan_task_add/edit (B-05) Beta features: - invites table + GET/POST /api/invites (P4.8) - invites/[token] validate + redeem (P4.8) - fs_project_dev_servers table + lib/server/dev-server-state.ts (P6.B1) - fs_project_secrets table + CRUD routes (P6.D2) - lib/integrations/brief-extract.ts (P3.7) Documentation: - app/api/ROUTES.md: full route map with auth + tenant
131 lines
4.6 KiB
TypeScript
131 lines
4.6 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",
|
|
"pdf-parse",
|
|
// Prevents Turbopack from bundling these packages and hitting the
|
|
// import-in-the-middle version mismatch warning on every request.
|
|
// Both ship a nested @opentelemetry/instrumentation@0.212 that wants
|
|
// iitm@2.x, but the project root has iitm@3.x.
|
|
"@fastify/otel",
|
|
"@prisma/instrumentation",
|
|
],
|
|
// 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",
|
|
|
|
// Verbose during beta: we want to *see* "Bundles uploaded: N" in
|
|
// Coolify's build log so we know source maps are flowing. Flip
|
|
// back to `!process.env.CI` once we trust it.
|
|
silent: false,
|
|
|
|
// 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);
|
|
},
|
|
});
|