Some checks are pending
E2E / Playwright e2e (push) Waiting to run
- Updated login and signup components to utilize AuthCard for better user experience during redirection. - Introduced AuthentikEmbedDialog for seamless integration of Authentik's identity portal within the application. - Enhanced password recovery and signup flows with dynamic theme handling and improved loading states. - Refactored existing components to streamline authentication processes and improve maintainability.
161 lines
4.3 KiB
JavaScript
161 lines
4.3 KiB
JavaScript
/*
|
|
* 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"
|
|
|
|
/** "s" for https/wss when SECURE=s (or true/1). */
|
|
function suiteSecureSuffix() {
|
|
const secure = process.env.SECURE?.trim().toLowerCase()
|
|
if (secure === "s" || secure === "true" || secure === "1") return "s"
|
|
return ""
|
|
}
|
|
|
|
/** Derive browser-facing NEXT_PUBLIC_* URLs from PUBLIC_HOST + SECURE. */
|
|
function suitePublicEnv() {
|
|
const host = (
|
|
process.env.PUBLIC_HOST ??
|
|
process.env.DOMAIN ??
|
|
"localhost"
|
|
).trim()
|
|
const s = suiteSecureSuffix()
|
|
const devPort = process.env.NEXT_DEV_PORT?.trim() || "3004"
|
|
const hasPort = host.includes(":")
|
|
const origin =
|
|
s || hasPort ? `http${s}://${host}` : `http${s}://${host}:${devPort}`
|
|
return {
|
|
NEXT_PUBLIC_APP_URL: origin,
|
|
NEXT_PUBLIC_WS_URL: `ws${s}://${host}/ws`,
|
|
NEXT_PUBLIC_OIDC_ISSUER: `${origin}/auth/application/o/ulti/`,
|
|
NEXT_PUBLIC_ONLYOFFICE_URL: `${origin}/office`,
|
|
NEXT_PUBLIC_HOCUSPOCUS_URL: `ws${s}://${host}/collab/`,
|
|
NEXT_PUBLIC_AI_ORIGIN: origin,
|
|
NEXT_PUBLIC_ULTISPACE_ORIGIN: origin,
|
|
}
|
|
}
|
|
|
|
/** Hostnames allowed to load /_next/* in dev (tunnel, LAN, public dev domain). */
|
|
function allowedDevOrigins() {
|
|
const hosts = new Set(["127.0.0.1", "localhost"])
|
|
const publicHost = (
|
|
process.env.PUBLIC_HOST ??
|
|
process.env.DOMAIN ??
|
|
""
|
|
).trim()
|
|
if (publicHost) hosts.add(publicHost)
|
|
const derived = suitePublicEnv().NEXT_PUBLIC_APP_URL
|
|
if (derived) {
|
|
try {
|
|
hosts.add(new URL(derived).hostname)
|
|
} catch {
|
|
/* ignore invalid origin */
|
|
}
|
|
}
|
|
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(),
|
|
env: suitePublicEnv(),
|
|
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
|