@lexibase/rdx-next 1.0.0 → 1.1.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/README.md CHANGED
@@ -2,6 +2,11 @@
2
2
 
3
3
  The official Next.js runtime for RDX documentation projects.
4
4
 
5
+ Generated projects use the main `@lexibase/rdx` package. This adapter remains
6
+ available for advanced integrations. It declares the shared UI as a compatible
7
+ peer dependency rather than owning a fixed UI copy. The main package supplies
8
+ the selected UI; direct adapter consumers must install a compatible UI themselves.
9
+
5
10
  Requires Node.js 22.18+ (22.x) or 24.11+ (24.x). Use the latest patch of either line.
6
11
  The MDX renderer keeps JavaScript expression blocking enabled. Markdown, fenced
7
12
  code and registered JSX components with literal props remain supported, but
package/bin/cli.d.mts ADDED
@@ -0,0 +1,2 @@
1
+ /** Run the adapter CLI with an optional prepared runtime template directory. */
2
+ export function runRdxCli(options?: { templateDir?: string }): Promise<void>
package/bin/cli.mjs ADDED
@@ -0,0 +1,129 @@
1
+ import { spawn } from 'node:child_process'
2
+ import { createRequire } from 'node:module'
3
+ import { access, cp, mkdir } from 'node:fs/promises'
4
+ import path from 'node:path'
5
+ import { fileURLToPath } from 'node:url'
6
+ import process from 'node:process'
7
+
8
+ import { createRdxProject } from '@lexibase/rdx-core/config'
9
+ import { createJiti } from 'jiti'
10
+
11
+ import { preparePublicAssets } from './public-assets.mjs'
12
+
13
+ export async function runRdxCli({ templateDir } = {}) {
14
+ const supportedCommands = new Set(['dev', 'build', 'start'])
15
+ let command = process.argv[2]
16
+ const commandArgs = process.argv.slice(3)
17
+ const projectRoot = process.cwd()
18
+ const packageRoot = path.resolve(
19
+ path.dirname(fileURLToPath(import.meta.url)),
20
+ '..'
21
+ )
22
+ const runtimeTemplate =
23
+ templateDir ?? path.join(packageRoot, 'templates', 'runtime')
24
+ const runtimeDirectory = path.join(projectRoot, '.rdx')
25
+
26
+ async function prepareRuntime() {
27
+ await mkdir(runtimeDirectory, { recursive: true })
28
+ await preparePublicAssets(projectRoot, runtimeDirectory)
29
+ await cp(runtimeTemplate, runtimeDirectory, {
30
+ force: true,
31
+ recursive: true,
32
+ })
33
+ }
34
+
35
+ async function main() {
36
+ if (!command || command === 'help' || command === '--help') {
37
+ console.log('Usage: rdx <dev|build|start|prepare|add|plugin-command>')
38
+ console.log(' rdx add versioning [--package-manager npm|pnpm|yarn]')
39
+ console.log(
40
+ 'Plugin commands are registered through plugins in rdx.config.ts.'
41
+ )
42
+ return
43
+ }
44
+
45
+ if (command === 'add') {
46
+ const { addVersioning, parseAddArguments } =
47
+ await import('./add-plugin.mjs')
48
+ const options = parseAddArguments(commandArgs)
49
+ await addVersioning(projectRoot, options)
50
+ command = 'prepare'
51
+ }
52
+
53
+ const configPath = path.join(projectRoot, 'rdx.config.ts')
54
+ try {
55
+ await access(configPath)
56
+ } catch {
57
+ throw new Error(
58
+ `Missing ${configPath}. Run rdx from the documentation project root.`
59
+ )
60
+ }
61
+
62
+ const jiti = createJiti(import.meta.url, {
63
+ moduleCache: false,
64
+ fsCache: false,
65
+ jsx: { runtime: 'automatic' },
66
+ })
67
+ let input
68
+ try {
69
+ input = await jiti.import(configPath, { default: true })
70
+ } catch (error) {
71
+ const hint =
72
+ error.code === 'MODULE_NOT_FOUND' ||
73
+ error.code === 'ERR_MODULE_NOT_FOUND'
74
+ ? ' If a configured plugin cannot be resolved, install its package in this project.'
75
+ : ''
76
+ throw new Error(`Could not load rdx.config.ts: ${error.message}${hint}`)
77
+ }
78
+
79
+ const project = await createRdxProject(input, {
80
+ rootDir: projectRoot,
81
+ command,
82
+ })
83
+ if (command === 'prepare') {
84
+ await prepareRuntime()
85
+ console.log('RDX runtime prepared in .rdx/')
86
+ return
87
+ }
88
+ if (!supportedCommands.has(command)) {
89
+ const pluginCommand = project.commands.find(
90
+ (entry) => entry.name === command
91
+ )
92
+ if (!pluginCommand)
93
+ throw new Error(
94
+ `Unknown command "${command}". Available: dev, build, start, prepare, add${project.commands.map((entry) => `, ${entry.name}`).join('')}. Install and configure the plugin that provides this command.`
95
+ )
96
+ await pluginCommand.run({
97
+ rootDir: projectRoot,
98
+ config: project.config,
99
+ command,
100
+ args: commandArgs,
101
+ })
102
+ return
103
+ }
104
+
105
+ await prepareRuntime()
106
+ const projectRequire = createRequire(path.join(projectRoot, 'package.json'))
107
+ const nextCli = projectRequire.resolve('next/dist/bin/next')
108
+ const child = spawn(
109
+ process.execPath,
110
+ [nextCli, command, runtimeDirectory, ...commandArgs],
111
+ { cwd: projectRoot, stdio: 'inherit' }
112
+ )
113
+ child.on('error', (error) => {
114
+ console.error(`[RDX] Could not start Next.js: ${error.message}`)
115
+ process.exitCode = 1
116
+ })
117
+ child.on('exit', (code, signal) => {
118
+ if (signal) process.kill(process.pid, signal)
119
+ process.exit(code ?? 1)
120
+ })
121
+ }
122
+
123
+ try {
124
+ await main()
125
+ } catch (error) {
126
+ console.error(`[RDX] ${error.message}`)
127
+ process.exitCode = 1
128
+ }
129
+ }
@@ -36,7 +36,11 @@ export function activateVersioning(source) {
36
36
  if (specifier.isTypeOnly) continue
37
37
  const imported = (specifier.propertyName ?? specifier.name).text
38
38
  if (
39
- ['@lexibase/rdx-next', '@lexibase/rdx-core/config'].includes(name) &&
39
+ [
40
+ '@lexibase/rdx',
41
+ '@lexibase/rdx-next',
42
+ '@lexibase/rdx-core/config',
43
+ ].includes(name) &&
40
44
  imported === 'defineConfig'
41
45
  )
42
46
  definitions.add(specifier.name.text)
package/bin/rdx.mjs CHANGED
@@ -1,124 +1,5 @@
1
1
  #!/usr/bin/env node
2
2
 
3
- import { spawn } from 'node:child_process'
4
- import { createRequire } from 'node:module'
5
- import { access, cp, mkdir } from 'node:fs/promises'
6
- import path from 'node:path'
7
- import { fileURLToPath } from 'node:url'
8
- import process from 'node:process'
3
+ import { runRdxCli } from './cli.mjs'
9
4
 
10
- import { createRdxProject } from '@lexibase/rdx-core/config'
11
- import { createJiti } from 'jiti'
12
-
13
- import { preparePublicAssets } from './public-assets.mjs'
14
-
15
- const supportedCommands = new Set(['dev', 'build', 'start'])
16
- let command = process.argv[2]
17
- const commandArgs = process.argv.slice(3)
18
- const projectRoot = process.cwd()
19
- const packageRoot = path.resolve(
20
- path.dirname(fileURLToPath(import.meta.url)),
21
- '..'
22
- )
23
- const runtimeTemplate = path.join(packageRoot, 'templates', 'runtime')
24
- const runtimeDirectory = path.join(projectRoot, '.rdx')
25
-
26
- async function prepareRuntime() {
27
- await mkdir(runtimeDirectory, { recursive: true })
28
- await preparePublicAssets(projectRoot, runtimeDirectory)
29
- await cp(runtimeTemplate, runtimeDirectory, { force: true, recursive: true })
30
- }
31
-
32
- async function main() {
33
- if (!command || command === 'help' || command === '--help') {
34
- console.log('Usage: rdx <dev|build|start|prepare|add|plugin-command>')
35
- console.log(' rdx add versioning [--package-manager npm|pnpm|yarn]')
36
- console.log(
37
- 'Plugin commands are registered through plugins in rdx.config.ts.'
38
- )
39
- return
40
- }
41
-
42
- if (command === 'add') {
43
- const { addVersioning, parseAddArguments } =
44
- await import('./add-plugin.mjs')
45
- const options = parseAddArguments(commandArgs)
46
- await addVersioning(projectRoot, options)
47
- command = 'prepare'
48
- }
49
-
50
- const configPath = path.join(projectRoot, 'rdx.config.ts')
51
- try {
52
- await access(configPath)
53
- } catch {
54
- throw new Error(
55
- `Missing ${configPath}. Run rdx from the documentation project root.`
56
- )
57
- }
58
-
59
- const jiti = createJiti(import.meta.url, {
60
- moduleCache: false,
61
- fsCache: false,
62
- jsx: { runtime: 'automatic' },
63
- })
64
- let input
65
- try {
66
- input = await jiti.import(configPath, { default: true })
67
- } catch (error) {
68
- const hint =
69
- error.code === 'MODULE_NOT_FOUND' || error.code === 'ERR_MODULE_NOT_FOUND'
70
- ? ' If a configured plugin cannot be resolved, install its package in this project.'
71
- : ''
72
- throw new Error(`Could not load rdx.config.ts: ${error.message}${hint}`)
73
- }
74
-
75
- const project = await createRdxProject(input, {
76
- rootDir: projectRoot,
77
- command,
78
- })
79
- if (command === 'prepare') {
80
- await prepareRuntime()
81
- console.log('RDX runtime prepared in .rdx/')
82
- return
83
- }
84
- if (!supportedCommands.has(command)) {
85
- const pluginCommand = project.commands.find(
86
- (entry) => entry.name === command
87
- )
88
- if (!pluginCommand)
89
- throw new Error(
90
- `Unknown command "${command}". Available: dev, build, start, prepare, add${project.commands.map((entry) => `, ${entry.name}`).join('')}. Install and configure the plugin that provides this command.`
91
- )
92
- await pluginCommand.run({
93
- rootDir: projectRoot,
94
- config: project.config,
95
- command,
96
- args: commandArgs,
97
- })
98
- return
99
- }
100
-
101
- await prepareRuntime()
102
- const projectRequire = createRequire(path.join(projectRoot, 'package.json'))
103
- const nextCli = projectRequire.resolve('next/dist/bin/next')
104
- const child = spawn(
105
- process.execPath,
106
- [nextCli, command, runtimeDirectory, ...commandArgs],
107
- { cwd: projectRoot, stdio: 'inherit' }
108
- )
109
- child.on('error', (error) => {
110
- console.error(`[RDX] Could not start Next.js: ${error.message}`)
111
- process.exitCode = 1
112
- })
113
- child.on('exit', (code, signal) => {
114
- if (signal) process.kill(process.pid, signal)
115
- process.exit(code ?? 1)
116
- })
117
- }
118
-
119
- try {
120
- await main()
121
- } catch (error) {
122
- console.error(`[RDX] ${error.message}`)
123
- process.exitCode = 1
124
- }
5
+ await runRdxCli()
@@ -9,6 +9,11 @@ declare function getSearchSources(project: RdxProject): {
9
9
  }[];
10
10
  declare function getSearchResponse(project: RdxProject, key: string): Response;
11
11
 
12
+ /** Read metadata from the same content source and index used by the page. */
13
+ declare function getDocumentMetadata({ project, slug, }: {
14
+ project: RdxProject;
15
+ slug?: string[];
16
+ }): Metadata;
12
17
  /** Translate the shared configuration through Next's native Metadata API. */
13
18
  declare function getRdxMetadata(config: RDXConfig): Metadata;
14
19
 
@@ -25,4 +30,4 @@ declare function DocsPage({ slug, project, }: {
25
30
  project: RdxProject;
26
31
  }): Promise<react.JSX.Element>;
27
32
 
28
- export { DocsPage, HomePage, RdxLayout, getRdxMetadata, getSearchResponse, getSearchSources };
33
+ export { DocsPage, HomePage, RdxLayout, getDocumentMetadata, getRdxMetadata, getSearchResponse, getSearchSources };
@@ -3,7 +3,7 @@ import {
3
3
  getDocument as getDocument2,
4
4
  getDocsPaths,
5
5
  getSourceOptions as getSourceOptions2,
6
- resolveDocsRoute
6
+ resolveDocsRoute as resolveDocsRoute2
7
7
  } from "@lexibase/rdx-core";
8
8
  import { Button } from "@lexibase/rdx-ui/components/button";
9
9
  import { ButtonLink } from "@lexibase/rdx-ui/components/button-link";
@@ -18,7 +18,7 @@ import {
18
18
  VersionDropdown
19
19
  } from "@lexibase/rdx-ui/components/version-dropdown";
20
20
  import { ThemeProvider } from "@lexibase/rdx-ui/providers/theme-provider";
21
- import { notFound, redirect } from "next/navigation";
21
+ import { notFound as notFound2, redirect } from "next/navigation";
22
22
 
23
23
  // src/runtime/mdx.ts
24
24
  import { compileMDX } from "next-mdx-remote/rsc";
@@ -76,6 +76,21 @@ function getSearchResponse(project, key) {
76
76
  }
77
77
 
78
78
  // src/runtime/metadata.ts
79
+ import { resolveDocsRoute } from "@lexibase/rdx-core";
80
+ import { notFound } from "next/navigation";
81
+ function getDocumentMetadata({
82
+ project,
83
+ slug
84
+ }) {
85
+ const route = resolveDocsRoute(project, slug);
86
+ if (!route.slug) return {};
87
+ if (!route.document) notFound();
88
+ const page = route.categories.flatMap((category) => category.pages).find((page2) => page2.slug === route.slug);
89
+ return {
90
+ title: page.title,
91
+ description: page.description || project.config.description
92
+ };
93
+ }
79
94
  function getRdxMetadata(config) {
80
95
  const { metadataBase, ...metadata } = config.metadata;
81
96
  const name = metadata.applicationName;
@@ -127,7 +142,7 @@ function RdxHeader({
127
142
  slug
128
143
  }) {
129
144
  const { config } = project;
130
- const { source, slug: currentSlug } = resolveDocsRoute(project, slug);
145
+ const { source, slug: currentSlug } = resolveDocsRoute2(project, slug);
131
146
  const options = project.sources.map((edition) => {
132
147
  const docs = getSourceOptions2(project, edition);
133
148
  const destination = currentSlug && getDocument2(currentSlug, docs) ? currentSlug : getDocsPaths(docs)[0];
@@ -196,7 +211,7 @@ async function DocsPage({
196
211
  slug: currentSlug,
197
212
  document,
198
213
  categories
199
- } = resolveDocsRoute(project, slug);
214
+ } = resolveDocsRoute2(project, slug);
200
215
  if (!currentSlug)
201
216
  return /* @__PURE__ */ jsxs(Fragment, { children: [
202
217
  /* @__PURE__ */ jsx(RdxHeader, { project, slug }),
@@ -205,7 +220,7 @@ async function DocsPage({
205
220
  /* @__PURE__ */ jsx("p", { children: "Add an .mdx file inside your configured documentation directory." })
206
221
  ] })
207
222
  ] });
208
- if (!document) notFound();
223
+ if (!document) notFound2();
209
224
  const { content } = await compileDocumentation(
210
225
  document.content,
211
226
  mdxComponents,
@@ -314,6 +329,7 @@ export {
314
329
  HomePage,
315
330
  RdxLayout,
316
331
  createRdxProject,
332
+ getDocumentMetadata,
317
333
  getProjectDocsPaths,
318
334
  getRdxMetadata,
319
335
  getSearchResponse,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lexibase/rdx-next",
3
- "version": "1.0.0",
3
+ "version": "1.1.0",
4
4
  "description": "The Next.js runtime for RDX documentation projects.",
5
5
  "license": "MIT",
6
6
  "type": "module",
@@ -11,6 +11,11 @@
11
11
  "rdx": "./bin/rdx.mjs"
12
12
  },
13
13
  "exports": {
14
+ "./package.json": "./package.json",
15
+ "./cli": {
16
+ "types": "./bin/cli.d.mts",
17
+ "import": "./bin/cli.mjs"
18
+ },
14
19
  "./config": {
15
20
  "types": "./config.d.mts",
16
21
  "import": "./config.mjs"
@@ -46,11 +51,11 @@
46
51
  "next-mdx-remote": "^6.0.0",
47
52
  "remark-gfm": "^4",
48
53
  "typescript": "6.0.3",
49
- "@lexibase/rdx-core": "1.0.0",
50
- "@lexibase/rdx-ui": "1.0.0",
51
- "@lexibase/rdx-types": "1.0.0"
54
+ "@lexibase/rdx-types": "1.0.0",
55
+ "@lexibase/rdx-core": "1.0.0"
52
56
  },
53
57
  "peerDependencies": {
58
+ "@lexibase/rdx-ui": "^1.0.0",
54
59
  "next": "^16.4.2",
55
60
  "react": "^19.3.1",
56
61
  "react-dom": "^19.3.1"
@@ -75,12 +80,13 @@
75
80
  "next": "^16.4.2",
76
81
  "react": "19.3.1",
77
82
  "react-dom": "19.3.1",
78
- "@rdx/typescript-config": "1.0.0",
79
- "@rdx/eslint-config": "1.0.0"
83
+ "@lexibase/rdx-ui": "1.0.0",
84
+ "@rdx/eslint-config": "1.0.0",
85
+ "@rdx/typescript-config": "1.0.0"
80
86
  },
81
87
  "scripts": {
82
- "dev": "tsup src/index.ts src/runtime/index.tsx --format esm --dts --watch --external @lexibase/rdx-core --external @lexibase/rdx-types --external next --external react --external react-dom --external next-mdx-remote",
83
- "build": "tsup src/index.ts src/runtime/index.tsx --format esm --dts --clean --external @lexibase/rdx-core --external @lexibase/rdx-types --external next --external react --external react-dom --external next-mdx-remote",
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",
89
+ "build": "tsup src/index.ts src/runtime/index.tsx --format esm --dts --clean --external @lexibase/rdx-core --external @lexibase/rdx-types --external @lexibase/rdx-ui --external next --external react --external react-dom --external next-mdx-remote",
84
90
  "lint": "eslint . --max-warnings 0",
85
91
  "check-types": "tsc --noEmit",
86
92
  "test": "node --test tests/*.test.mjs",
@@ -1,7 +1,21 @@
1
- import { DocsPage, getProjectDocsPaths } from '@lexibase/rdx-next/runtime'
1
+ import type { Metadata } from 'next'
2
+ import {
3
+ DocsPage,
4
+ getDocumentMetadata,
5
+ getProjectDocsPaths,
6
+ } from '@lexibase/rdx-next/runtime'
2
7
 
3
8
  import { getProject } from '../../../rdx-project'
4
9
 
10
+ export async function generateMetadata({
11
+ params,
12
+ }: {
13
+ params: Promise<{ slug?: string[] }>
14
+ }): Promise<Metadata> {
15
+ const { slug } = await params
16
+ return getDocumentMetadata({ project: await getProject(), slug })
17
+ }
18
+
5
19
  export async function generateStaticParams() {
6
20
  return getProjectDocsPaths(await getProject()).map((slug) => ({
7
21
  slug: slug.split('/'),