jamdesk 1.1.5 → 1.1.6

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/dist/lib/deps.js CHANGED
@@ -20,13 +20,13 @@ const DEPS_DIR = path.join(JAMDESK_DIR, 'node_modules');
20
20
  // Match build-service versions exactly
21
21
  const REQUIRED_DEPS = {
22
22
  // Next.js and React
23
- 'next': '^16.2.0',
23
+ 'next': '16.1.7',
24
24
  // OpenAPI validation (for API reference docs)
25
25
  '@apidevtools/swagger-parser': '^12.1.0',
26
26
  'openapi-types': '^12.1.3',
27
27
  'react': '^19.2.4',
28
28
  'react-dom': '^19.2.4',
29
- '@next/mdx': '^16.2.0',
29
+ '@next/mdx': '16.1.7',
30
30
  'next-mdx-remote': '^6.0.0',
31
31
  'next-themes': '^0.4.6',
32
32
  // Icons
@@ -85,7 +85,7 @@ const REQUIRED_DEPS = {
85
85
  '@types/node': '^25.5.0',
86
86
  '@types/react': '^19.2.14',
87
87
  '@types/react-dom': '^19.0.0',
88
- '@next/third-parties': '^16.2.0',
88
+ '@next/third-parties': '16.1.7',
89
89
  };
90
90
  /**
91
91
  * Generate a hash of REQUIRED_DEPS to detect when dependencies change.
@@ -1 +1 @@
1
- {"version":3,"file":"deps.js","sourceRoot":"","sources":["../../src/lib/deps.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"deps.js","sourceRoot":"","sources":["../../src/lib/deps.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "jamdesk",
3
- "version": "1.1.5",
3
+ "version": "1.1.6",
4
4
  "description": "CLI for Jamdesk — build, preview, and deploy documentation sites from MDX. Dev server with hot reload, 50+ components, OpenAPI support, AI search, and Mintlify migration",
5
5
  "keywords": [
6
6
  "jamdesk",
@@ -714,7 +714,7 @@ export default async function DocPage({ params }: PageProps) {
714
714
 
715
715
  {/* Previous/Next Navigation */}
716
716
  <PageNavigation currentSlug={slug.join('/')} config={config} />
717
- <SocialFooter config={config} hidden={data.hideFooter} />
717
+ <SocialFooter config={config} hidden={data.hideFooter} projectSlug={projectSlug ?? undefined} />
718
718
  </article>
719
719
  </ApiPageWrapper></>
720
720
  );
@@ -771,7 +771,7 @@ export default async function DocPage({ params }: PageProps) {
771
771
  {/* Previous/Next Navigation - inside prose to match content width */}
772
772
  <PageNavigation currentSlug={slug.join('/')} config={config} isWideMode={isWideMode || hasPanel} />
773
773
  </div>
774
- <SocialFooter config={config} hidden={data.hideFooter} />
774
+ <SocialFooter config={config} hidden={data.hideFooter} projectSlug={projectSlug ?? undefined} />
775
775
  </article>
776
776
  );
777
777
 
@@ -42,11 +42,8 @@ const DEFAULT_FAVICON = `${ASSET_PREFIX}/branding/favicon.svg`;
42
42
  */
43
43
  function getFaviconPath(favicon: Favicon | undefined, assetVersion?: string): string {
44
44
  if (!favicon) return DEFAULT_FAVICON;
45
- if (typeof favicon === 'string') {
46
- return transformConfigImagePath(favicon, assetVersion) || DEFAULT_FAVICON;
47
- }
48
- // Object format: return light variant (dark mode handled client-side)
49
- return transformConfigImagePath(favicon.light, assetVersion) || DEFAULT_FAVICON;
45
+ const raw = typeof favicon === 'string' ? favicon : favicon.light;
46
+ return transformConfigImagePath(raw, assetVersion) || DEFAULT_FAVICON;
50
47
  }
51
48
 
