deer-flow/frontend/next.config.js
DeepCold e17aff57a0
fix(frontend): allow dev-server access from non-localhost hosts (#4471)
Opening the dev stack on a LAN address or a proxied hostname serves the
SSR HTML but never hydrates: Next.js answers /_next/*, /__nextjs_font/*,
and HMR with 403 for any host it was not started on. The page renders, so
it looks up — but no client handler is attached, and the login form's
onSubmit never fires. It reads as "login is broken" rather than as an
asset problem, and the only clue is a warning in the dev-server log.

Wire Next's allowedDevOrigins to a new DEER_FLOW_DEV_ALLOWED_ORIGINS env
var. Unset by default, so the localhost-only default is unchanged; it is
also dev-only, as Next ignores allowedDevOrigins in production builds.

Entries are reduced to the bare host that allowedDevOrigins matches
against, since an entry pasted from the address bar as
"http://192.168.1.10:2026" would otherwise match nothing and leave the
operator with the same 403 they were trying to fix.

Reported in #54 and #203.

Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-07-26 21:34:50 +08:00

84 lines
2.3 KiB
JavaScript

/**
* Run `build` or `dev` with `SKIP_ENV_VALIDATION` to skip env validation. This is especially useful
* for Docker builds.
*/
import "./src/env.js";
import { getAllowedDevOrigins } from "./src/dev-origins.js";
function getInternalServiceURL(envKey, fallbackURL) {
const configured = process.env[envKey]?.trim();
return configured && configured.length > 0
? configured.replace(/\/+$/, "")
: fallbackURL;
}
import nextra from "nextra";
const withNextra = nextra({});
/** @type {import("next").NextConfig} */
const config = {
output:
process.env.NEXT_CONFIG_BUILD_OUTPUT === "standalone"
? "standalone"
: undefined,
i18n: {
locales: ["en", "zh"],
defaultLocale: "en",
},
devIndicators: false,
allowedDevOrigins: getAllowedDevOrigins(),
async rewrites() {
const rewrites = [];
const gatewayURL = getInternalServiceURL(
"DEER_FLOW_INTERNAL_GATEWAY_BASE_URL",
"http://127.0.0.1:8001",
);
if (!process.env.NEXT_PUBLIC_LANGGRAPH_BASE_URL) {
rewrites.push({
source: "/api/langgraph",
destination: `${gatewayURL}/api`,
});
rewrites.push({
source: "/api/langgraph/:path*",
destination: `${gatewayURL}/api/:path*`,
});
}
if (!process.env.NEXT_PUBLIC_BACKEND_BASE_URL) {
rewrites.push({
source: "/api/agents",
destination: `${gatewayURL}/api/agents`,
});
rewrites.push({
source: "/api/agents/:path*",
destination: `${gatewayURL}/api/agents/:path*`,
});
rewrites.push({
source: "/api/skills",
destination: `${gatewayURL}/api/skills`,
});
rewrites.push({
source: "/api/skills/:path*",
destination: `${gatewayURL}/api/skills/:path*`,
});
// Catch-all for remaining gateway API routes (models, threads, memory,
// mcp, artifacts, uploads, suggestions, runs, etc.) that don't have
// their own NEXT_PUBLIC_* env var toggle.
//
// NOTE: this must come AFTER the /api/langgraph rewrite above so that
// LangGraph-compatible routes keep their public prefix while Gateway
// receives its native /api/* paths.
rewrites.push({
source: "/api/:path*",
destination: `${gatewayURL}/api/:path*`,
});
}
return rewrites;
},
};
export default withNextra(config);