jamdesk 1.0.11 → 1.0.13

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.
@@ -52,10 +52,15 @@ describe('generateWorkerCode', () => {
52
52
  const code = generateWorkerCode(testConfig);
53
53
  expect(code).toContain('cacheEverything: true');
54
54
  });
55
- it('does not cache server errors', () => {
55
+ it('does not cache redirects or server errors', () => {
56
56
  const code = generateWorkerCode(testConfig);
57
+ expect(code).toContain('"300-399": 0');
57
58
  expect(code).toContain('"500-599": 0');
58
59
  });
60
+ it('passes redirects through to browser', () => {
61
+ const code = generateWorkerCode(testConfig);
62
+ expect(code).toContain('redirect: "manual"');
63
+ });
59
64
  });
60
65
  describe('generateWranglerConfig', () => {
61
66
  it('generates valid TOML with catch-all route', () => {
@@ -1 +1 @@
1
- {"version":3,"file":"deploy-templates.test.js","sourceRoot":"","sources":["../../../src/__tests__/unit/deploy-templates.test.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"deploy-templates.test.js","sourceRoot":"","sources":["../../../src/__tests__/unit/deploy-templates.test.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"templates.d.ts","sourceRoot":"","sources":["../../../src/commands/deploy/templates.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAC;AAEnD,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,gBAAgB,GAAG,MAAM,CAuEnE;AAED,wBAAgB,sBAAsB,CAAC,MAAM,EAAE,gBAAgB,GAAG,MAAM,CAuBvE;AAED,wBAAgB,mBAAmB,CAAC,MAAM,EAAE,gBAAgB,GAAG,MAAM,CAqBpE;AAED;;GAEG;AACH,wBAAgB,iBAAiB,IAAI,MAAM,CAK1C;AAsCD;;;;;;;GAOG;AACH,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAexD"}
1
+ {"version":3,"file":"templates.d.ts","sourceRoot":"","sources":["../../../src/commands/deploy/templates.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAC;AAEnD,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,gBAAgB,GAAG,MAAM,CA4EnE;AAED,wBAAgB,sBAAsB,CAAC,MAAM,EAAE,gBAAgB,GAAG,MAAM,CAuBvE;AAED,wBAAgB,mBAAmB,CAAC,MAAM,EAAE,gBAAgB,GAAG,MAAM,CAqBpE;AAED;;GAEG;AACH,wBAAgB,iBAAiB,IAAI,MAAM,CAK1C;AAsCD;;;;;;;GAOG;AACH,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAexD"}
@@ -56,18 +56,23 @@ export default {
56
56
  // Custom header for domain verification (Vercel strips standard forwarding headers)
57
57
  headers.set("X-Jamdesk-Forwarded-Host", url.hostname);
58
58
 
59
+ // Don't follow redirects — let the browser handle them so the URL updates.
60
+ // Without this, redirects happen internally and the browser URL doesn't change,
61
+ // which causes the sidebar to mis-highlight the active page.
59
62
  const proxyRequest = new Request(proxyUrl, {
60
63
  method: request.method,
61
- headers: headers,
64
+ headers,
62
65
  body: request.body,
66
+ redirect: "manual",
63
67
  });
64
68
 
65
69
  // Cache all content types at Cloudflare edge (CF doesn't cache HTML by default).
66
70
  // Cache duration is controlled by upstream Cache-Control headers.
71
+ // Never cache redirects or errors — they must always hit origin.
67
72
  return fetch(proxyRequest, {
68
73
  cf: {
69
74
  cacheEverything: true,
70
- cacheTtlByStatus: { "500-599": 0 },
75
+ cacheTtlByStatus: { "300-399": 0, "500-599": 0 },
71
76
  },
72
77
  });
73
78
  },
@@ -1 +1 @@
1
- {"version":3,"file":"templates.js","sourceRoot":"","sources":["../../../src/commands/deploy/templates.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAIH,MAAM,UAAU,kBAAkB,CAAC,MAAwB;IACzD,MAAM,EAAE,IAAI,EAAE,UAAU,EAAE,GAAG,MAAM,CAAC;IACpC,MAAM,WAAW,GAAG,GAAG,IAAI,cAAc,CAAC;IAE1C,OAAO;;;;aAII,UAAU,mCAAmC,WAAW;;;;;;wBAM7C,WAAW;;;;KAI9B,UAAU;;;;;;;;sBAQO,UAAU;6BACH,UAAU,6BAA6B,UAAU;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA2C7E,CAAC;AACF,CAAC;AAED,MAAM,UAAU,sBAAsB,CAAC,MAAwB;IAC7D,MAAM,EAAE,MAAM,EAAE,QAAQ,EAAE,GAAG,MAAM,CAAC;IACpC,MAAM,UAAU,GAAG,cAAc,MAAM,CAAC,OAAO,CAAC,KAAK,EAAE,GAAG,CAAC,EAAE,CAAC;IAE9D,OAAO;;;;;UAKC,UAAU;;;;;;;iBAOH,MAAM,qBAAqB,QAAQ;;;;;;CAMnD,CAAC;AACF,CAAC;AAED,MAAM,UAAU,mBAAmB,CAAC,MAAwB;IAC1D,MAAM,EAAE,MAAM,EAAE,GAAG,MAAM,CAAC;IAC1B,MAAM,WAAW,GAAG,cAAc,MAAM,CAAC,OAAO,CAAC,KAAK,EAAE,GAAG,CAAC,EAAE,CAAC;IAE/D,MAAM,GAAG,GAAG;QACV,IAAI,EAAE,WAAW;QACjB,OAAO,EAAE,OAAO;QAChB,WAAW,EAAE,mCAAmC,MAAM,EAAE;QACxD,IAAI,EAAE,UAAU;QAChB,OAAO,EAAE;YACP,MAAM,EAAE,iBAAiB;YACzB,GAAG,EAAE,cAAc;SACpB;QACD,eAAe,EAAE;YACf,QAAQ,EAAE,QAAQ;SACnB;QACD,QAAQ,EAAE,CAAC,mBAAmB,EAAE,SAAS,EAAE,eAAe,EAAE,OAAO,CAAC;QACpE,OAAO,EAAE,IAAI;KACd,CAAC;IAEF,OAAO,IAAI,CAAC,SAAS,CAAC,GAAG,EAAE,IAAI,EAAE,CAAC,CAAC,GAAG,IAAI,CAAC;AAC7C,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,iBAAiB;IAC/B,OAAO;;;CAGR,CAAC;AACF,CAAC;AAED;;;GAGG;AACH,MAAM,eAAe,GAAG,IAAI,GAAG,CAAC;IAC9B,KAAK;IACL,OAAO;IACP,QAAQ;IACR,OAAO;IACP,OAAO;IACP,YAAY;IACZ,QAAQ;IACR,QAAQ;IACR,QAAQ;IACR,cAAc;IACd,OAAO;IACP,QAAQ;IACR,eAAe;IACf,OAAO;IACP,QAAQ;IACR,SAAS;IACT,QAAQ;IACR,QAAQ;IACR,QAAQ;IACR,OAAO;IACP,OAAO;IACP,QAAQ;IACR,OAAO;IACP,QAAQ;IACR,oBAAoB;IACpB,QAAQ;IACR,QAAQ;IACR,QAAQ;IACR,QAAQ;CACT,CAAC,CAAC;AAEH;;;;;;;GAOG;AACH,MAAM,UAAU,iBAAiB,CAAC,MAAc;IAC9C,MAAM,KAAK,GAAG,MAAM,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;IAChC,IAAI,KAAK,CAAC,MAAM,IAAI,CAAC,EAAE,CAAC;QACtB,OAAO,MAAM,CAAC;IAChB,CAAC;IAED,sDAAsD;IACtD,MAAM,OAAO,GAAG,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;IAC1C,IAAI,eAAe,CAAC,GAAG,CAAC,OAAO,CAAC,EAAE,CAAC;QACjC,8CAA8C;QAC9C,OAAO,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;IACnC,CAAC;IAED,0CAA0C;IAC1C,OAAO,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;AACnC,CAAC"}
1
+ {"version":3,"file":"templates.js","sourceRoot":"","sources":["../../../src/commands/deploy/templates.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAIH,MAAM,UAAU,kBAAkB,CAAC,MAAwB;IACzD,MAAM,EAAE,IAAI,EAAE,UAAU,EAAE,GAAG,MAAM,CAAC;IACpC,MAAM,WAAW,GAAG,GAAG,IAAI,cAAc,CAAC;IAE1C,OAAO;;;;aAII,UAAU,mCAAmC,WAAW;;;;;;wBAM7C,WAAW;;;;KAI9B,UAAU;;;;;;;;sBAQO,UAAU;6BACH,UAAU,6BAA6B,UAAU;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAgD7E,CAAC;AACF,CAAC;AAED,MAAM,UAAU,sBAAsB,CAAC,MAAwB;IAC7D,MAAM,EAAE,MAAM,EAAE,QAAQ,EAAE,GAAG,MAAM,CAAC;IACpC,MAAM,UAAU,GAAG,cAAc,MAAM,CAAC,OAAO,CAAC,KAAK,EAAE,GAAG,CAAC,EAAE,CAAC;IAE9D,OAAO;;;;;UAKC,UAAU;;;;;;;iBAOH,MAAM,qBAAqB,QAAQ;;;;;;CAMnD,CAAC;AACF,CAAC;AAED,MAAM,UAAU,mBAAmB,CAAC,MAAwB;IAC1D,MAAM,EAAE,MAAM,EAAE,GAAG,MAAM,CAAC;IAC1B,MAAM,WAAW,GAAG,cAAc,MAAM,CAAC,OAAO,CAAC,KAAK,EAAE,GAAG,CAAC,EAAE,CAAC;IAE/D,MAAM,GAAG,GAAG;QACV,IAAI,EAAE,WAAW;QACjB,OAAO,EAAE,OAAO;QAChB,WAAW,EAAE,mCAAmC,MAAM,EAAE;QACxD,IAAI,EAAE,UAAU;QAChB,OAAO,EAAE;YACP,MAAM,EAAE,iBAAiB;YACzB,GAAG,EAAE,cAAc;SACpB;QACD,eAAe,EAAE;YACf,QAAQ,EAAE,QAAQ;SACnB;QACD,QAAQ,EAAE,CAAC,mBAAmB,EAAE,SAAS,EAAE,eAAe,EAAE,OAAO,CAAC;QACpE,OAAO,EAAE,IAAI;KACd,CAAC;IAEF,OAAO,IAAI,CAAC,SAAS,CAAC,GAAG,EAAE,IAAI,EAAE,CAAC,CAAC,GAAG,IAAI,CAAC;AAC7C,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,iBAAiB;IAC/B,OAAO;;;CAGR,CAAC;AACF,CAAC;AAED;;;GAGG;AACH,MAAM,eAAe,GAAG,IAAI,GAAG,CAAC;IAC9B,KAAK;IACL,OAAO;IACP,QAAQ;IACR,OAAO;IACP,OAAO;IACP,YAAY;IACZ,QAAQ;IACR,QAAQ;IACR,QAAQ;IACR,cAAc;IACd,OAAO;IACP,QAAQ;IACR,eAAe;IACf,OAAO;IACP,QAAQ;IACR,SAAS;IACT,QAAQ;IACR,QAAQ;IACR,QAAQ;IACR,OAAO;IACP,OAAO;IACP,QAAQ;IACR,OAAO;IACP,QAAQ;IACR,oBAAoB;IACpB,QAAQ;IACR,QAAQ;IACR,QAAQ;IACR,QAAQ;CACT,CAAC,CAAC;AAEH;;;;;;;GAOG;AACH,MAAM,UAAU,iBAAiB,CAAC,MAAc;IAC9C,MAAM,KAAK,GAAG,MAAM,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;IAChC,IAAI,KAAK,CAAC,MAAM,IAAI,CAAC,EAAE,CAAC;QACtB,OAAO,MAAM,CAAC;IAChB,CAAC;IAED,sDAAsD;IACtD,MAAM,OAAO,GAAG,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;IAC1C,IAAI,eAAe,CAAC,GAAG,CAAC,OAAO,CAAC,EAAE,CAAC;QACjC,8CAA8C;QAC9C,OAAO,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;IACnC,CAAC;IAED,0CAA0C;IAC1C,OAAO,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;AACnC,CAAC"}
package/dist/lib/deps.js CHANGED
@@ -54,7 +54,7 @@ const REQUIRED_DEPS = {
54
54
  'remark-math': '^6.0.0',
55
55
  'remark-smartypants': '^3.0.2',
56
56
  // Math/LaTeX rendering
57
- 'katex': '^0.16.28',
57
+ 'katex': '^0.16.33',
58
58
  // Diagrams
59
59
  'mermaid': '^11.12.2',
60
60
  // YAML parsing (for OpenAPI specs)
@@ -70,8 +70,8 @@ const REQUIRED_DEPS = {
70
70
  'unist-util-visit': '^5.0.0',
71
71
  'hast': '^1.0.0',
72
72
  // CSS
73
- 'tailwindcss': '^4.2.0',
74
- '@tailwindcss/postcss': '^4.2.0',
73
+ 'tailwindcss': '^4.2.1',
74
+ '@tailwindcss/postcss': '^4.2.1',
75
75
  '@tailwindcss/typography': '^0.5.10',
76
76
  'postcss': '^8.4.32',
77
77
  'autoprefixer': '^10.4.24',
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "jamdesk",
3
- "version": "1.0.11",
3
+ "version": "1.0.13",
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",
@@ -93,7 +93,7 @@
93
93
  },
94
94
  "dependencies": {
95
95
  "@apidevtools/swagger-parser": "^12.1.0",
96
- "@inquirer/prompts": "^8.1.0",
96
+ "@inquirer/prompts": "^8.3.0",
97
97
  "ajv": "^8.17.1",
98
98
  "chalk": "^5.3.0",
99
99
  "commander": "^14.0.3",
@@ -610,9 +610,12 @@ export default async function DocPage({ params }: PageProps) {
610
610
  />
611
611
  )}
612
612
 
613
- {/* Additional MDX content (e.g., ResponseExample) */}
613
+ {/* Additional MDX content strip <ResponseExample> on OpenAPI pages
614
+ (auto-generated ResponseExamplePanel already handles responses) */}
614
615
  <MDXRemote
615
- source={content}
616
+ source={openApiEndpointData
617
+ ? content.replace(/<ResponseExample>[\s\S]*?<\/ResponseExample>/g, '')
618
+ : content}
616
619
  components={AllComponentsWithInline}
617
620
  options={{
618
621
  // Keep expression props (e.g. cols={2}) compatible under next-mdx-remote v6.
@@ -16,6 +16,7 @@ import path from 'path';
16
16
  import type { DocsConfig, Favicon, FontConfig } from '@/lib/docs-types';
17
17
  import { ASSET_PREFIX, transformConfigImagePath } from '@/lib/docs-types';
18
18
  import { LinkPrefixProvider } from '@/lib/link-prefix-context';
19
+ import { getAnalyticsScript } from '@/lib/analytics-script';
19
20
 
20
21
  // Pre-load fonts - Next.js will tree-shake unused ones
21
22
  const inter = Inter({
@@ -223,9 +224,11 @@ export default async function RootLayout({
223
224
  }) {
224
225
  // Get config - from R2 in ISR mode, from filesystem in static mode
225
226
  let config: DocsConfig;
227
+ let resolvedProjectSlug: string | null = null;
226
228
  if (isIsrMode()) {
227
229
  const headersList = await headers();
228
230
  const projectSlug = getProjectFromRequest(headersList);
231
+ resolvedProjectSlug = projectSlug;
229
232
  const hostAtDocs = getHostAtDocs(headersList);
230
233
  if (projectSlug) {
231
234
  try {
@@ -279,9 +282,10 @@ export default async function RootLayout({
279
282
  // Link prefix for hostAtDocs: when true, MDX component links need /docs prefix
280
283
  const linkPrefix = config.hostAtDocs ? '/docs' : '';
281
284
 
282
- // Jamdesk Analytics - built-in tracking for all documentation sites
283
- // Tracks page views and sends to dashboard analytics endpoint
284
- const analyticsEnabled = config.analytics?.enabled !== false; // Default true
285
+ // Jamdesk Analytics - enabled by default, opt-out via analytics.enabled: false
286
+ const analyticsScript = config.analytics?.enabled !== false
287
+ ? getAnalyticsScript(resolvedProjectSlug)
288
+ : null;
285
289
 
286
290
  return (
287
291
  <html lang="en" suppressHydrationWarning>
@@ -420,122 +424,8 @@ export default async function RootLayout({
420
424
  <style dangerouslySetInnerHTML={{ __html: customCss }} />
421
425
  )}
422
426
  {/* Jamdesk Analytics - tracks page views for analytics dashboard */}
423
- {analyticsEnabled && (
424
- <script
425
- dangerouslySetInnerHTML={{
426
- __html: `
427
- (function() {
428
- // Extract project slug from hostname (e.g., "acme" from "acme.jamdesk.com")
429
- var h = location.hostname;
430
- var parts = h.split('.');
431
- var slug = null;
432
-
433
- // Check for *.jamdesk.com, *.jamdesk.dev, or *.jamdesk.app subdomains
434
- if ((h.endsWith('.jamdesk.com') || h.endsWith('.jamdesk.dev') || h.endsWith('.jamdesk.app')) && parts.length >= 3) {
435
- slug = parts[0];
436
- }
437
-
438
- // Skip tracking for localhost or if no valid slug
439
- if (!slug || h.indexOf('localhost') !== -1) {
440
- console.log('[Jamdesk Analytics] Skipped: no valid project slug');
441
- return;
442
- }
443
-
444
- // Generate session ID (persisted for 30 minutes of inactivity)
445
- var SESSION_KEY = 'jd_sid';
446
- var SESSION_TIMEOUT = 30 * 60 * 1000; // 30 minutes
447
-
448
- function getSessionId() {
449
- var stored = sessionStorage.getItem(SESSION_KEY);
450
- var data = stored ? JSON.parse(stored) : null;
451
- var now = Date.now();
452
-
453
- if (data && (now - data.lastActivity) < SESSION_TIMEOUT) {
454
- data.lastActivity = now;
455
- sessionStorage.setItem(SESSION_KEY, JSON.stringify(data));
456
- return data.id;
457
- }
458
-
459
- // New session
460
- var newId = Math.random().toString(36).substr(2, 9) + Date.now().toString(36);
461
- sessionStorage.setItem(SESSION_KEY, JSON.stringify({ id: newId, lastActivity: now }));
462
- return newId;
463
- }
464
-
465
- // Get timezone for country fallback
466
- function getTimezone() {
467
- try {
468
- return Intl.DateTimeFormat().resolvedOptions().timeZone;
469
- } catch (e) {
470
- return null;
471
- }
472
- }
473
-
474
- // Track page view
475
- function trackPageView() {
476
- var data = {
477
- projectSlug: slug,
478
- path: location.pathname,
479
- referrer: document.referrer || null,
480
- userAgent: navigator.userAgent,
481
- sessionId: getSessionId(),
482
- type: 'pageview',
483
- eventId: slug + '-' + location.pathname + '-' + Date.now(),
484
- timezone: getTimezone()
485
- };
486
-
487
- // Send to analytics endpoint (proxied via first-party domain to avoid ad blockers)
488
- fetch('/_jd/ev', {
489
- method: 'POST',
490
- headers: { 'Content-Type': 'application/json' },
491
- body: JSON.stringify(data),
492
- keepalive: true
493
- }).catch(function() { /* Ignore errors */ });
494
- }
495
-
496
- // Track current path to avoid duplicate tracking
497
- var lastTrackedPath = location.pathname;
498
-
499
- // Track page view (with deduplication)
500
- function trackIfNewPath() {
501
- var currentPath = location.pathname;
502
- if (currentPath !== lastTrackedPath) {
503
- lastTrackedPath = currentPath;
504
- trackPageView();
505
- }
506
- }
507
-
508
- // Track initial page view
509
- trackPageView();
510
-
511
- // Track SPA navigation (History API)
512
- var origPushState = history.pushState;
513
- history.pushState = function() {
514
- origPushState.apply(this, arguments);
515
- setTimeout(trackIfNewPath, 0);
516
- };
517
-
518
- var origReplaceState = history.replaceState;
519
- history.replaceState = function() {
520
- origReplaceState.apply(this, arguments);
521
- setTimeout(trackIfNewPath, 0);
522
- };
523
-
524
- window.addEventListener('popstate', function() {
525
- setTimeout(trackIfNewPath, 0);
526
- });
527
-
528
- // Fallback: Poll for URL changes (catches Next.js soft navigation)
529
- setInterval(function() {
530
- if (location.pathname !== lastTrackedPath) {
531
- lastTrackedPath = location.pathname;
532
- trackPageView();
533
- }
534
- }, 1000);
535
- })();
536
- `,
537
- }}
538
- />
427
+ {analyticsScript && (
428
+ <script dangerouslySetInnerHTML={{ __html: analyticsScript }} />
539
429
  )}
540
430
  </head>
541
431
  <body className={fontClassName} data-theme={themeName || 'jam'}>
@@ -361,6 +361,24 @@ export function ApiPageWrapper({ children }: ApiPageWrapperProps) {
361
361
  return () => window.removeEventListener('resize', handleResize);
362
362
  }, [isDesktop, mounted, applyPanelHeights]);
363
363
 
364
+ // Recalculate sidebar panel heights when a CodePanel switches tabs
365
+ useEffect(() => {
366
+ if (!sidebarRef.current || !isDesktop || !mounted) return;
367
+
368
+ const handleTabChange = (e: Event) => {
369
+ const panel = (e.target as Element).closest('[data-code-panel]');
370
+ if (panel) {
371
+ // Invalidate cached measurement — content changed
372
+ panelDataRef.current.delete(panel);
373
+ requestAnimationFrame(() => applyPanelHeights());
374
+ }
375
+ };
376
+
377
+ const sidebar = sidebarRef.current;
378
+ sidebar.addEventListener('codepanel-tab-change', handleTabChange);
379
+ return () => sidebar.removeEventListener('codepanel-tab-change', handleTabChange);
380
+ }, [isDesktop, mounted, applyPanelHeights]);
381
+
364
382
  return (
365
383
  <div className="flex h-full">
366
384
  {/* Main content area with independent scroll */}
@@ -877,10 +877,10 @@ function CodeExamplesSection({ examples }: { examples: CodeExamples }) {
877
877
  * Renders full endpoint documentation from OpenAPI spec data.
878
878
  * Composes existing ParamField, ResponseField, and CodeGroup components.
879
879
  */
880
- export function OpenApiEndpoint({
881
- endpoint,
880
+ export function OpenApiEndpoint({
881
+ endpoint,
882
882
  codeExamples,
883
- children
883
+ children
884
884
  }: OpenApiEndpointProps) {
885
885
  const {
886
886
  method,
@@ -174,17 +174,77 @@ function findNavigationPath(config: DocsConfig, targetSlug: string): BreadcrumbI
174
174
  }
175
175
 
176
176
  /**
177
- * Get page title from frontmatter or slug
177
+ * Find the page's navigation title from docs.json config.
178
+ * Falls back to formatting the last slug segment.
178
179
  */
179
180
  function getPageTitle(slug: string[], config?: DocsConfig): string {
180
- // For now, just format the last segment nicely
181
- // TODO: Could read from frontmatter or navigation title
181
+ if (config) {
182
+ const targetSlug = slug.join('/');
183
+ const title = findPageNavTitle(config, targetSlug);
184
+ if (title) return title;
185
+ }
182
186
  const lastSegment = slug[slug.length - 1];
183
187
  return lastSegment
184
188
  .replace(/-/g, ' ')
185
189
  .replace(/\b\w/g, (l) => l.toUpperCase());
186
190
  }
187
191
 
192
+ /**
193
+ * Search navigation for the page's title (from enhanced nav or page object).
194
+ */
195
+ function findPageNavTitle(config: DocsConfig, targetSlug: string): string | null {
196
+ const nav = config.navigation;
197
+
198
+ function searchPages(pages: (NavigationPage | GroupConfig)[]): string | null {
199
+ for (const item of pages) {
200
+ if (typeof item === 'object' && 'group' in item) {
201
+ const groupItem = item as GroupConfig;
202
+ if (groupItem.pages) {
203
+ const found = searchPages(groupItem.pages);
204
+ if (found) return found;
205
+ }
206
+ } else {
207
+ const { path, title } = normalizeNavPage(item as NavigationPage);
208
+ if (path === targetSlug) return title;
209
+ }
210
+ }
211
+ return null;
212
+ }
213
+
214
+ function searchGroups(groups: GroupConfig[]): string | null {
215
+ for (const group of groups) {
216
+ if (group.pages) {
217
+ const found = searchPages(group.pages);
218
+ if (found) return found;
219
+ }
220
+ }
221
+ return null;
222
+ }
223
+
224
+ // Search all navigation structures
225
+ if (nav.languages) {
226
+ for (const lang of nav.languages) {
227
+ if (lang.tabs) {
228
+ for (const tab of lang.tabs) {
229
+ if (tab.groups) { const r = searchGroups(tab.groups); if (r) return r; }
230
+ }
231
+ }
232
+ }
233
+ }
234
+ if (nav.anchors) {
235
+ for (const anchor of nav.anchors) {
236
+ if (anchor.groups) { const r = searchGroups(anchor.groups); if (r) return r; }
237
+ }
238
+ }
239
+ if (nav.tabs) {
240
+ for (const tab of nav.tabs) {
241
+ if (tab.groups) { const r = searchGroups(tab.groups); if (r) return r; }
242
+ }
243
+ }
244
+ if (nav.groups) { const r = searchGroups(nav.groups); if (r) return r; }
245
+ return null;
246
+ }
247
+
188
248
  export function Breadcrumb({ slug, config }: BreadcrumbProps) {
189
249
  const linkPrefix = useLinkPrefix();
190
250
  const homeLink = config ? `${linkPrefix}/${getFirstPage(config)}` : `${linkPrefix}/introduction`;
@@ -53,10 +53,11 @@ interface NavPageProps {
53
53
  pathname: string | null;
54
54
  layout: LayoutVariant;
55
55
  onPrefetch: (path: string) => void;
56
+ onNavigate: (href: string) => void;
56
57
  linkPrefix?: string; // e.g., '/docs' when hostAtDocs is true
57
58
  }
58
59
 
59
- export const NavPage = React.memo(function NavPage({ page, pathname, layout, onPrefetch, linkPrefix = '' }: NavPageProps) {
60
+ export const NavPage = React.memo(function NavPage({ page, pathname, layout, onPrefetch, onNavigate, linkPrefix = '' }: NavPageProps) {
60
61
  const href = `${linkPrefix}/${page.path}`;
61
62
  const isActive = pathname === href;
62
63
  const colors = page.method ? methodColors[page.method] : null;
@@ -67,6 +68,7 @@ export const NavPage = React.memo(function NavPage({ page, pathname, layout, onP
67
68
  href={href}
68
69
  prefetch={false}
69
70
  onMouseEnter={() => onPrefetch(page.path)}
71
+ onClick={() => onNavigate(href)}
70
72
  className={`flex items-center gap-2 ${layout === 'header-logo' ? 'pr-3' : 'px-3'} py-1.5 rounded-lg text-sm transition-colors ${
71
73
  isActive
72
74
  ? 'text-[var(--color-primary)] nav-active'
@@ -92,6 +94,30 @@ export const NavPage = React.memo(function NavPage({ page, pathname, layout, onP
92
94
  );
93
95
  });
94
96
 
97
+ /** Find the first page path in a group, searching items, pages, and nested groups */
98
+ function findFirstPageInGroups(groups: ResolvedGroup[]): string | null {
99
+ for (const group of groups) {
100
+ // Prefer ordered items array (includes both pages and nested groups in order)
101
+ if (group.items) {
102
+ for (const item of group.items) {
103
+ if (item.type === 'page') return item.page.path;
104
+ if (item.type === 'group') {
105
+ const nested = findFirstPageInGroups([item.group]);
106
+ if (nested) return nested;
107
+ }
108
+ }
109
+ } else {
110
+ // Legacy format: pages + nested arrays
111
+ if (group.pages.length > 0) return group.pages[0].path;
112
+ if (group.nested) {
113
+ const nested = findFirstPageInGroups(group.nested);
114
+ if (nested) return nested;
115
+ }
116
+ }
117
+ }
118
+ return null;
119
+ }
120
+
95
121
  /** Find all groups in the path from root to the page containing currentPath */
96
122
  function findGroupsContainingPath(groups: ResolvedGroup[], currentPath: string, parentNames: string[] = []): Set<string> {
97
123
  const result = new Set<string>();
@@ -121,8 +147,9 @@ export function Sidebar({ config, layout = 'header-logo', tabsPosition: tabsPosi
121
147
  const sidebarRef = useRef<HTMLElement>(null);
122
148
  const linkPrefix = useLinkPrefix();
123
149
 
124
- // Optimistic pathname: use pending (from search navigation) until real pathname catches up
125
- const handleSearchNavigate = useCallback((url: string) => {
150
+ // Optimistic navigation: immediately highlight clicked link while page loads.
151
+ // Strips hash fragments so anchor links (e.g. /page#section) match pathname.
152
+ const handleNavigate = useCallback((url: string) => {
126
153
  setPendingPathname(url.split('#')[0]);
127
154
  }, []);
128
155
 
@@ -148,28 +175,43 @@ export function Sidebar({ config, layout = 'header-logo', tabsPosition: tabsPosi
148
175
  // In sidebar-logo layout, logo and search are in sidebar
149
176
  const showLogoInSidebar = layout === 'sidebar-logo';
150
177
  const showSearchInSidebar = layout === 'sidebar-logo';
151
-
178
+
152
179
  // Logo configuration
153
180
  const logoConfig = normalizeLogo(config.logo, config.assetVersion);
154
181
  const logoHref = logoConfig?.href || '/';
155
182
  const logoSrc = logoConfig ? (isDark && logoConfig.dark ? logoConfig.dark : logoConfig.light) : null;
156
183
  const showLogoImage = logoSrc && !logoError;
157
184
 
158
- // Resolve navigation using the new resolver
159
- // Use the actual pathname never fall back to '/docs' which resolves the wrong
160
- // active tab and causes the sidebar to highlight "Introduction" instead of the current page
185
+ // Resolve navigation structure (tab/anchor selection) using the raw pathname.
186
+ // Uses effectivePathname (not activePathname) because navigation resolution
187
+ // needs the actual URL for correct tab detection activePathname is only for
188
+ // highlight matching within the resolved groups.
161
189
  const resolvedNav = useMemo(() => {
162
190
  return resolveNavigation(config, effectivePathname || pathname || '/');
163
191
  }, [config, effectivePathname, pathname]);
164
192
 
193
+ // Normalize bare root path to first page path for active state highlighting.
194
+ // When an upstream proxy (e.g., Cloudflare Worker) follows the server redirect
195
+ // from /docs → /docs/introduction internally, the browser URL stays at /docs.
196
+ // This causes usePathname() to return "/docs" which doesn't match any nav link.
197
+ // Map the bare root to the first page so the sidebar highlights correctly.
198
+ const activePathname = useMemo(() => {
199
+ if (!effectivePathname) return effectivePathname;
200
+ const rootPath = linkPrefix || '/';
201
+ if (effectivePathname !== rootPath) return effectivePathname;
202
+
203
+ const firstPage = findFirstPageInGroups(resolvedNav.groups);
204
+ return firstPage ? `${linkPrefix}/${firstPage}` : effectivePathname;
205
+ }, [effectivePathname, linkPrefix, resolvedNav.groups]);
206
+
165
207
  // Track if this is the initial mount (for resetting expanded state on refresh)
166
208
  const isInitialMount = useRef(true);
167
209
 
168
210
  // Memoize the groups that should be expanded for the current page
169
211
  const groupsForCurrentPage = useMemo(() => {
170
- const currentPath = effectivePathname?.replace(/^\/(?:docs\/)?/, '') || '';
212
+ const currentPath = activePathname?.replace(/^\/(?:docs\/)?/, '') || '';
171
213
  return findGroupsContainingPath(resolvedNav.groups, currentPath);
172
- }, [resolvedNav.groups, effectivePathname]);
214
+ }, [resolvedNav.groups, activePathname]);
173
215
 
174
216
  // Expand groups containing current page
175
217
  // On initial mount: reset to only current page's groups
@@ -241,7 +283,7 @@ export function Sidebar({ config, layout = 'header-logo', tabsPosition: tabsPosi
241
283
  });
242
284
 
243
285
  return () => cancelAnimationFrame(rafId);
244
- }, [effectivePathname]);
286
+ }, [activePathname]);
245
287
 
246
288
  // Prevent body scroll when sidebar is open on mobile
247
289
  useEffect(() => {
@@ -255,16 +297,6 @@ export function Sidebar({ config, layout = 'header-logo', tabsPosition: tabsPosi
255
297
  };
256
298
  }, [isOpen]);
257
299
 
258
- // Find the first page in a group (including nested groups)
259
- function findFirstPageInGroup(g: ResolvedGroup): string | null {
260
- if (g.pages.length > 0) return g.pages[0].path;
261
- for (const nested of g.nested || []) {
262
- const nestedFirst = findFirstPageInGroup(nested);
263
- if (nestedFirst) return nestedFirst;
264
- }
265
- return null;
266
- }
267
-
268
300
  // Toggle group expansion; if expanding, navigate to first page
269
301
  const handleGroupClick = useCallback((group: ResolvedGroup) => {
270
302
  setExpandedGroups(prev => {
@@ -272,7 +304,7 @@ export function Sidebar({ config, layout = 'header-logo', tabsPosition: tabsPosi
272
304
  if (prev.has(group.name)) {
273
305
  newSet.delete(group.name);
274
306
  } else {
275
- const firstPagePath = findFirstPageInGroup(group);
307
+ const firstPagePath = findFirstPageInGroups([group]);
276
308
  if (firstPagePath) router.push(`${linkPrefix}/${firstPagePath}`);
277
309
  newSet.add(group.name);
278
310
  }
@@ -346,9 +378,10 @@ export function Sidebar({ config, layout = 'header-logo', tabsPosition: tabsPosi
346
378
  <NavPage
347
379
  key={p.page.path}
348
380
  page={p.page}
349
- pathname={effectivePathname}
381
+ pathname={activePathname}
350
382
  layout={layout}
351
383
  onPrefetch={handlePrefetch}
384
+ onNavigate={handleNavigate}
352
385
  linkPrefix={linkPrefix}
353
386
  />
354
387
  ))}
@@ -384,9 +417,10 @@ export function Sidebar({ config, layout = 'header-logo', tabsPosition: tabsPosi
384
417
  <NavPage
385
418
  key={page.path}
386
419
  page={page}
387
- pathname={effectivePathname}
420
+ pathname={activePathname}
388
421
  layout={layout}
389
422
  onPrefetch={handlePrefetch}
423
+ onNavigate={handleNavigate}
390
424
  linkPrefix={linkPrefix}
391
425
  />
392
426
  ))}
@@ -431,20 +465,7 @@ export function Sidebar({ config, layout = 'header-logo', tabsPosition: tabsPosi
431
465
  );
432
466
  }
433
467
 
434
- // Find the first page in this anchor's groups
435
- const findFirstPage = (groups: ResolvedGroup[]): string | null => {
436
- for (const group of groups) {
437
- if (group.pages.length > 0) {
438
- return group.pages[0].path;
439
- }
440
- if (group.nested) {
441
- const nestedFirst = findFirstPage(group.nested);
442
- if (nestedFirst) return nestedFirst;
443
- }
444
- }
445
- return null;
446
- };
447
- const firstPagePath = findFirstPage(anchor.groups);
468
+ const firstPagePath = findFirstPageInGroups(anchor.groups);
448
469
 
449
470
  return (
450
471
  <button
@@ -721,7 +742,7 @@ export function Sidebar({ config, layout = 'header-logo', tabsPosition: tabsPosi
721
742
  </aside>
722
743
 
723
744
  {/* Search Modal - shown when search is opened from sidebar */}
724
- <SearchModal isOpen={isSearchOpen} onClose={() => setIsSearchOpen(false)} onNavigate={handleSearchNavigate} />
745
+ <SearchModal isOpen={isSearchOpen} onClose={() => setIsSearchOpen(false)} onNavigate={handleNavigate} />
725
746
  </>
726
747
  );
727
748
  }
@@ -0,0 +1,25 @@
1
+ // Auto-generated file - do not edit manually
2
+ // @ts-nocheck
3
+
4
+ import React from 'react';
5
+
6
+ // Import built-in MDX components that snippets can use
7
+ import { Note, Info, Warning, Tip, Check, Danger, Callout } from '@/components/mdx/Callouts';
8
+ import { Card } from '@/components/mdx/Card';
9
+ import { CardGroup } from '@/components/mdx/CardGroup';
10
+ import { ParamField } from '@/components/mdx/ParamField';
11
+ import { ResponseField } from '@/components/mdx/ResponseField';
12
+ import { Accordion, AccordionGroup } from '@/components/mdx/Accordion';
13
+ import { CodeGroup } from '@/components/mdx/CodeGroup';
14
+ import { Steps, Step } from '@/components/mdx/Steps';
15
+
16
+
17
+ const CodeLink = ({ title, href }: any) => {
18
+ return (
19
+ <Card title={`${title}`} href={`${href}`} horizontal icon="code">
20
+ {" "}
21
+ </Card>
22
+ );
23
+ };
24
+
25
+ export default CodeLink;