jamdesk 1.1.79 → 1.1.80

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.
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=api-page-panel-validator.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"api-page-panel-validator.test.d.ts","sourceRoot":"","sources":["../../../src/__tests__/unit/api-page-panel-validator.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,30 @@
1
+ import { describe, it, expect } from 'vitest';
2
+ import { validateApiPagePanels } from '../../lib/api-page-panel-validator.js';
3
+ const apiFront = `---
4
+ title: Get Batch
5
+ api: 'GET /v1/foo'
6
+ ---
7
+ `;
8
+ const openapiFront = `---
9
+ title: Get Batch
10
+ openapi: 'GET /v1/foo'
11
+ ---
12
+ `;
13
+ const fenced = '\n```bash\ncurl X\n```\n';
14
+ const wrapped = '\n<RequestExample>\n\n```bash\ncurl X\n```\n\n</RequestExample>\n';
15
+ describe('cli/api-page-panel-validator', () => {
16
+ it('warns on api: page with inline code', () => {
17
+ expect(validateApiPagePanels('p.mdx', apiFront + fenced)).not.toBeNull();
18
+ });
19
+ it('skips openapi: pages', () => {
20
+ expect(validateApiPagePanels('p.mdx', openapiFront + fenced)).toBeNull();
21
+ });
22
+ it('clean when wrappers present', () => {
23
+ expect(validateApiPagePanels('p.mdx', apiFront + wrapped)).toBeNull();
24
+ });
25
+ it('warns when wrapper name is only mentioned in inline backticks', () => {
26
+ const body = '\nUse the `<RequestExample>` component to wrap each example.\n' + fenced;
27
+ expect(validateApiPagePanels('p.mdx', apiFront + body)).not.toBeNull();
28
+ });
29
+ });
30
+ //# sourceMappingURL=api-page-panel-validator.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"api-page-panel-validator.test.js","sourceRoot":"","sources":["../../../src/__tests__/unit/api-page-panel-validator.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,EAAE,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AAC9C,OAAO,EAAE,qBAAqB,EAAE,MAAM,uCAAuC,CAAC;AAE9E,MAAM,QAAQ,GAAG;;;;CAIhB,CAAC;AACF,MAAM,YAAY,GAAG;;;;CAIpB,CAAC;AACF,MAAM,MAAM,GAAG,0BAA0B,CAAC;AAC1C,MAAM,OAAO,GAAG,mEAAmE,CAAC;AAEpF,QAAQ,CAAC,8BAA8B,EAAE,GAAG,EAAE;IAC5C,EAAE,CAAC,qCAAqC,EAAE,GAAG,EAAE;QAC7C,MAAM,CAAC,qBAAqB,CAAC,OAAO,EAAE,QAAQ,GAAG,MAAM,CAAC,CAAC,CAAC,GAAG,CAAC,QAAQ,EAAE,CAAC;IAC3E,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,sBAAsB,EAAE,GAAG,EAAE;QAC9B,MAAM,CAAC,qBAAqB,CAAC,OAAO,EAAE,YAAY,GAAG,MAAM,CAAC,CAAC,CAAC,QAAQ,EAAE,CAAC;IAC3E,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,6BAA6B,EAAE,GAAG,EAAE;QACrC,MAAM,CAAC,qBAAqB,CAAC,OAAO,EAAE,QAAQ,GAAG,OAAO,CAAC,CAAC,CAAC,QAAQ,EAAE,CAAC;IACxE,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,+DAA+D,EAAE,GAAG,EAAE;QACvE,MAAM,IAAI,GACR,gEAAgE,GAAG,MAAM,CAAC;QAC5E,MAAM,CAAC,qBAAqB,CAAC,OAAO,EAAE,QAAQ,GAAG,IAAI,CAAC,CAAC,CAAC,GAAG,CAAC,QAAQ,EAAE,CAAC;IACzE,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"validate.d.ts","sourceRoot":"","sources":["../../src/commands/validate.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAeH,MAAM,WAAW,eAAe;IAC9B,OAAO,EAAE,OAAO,CAAC;IACjB,OAAO,CAAC,EAAE,OAAO,CAAC;CACnB;AAUD,wBAAsB,QAAQ,CAAC,OAAO,EAAE,eAAe,GAAG,OAAO,CAAC,IAAI,CAAC,CAgPtE"}
1
+ {"version":3,"file":"validate.d.ts","sourceRoot":"","sources":["../../src/commands/validate.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAgBH,MAAM,WAAW,eAAe;IAC9B,OAAO,EAAE,OAAO,CAAC;IACjB,OAAO,CAAC,EAAE,OAAO,CAAC;CACnB;AAUD,wBAAsB,QAAQ,CAAC,OAAO,EAAE,eAAe,GAAG,OAAO,CAAC,IAAI,CAAC,CA4QtE"}
@@ -15,6 +15,7 @@ import { extractAllPages } from '../lib/mdx-validator.js';
15
15
  import { validateBrandingAssets } from '../lib/validate-branding.js';
16
16
  import { ensureDependencies } from '../lib/deps.js';
17
17
  import { rewriteRelativeMdxImports } from '../lib/relative-mdx-imports.js';
18
+ import { validateApiPagePanels } from '../lib/api-page-panel-validator.js';
18
19
  export async function validate(options) {
19
20
  const { verbose } = options;
20
21
  const projectDir = process.cwd();
@@ -83,6 +84,30 @@ export async function validate(options) {
83
84
  console.log(` Name: ${result.config.name}`);
84
85
  console.log(` Theme: ${result.config.theme || 'jam (default)'}`);
85
86
  }
87
+ // Step 2.7: API pages with inline code blocks (no Request/Response wrappers)
88
+ if (result.config) {
89
+ const apiPagePanelWarnings = [];
90
+ const pages = extractAllPages(result.config.navigation);
91
+ for (const relPath of pages) {
92
+ const fullPath = path.join(projectDir, `${relPath}.mdx`);
93
+ if (!(await fs.pathExists(fullPath)))
94
+ continue;
95
+ const content = await fs.readFile(fullPath, 'utf-8');
96
+ const warning = validateApiPagePanels(relPath, content);
97
+ if (warning?.message) {
98
+ apiPagePanelWarnings.push({ file: warning.file, message: warning.message });
99
+ }
100
+ }
101
+ if (apiPagePanelWarnings.length > 0) {
102
+ console.log('');
103
+ output.warn('API pages with inline code blocks (no Request/Response wrappers):');
104
+ for (const w of apiPagePanelWarnings) {
105
+ console.log(` - ${w.file}`);
106
+ }
107
+ console.log('');
108
+ output.hint('Wrap each example with <RequestExample> or <ResponseExample> to render in the right panel.');
109
+ }
110
+ }
86
111
  // Step 3: Validate MDX syntax (unless skipped)
87
112
  if (!options.skipMdx && result.config) {
88
113
  await ensureDependencies(verbose);
@@ -1 +1 @@
1
- {"version":3,"file":"validate.js","sourceRoot":"","sources":["../../src/commands/validate.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"validate.js","sourceRoot":"","sources":["../../src/commands/validate.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,19 @@
1
+ /**
2
+ * API Page Panel Validator (CLI)
3
+ *
4
+ * Warns when an `api:` page has fenced code blocks that are not wrapped in
5
+ * <RequestExample> or <ResponseExample>. Unwrapped code blocks render inline
6
+ * in the page body and do NOT populate the right-side code panel.
7
+ *
8
+ * This is the CLI copy of build-service's validateApiPagePanels. The wrapper
9
+ * regex MUST stay byte-for-byte identical to containsCodePanelWrapper in
10
+ * builder/build-service/lib/preprocess-mdx.ts. If you change one, change the other.
11
+ */
12
+ type BuildWarning = {
13
+ type: 'inline_code_on_api_page';
14
+ file: string;
15
+ message?: string;
16
+ };
17
+ export declare function validateApiPagePanels(filePath: string, content: string): BuildWarning | null;
18
+ export {};
19
+ //# sourceMappingURL=api-page-panel-validator.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"api-page-panel-validator.d.ts","sourceRoot":"","sources":["../../src/lib/api-page-panel-validator.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAQH,KAAK,YAAY,GAAG;IAClB,IAAI,EAAE,yBAAyB,CAAC;IAChC,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB,CAAC;AAeF,wBAAgB,qBAAqB,CACnC,QAAQ,EAAE,MAAM,EAChB,OAAO,EAAE,MAAM,GACd,YAAY,GAAG,IAAI,CAoBrB"}
@@ -0,0 +1,46 @@
1
+ /**
2
+ * API Page Panel Validator (CLI)
3
+ *
4
+ * Warns when an `api:` page has fenced code blocks that are not wrapped in
5
+ * <RequestExample> or <ResponseExample>. Unwrapped code blocks render inline
6
+ * in the page body and do NOT populate the right-side code panel.
7
+ *
8
+ * This is the CLI copy of build-service's validateApiPagePanels. The wrapper
9
+ * regex MUST stay byte-for-byte identical to containsCodePanelWrapper in
10
+ * builder/build-service/lib/preprocess-mdx.ts. If you change one, change the other.
11
+ */
12
+ import matter from 'gray-matter';
13
+ import { preprocessFrontmatter } from './frontmatter-utils.js';
14
+ const FENCED_CODE_RE = /(^|\n)```/;
15
+ // MUST match builder/build-service/lib/preprocess-mdx.ts containsCodePanelWrapper
16
+ // regex byte-for-byte. If you change one, change the other.
17
+ const WRAPPER_RE = /<(?:RequestExample|ResponseExample)(?:\s|>|\/)/;
18
+ function stripFencedCodeBlocks(content) {
19
+ return content.replace(/```[\s\S]*?```/g, '');
20
+ }
21
+ function stripInlineBackticks(content) {
22
+ return content.replace(/`[^`\n]+`/g, '');
23
+ }
24
+ export function validateApiPagePanels(filePath, content) {
25
+ let parsed;
26
+ try {
27
+ parsed = matter(preprocessFrontmatter(content));
28
+ }
29
+ catch {
30
+ return null;
31
+ }
32
+ const { data, content: body } = parsed;
33
+ if (!data.api || data.openapi)
34
+ return null;
35
+ if (!FENCED_CODE_RE.test(body))
36
+ return null;
37
+ if (WRAPPER_RE.test(stripInlineBackticks(stripFencedCodeBlocks(body))))
38
+ return null;
39
+ return {
40
+ type: 'inline_code_on_api_page',
41
+ file: filePath,
42
+ message: 'API page has fenced code blocks but no <RequestExample> or <ResponseExample> wrappers. ' +
43
+ 'Wrap each example to populate the right-side panel.',
44
+ };
45
+ }
46
+ //# sourceMappingURL=api-page-panel-validator.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"api-page-panel-validator.js","sourceRoot":"","sources":["../../src/lib/api-page-panel-validator.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,OAAO,MAAM,MAAM,aAAa,CAAC;AACjC,OAAO,EAAE,qBAAqB,EAAE,MAAM,wBAAwB,CAAC;AAW/D,MAAM,cAAc,GAAG,WAAW,CAAC;AACnC,kFAAkF;AAClF,4DAA4D;AAC5D,MAAM,UAAU,GAAG,gDAAgD,CAAC;AAEpE,SAAS,qBAAqB,CAAC,OAAe;IAC5C,OAAO,OAAO,CAAC,OAAO,CAAC,iBAAiB,EAAE,EAAE,CAAC,CAAC;AAChD,CAAC;AAED,SAAS,oBAAoB,CAAC,OAAe;IAC3C,OAAO,OAAO,CAAC,OAAO,CAAC,YAAY,EAAE,EAAE,CAAC,CAAC;AAC3C,CAAC;AAED,MAAM,UAAU,qBAAqB,CACnC,QAAgB,EAChB,OAAe;IAEf,IAAI,MAAM,CAAC;IACX,IAAI,CAAC;QACH,MAAM,GAAG,MAAM,CAAC,qBAAqB,CAAC,OAAO,CAAC,CAAC,CAAC;IAClD,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,CAAC;IACd,CAAC;IAED,MAAM,EAAE,IAAI,EAAE,OAAO,EAAE,IAAI,EAAE,GAAG,MAAM,CAAC;IACvC,IAAI,CAAC,IAAI,CAAC,GAAG,IAAI,IAAI,CAAC,OAAO;QAAE,OAAO,IAAI,CAAC;IAC3C,IAAI,CAAC,cAAc,CAAC,IAAI,CAAC,IAAI,CAAC;QAAE,OAAO,IAAI,CAAC;IAC5C,IAAI,UAAU,CAAC,IAAI,CAAC,oBAAoB,CAAC,qBAAqB,CAAC,IAAI,CAAC,CAAC,CAAC;QAAE,OAAO,IAAI,CAAC;IAEpF,OAAO;QACL,IAAI,EAAE,yBAAyB;QAC/B,IAAI,EAAE,QAAQ;QACd,OAAO,EACL,yFAAyF;YACzF,qDAAqD;KACxD,CAAC;AACJ,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "jamdesk",
3
- "version": "1.1.79",
3
+ "version": "1.1.80",
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",
@@ -5,6 +5,8 @@ import { CODEPANEL_TAB_CHANGE_EVENT } from '@/components/ui/CodePanel';
5
5
 
6
6
  interface ApiPageWrapperProps {
7
7
  children: ReactNode;
8
+ /** SSR hint: whether this page has code panel content in the right sidebar. */
9
+ hasCodePanels?: boolean;
8
10
  }
9
11
 
10
12
  /**
@@ -92,7 +94,7 @@ function getMinCodeContentHeight(): number {
92
94
  * - When viewport shrinks, bottom panel shrinks first (to 5 lines min), then top
93
95
  * - Content scrolls within each box when it exceeds the visible height
94
96
  */
95
- export function ApiPageWrapper({ children }: ApiPageWrapperProps) {
97
+ export function ApiPageWrapper({ children, hasCodePanels = true }: ApiPageWrapperProps) {
96
98
  const containerRef = useRef<HTMLDivElement>(null);
97
99
  const sidebarRef = useRef<HTMLDivElement>(null);
98
100
  const [isDesktop, setIsDesktop] = useState(false);
@@ -303,6 +305,7 @@ export function ApiPageWrapper({ children }: ApiPageWrapperProps) {
303
305
 
304
306
  // Handle panel movement based on viewport
305
307
  useEffect(() => {
308
+ if (!hasCodePanels) return;
306
309
  if (!containerRef.current || !sidebarRef.current || !mounted) return;
307
310
 
308
311
  const prose = containerRef.current.querySelector('.prose');
@@ -353,10 +356,11 @@ export function ApiPageWrapper({ children }: ApiPageWrapperProps) {
353
356
  observer.observe(prose, { childList: true, subtree: true });
354
357
 
355
358
  return () => observer.disconnect();
356
- }, [isDesktop, mounted, movePanelToSidebar, movePanelToProse, applyPanelHeights]);
359
+ }, [hasCodePanels, isDesktop, mounted, movePanelToSidebar, movePanelToProse, applyPanelHeights]);
357
360
 
358
361
  // Handle window resize to adjust panel heights
359
362
  useEffect(() => {
363
+ if (!hasCodePanels) return;
360
364
  if (!isDesktop || !mounted) return;
361
365
 
362
366
  const handleResize = () => {
@@ -367,10 +371,11 @@ export function ApiPageWrapper({ children }: ApiPageWrapperProps) {
367
371
 
368
372
  window.addEventListener('resize', handleResize);
369
373
  return () => window.removeEventListener('resize', handleResize);
370
- }, [isDesktop, mounted, applyPanelHeights]);
374
+ }, [hasCodePanels, isDesktop, mounted, applyPanelHeights]);
371
375
 
372
376
  // Recalculate sidebar panel heights when a CodePanel switches tabs
373
377
  useEffect(() => {
378
+ if (!hasCodePanels) return;
374
379
  if (!sidebarRef.current || !isDesktop || !mounted) return;
375
380
 
376
381
  const handleTabChange = (e: Event) => {
@@ -385,7 +390,7 @@ export function ApiPageWrapper({ children }: ApiPageWrapperProps) {
385
390
  const sidebar = sidebarRef.current;
386
391
  sidebar.addEventListener(CODEPANEL_TAB_CHANGE_EVENT, handleTabChange);
387
392
  return () => sidebar.removeEventListener(CODEPANEL_TAB_CHANGE_EVENT, handleTabChange);
388
- }, [isDesktop, mounted, applyPanelHeights]);
393
+ }, [hasCodePanels, isDesktop, mounted, applyPanelHeights]);
389
394
 
390
395
  return (
391
396
  <div className="flex h-full">
@@ -394,12 +399,17 @@ export function ApiPageWrapper({ children }: ApiPageWrapperProps) {
394
399
  id="content-scroll-container"
395
400
  className="flex-1 min-w-0 lg:overflow-y-auto lg:h-full content-scroll"
396
401
  >
397
- <div ref={containerRef} className="api-page-layout">
402
+ <div
403
+ ref={containerRef}
404
+ className={hasCodePanels ? 'api-page-layout with-sidebar' : 'api-page-layout'}
405
+ >
398
406
  {children}
399
407
  </div>
400
408
  </div>
401
409
  {/* Sticky sidebar container for code panels on desktop */}
402
- <div ref={sidebarRef} className="code-panels-sidebar lg:ml-0.5" />
410
+ {hasCodePanels && (
411
+ <div ref={sidebarRef} className="code-panels-sidebar lg:ml-0.5" />
412
+ )}
403
413
  </div>
404
414
  );
405
415
  }
@@ -9,6 +9,7 @@ import { useShikiHighlightMultiple } from '@/hooks/useShikiHighlight';
9
9
  import { preloadHighlighter } from '@/lib/shiki-client';
10
10
  import ReactMarkdown from 'react-markdown';
11
11
  import { resolveServerUrl } from '@/lib/openapi/resolve-server-url';
12
+ import { getResponseExample } from '@/lib/openapi/response-examples';
12
13
  // Icons use Font Awesome CSS classes for lightweight rendering
13
14
  import type {
14
15
  OpenApiEndpointData,
@@ -383,99 +384,6 @@ function RequestBodySection({
383
384
  );
384
385
  }
385
386
 
386
- /**
387
- * Generate example JSON from schema
388
- */
389
- function generateExampleFromSchema(schema: JsonSchema, depth = 0): unknown {
390
- if (depth > 5) return null; // Prevent infinite recursion
391
-
392
- // If there's an explicit example, use it
393
- if (schema.example !== undefined) {
394
- return schema.example;
395
- }
396
-
397
- // Handle different types
398
- const type = Array.isArray(schema.type) ? schema.type[0] : schema.type;
399
-
400
- if (schema.enum && schema.enum.length > 0) {
401
- return schema.enum[0];
402
- }
403
-
404
- switch (type) {
405
- case 'object':
406
- if (schema.properties) {
407
- const obj: Record<string, unknown> = {};
408
- for (const [key, propSchema] of Object.entries(schema.properties)) {
409
- obj[key] = generateExampleFromSchema(propSchema, depth + 1);
410
- }
411
- return obj;
412
- }
413
- return {};
414
-
415
- case 'array':
416
- if (schema.items) {
417
- return [generateExampleFromSchema(schema.items, depth + 1)];
418
- }
419
- return [];
420
-
421
- case 'string':
422
- if (schema.format === 'date') return '2024-01-15';
423
- if (schema.format === 'date-time') return '2024-01-15T10:30:00Z';
424
- if (schema.format === 'email') return 'user@example.com';
425
- if (schema.format === 'uri' || schema.format === 'url') return 'https://example.com';
426
- if (schema.format === 'uuid') return '550e8400-e29b-41d4-a716-446655440000';
427
- return 'string';
428
-
429
- case 'integer':
430
- case 'number':
431
- if (schema.minimum !== undefined) return schema.minimum;
432
- if (schema.maximum !== undefined) return schema.maximum;
433
- return type === 'integer' ? 1 : 1.0;
434
-
435
- case 'boolean':
436
- return true;
437
-
438
- case 'null':
439
- return null;
440
-
441
- default:
442
- return null;
443
- }
444
- }
445
-
446
- /**
447
- * Get response example from response content
448
- */
449
- function getResponseExample(response: ParsedResponse): unknown | null {
450
- const jsonContent = response.content?.['application/json'];
451
- if (!jsonContent) return null;
452
-
453
- // Check for explicit example
454
- if (jsonContent.example !== undefined) {
455
- return jsonContent.example;
456
- }
457
-
458
- // Check for examples (use first one)
459
- if (jsonContent.examples) {
460
- const firstExample = Object.values(jsonContent.examples)[0];
461
- if (firstExample?.value !== undefined) {
462
- return firstExample.value;
463
- }
464
- }
465
-
466
- // Check schema example
467
- if (jsonContent.schema?.example !== undefined) {
468
- return jsonContent.schema.example;
469
- }
470
-
471
- // Generate from schema
472
- if (jsonContent.schema) {
473
- return generateExampleFromSchema(jsonContent.schema);
474
- }
475
-
476
- return null;
477
- }
478
-
479
387
  /**
480
388
  * Response section with field documentation
481
389
  * Only shows response codes that have content (schema or example)
@@ -0,0 +1,45 @@
1
+ import matter from 'gray-matter';
2
+ import type { BuildWarning } from '../shared/status-reporter';
3
+ import { containsCodePanelWrapper } from './preprocess-mdx';
4
+ import { preprocessFrontmatter } from './frontmatter-utils';
5
+
6
+ const FENCED_CODE_RE = /(^|\n)```/;
7
+
8
+ /**
9
+ * Detect a common authoring mistake on manual `api:` pages:
10
+ * fenced code blocks in the body but no <RequestExample>/<ResponseExample>
11
+ * wrappers. The two-column API layout would render an empty right sidebar
12
+ * (Phase 1 collapses it, but the customer still misses out on the intended
13
+ * UX). Warn so they can wrap the examples.
14
+ *
15
+ * Skips `openapi:` pages — those auto-render ResponseExamplePanel from the
16
+ * spec, and a fenced code block on those is usually supplementary docs
17
+ * (Python SDK, batch script). Too noisy to warn there.
18
+ *
19
+ * Pure function — no I/O. Pass relative file path + raw content.
20
+ */
21
+ export function validateApiPagePanels(
22
+ filePath: string,
23
+ content: string,
24
+ ): BuildWarning | null {
25
+ let parsed;
26
+ try {
27
+ parsed = matter(preprocessFrontmatter(content));
28
+ } catch {
29
+ return null;
30
+ }
31
+
32
+ const { data, content: body } = parsed;
33
+ if (!data.api || data.openapi) return null;
34
+ if (!FENCED_CODE_RE.test(body)) return null;
35
+ if (containsCodePanelWrapper(body)) return null;
36
+
37
+ return {
38
+ type: 'inline_code_on_api_page',
39
+ file: filePath,
40
+ message:
41
+ 'API page has fenced code blocks but no <RequestExample> or <ResponseExample> wrappers. ' +
42
+ 'Code blocks will render inline instead of in the right-side panel. ' +
43
+ 'Wrap each example with <RequestExample> or <ResponseExample> to populate the sidebar.',
44
+ };
45
+ }
@@ -0,0 +1,47 @@
1
+ import type { ParsedResponse } from './types';
2
+ import { generateExampleFromSchema } from './schema-examples';
3
+
4
+ /**
5
+ * Get response example from response content.
6
+ * Mirrors the logic that ResponseExamplePanel uses to decide whether
7
+ * to render a tab — keep these in lockstep.
8
+ */
9
+ export function getResponseExample(response: ParsedResponse): unknown | null {
10
+ const jsonContent = response.content?.['application/json'];
11
+ if (!jsonContent) return null;
12
+
13
+ if (jsonContent.example !== undefined) {
14
+ return jsonContent.example;
15
+ }
16
+
17
+ if (jsonContent.examples) {
18
+ const firstExample = Object.values(jsonContent.examples)[0];
19
+ if (firstExample?.value !== undefined) {
20
+ return firstExample.value;
21
+ }
22
+ }
23
+
24
+ if (jsonContent.schema?.example !== undefined) {
25
+ return jsonContent.schema.example;
26
+ }
27
+
28
+ if (jsonContent.schema) {
29
+ return generateExampleFromSchema(jsonContent.schema);
30
+ }
31
+
32
+ return null;
33
+ }
34
+
35
+ /**
36
+ * True iff at least one response will produce a tab in ResponseExamplePanel.
37
+ * Used at SSR time to decide whether the API-page sidebar will be non-empty.
38
+ */
39
+ export function hasAnyResponseExample(
40
+ responses: Record<string, ParsedResponse> | undefined,
41
+ ): boolean {
42
+ if (!responses) return false;
43
+ for (const r of Object.values(responses)) {
44
+ if (getResponseExample(r) !== null) return true;
45
+ }
46
+ return false;
47
+ }
@@ -0,0 +1,63 @@
1
+ import type { JsonSchema } from './types';
2
+
3
+ /**
4
+ * Generate example JSON from schema.
5
+ * Pure function — no React or browser deps.
6
+ * Used by both ResponseExamplePanel (client) and response-examples.ts (server).
7
+ */
8
+ export function generateExampleFromSchema(schema: JsonSchema, depth = 0): unknown {
9
+ if (depth > 5) return null; // Prevent infinite recursion
10
+
11
+ // If there's an explicit example, use it
12
+ if (schema.example !== undefined) {
13
+ return schema.example;
14
+ }
15
+
16
+ // Handle different types
17
+ const type = Array.isArray(schema.type) ? schema.type[0] : schema.type;
18
+
19
+ if (schema.enum && schema.enum.length > 0) {
20
+ return schema.enum[0];
21
+ }
22
+
23
+ switch (type) {
24
+ case 'object':
25
+ if (schema.properties) {
26
+ const obj: Record<string, unknown> = {};
27
+ for (const [key, propSchema] of Object.entries(schema.properties)) {
28
+ obj[key] = generateExampleFromSchema(propSchema, depth + 1);
29
+ }
30
+ return obj;
31
+ }
32
+ return {};
33
+
34
+ case 'array':
35
+ if (schema.items) {
36
+ return [generateExampleFromSchema(schema.items, depth + 1)];
37
+ }
38
+ return [];
39
+
40
+ case 'string':
41
+ if (schema.format === 'date') return '2024-01-15';
42
+ if (schema.format === 'date-time') return '2024-01-15T10:30:00Z';
43
+ if (schema.format === 'email') return 'user@example.com';
44
+ if (schema.format === 'uri' || schema.format === 'url') return 'https://example.com';
45
+ if (schema.format === 'uuid') return '550e8400-e29b-41d4-a716-446655440000';
46
+ return 'string';
47
+
48
+ case 'integer':
49
+ case 'number':
50
+ if (schema.minimum !== undefined) return schema.minimum;
51
+ if (schema.maximum !== undefined) return schema.maximum;
52
+ return type === 'integer' ? 1 : 1.0;
53
+
54
+ case 'boolean':
55
+ return true;
56
+
57
+ case 'null':
58
+ return null;
59
+
60
+ default:
61
+ return null;
62
+ }
63
+ }
@@ -995,6 +995,47 @@ export function containsView(content: string): boolean {
995
995
  return /<View(?:\s|>)/.test(content);
996
996
  }
997
997
 
998
+ /**
999
+ * Strip fenced code blocks (```...```) so wrapper-detection regexes don't
1000
+ * match inside docs that demonstrate wrapper syntax. Greedy + non-overlapping;
1001
+ * does not handle nested fences (rare in MDX).
1002
+ */
1003
+ function stripFencedCodeBlocks(content: string): string {
1004
+ return content.replace(/```[\s\S]*?```/g, '');
1005
+ }
1006
+
1007
+ /**
1008
+ * Strip inline backtick spans (`...`) so wrapper-detection regexes don't
1009
+ * match wrapper names mentioned in prose (e.g. "use the `<RequestExample>`
1010
+ * component"). Single-line spans only — per the markdown spec, inline code
1011
+ * does not span newlines. Run AFTER stripFencedCodeBlocks so triple-backtick
1012
+ * fences are already gone and won't be partially consumed.
1013
+ */
1014
+ function stripInlineBackticks(content: string): string {
1015
+ return content.replace(/`[^`\n]+`/g, '');
1016
+ }
1017
+
1018
+ /**
1019
+ * Check whether MDX content contains a <RequestExample> or <ResponseExample>
1020
+ * wrapper. These are the only MDX components (other than the auto-rendered
1021
+ * ResponseExamplePanel from openapi: frontmatter) that produce a `data-code-panel`
1022
+ * element — i.e., something that fills the API-page sidebar.
1023
+ *
1024
+ * Wrappers appearing inside fenced code blocks or inline backtick spans
1025
+ * (e.g. docs about the syntax itself) are intentionally ignored.
1026
+ *
1027
+ * @param content - Raw MDX content
1028
+ * @returns true if a request/response example wrapper is present
1029
+ */
1030
+ export function containsCodePanelWrapper(content: string): boolean {
1031
+ // Match `<RequestExample` followed by whitespace, `>`, or `/` (self-closing).
1032
+ // The trailing `/` covers `<RequestExample />` / `<RequestExample/>` while still
1033
+ // refusing `<RequestExampleHelper>` (the next char after the name must be a
1034
+ // boundary, not another identifier char).
1035
+ const stripped = stripInlineBackticks(stripFencedCodeBlocks(content));
1036
+ return /<(?:RequestExample|ResponseExample)(?:\s|>|\/)/.test(stripped);
1037
+ }
1038
+
998
1039
  /**
999
1040
  * Preprocess MDX content for rendering.
1000
1041
  *
@@ -0,0 +1,28 @@
1
+ import { containsCodePanelWrapper } from './preprocess-mdx';
2
+ import { hasAnyResponseExample } from './openapi/response-examples';
3
+ import type { OpenApiEndpointData } from './openapi/types';
4
+
5
+ // Permissive on the import-clause side so we cover default (`import X`),
6
+ // named (`import { X }`), and namespace (`import * as X`) shapes. We only
7
+ // require `import` -> `from '/snippets/...'`.
8
+ const SNIPPET_IMPORT_RE = /import[^;'"\n]*\bfrom\s+['"]\/snippets\//;
9
+
10
+ /**
11
+ * Decide at SSR time whether an API page will have any content in the
12
+ * right-side code panel sidebar. When false, ApiPageWrapper renders
13
+ * single-column to avoid leaving a 460px blank gutter.
14
+ *
15
+ * Fails safe: when the page imports a snippet (which could carry
16
+ * <RequestExample>/<ResponseExample> wrappers we can't statically resolve),
17
+ * returns true so the sidebar is preserved. Worst case: we keep the empty
18
+ * sidebar on a page that wouldn't actually have panels — same as today.
19
+ */
20
+ export function computeHasCodePanels(
21
+ endpoint: OpenApiEndpointData | null,
22
+ rawMdxContent: string,
23
+ ): boolean {
24
+ if (hasAnyResponseExample(endpoint?.responses)) return true;
25
+ if (containsCodePanelWrapper(rawMdxContent)) return true;
26
+ if (SNIPPET_IMPORT_RE.test(rawMdxContent)) return true;
27
+ return false;
28
+ }
@@ -36,6 +36,7 @@ import { rehypeNoZoomToData } from '@/lib/rehype-nozoom-to-data';
36
36
  import { rehypeUnwrapNestedAnchors } from './rehype-unwrap-nested-anchors';
37
37
  import { loadSnippetsAndInlineComponents } from './render-doc-page-parallel-helpers';
38
38
  import { tryOpenApiCandidatesInParallel, makeTryOpenApiSpec, formatFallbackWarning } from './render-doc-page-openapi-helpers';
39
+ import { computeHasCodePanels } from './render-doc-page-helpers';
39
40
  import { logger } from '../shared/logger';
40
41
  import { preprocessMdx, containsPanel, containsView, buildSnippetAliasMap } from '@/lib/preprocess-mdx';
41
42
  import { loadSnippetsForIsr } from '@/lib/snippet-loader-isr';
@@ -516,9 +517,16 @@ export async function renderDocPage(input: RenderInput): Promise<ReactElement> {
516
517
  const resolvedMdxAuth = resolveAuth(mdxEndpointData, config);
517
518
  const resolvedOpenApiAuth = resolveAuth(openApiEndpointData, config);
518
519
 
520
+ // Pass the RAW MDX content — preprocessMdx() runs stripSnippetImports(),
521
+ // which would erase the `import X from '/snippets/...'` lines that the
522
+ // snippet escape hatch in computeHasCodePanels() looks for.
523
+ const hasCodePanels = isApiPage
524
+ ? computeHasCodePanels(openApiEndpointData, rawContent)
525
+ : false;
526
+
519
527
  if (isApiPage) {
520
528
  return (
521
- <>{jsonLdScript}<ApiPageWrapper>
529
+ <>{jsonLdScript}<ApiPageWrapper hasCodePanels={hasCodePanels}>
522
530
  <article className="px-4 sm:px-6 lg:px-8 py-6 sm:py-10 flex-1 min-w-0">
523
531
  <Breadcrumb slug={slug} config={config} />
524
532
 
@@ -15,6 +15,7 @@ import { transform } from '@babel/standalone';
15
15
  import { fetchSnippet } from './r2-content';
16
16
  import { extractSnippetImports } from './preprocess-mdx';
17
17
  import { filterVisibility } from './visibility-filter';
18
+ import { mdxSecurityOptions } from './mdx-security-options';
18
19
 
19
20
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
20
21
  type AnyComponent = React.ComponentType<any>;
@@ -225,6 +226,46 @@ function extractExports(transpiledCode: string): Record<string, string> {
225
226
  return exports;
226
227
  }
227
228
 
229
+ /**
230
+ * Detect plain-markdown snippet source — Mintlify-style snippet files that
231
+ * contain only markdown text (with optional inline JSX components) and have no
232
+ * `export` declarations. The existing JSX compile path runs source through
233
+ * Babel which throws on the first non-JSX word; we need a different compile
234
+ * strategy for these.
235
+ *
236
+ * Strips fenced code blocks and inline backticks before scanning so an
237
+ * `export const` example inside a documentation block doesn't false-positive
238
+ * as a JSX-style snippet.
239
+ */
240
+ function isPlainMarkdownSnippet(source: string): boolean {
241
+ const stripped = source
242
+ .replace(/```[\s\S]*?```/g, '')
243
+ .replace(/`[^`]*`/g, '');
244
+ return !/^\s*export\s+(?:async\s+)?(?:const|function|class|default|type|interface|\{|\*)/m.test(stripped);
245
+ }
246
+
247
+ /**
248
+ * Compile a plain-markdown snippet via next-mdx-remote/rsc's compileMDX.
249
+ *
250
+ * Returns a stable component that re-emits the pre-compiled JSX. Components
251
+ * referenced inside the snippet body (e.g. `<Note>`) are resolved against the
252
+ * built-in components map at compile time.
253
+ */
254
+ async function compilePlainMdxSnippet(
255
+ source: string,
256
+ builtInComponents: Record<string, AnyComponent>
257
+ ): Promise<AnyComponent> {
258
+ const { compileMDX } = await import('next-mdx-remote/rsc');
259
+ const { content } = await compileMDX({
260
+ source,
261
+ components: builtInComponents,
262
+ options: { ...mdxSecurityOptions, parseFrontmatter: true },
263
+ });
264
+ const PlainMdxSnippet: AnyComponent = () => content as React.ReactElement;
265
+ PlainMdxSnippet.displayName = 'PlainMdxSnippet';
266
+ return PlainMdxSnippet;
267
+ }
268
+
228
269
  /**
229
270
  * Compile a single snippet into React components.
230
271
  */
@@ -251,6 +292,22 @@ async function compileSnippet(
251
292
  const isClientComponent =
252
293
  trimmed.startsWith("'use client'") || trimmed.startsWith('"use client"');
253
294
 
295
+ // Plain-markdown snippets (no `export …`) need a different compile path —
296
+ // Babel chokes on the first non-JSX word. Detect upfront and route to
297
+ // compileMDX, registering the result under the `default` export key so the
298
+ // alias-mapping path at the call site picks it up.
299
+ if (isPlainMarkdownSnippet(source)) {
300
+ const component = await compilePlainMdxSnippet(source, builtInComponents);
301
+ // Plain markdown is server-rendered via compileMDX; the `'use client'`
302
+ // detection above doesn't apply (markdown can't carry a directive).
303
+ const result: CompiledSnippet = {
304
+ exports: { default: component },
305
+ isClientComponent: false,
306
+ };
307
+ snippetComponentCache.set(cacheKey, { result, timestamp: Date.now() });
308
+ return result;
309
+ }
310
+
254
311
  // Transpile JSX to JavaScript
255
312
  const transpiled = transpileJsx(source);
256
313
 
@@ -31,6 +31,51 @@ const CONTENT_TYPES: Record<string, string> = {
31
31
  '.txt': 'text/plain; charset=utf-8',
32
32
  };
33
33
 
34
+ /**
35
+ * Filenames that should be suppressed (404) on direct upstream hits
36
+ * (`x-jd-noindex: true`). These advertise the project's URL inventory and
37
+ * have no business being served from a non-canonical host.
38
+ *
39
+ * `robots.txt` is handled separately — it returns a Disallow-all directive,
40
+ * not a 404, so crawlers get an explicit "don't crawl" signal.
41
+ *
42
+ * `search-data.json` is intentionally NOT in this list: a real user landing
43
+ * on the upstream subdomain would still hit it from the in-page search UI.
44
+ */
45
+ const NOINDEX_SUPPRESSED_FILES = new Set([
46
+ 'sitemap.xml', 'llms.txt', 'llms-full.txt', 'feed.xml',
47
+ ]);
48
+
49
+ /**
50
+ * Build a no-store synthetic response for direct upstream subdomain hits, or
51
+ * return null if this filename should fall through to the R2 fetch even when
52
+ * `x-jd-noindex: true` is set (i.e., `search-data.json`).
53
+ *
54
+ * Cache-Control: no-store — the noindex flag flips off the moment a project
55
+ * registers a customDomain; CDN edge caching would lock new customers out
56
+ * of indexing for up to s-maxage seconds after they onboard.
57
+ */
58
+ function buildNoindexResponse(filename: string): (() => NextResponse) | null {
59
+ if (filename === 'robots.txt') {
60
+ // Inlined rather than reusing generateRobotsTxt() from static-artifacts.ts —
61
+ // that helper's transitive import chain (enhance-navigation, docs-types,
62
+ // language-utils) breaks Next.js webpack bundling for this route module.
63
+ return () => new NextResponse('User-agent: *\nDisallow: /\n', {
64
+ headers: {
65
+ 'Content-Type': 'text/plain; charset=utf-8',
66
+ 'Cache-Control': 'no-store',
67
+ },
68
+ });
69
+ }
70
+ if (NOINDEX_SUPPRESSED_FILES.has(filename)) {
71
+ return () => new NextResponse('Not found', {
72
+ status: 404,
73
+ headers: { 'Cache-Control': 'no-store' },
74
+ });
75
+ }
76
+ return null;
77
+ }
78
+
34
79
  /**
35
80
  * Infer content type from filename extension.
36
81
  */
@@ -55,6 +100,7 @@ export function createStaticFileHandler(
55
100
  ): (request: NextRequest) => Promise<NextResponse> {
56
101
  const contentType = contentTypeOverride || getContentType(filename);
57
102
  const cacheControl = cacheControlOverride || 'public, max-age=3600, s-maxage=3600';
103
+ const synthesizeNoindexResponse = buildNoindexResponse(filename);
58
104
 
59
105
  return async function GET(request: NextRequest): Promise<NextResponse> {
60
106
  if (!isIsrMode()) {
@@ -71,6 +117,13 @@ export function createStaticFileHandler(
71
117
  return new NextResponse('Not found', { status: 404 });
72
118
  }
73
119
 
120
+ // X-Robots-Tag on the response prevents indexing, but the upstream's
121
+ // robots.txt and sitemap still advertise crawl targets — so Googlebot
122
+ // keeps fetching the duplicate copy. Cut crawl waste at the protocol level.
123
+ if (synthesizeNoindexResponse && request.headers.get('x-jd-noindex') === 'true') {
124
+ return synthesizeNoindexResponse();
125
+ }
126
+
74
127
  const projectSlug = request.headers.get('x-project-slug');
75
128
 
76
129
  if (!projectSlug) {
@@ -22,7 +22,7 @@ export interface ProgressUpdate {
22
22
  }
23
23
 
24
24
  /** Warning types that can occur during builds (non-blocking) */
25
- export type BuildWarningType = 'broken_link' | 'auto_migrate' | 'missing_asset' | 'missing_page' | 'missing_openapi_ref';
25
+ export type BuildWarningType = 'broken_link' | 'auto_migrate' | 'missing_asset' | 'missing_page' | 'missing_openapi_ref' | 'inline_code_on_api_page';
26
26
 
27
27
  /** Build warning structure */
28
28
  export interface BuildWarning {
@@ -951,8 +951,10 @@ pre.shiki[data-line-numbers] .line.diff-remove::after {
951
951
  overflow: hidden;
952
952
  }
953
953
 
954
- /* Hide panels in prose on desktop - prevents flash before JS moves them to sidebar */
955
- .api-page-layout .prose [data-code-panel] {
954
+ /* Hide panels in prose on desktop - prevents flash before JS moves them to sidebar.
955
+ * Scoped to .with-sidebar so pages without a sidebar (hasCodePanels=false)
956
+ * keep any leaked panel visible inline rather than hiding it forever. */
957
+ .api-page-layout.with-sidebar .prose [data-code-panel] {
956
958
  display: none !important;
957
959
  }
958
960
  }
@@ -2165,9 +2165,9 @@
2165
2165
  }
2166
2166
  },
2167
2167
  "node_modules/baseline-browser-mapping": {
2168
- "version": "2.10.28",
2169
- "resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.10.28.tgz",
2170
- "integrity": "sha512-Ic44hnOtFIgravCunj1ifSoQPSUrkNiJuH9Mf6jr2jjoA74icqV8wU0KuadXeOR8zuIJMOoTv0GuQjZ9ZYNMeA==",
2168
+ "version": "2.10.29",
2169
+ "resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.10.29.tgz",
2170
+ "integrity": "sha512-Asa2krT+XTPZINCS+2QcyS8WTkObE77RwkydwF7h6DmnKqbvlalz93m/dnphUyCa6SWSP51VgtEUf2FN+gelFQ==",
2171
2171
  "license": "Apache-2.0",
2172
2172
  "bin": {
2173
2173
  "baseline-browser-mapping": "dist/cli.cjs"