/* * Copyright (c) 2026 Eliott Guillaumin * All rights reserved. */ import path from "node:path" import { fileURLToPath } from "node:url" /** @type {import('next').NextConfig} */ const projectRoot = path.dirname(fileURLToPath(import.meta.url)) const ultiProxyOrigin = process.env.ULTI_PROXY_ORIGIN ?? "http://127.0.0.1" /** Hostnames allowed to load /_next/* in dev (tunnel, LAN, public dev domain). */ function allowedDevOrigins() { const hosts = new Set([ "127.0.0.1", "localhost", "192.168.0.20", "100.120.4.66", "dev.ultispace.fr", "dev.ultimail.fr", ]) const appUrl = process.env.NEXT_PUBLIC_APP_URL?.trim() if (appUrl) { try { hosts.add(new URL(appUrl).hostname) } catch { /* ignore invalid NEXT_PUBLIC_APP_URL */ } } return [...hosts] } /** * Mobile (Tauri) build: a fully static export with no server runtime. The * server-only API route handlers are named `route.web.ts` and are excluded * here by NOT registering the `web.ts` page extension (see `pageExtensions`), * so they only compile for the web/standalone build. */ const isMobile = process.env.NEXT_PUBLIC_MOBILE === "1" const webPageExtensions = ["web.tsx", "web.ts", "tsx", "ts", "jsx", "js"] const mobilePageExtensions = ["tsx", "ts", "jsx", "js"] /** @type {import('next').NextConfig} */ const baseConfig = { outputFileTracingRoot: projectRoot, allowedDevOrigins: allowedDevOrigins(), typescript: { ignoreBuildErrors: true, }, images: { unoptimized: true, }, turbopack: { resolveAlias: { canvas: "./lib/empty-module.mjs", }, }, webpack: (config) => { config.resolve.alias = { ...config.resolve.alias, canvas: false, } return config }, } const webConfig = { ...baseConfig, output: "standalone", // Docker standalone tracing only — do not set turbopack.root to projectRoot: // breaks Tailwind @import resolution (resolves from parent /Users/red/workdev). pageExtensions: webPageExtensions, async redirects() { return [ { source: "/mail/settings", destination: "/settings", permanent: true, }, { source: "/mail/settings/:section*", destination: "/settings/:section*", permanent: true, }, { source: "/compte", destination: "/account", permanent: true, }, { source: "/compte/:section*", destination: "/account/:section*", permanent: true, }, ] }, async rewrites() { return [ { source: "/api/v1/:path*", destination: `${ultiProxyOrigin}/api/v1/:path*`, }, { source: "/ai/:path*", destination: `${ultiProxyOrigin}/ai/:path*`, }, { source: "/ai", destination: `${ultiProxyOrigin}/ai`, }, ] }, } const mobileConfig = { ...baseConfig, output: "export", // Mobile shells navigate client-side; the static export serves the start // route (e.g. /mail) and Next's router + native deep-links handle the rest. trailingSlash: true, pageExtensions: mobilePageExtensions, // No rewrites/redirects: the bundle calls an absolute backend URL chosen at // runtime by the server picker, and path redirects run client-side. } const nextConfig = isMobile ? mobileConfig : webConfig export default nextConfig