forked from CopilotKit/CopilotKit
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathnext.config.ts
More file actions
138 lines (132 loc) · 4.94 KB
/
Copy pathnext.config.ts
File metadata and controls
138 lines (132 loc) · 4.94 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
import type { NextConfig } from "next";
import fs from "fs";
import path from "path";
import { fileURLToPath } from "url";
const __dirname = path.dirname(fileURLToPath(import.meta.url));
function localBackendsEnv(): string {
if (process.env.SHOWCASE_LOCAL !== "1") return "";
const portsPath = path.resolve(__dirname, "..", "shared", "local-ports.json");
if (!fs.existsSync(portsPath)) return "";
const ports = JSON.parse(fs.readFileSync(portsPath, "utf-8")) as Record<
string,
number
>;
const map: Record<string, string> = {};
for (const [slug, port] of Object.entries(ports)) {
map[slug] = `http://localhost:${port}`;
}
return JSON.stringify(map);
}
// Read registry to get the list of framework slugs owned by the docs
// shell. Any path whose first segment is a framework slug must 301 to
// docs.showcase.copilotkit.ai. This list is derived at build time so
// the redirect table tracks registry changes automatically — no manual
// sync between next.config.ts and the docs shell's ownership list.
function frameworkSlugs(): string[] {
const registryPath = path.resolve(__dirname, "src", "data", "registry.json");
if (!fs.existsSync(registryPath)) {
// In production the registry is a required build-time artifact; missing
// it means our redirect table is wrong. Fail loud so the deploy stops
// rather than silently shipping a site where /<slug> 404s. In dev the
// file may legitimately not exist yet (e.g. before generate-registry.ts
// has run) so we stay quiet — returning [] matches dev-server behavior.
if (process.env.NODE_ENV === "production") {
throw new Error(
`[next.config] registry.json missing at ${registryPath} — ` +
`framework redirects cannot be built. Run generate-registry.ts before building.`,
);
}
return [];
}
try {
const registry = JSON.parse(fs.readFileSync(registryPath, "utf-8")) as {
integrations?: { slug: string }[];
};
return (registry.integrations ?? []).map((i) => i.slug);
} catch (err) {
// Corrupt registry: in production, rip the cord — every /<slug> redirect
// would vanish and we'd silently serve 404s for every framework route.
// In dev, log and keep going so the dev loop isn't fatally broken by a
// transient mid-write or bad hand edit.
const message = (err as Error).message;
if (process.env.NODE_ENV === "production") {
throw new Error(
`[next.config] registry.json at ${registryPath} is unparseable: ${message}. ` +
`Refusing to build with missing framework redirects.`,
);
}
console.warn(
`[next.config] registry.json at ${registryPath} is unparseable: ${message}. ` +
`Framework redirects will be empty until fixed.`,
);
return [];
}
}
const DOCS_HOST = "https://docs.showcase.copilotkit.ai";
const nextConfig: NextConfig = {
env: {
// NEXT_PUBLIC_BASE_URL intentionally NOT listed here: it must be
// read at request time via runtime-config (otherwise `next build`
// re-bakes the build-time value into every chunk). NEXT_PUBLIC_LOCAL_BACKENDS
// is fine to bake because it is computed from `shared/local-ports.json`
// (a JSON file on disk, not an env var) and only used in local-dev.
NEXT_PUBLIC_LOCAL_BACKENDS: localBackendsEnv(),
},
serverExternalPackages: ["@copilotkit/runtime", "@copilotkitnext/runtime"],
async redirects() {
const slugs = frameworkSlugs();
// Fixed docs-route redirects — whole sections (docs, ag-ui, reference)
// now live on docs.showcase.copilotkit.ai. Use 301 (permanent) so
// search engines carry authority over to the new host.
const fixed = [
{
source: "/docs",
destination: `${DOCS_HOST}`,
permanent: true,
},
{
source: "/docs/:path*",
destination: `${DOCS_HOST}/:path*`,
permanent: true,
},
{
source: "/ag-ui",
destination: `${DOCS_HOST}/ag-ui`,
permanent: true,
},
{
source: "/ag-ui/:path*",
destination: `${DOCS_HOST}/ag-ui/:path*`,
permanent: true,
},
{
source: "/reference",
destination: `${DOCS_HOST}/reference`,
permanent: true,
},
{
source: "/reference/:path*",
destination: `${DOCS_HOST}/reference/:path*`,
permanent: true,
},
];
// Framework-scoped routes — /<slug> and /<slug>/... both go to the
// docs host. Enumerated from registry rather than a `:slug*` wildcard
// so we DON'T blanket-redirect /integrations or /matrix (which are
// owned by shell).
const frameworkRedirects = slugs.flatMap((slug) => [
{
source: `/${slug}`,
destination: `${DOCS_HOST}/${slug}`,
permanent: true,
},
{
source: `/${slug}/:path*`,
destination: `${DOCS_HOST}/${slug}/:path*`,
permanent: true,
},
]);
return [...fixed, ...frameworkRedirects];
},
};
export default nextConfig;