@lexibase/rdx-next 3.1.0 → 3.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/config.d.mts CHANGED
@@ -1,8 +1,13 @@
1
1
  /** Common build root for the documentation project and its installed Next.js. */
2
2
  export function getRdxBuildRoot(rootDir: string): Promise<string>
3
3
 
4
- /** Explicit deployment files for a native Next.js application using RDX. */
4
+ /** Explicit deployment files and historical route redirects for a native Next.js application. */
5
5
  export function getRdxTracingConfig(options: {
6
6
  rootDir: string
7
7
  appDir?: string
8
- }): Promise<{ outputFileTracingIncludes: Record<string, string[]> }>
8
+ }): Promise<{
9
+ outputFileTracingIncludes: Record<string, string[]>
10
+ redirects?: () => Promise<
11
+ { source: string; destination: string; permanent: boolean }[]
12
+ >
13
+ }>
package/config.mjs CHANGED
@@ -62,7 +62,7 @@ function literalPattern(filename) {
62
62
  .replace(/([*?[\]{}()!+@])/g, '\\$1')
63
63
  }
64
64
 
65
- /** Next.js tracing for configured RDX content, independent of plugin names. */
65
+ /** Next.js tracing and historical route redirects, independent of plugin names. */
66
66
  export async function getRdxTracingConfig({ rootDir, appDir = rootDir }) {
67
67
  rootDir = path.resolve(rootDir)
68
68
  appDir = path.resolve(appDir)
@@ -77,11 +77,17 @@ export async function getRdxTracingConfig({ rootDir, appDir = rootDir }) {
77
77
  const project = await createRdxProject(input, { rootDir })
78
78
  const files = (
79
79
  await Promise.all(
80
- project.sources.map((source) =>
81
- contentFiles(
82
- resolveProjectPath(rootDir, source.docsDir, 'content source docsDir')
80
+ project.sources
81
+ .filter((source) => source.redirectTo === undefined)
82
+ .map((source) =>
83
+ contentFiles(
84
+ resolveProjectPath(
85
+ rootDir,
86
+ source.docsDir,
87
+ 'content source docsDir'
88
+ )
89
+ )
83
90
  )
84
- )
85
91
  )
86
92
  ).flat()
87
93
  for (const filename of project.runtimeFiles) {
@@ -94,7 +100,15 @@ export async function getRdxTracingConfig({ rootDir, appDir = rootDir }) {
94
100
  throw new Error(`Plugin runtimeFiles must name a file: ${filename}`)
95
101
  files.push(resolved)
96
102
  }
103
+ const redirects = project.sources
104
+ .filter((source) => source.redirectTo !== undefined)
105
+ .map((source) => ({
106
+ source: `/docs/${source.routePrefix}/:path*`,
107
+ destination: `/docs/${source.redirectTo}/:path*`,
108
+ permanent: true,
109
+ }))
97
110
  return {
111
+ ...(redirects.length ? { redirects: async () => redirects } : {}),
98
112
  outputFileTracingIncludes: {
99
113
  '/*': [
100
114
  ...new Set(
@@ -11,6 +11,7 @@ import { DocsToc } from "@lexibase/rdx-ui/components/docs-toc";
11
11
  import { DocsPageTransition } from "@lexibase/rdx-ui/components/docs-page-transition";
12
12
  import { DocsSearch } from "@lexibase/rdx-ui/components/docs-search";
13
13
  import { Home } from "@lexibase/rdx-ui/components/home";
14
+ import { SkipLink } from "@lexibase/rdx-ui/components/skip-link";
14
15
  import { FooterCredit } from "@lexibase/rdx-ui/components/footer-credit";
15
16
  import { Logo } from "@lexibase/rdx-ui/components/logo";
16
17
  import { getMdxComponents } from "@lexibase/rdx-ui/components/mdx-components";
@@ -22,7 +23,7 @@ import {
22
23
  VersionDropdown
23
24
  } from "@lexibase/rdx-ui/components/version-dropdown";
24
25
  import { ThemeProvider } from "@lexibase/rdx-ui/providers/theme-provider";
25
- import { notFound as notFound2, redirect } from "next/navigation";
26
+ import { notFound as notFound2, redirect, permanentRedirect } from "next/navigation";
26
27
 
27
28
  // src/runtime/mdx.ts
28
29
  import { compileMDX } from "next-mdx-remote/rsc";
@@ -59,12 +60,12 @@ import { createRdxProject, getProjectDocsPaths } from "@lexibase/rdx-core";
59
60
  import { getDocsIndex, getDocument, getSourceOptions } from "@lexibase/rdx-core";
60
61
  import { buildSearchIndex } from "@lexibase/rdx-core/search";
61
62
  function getSearchSources(project) {
62
- return project.config.search ? project.sources.map((source) => ({ source: source.routePrefix || "_" })) : [];
63
+ return project.config.search ? project.sources.filter((source) => source.redirectTo === void 0).map((source) => ({ source: source.routePrefix || "_" })) : [];
63
64
  }
64
65
  function getSearchResponse(project, key) {
65
66
  if (!project.config.search) return new Response(null, { status: 404 });
66
67
  const source = project.sources.find(
67
- (entry) => (entry.routePrefix || "_") === key
68
+ (entry) => entry.redirectTo === void 0 && (entry.routePrefix || "_") === key
68
69
  );
69
70
  if (!source) return new Response(null, { status: 404 });
70
71
  const options = getSourceOptions(project, source);
@@ -92,6 +93,7 @@ function getDocumentMetadata({
92
93
  slug
93
94
  }) {
94
95
  const route = resolveDocsRoute(project, slug);
96
+ if (route.source.redirectTo !== void 0) return {};
95
97
  if (!route.slug) return {};
96
98
  if (!route.document) notFound();
97
99
  const page = route.categories.flatMap((category) => category.pages).find((page2) => page2.slug === route.slug);
@@ -140,7 +142,6 @@ function RdxLayout({
140
142
  config,
141
143
  bodyClassName
142
144
  }) {
143
- const messages = getMessages(config.lang);
144
145
  return /* @__PURE__ */ jsx("html", { suppressHydrationWarning: true, lang: config.lang ?? "en", children: /* @__PURE__ */ jsx("body", { className: bodyClassName, children: /* @__PURE__ */ jsx(
145
146
  ThemeProvider,
146
147
  {
@@ -149,7 +150,7 @@ function RdxLayout({
149
150
  attribute: "class",
150
151
  defaultTheme: config.theme?.defaultTheme ?? "system",
151
152
  children: /* @__PURE__ */ jsxs(LocaleProvider, { lang: config.lang, children: [
152
- /* @__PURE__ */ jsx("a", { className: "rdx-skip-link", href: "#rdx-main", children: messages.skipContent }),
153
+ /* @__PURE__ */ jsx(SkipLink, { lang: config.lang }),
153
154
  /* @__PURE__ */ jsx("div", { className: "flex flex-col h-dvh", children })
154
155
  ] })
155
156
  }
@@ -162,7 +163,7 @@ function RdxHeader({
162
163
  const { config } = project;
163
164
  const messages = getMessages(config.lang);
164
165
  const { source, slug: currentSlug } = resolveDocsRoute2(project, slug);
165
- const options = project.sources.map((edition) => {
166
+ const options = project.sources.filter((edition) => edition.redirectTo === void 0).map((edition) => {
166
167
  const docs = getSourceOptions2(project, edition);
167
168
  const destination = currentSlug && getDocument2(currentSlug, docs) ? currentSlug : getDocsPaths(docs)[0];
168
169
  return {
@@ -239,6 +240,14 @@ async function DocsPage({
239
240
  document,
240
241
  categories
241
242
  } = resolveDocsRoute2(project, slug);
243
+ if (source.redirectTo !== void 0)
244
+ permanentRedirect(
245
+ [
246
+ "/docs",
247
+ source.redirectTo,
248
+ ...slug?.slice(1).map(encodeURIComponent) ?? []
249
+ ].join("/")
250
+ );
242
251
  if (!currentSlug)
243
252
  return /* @__PURE__ */ jsxs(Fragment, { children: [
244
253
  /* @__PURE__ */ jsx(RdxHeader, { project, slug }),
@@ -302,23 +311,23 @@ async function DocsPage({
302
311
  {
303
312
  className: `w-full min-h-full bg-background px-7 flex flex-col gap-5 pb-8 md:py-8 ${project.config.TOC ? "xl:pr-20" : ""}`,
304
313
  children: [
305
- /* @__PURE__ */ jsxs("div", { className: "w-full flex flex-col gap-5 md:mx-auto md:max-w-[860px] pt-14 md:pt-0 flex-1", children: [
306
- /* @__PURE__ */ jsxs("header", { className: "mb-6", children: [
307
- source.badge && /* @__PURE__ */ jsx("p", { className: "text-sm text-muted-foreground mb-4", children: source.badge === "Archived" ? messages.archivedVersion : source.badge }),
308
- /* @__PURE__ */ jsx("span", { className: "text-xs text-zinc-600 font-semibold uppercase block -mb-0.5", children: category?.title }),
309
- /* @__PURE__ */ jsx("h1", { className: "text-4xl uppercase font-bold mb-2", children: title }),
310
- description && /* @__PURE__ */ jsx("p", { className: "text-sm text-ring max-w-[726px]", children: description })
311
- ] }),
312
- /* @__PURE__ */ jsx(
313
- "main",
314
- {
315
- id: "rdx-main",
316
- tabIndex: -1,
317
- className: "h-full w-full flex-1 max-w-[960px]",
318
- children: content
319
- }
320
- )
321
- ] }),
314
+ /* @__PURE__ */ jsxs(
315
+ "main",
316
+ {
317
+ id: "rdx-main",
318
+ tabIndex: -1,
319
+ className: "w-full flex flex-col gap-5 md:mx-auto md:max-w-[860px] pt-14 md:pt-0 flex-1 outline-none",
320
+ children: [
321
+ /* @__PURE__ */ jsxs("header", { className: "mb-6", children: [
322
+ source.badge && /* @__PURE__ */ jsx("p", { className: "text-sm text-muted-foreground mb-4", children: source.badge === "Archived" ? messages.archivedVersion : source.badge }),
323
+ /* @__PURE__ */ jsx("span", { className: "text-xs text-zinc-600 font-semibold uppercase block -mb-0.5", children: category?.title }),
324
+ /* @__PURE__ */ jsx("h1", { className: "text-4xl uppercase font-bold mb-2", children: title }),
325
+ description && /* @__PURE__ */ jsx("p", { className: "text-sm text-ring max-w-[726px]", children: description })
326
+ ] }),
327
+ /* @__PURE__ */ jsx("div", { className: "h-full w-full flex-1 max-w-[960px]", children: content })
328
+ ]
329
+ }
330
+ ),
322
331
  /* @__PURE__ */ jsxs("footer", { className: "flex flex-col", children: [
323
332
  /* @__PURE__ */ jsxs("section", { className: "flex items-center justify-between", children: [
324
333
  previous ? /* @__PURE__ */ jsx(
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lexibase/rdx-next",
3
- "version": "3.1.0",
3
+ "version": "3.2.0",
4
4
  "description": "The Next.js runtime for RDX documentation projects.",
5
5
  "license": "MIT",
6
6
  "type": "module",
@@ -51,11 +51,11 @@
51
51
  "next-mdx-remote": "^6.0.0",
52
52
  "remark-gfm": "^4",
53
53
  "typescript": "6.0.3",
54
- "@lexibase/rdx-types": "1.1.1",
55
- "@lexibase/rdx-core": "1.3.0"
54
+ "@lexibase/rdx-core": "1.4.0",
55
+ "@lexibase/rdx-types": "1.2.0"
56
56
  },
57
57
  "peerDependencies": {
58
- "@lexibase/rdx-ui": "^3.1.0",
58
+ "@lexibase/rdx-ui": "^3.2.0",
59
59
  "next": "^16.4.2",
60
60
  "react": "^19.3.1",
61
61
  "react-dom": "^19.3.1"
@@ -80,9 +80,9 @@
80
80
  "next": "^16.4.2",
81
81
  "react": "19.3.1",
82
82
  "react-dom": "19.3.1",
83
- "@rdx/eslint-config": "1.0.0",
84
- "@lexibase/rdx-ui": "3.1.0",
85
- "@rdx/typescript-config": "1.0.0"
83
+ "@lexibase/rdx-ui": "3.2.0",
84
+ "@rdx/typescript-config": "1.0.0",
85
+ "@rdx/eslint-config": "1.0.0"
86
86
  },
87
87
  "scripts": {
88
88
  "dev": "tsup src/index.ts src/runtime/index.tsx --format esm --dts --watch --external @lexibase/rdx-core --external @lexibase/rdx-types --external @lexibase/rdx-ui --external next --external react --external react-dom --external next-mdx-remote",
@@ -2,16 +2,4 @@
2
2
  /* Register the entry file directly: consumer ignore rules can hide nested dist folders. */
3
3
  @source '../../dist/runtime/index.js';
4
4
 
5
- /* Colors, buttons, dropdowns and typography come from the shared UI theme. */
6
- .rdx-skip-link {
7
- position: fixed;
8
- top: -100px;
9
- left: 16px;
10
- z-index: 100;
11
- padding: 12px;
12
- background: var(--background);
13
- color: var(--foreground);
14
- }
15
- .rdx-skip-link:focus {
16
- top: 12px;
17
- }
5
+ /* Colors, focus navigation and typography come from the shared UI theme. */