52
49
  const FALLBACK_METADATA: Metadata = {
@@ -350,7 +347,7 @@ export default async function RootLayout({
350
347
  : null;
351
348
 
352
349
  return (
353
- <html lang="en" suppressHydrationWarning>
350
+ <html lang="en" suppressHydrationWarning data-scroll-behavior="smooth">
354
351
  <head>
355
352
  {/* Add viewport meta for mobile */}
356
353
  <meta name="viewport" content="width=device-width, initial-scale=1" />
@@ -7,18 +7,20 @@ import { getIconClass } from '@/lib/icon-utils';
7
7
  // Branding configuration (read at build time from environment variables)
8
8
  // Uses NEXT_PUBLIC_ prefix so these are inlined during build for client components
9
9
  const showBranding = process.env.NEXT_PUBLIC_SHOW_BRANDING !== 'false'; // Default true
10
- const projectSlug = process.env.NEXT_PUBLIC_PROJECT_SLUG || 'docs';
11
10
 
12
11
  /**
13
- * Generate branding URL with UTM parameters for attribution tracking
12
+ * Generate branding URL with UTM parameters for attribution tracking.
13
+ * projectSlug is passed as a prop (works in ISR multi-tenant mode).
14
+ * Falls back to NEXT_PUBLIC_PROJECT_SLUG env var (works in CLI dev mode).
14
15
  */
15
- function getBrandingUrl(): string {
16
+ function getBrandingUrl(projectSlug: string): string {
16
17
  return `https://www.jamdesk.com?utm_campaign=poweredBy&utm_medium=referral&utm_source=${projectSlug}`;
17
18
  }
18
19
 
19
20
  interface SocialFooterProps {
20
21
  config: DocsConfig;
21
22
  hidden?: boolean;
23
+ projectSlug?: string;
22
24
  }
23
25
 
24
26
  /**
@@ -134,7 +136,7 @@ function SocialIcons({ socials }: { socials: Partial<Record<SocialPlatform, stri
134
136
  );
135
137
  }
136
138
 
137
- export function SocialFooter({ config, hidden }: SocialFooterProps) {
139
+ export function SocialFooter({ config, hidden, projectSlug }: SocialFooterProps) {
138
140
  if (hidden) return null;
139
141
 
140
142
  const { socials, links } = config.footer || {};
@@ -148,6 +150,9 @@ export function SocialFooter({ config, hidden }: SocialFooterProps) {
148
150
  return null;
149
151
  }
150
152
 
153
+ // Resolve slug: prop (ISR) → env var (CLI dev) → fallback
154
+ const slug = projectSlug || process.env.NEXT_PUBLIC_PROJECT_SLUG || 'docs';
155
+
151
156
  return (
152
157
  <footer className="mt-12 sm:mt-16 pt-6 sm:pt-8 border-t border-[var(--color-border)]">
153
158
  {hasLinks && <LinkColumns columns={links} />}
@@ -156,7 +161,7 @@ export function SocialFooter({ config, hidden }: SocialFooterProps) {
156
161
  {hasSocials && <SocialIcons socials={socials} />}
157
162
  {showBranding && (
158
163
  <a
159
- href={getBrandingUrl()}
164
+ href={getBrandingUrl(slug)}
160
165
  target="_blank"
161
166
  rel="noopener noreferrer"
162
167
  className="group flex items-center gap-1 text-sm text-[#AEAEAE] hover:text-[#6A6D70] transition-colors whitespace-nowrap"
@@ -1,17 +1,7 @@
1
1
  'use client';
2
2
 
3
3
  import { useState, useEffect } from 'react';
4
- import { highlightCode } from '@/lib/shiki-client';
5
-
6
- /**
7
- * Escape HTML entities for fallback rendering
8
- */
9
- function escapeHtml(text: string): string {
10
- return text
11
- .replace(/&/g, '&amp;')
12
- .replace(/</g, '&lt;')
13
- .replace(/>/g, '&gt;');
14
- }
4
+ import { escapeHtml, highlightCode } from '@/lib/shiki-client';
15
5
 
16
6
  /**
17
7
  * Hook for async Shiki syntax highlighting
@@ -866,16 +866,25 @@ export function appendAssetVersion(url: string, assetVersion?: string): string {
866
866
  * Transform an image path from /images/... to /_jd/images/...
867
867
  *
868
868
  * Used for config-defined images (favicon, logo) that need the asset prefix.
869
+ * Also normalizes relative paths and strips /public/ prefix (Next.js convention).
869
870
  */
870
871
  export function transformConfigImagePath(
871
872
  path: string | undefined,
872
873
  assetVersion?: string,
873
874
  ): string | undefined {
874
875
  if (!path) return path;
875
- if (path.startsWith('/images/')) {
876
- return appendAssetVersion(ASSET_PREFIX + path, assetVersion);
876
+ // Skip external URLs
877
+ if (path.startsWith('http://') || path.startsWith('https://') || path.startsWith('//')) {
878
+ return path;
877
879
  }
878
- return path;
880
+ // Ensure absolute path — relative paths break on nested routes
881
+ let normalized = path.startsWith('/') ? path : `/${path}`;
882
+ // Strip /public/ prefix (Next.js convention: public/logo.png served at /logo.png)
883
+ normalized = normalized.replace(/^\/public\//, '/');
884
+ if (normalized.startsWith('/images/')) {
885
+ return appendAssetVersion(ASSET_PREFIX + normalized, assetVersion);
886
+ }
887
+ return normalized;
879
888
  }
880
889
 
881
890
  /**
@@ -1,6 +1,7 @@
1
1
  import fs from 'fs';
2
2
  import * as fsPromises from 'fs/promises';
3
3
  import path from 'path';
4
+ import matter from 'gray-matter';
4
5
 
5
6
  // Re-export types from client-safe module
6
7
  export type {
@@ -17,6 +18,11 @@ export { normalizeNavPage } from './docs-types';
17
18
 
18
19
  import type { DocsConfig } from './docs-types';
19
20
  import { normalizeConfig } from './normalize-config';
21
+ import {
22
+ enhanceConfigNavigation,
23
+ RECURSE_KEYS,
24
+ type PageInfo,
25
+ } from './enhance-navigation';
20
26
 
21
27
  /**
22
28
  * Get the current project name from environment variable.
@@ -85,6 +91,70 @@ export function getImagesDir(): string {
85
91
  return path.join(process.cwd(), 'content', 'images');
86
92
  }
87
93
 
94
+ /**
95
+ * Collect all unique page paths from a navigation structure.
96
+ * Walks pages arrays for leaf entries and recurses into groups/tabs/anchors/etc.
97
+ */
98
+ function collectNavPagePaths(nav: unknown, paths = new Set<string>()): Set<string> {
99
+ if (!nav || typeof nav !== 'object') return paths;
100
+ const obj = nav as Record<string, unknown>;
101
+
102
+ if (Array.isArray(obj.pages)) {
103
+ for (const item of obj.pages) {
104
+ if (typeof item === 'string') {
105
+ paths.add(item);
106
+ } else if (item && typeof item === 'object') {
107
+ if ('page' in item) paths.add((item as { page: string }).page);
108
+ if ('group' in item) collectNavPagePaths(item, paths);
109
+ }
110
+ }
111
+ }
112
+
113
+ for (const key of RECURSE_KEYS) {
114
+ if (Array.isArray(obj[key])) {
115
+ for (const child of obj[key] as unknown[]) {
116
+ collectNavPagePaths(child, paths);
117
+ }
118
+ }
119
+ }
120
+
121
+ return paths;
122
+ }
123
+
124
+ /**
125
+ * Extract just the YAML frontmatter from an MDX file without parsing the full body.
126
+ * Reads only the frontmatter block (between --- delimiters) to avoid loading
127
+ * potentially large MDX content into memory.
128
+ */
129
+ function readFrontmatterOnly(filePath: string): Record<string, unknown> {
130
+ const raw = fs.readFileSync(filePath, 'utf8');
131
+ if (!raw.startsWith('---')) return {};
132
+ const endMatch = raw.slice(3).match(/\n---(\r?\n|$)/);
133
+ if (!endMatch) return {};
134
+ // Pass only the frontmatter slice to gray-matter
135
+ const fmEnd = 3 + endMatch.index! + endMatch[0].length;
136
+ const { data } = matter(raw.slice(0, fmEnd));
137
+ return data;
138
+ }
139
+
140
+ /**
141
+ * Enhance navigation config with frontmatter metadata (titles, API methods, icons).
142
+ * Reads MDX frontmatter for all nav pages and merges into the config.
143
+ */
144
+ function enhanceNavInDev(config: DocsConfig): DocsConfig {
145
+ const contentDir = getContentDir();
146
+ const pagePaths = collectNavPagePaths(config.navigation);
147
+ const pageInfos: PageInfo[] = [...pagePaths].map((pagePath) => {
148
+ const mdxPath = path.join(contentDir, pagePath + '.mdx');
149
+ try {
150
+ return { path: pagePath, frontmatter: readFrontmatterOnly(mdxPath), content: '' };
151
+ } catch {
152
+ return { path: pagePath, frontmatter: {}, content: '' };
153
+ }
154
+ });
155
+ return enhanceConfigNavigation(config, pageInfos);
156
+ }
157
+
88
158
  // Cache the config to avoid re-parsing 368KB+ JSON for every page during SSR.
89
159
  // In development, reads from the project source (not public/docs.json) and uses
90
160
  // mtime-based invalidation so docs.json edits are picked up on browser refresh
@@ -108,11 +178,19 @@ export function getDocsConfig(): DocsConfig {
108
178
  }
109
179
  }
110
180
 
181
+ // Capture mtime before reading so we don't need a second statSync
182
+ const currentMtimeMs = fs.statSync(docsPath).mtimeMs;
111
183
  const fileContents = fs.readFileSync(docsPath, 'utf8');
112
184
  const rawConfig = JSON.parse(fileContents);
113
185
 
114
186
  // Normalize Mintlify fields to Jamdesk format
115
- const { config, warnings } = normalizeConfig(rawConfig);
187
+ let { config, warnings } = normalizeConfig(rawConfig);
188
+
189
+ // In dev, enhance navigation with frontmatter (API methods, sidebarTitles, icons).
190
+ // In production/ISR, this is done during the build pipeline before R2 upload.
191
+ if (isDev) {
192
+ config = enhanceNavInDev(config);
193
+ }
116
194
 
117
195
  // Log deprecation warnings (only once due to caching)
118
196
  if (warnings.length > 0 && !deprecationWarningsLogged) {
@@ -123,7 +201,7 @@ export function getDocsConfig(): DocsConfig {
123
201
  }
124
202
 
125
203
  cachedConfig = config;
126
- cachedMtimeMs = fs.statSync(docsPath).mtimeMs;
204
+ cachedMtimeMs = currentMtimeMs;
127
205
  return cachedConfig;
128
206
  }
129
207
 
@@ -70,6 +70,16 @@ export async function collectAssetFiles(projectDir: string): Promise<string[]> {
70
70
  return files;
71
71
  }
72
72
 
73
+ /**
74
+ * Normalize an asset path for R2 storage.
75
+ *
76
+ * Strips leading public/ prefix to match Next.js convention where files in
77
+ * public/ are served at the root URL path (e.g., public/logo.png → /logo.png).
78
+ */
79
+ export function normalizeAssetPath(assetPath: string): string {
80
+ return assetPath.replace(/^public\//, '');
81
+ }
82
+
73
83
  /**
74
84
  * Collect snippet files from project directory.
75
85
  *
@@ -338,6 +338,9 @@ const STATIC_ASSET_PREFIXES = [
338
338
  `${ASSET_PREFIX}/fonts/`, // Font Awesome web fonts
339
339
  ] as const;
340
340
 
341
+ /** Pattern to strip the /_jd/ prefix from asset paths */
342
+ const ASSET_PREFIX_PATTERN = new RegExp(`^${ASSET_PREFIX}/`);
343
+
341
344
  /**
342
345
  * Check if middleware should run for this path.
343
346
  *
@@ -535,8 +538,12 @@ export function isAssetRequest(pathname: string): boolean {
535
538
  * @returns Assets API path (e.g., '/api/assets/images/logo.png')
536
539
  */
537
540
  export function getAssetsApiPath(pathname: string): string {
538
- // Strip asset prefix and leading slash (R2 stores at images/, not _jd/images/)
539
- const prefixPattern = new RegExp(`^${ASSET_PREFIX}/`);
540
- const assetPath = pathname.replace(prefixPattern, '').replace(/^\//, '');
541
+ // Strip /_jd/ prefix and leading slash, then normalize away public/ prefix.
542
+ // Users may reference assets as /public/logo.png (mirroring file-system layout)
543
+ // or /logo.png (Next.js convention) — both resolve to the same R2 key.
544
+ const assetPath = pathname
545
+ .replace(ASSET_PREFIX_PATTERN, '')
546
+ .replace(/^\//, '')
547
+ .replace(/^public\//, '');
541
548
  return `/api/assets/${assetPath}`;
542
549
  }
@@ -1,12 +1,23 @@
1
1
  /**
2
2
  * Client-side Shiki syntax highlighting utility
3
3
  * Used for dynamic code highlighting (e.g., OpenAPI code examples)
4
+ *
5
+ * Uses shiki/core + JavaScript regex engine to avoid WASM loading.
6
+ * Turbopack can't bundle WASM files for client delivery (Next.js #84972),
7
+ * so the default shiki import (which uses Oniguruma WASM) causes ChunkLoadError.
8
+ * The JS engine handles all client languages perfectly without WASM.
4
9
  */
5
10
  'use client';
6
11
 
7
- import type { Highlighter, BundledLanguage, BundledTheme } from 'shiki';
12
+ import type { HighlighterCore } from 'shiki/core';
13
+ import type { BundledLanguage, BundledTheme } from 'shiki';
8
14
 
9
- let highlighter: Highlighter | null = null;
15
+ // Cache the Promise (not the resolved value) to prevent duplicate instances
16
+ // when concurrent callers both see null before the first resolves.
17
+ // Matches the pattern in shiki-highlighter.ts (server-side).
18
+ let highlighterPromise: Promise<HighlighterCore> | null = null;
19
+ // Separate resolved reference for synchronous access (highlightCodeSync)
20
+ let highlighterInstance: HighlighterCore | null = null;
10
21
 
11
22
  // Languages needed for API code examples
12
23
  const CLIENT_LANGUAGES: BundledLanguage[] = [
@@ -25,24 +36,54 @@ const THEMES = {
25
36
  };
26
37
 
27
38
  /**
28
- * Get or initialize the Shiki highlighter for client-side use
39
+ * Get or initialize the Shiki highlighter for client-side use.
40
+ * Uses shiki/core with JavaScript engine (no WASM) for Turbopack compatibility.
29
41
  */
30
- async function getHighlighter(): Promise<Highlighter> {
31
- if (!highlighter) {
32
- const { createHighlighter } = await import('shiki');
33
-
34
- highlighter = await createHighlighter({
35
- themes: [THEMES.dark, THEMES.light],
36
- langs: CLIENT_LANGUAGES,
42
+ async function getHighlighter(): Promise<HighlighterCore> {
43
+ if (!highlighterPromise) {
44
+ highlighterPromise = (async () => {
45
+ const [
46
+ { createHighlighterCore },
47
+ { createJavaScriptRegexEngine },
48
+ ] = await Promise.all([
49
+ import('shiki/core'),
50
+ import('shiki/engine/javascript'),
51
+ ]);
52
+
53
+ // Keep in sync with CLIENT_LANGUAGES above
54
+ const hl = await createHighlighterCore({
55
+ themes: [
56
+ import('shiki/themes/github-dark-default.mjs'),
57
+ import('shiki/themes/github-light-default.mjs'),
58
+ ],
59
+ langs: [
60
+ import('shiki/langs/javascript.mjs'),
61
+ import('shiki/langs/typescript.mjs'),
62
+ import('shiki/langs/python.mjs'),
63
+ import('shiki/langs/bash.mjs'),
64
+ import('shiki/langs/json.mjs'),
65
+ import('shiki/langs/shell.mjs'),
66
+ ],
67
+ engine: createJavaScriptRegexEngine(),
68
+ });
69
+ highlighterInstance = hl;
70
+ return hl;
71
+ })().catch((err) => {
72
+ // Clear cached state so next call retries instead of returning
73
+ // the same rejected promise forever (no page reload needed)
74
+ highlighterPromise = null;
75
+ highlighterInstance = null;
76
+ throw err;
37
77
  });
38
78
  }
39
- return highlighter;
79
+ return highlighterPromise;
40
80
  }
41
81
 
42
82
  /**
43
- * Escape HTML entities for fallback rendering
83
+ * Escape HTML entities for fallback rendering.
84
+ * Exported for reuse by useShikiHighlight hook.
44
85
  */
45
- function escapeHtml(text: string): string {
86
+ export function escapeHtml(text: string): string {
46
87
  return text
47
88
  .replace(/&/g, '&amp;')
48
89
  .replace(/</g, '&lt;')
@@ -56,14 +97,14 @@ function escapeHtml(text: string): string {
56
97
  * This is useful for initial render - the component can re-render when highlighting is done
57
98
  */
58
99
  export function highlightCodeSync(code: string, language: string): string {
59
- if (!highlighter) {
100
+ if (!highlighterInstance) {
60
101
  // Return escaped code if highlighter not ready yet
61
102
  return escapeHtml(code);
62
103
  }
63
104
 
64
105
  try {
65
106
  const lang = normalizeLanguage(language);
66
- return highlighter.codeToHtml(code, {
107
+ return highlighterInstance.codeToHtml(code, {
67
108
  lang,
68
109
  themes: THEMES,
69
110
  defaultColor: 'dark',
@@ -104,6 +145,14 @@ export async function preloadHighlighter(): Promise<void> {
104
145
  await getHighlighter();
105
146
  }
106
147
 
148
+ /**
149
+ * Reset the highlighter cache (useful for testing).
150
+ */
151
+ export function resetClientHighlighterCache(): void {
152
+ highlighterPromise = null;
153
+ highlighterInstance = null;
154
+ }
155
+
107
156
  /**
108
157
  * Normalize language aliases
109
158
  */
@@ -1,7 +1,7 @@
1
1
  /**
2
2
  * Static Artifact Generator for ISR Mode
3
3
  *
4
- * Generates sitemap.xml, llms.txt, robots.txt, feed.xml, and search-data.json
4
+ * Generates sitemap.xml, llms.txt, llms-full.txt, robots.txt, feed.xml, and search-data.json
5
5
  * for ISR projects. These are uploaded to R2 alongside the MDX content.
6
6
  */
7
7
 
@@ -249,6 +249,79 @@ export function extractNavigationPaths(
249
249
  return paths;
250
250
  }
251
251
 
252
+ /**
253
+ * Page info with content for llms-full.txt generation.
254
+ */
255
+ export interface LlmsFullPageInfo {
256
+ /** File path with extension */
257
+ path: string;
258
+ /** Raw MDX content (frontmatter stripped) */
259
+ content: string;
260
+ /** Frontmatter from MDX file */
261
+ frontmatter: {
262
+ title?: string;
263
+ description?: string;
264
+ noindex?: boolean;
265
+ hidden?: boolean;
266
+ seo?: {
267
+ noindex?: boolean;
268
+ };
269
+ };
270
+ }
271
+
272
+ /**
273
+ * Options for generating llms-full.txt.
274
+ */
275
+ export interface LlmsFullTxtOptions {
276
+ /** Documentation name */
277
+ name: string;
278
+ /** Pages with full content */
279
+ pages: LlmsFullPageInfo[];
280
+ /** Block all crawlers - generates empty file */
281
+ noindex?: boolean;
282
+ }
283
+
284
+ /**
285
+ * Generate llms-full.txt with complete documentation content for LLM context windows.
286
+ * Follows https://llmstxt.org/ spec.
287
+ */
288
+ export function generateLlmsFullTxt(options: LlmsFullTxtOptions): string {
289
+ const { name, pages, noindex = false } = options;
290
+
291
+ if (noindex) {
292
+ return '';
293
+ }
294
+
295
+ const visiblePages = pages.filter(p =>
296
+ !p.frontmatter.noindex && !p.frontmatter.hidden && !p.frontmatter.seo?.noindex
297
+ );
298
+
299
+ const parts: string[] = [
300
+ `# ${name} - Complete Documentation\n\n`,
301
+ `> This file contains the complete documentation for ${name}.\n`,
302
+ `> Total pages: ${visiblePages.length}\n\n`,
303
+ `---\n\n`,
304
+ ];
305
+
306
+ for (const page of visiblePages) {
307
+ const title = page.frontmatter.title || page.path.replace(/\.mdx?$/, '');
308
+ parts.push(`## ${title}\n\n`);
309
+
310
+ if (page.frontmatter.description) {
311
+ parts.push(`*${page.frontmatter.description}*\n\n`);
312
+ }
313
+
314
+ const content = page.content.trim();
315
+ if (content) {
316
+ parts.push(`${content}\n\n`);
317
+ }
318
+
319
+ parts.push(`---\n\n`);
320
+ }
321
+
322
+ return parts.join('').trim();
323
+ }
324
+
252
325
  /**
253
326
  * Options for generating all artifacts.
254
327
  */
@@ -269,6 +342,8 @@ export interface GenerateAllOptions {
269
342
  noindex?: boolean;
270
343
  /** Pages with rss: true frontmatter (for RSS feed generation) */
271
344
  rssPages?: RssPageInfo[];
345
+ /** Pages with full content (for llms-full.txt generation) */
346
+ llmsFullPages?: LlmsFullPageInfo[];
272
347
  }
273
348
 
274
349
  /**
@@ -277,6 +352,7 @@ export interface GenerateAllOptions {
277
352
  export interface GeneratedArtifacts {
278
353
  sitemap: string;
279
354
  llmsTxt: string;
355
+ llmsFullTxt: string;
280
356
  robotsTxt: string;
281
357
  rssFeed: string | null;
282
358
  }
@@ -289,13 +365,16 @@ export interface GeneratedArtifacts {
289
365
  */
290
366
  export function generateAllArtifacts(options: GenerateAllOptions): GeneratedArtifacts {
291
367
  const {
292
- baseUrl, name, description, pages, hostAtDocs, noindex, rssPages,
368
+ baseUrl, name, description, pages, hostAtDocs, noindex, rssPages, llmsFullPages,
293
369
  } = options;
294
370
 
295
371
  const sitemap = generateSitemap({ baseUrl, pages, hostAtDocs, noindex });
296
372
  const llmsTxt = generateLlmsTxt({
297
373
  name, description, baseUrl, pages, hostAtDocs, noindex,
298
374
  });
375
+ const llmsFullTxt = llmsFullPages
376
+ ? generateLlmsFullTxt({ name, pages: llmsFullPages, noindex })
377
+ : '';
299
378
  const robotsTxt = generateRobotsTxt({ baseUrl, hostAtDocs, noindex });
300
379
 
301
380
  // Generate RSS feed if any pages have rss: true
@@ -309,7 +388,7 @@ export function generateAllArtifacts(options: GenerateAllOptions): GeneratedArti
309
388
  }
310
389
  }
311
390
 
312
- return { sitemap, llmsTxt, robotsTxt, rssFeed };
391
+ return { sitemap, llmsTxt, llmsFullTxt, robotsTxt, rssFeed };
313
392
  }
314
393
 
315
394
  // =============================================================================
@@ -1,9 +1,9 @@
1
1
  /**
2
- * Shared handler for static file routes (sitemap.xml, robots.txt, llms.txt, search-data.json, feed.xml).
2
+ * Shared handler for static file routes (sitemap.xml, robots.txt, llms.txt, llms-full.txt, search-data.json, feed.xml).
3
3
  *
4
4
  * All static file routes follow the same pattern: check ISR mode, extract project slug,
5
5
  * fetch from R2, and return with appropriate headers. This helper eliminates the
6
- * duplication across 10 route files (5 at root + 5 at /docs).
6
+ * duplication across 12 route files (6 at root + 6 at /docs).
7
7
  */
8
8
 
9
9
  import { NextRequest, NextResponse } from 'next/server';
@@ -12,9 +12,9 @@ import { log } from '@/lib/logger';
12
12
  import { isIsrMode } from '@/lib/page-isr-helpers';
13
13
  import { fetchStaticFile } from '@/lib/r2-content';
14
14
 
15
- /** Filenames served via createStaticFileHandler (5 at root + 5 at /docs). */
15
+ /** Filenames served via createStaticFileHandler (6 at root + 6 at /docs). */
16
16
  export const STATIC_FILE_NAMES = [
17
- 'sitemap.xml', 'robots.txt', 'llms.txt', 'feed.xml', 'search-data.json',
17
+ 'sitemap.xml', 'robots.txt', 'llms.txt', 'llms-full.txt', 'feed.xml', 'search-data.json',
18
18
  ] as const;
19
19
 
20
20
  /** All CDN paths for static file routes — used by revalidation to purge CDN cache. */
@@ -423,15 +423,10 @@ async function runDev() {
423
423
  env,
424
424
  });
425
425
 
426
- // Step 2.5: Enhance navigation with MDX frontmatter (titles, API methods)
427
- console.log('🔧 Enhancing navigation with frontmatter...');
428
- execSync(`node scripts/enhance-navigation.cjs --project ${effectiveProjectName}`, {
429
- stdio: 'inherit',
430
- cwd: path.join(__dirname, '..'),
431
- env,
432
- });
426
+ // Navigation enhancement (titles, API method badges) is now handled inline
427
+ // by getDocsConfig() in dev mode — no separate startup step needed.
433
428
 
434
- // Step 2.6: Compile snippets (if project has snippets folder)
429
+ // Step 2.5: Compile snippets (if project has snippets folder)
435
430
  const snippetsDir = path.join(projectDir, 'snippets');
436
431
  if (fs.existsSync(snippetsDir)) {
437
432
  console.log('🧩 Compiling snippets...');
@@ -461,11 +456,9 @@ async function runDev() {
461
456
  console.log(`\n🚀 Starting dev server on port ${port}...`);
462
457
  // Get first page and OpenAPI config from docs.json (reuse projectDocsJson from step 1)
463
458
  let firstPage = 'introduction';
464
- let hasOpenApi = false;
465
459
  try {
466
460
  const docsConfig = JSON.parse(fs.readFileSync(projectDocsJson, 'utf-8'));
467
461
  firstPage = getFirstPage(docsConfig);
468
- hasOpenApi = Boolean(docsConfig.api?.openapi);
469
462
  } catch {
470
463
  // Fall back to defaults if docs.json can't be read
471
464
  }
@@ -98,42 +98,30 @@ function parseOpenApiMethod(openapiField) {
98
98
  /**
99
99
  * Collect all page paths from navigation structure
100
100
  */
101
+ // Keys whose children are sub-nodes (must stay in sync with enhance-navigation.ts RECURSE_KEYS)
102
+ const RECURSE_KEYS = ['groups', 'tabs', 'anchors', 'dropdowns', 'products', 'versions', 'languages', 'menu'];
103
+
101
104
  function collectPagePaths(navigation, paths = new Set()) {
102
105
  if (!navigation) return paths;
103
106
 
104
- // Handle pages array
107
+ // Handle pages array — contains leaf page entries mixed with nested groups
105
108
  if (navigation.pages && Array.isArray(navigation.pages)) {
106
109
  for (const page of navigation.pages) {
107
- const pagePath = typeof page === 'string' ? page : page?.page;
108
- if (pagePath) paths.add(pagePath);
109
- }
110
- }
111
-
112
- // Handle groups array
113
- if (navigation.groups && Array.isArray(navigation.groups)) {
114
- for (const group of navigation.groups) {
115
- collectPagePaths(group, paths);
116
- }
117
- }
118
-
119
- // Handle tabs array
120
- if (navigation.tabs && Array.isArray(navigation.tabs)) {
121
- for (const tab of navigation.tabs) {
122
- collectPagePaths(tab, paths);
123
- }
124
- }
125
-
126
- // Handle anchors array
127
- if (navigation.anchors && Array.isArray(navigation.anchors)) {
128
- for (const anchor of navigation.anchors) {
129
- collectPagePaths(anchor, paths);
110
+ if (page && typeof page === 'object' && 'group' in page) {
111
+ collectPagePaths(page, paths);
112
+ } else {
113
+ const pagePath = typeof page === 'string' ? page : page?.page;
114
+ if (pagePath) paths.add(pagePath);
115
+ }
130
116
  }
131
117
  }
132
118
 
133
- // Handle languages array (multi-language docs)
134
- if (navigation.languages && Array.isArray(navigation.languages)) {
135
- for (const lang of navigation.languages) {
136
- collectPagePaths(lang, paths);
119
+ // Recurse into all structural keys
120
+ for (const key of RECURSE_KEYS) {
121
+ if (Array.isArray(navigation[key])) {
122
+ for (const child of navigation[key]) {
123
+ collectPagePaths(child, paths);
124
+ }
137
125
  }
138
126
  }
139
127
 
@@ -378,9 +378,7 @@
378
378
  text-decoration: none;
379
379
  }
380
380
 
381
- /* Smooth scrolling for anchor links */
382
381
  html {
383
- scroll-behavior: smooth;
384
382
  /* Prevent horizontal overflow on mobile */
385
383
  overflow-x: hidden;
386
384
  }