mirror of
https://github.com/nexu-io/open-design.git
synced 2026-10-27 09:51:12 +01:00
* feat(dev): add desktop tools-dev control plane * refactor(sidecar): split Open Design contracts Move Open Design-specific sidecar protocol definitions into @open-design/contracts so sidecar and platform can remain descriptor-driven primitives. * refactor(daemon): organize package sources Keep daemon app code, tests, and sidecar entrypoints in separate package directories so each layer can be built and verified independently. * chore(repo): streamline maintenance entrypoints Centralize agent guidance by directory and reduce root command chains while preserving the existing build scope. * docs: translate agent guidance to English * fix(sidecar): tolerate stale IPC sockets Remove stale Unix socket files only after confirming no listener is active, so tools-dev can restart after unclean shutdowns.
74 lines
3.0 KiB
TypeScript
74 lines
3.0 KiB
TypeScript
import type { NextConfig } from 'next';
|
|
import { dirname, isAbsolute, relative } from 'node:path';
|
|
import { fileURLToPath } from 'node:url';
|
|
|
|
// Daemon port the local Express server binds to (see apps/daemon/src/cli.ts). The
|
|
// dev-all launcher overrides OD_PORT after probing for a free port; we read
|
|
// the same env so /api, /artifacts, and /frames always reach the right
|
|
// daemon instance during `next dev`.
|
|
const DAEMON_PORT = Number(process.env.OD_PORT) || 7456;
|
|
const DAEMON_ORIGIN = `http://127.0.0.1:${DAEMON_PORT}`;
|
|
|
|
// We ship as a static export so the existing `od` daemon can keep serving a
|
|
// single-process production build (out/ replaces the old dist/). Project IDs
|
|
// are unbounded user input, so we route everything through a single optional
|
|
// catch-all client page (`app/[[...slug]]/page.tsx`) that reads the URL at
|
|
// runtime — Next.js generates one shell HTML, the daemon falls back to it
|
|
// for any non-API request, and the existing client router renders the right
|
|
// view.
|
|
const isProd = process.env.NODE_ENV !== 'development';
|
|
|
|
const WEB_ROOT = dirname(fileURLToPath(import.meta.url));
|
|
|
|
function resolveDevDistDir() {
|
|
const configured = process.env.OD_WEB_DIST_DIR;
|
|
if (!configured) return '.next';
|
|
return isAbsolute(configured) ? relative(WEB_ROOT, configured) || '.' : configured;
|
|
}
|
|
|
|
const DEV_DIST_DIR = resolveDevDistDir();
|
|
|
|
function resolveDevTsconfigPath() {
|
|
const configured = process.env.OD_WEB_TSCONFIG_PATH;
|
|
if (!configured) return undefined;
|
|
return isAbsolute(configured) ? relative(WEB_ROOT, configured) || 'tsconfig.json' : configured;
|
|
}
|
|
|
|
const DEV_TSCONFIG_PATH = resolveDevTsconfigPath();
|
|
|
|
const nextConfig: NextConfig = {
|
|
allowedDevOrigins: ['127.0.0.1'],
|
|
reactStrictMode: true,
|
|
...(DEV_TSCONFIG_PATH ? { typescript: { tsconfigPath: DEV_TSCONFIG_PATH } } : {}),
|
|
// Keep the bundle output predictable so the daemon's STATIC_DIR can point
|
|
// at it without any glob trickery.
|
|
distDir: isProd ? 'out' : DEV_DIST_DIR,
|
|
...(isProd
|
|
? {
|
|
output: 'export' as const,
|
|
// `next export` skips trailing slashes by default; opting in keeps
|
|
// the daemon's static fallback simple (every directory has its own
|
|
// index.html on disk).
|
|
trailingSlash: true,
|
|
images: { unoptimized: true },
|
|
}
|
|
: {
|
|
async rewrites() {
|
|
// In dev we run the daemon on a sibling port; proxy the app API
|
|
// proxy so the SPA can hit /api, /artifacts, and /frames without
|
|
// CORS gymnastics. SSE on /api/chat works through this rewrite
|
|
// because Next.js's dev server streams responses unbuffered.
|
|
return [
|
|
{ source: '/api/:path*', destination: `${DAEMON_ORIGIN}/api/:path*` },
|
|
{ source: '/artifacts/:path*', destination: `${DAEMON_ORIGIN}/artifacts/:path*` },
|
|
{ source: '/frames/:path*', destination: `${DAEMON_ORIGIN}/frames/:path*` },
|
|
];
|
|
},
|
|
devIndicators: {
|
|
position: 'bottom-right',
|
|
},
|
|
}),
|
|
};
|
|
|
|
export default nextConfig;
|