10BC0 [Docs][Util][Content] - refactor docs to single source by madster456 · Pull Request #919 · stack-auth/stack-auth · GitHub
[go: up one dir, main page]

Skip to content

Conversation

madster456
Copy link
Collaborator
@madster456 madster456 commented Oct 1, 2025

Removes Platform selection, moves docs to single /content folder and no longer gens docs. Only API docs are generated here.

High-level PR Summary

This PR makes significant changes to the documentation structure by removing platform-specific content organization and consolidating docs into a single /content folder. The primary goal is to simplify the documentation architecture by eliminating the platform-specific routing (Next.js, React, JavaScript, Python) and instead organizing content by topic (guides, SDK, components) regardless of platform. The PR removes platform selection functionality, platform-specific navigation, and the automatic generation of platform-specific documentation pages. It introduces a new docs tree filtering system that organizes content by section rather than by platform. These changes should make the documentation more maintainable and easier to navigate while focusing on the content itself rather than platform-specific variations.

⏱️ Estimated Review Time: 30-90 minutes

💡 Review Order Suggestion
Order File Path
1 docs/package.json
2 docs/src/lib/docs-tree.ts
3 docs/src/lib/navigation-utils.ts
4 docs/src/components/homepage/iconHover.tsx
5 docs/src/components/sdk/overview.tsx
6 docs/src/components/layouts/shared/section-utils.ts
7 docs/src/components/layout/custom-search-dialog.tsx
8 docs/src/app/api/search/route.ts
9 docs/src/app/docs/[[...slug]]/page.tsx
10 docs/src/components/layouts/docs-header-wrapper.tsx
11 docs/src/components/layouts/docs-layout-router.tsx
12 docs/src/components/layouts/docs.tsx
13 package.json

Need help? Join our Discord

Summary by CodeRabbit

  • New Features

    • Interactive PlatformCodeblock for switching platform/framework code examples.
  • Documentation

    • Major expansion: comprehensive Guides, SDK reference, Components, and API docs (auth providers, API keys, emails, JWT, OAuth, teams, 2FA, webhooks, customization, examples, CLI, self-host, integrations).
  • Refactor

    • Unified docs into section-based navigation (Guides/SDK/Components); removed per-platform selectors/redirects and platform-specific filtering; simplified search and homepage docs presentation; various layout and UI refinements.
  • Chores

    • Removed legacy docs-generation/config and streamlined build/dev scripts.

Copy link
vercel bot commented Oct 1, 2025

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Preview Comments Updated (UTC)
stack-backend Ready Ready Preview Comment Oct 8, 2025 11:38am
stack-dashboard Ready Ready Preview Comment Oct 8, 2025 11:38am
stack-demo Ready Ready Preview Comment Oct 8, 2025 11:38am
stack-docs Error Error Oct 8, 2025 11:38am

Copy link
Contributor
coderabbitai bot commented Oct 1, 2025

Walkthrough

Removed platform-specific docs generation and persistence, refactored docs to section-based routing and navigation, simplified search and redirects, added PlatformCodeblock and platform/framework config, updated build/dev scripts and .gitignore, and added many new Guides, Components, and SDK documentation pages.

Changes

Cohort / File(s) Summary
Platform removal & generators
docs/docs-platform.yml, docs/scripts/generate-docs.js, docs/scripts/generate-platform-navigation.js, docs/src/lib/platform-utils.ts, docs/src/hooks/use-platform-persistence.ts, docs/src/hooks/use-platform-preference.ts, docs/src/components/platform-redirect.tsx, docs/src/components/layout/root-toggle.tsx, docs/src/components/layout/platform-aware-header.tsx
Remove platform-driven generation, navigation config, platform utilities, persistence hooks, platform redirect and UI, and generator scripts.
Section-based layout & nav refactor
docs/src/lib/docs-tree.ts, docs/src/lib/navigation-utils.ts, docs/src/components/layouts/docs-header-wrapper.tsx, docs/src/components/layouts/docs-layout-router.tsx, docs/src/components/layouts/docs.tsx, docs/src/components/layouts/shared/section-utils.ts
Add section-aware tree filtering, static nav links, and replace platform-aware header/sidebar logic with section-based rendering and simplified sidebar generation.
Homepage, search & routing
docs/src/components/homepage/iconHover.tsx, docs/src/components/layout/custom-search-dialog.tsx, docs/src/app/api/search/route.ts, docs/src/app/docs/[[...slug]]/page.tsx, docs/src/components/sdk/overview.tsx
Remove platform selection from homepage and search dialog; search dedup/sort now uses score-only; docs root redirect picks a default section URL; SDK URLs normalized under /docs/sdk.
PlatformCodeblock & config
docs/src/components/mdx/platform-codeblock.tsx, docs/src/components/mdx/platform-config.ts, docs/src/mdx-components.tsx, docs/content/docs/(guides)/getting-started/platform-codeblock-example.mdx
Add PlatformCodeblock MDX component with global/session sync, Shiki highlighting, platform/framework config helpers, and an example MDX page.
Docs content — Guides
docs/content/docs/(guides)/* (many new files; e.g., concepts/*, auth-providers/*, getting-started/*, customization/*, backend-integration.mdx, oauth.mdx, jwt.mdx, emails.mdx, webhooks.mdx, orgs-and-teams.mdx, permissions.mdx)
Add numerous Guides pages with examples, code snippets, and navigation metadata (meta.json).
Docs content — Components
docs/content/docs/components/* (index, sign-in.mdx, sign-up.mdx, credential-sign-in.mdx, credential-sign-up.mdx, oauth-button*.mdx, user-button.mdx, account-settings.mdx, forgot-password.mdx, password-reset.mdx, stack-provider.mdx, stack-theme.mdx, stack-handler.mdx, meta.json, etc.)
Add component reference MDX pages, props tables, demos, and metadata for component docs.
Docs content — SDK & types
docs/content/docs/sdk/* (index.mdx, overview-new.mdx, meta.json, hooks/, objects/, types/*)
Add SDK reference pages, hooks docs, object/type reference MDX files and exported mdx constants.
Scripts, packages & ignore
package.json, docs/package.json, docs/.gitignore
Remove docs-generation scripts and watchers; simplify build/dev scripts to rely on OpenAPI and Next.js; update .gitignore to ignore generated API/OpenAPI output.
UI / layout & styling tweaks
multiple files under docs/src/components/*, docs/src/app/*, docs/src/app/global.css (e.g., shared-header, header wrappers, TOC, api layout, chat/auth panels, dynamic overlay)
Adjust header layout, sidebar behavior, TOC/chat/auth panel positioning, overlay styling, and spacing to align with section-based layout and removed platform UI.

Sequence Diagram(s)

sequenceDiagram
  autonumber
  participant U as User
  participant R as Next.js Router
  participant L as DocsLayout
  participant T as DocsTree
  participant H as SharedHeader

  U->>R: Navigate to /docs/...
  R->>L: Render docs layout with page tree
  L->>T: resolveDocsSection(pathname)
  T-->>L: filtered sectionTree
  L->>H: generateNavLinks()
  L-->>U: Render content + section-specific sidebar
Loading
sequenceDiagram
  autonumber
  participant U as User
  participant D as Search Dialog
  participant S as Search API

  U->>D: open / type query
  D->>S: fetch results
  S-->>D: results (scored)
  D->>D: group by basePath, sort by score (no platform tie-break)
  D-->>U: render flattened results
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Possibly related PRs

Poem

I thump through docs from section to guide,
Tabs and platforms gently set aside.
Codeblocks glow with Shiki's light,
Headers tidy, navs take flight.
Carrots baked, the docs hop wide — hooray! 🥕📚

Pre-merge checks and finishing touches

❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (2 passed)
Check name Status Explanation
Title Check ✅ Passed The title “[Docs][Util][Content] - refactor docs to single source” concisely highlights the main change of consolidating documentation into a single source and categorizes the change with clear tags. It avoids file lists, emojis, or overly vague terms and conveys the primary intent of the PR to teammates scanning the history.
Description Check ✅ Passed The pull request description includes the required CONTRIBUTING.md reminder comment and provides a clear one-sentence summary followed by a high-level overview, detailed objectives, and a suggested review order. It exceeds the minimal template requirements and gives reviewers ample context to understand the scope and impact of the changes.
✨ Finishing touches
  • 📝 Generate Docstrings
🧪 Generate unit tests
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch docs/rework/platforms

📜 Recent review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 0591064 and 19ccd77.

📒 Files selected for processing (1)
  • docs/src/components/mdx/dynamic-code-block-overlay.tsx (2 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • docs/src/components/mdx/dynamic-code-block-overlay.tsx
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (9)
  • GitHub Check: Vercel Agent Review
  • GitHub Check: restart-dev-and-test
  • GitHub Check: all-good
  • GitHub Check: build (22.x)
  • GitHub Check: build (22.x)
  • GitHub Check: docker
  • GitHub Check: docker
  • GitHub Check: lint_and_build (latest)
  • GitHub Check: Security Check

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Contributor
ellipsis-dev bot commented Oct 1, 2025

⚠️ This PR is too big for Ellipsis, but support for larger PRs is coming soon. If you want us to prioritize this feature, let us know at help@ellipsis.dev


Generated with ❤️ by ellipsis.dev

Copy link
@recurseml recurseml bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Review by RecurseML

🔍 Review performed on f5a3a99..47ccd2b

  Severity     Location     Issue     Delete  
Medium docs/src/lib/docs-tree.ts:8 URL string concatenation instead of using proper URL construction utility
Medium docs/src/lib/docs-tree.ts:12 URL string concatenation instead of using proper URL construction utility
Medium docs/src/lib/docs-tree.ts:59 Non-null assertion with ! operator instead of ?? throwErr pattern
Medium docs/src/lib/docs-tree.ts:83 URL string concatenation instead of using proper URL construction utility
Medium docs/src/lib/docs-tree.ts:87 URL string concatenation instead of using proper URL construction utility
Medium docs/src/lib/docs-tree.ts:91 URL string concatenation instead of using proper URL construction utility
Medium docs/src/lib/docs-tree.ts:95 URL string concatenation instead of using proper URL construction utility
Low docs/src/lib/navigation-utils.ts:17 The code change removes URL string concatenation which is the correct approach according to the custom rule
Low docs/src/lib/navigation-utils.ts:27 The code change appropriately replaces URL string concatenation with constants
✅ Files analyzed, no issues (3)

docs/src/components/homepage/iconHover.tsx
docs/src/app/docs/[[...slug]]/page.tsx
docs/src/components/layouts/docs-header-wrapper.tsx

⏭️ Files skipped (102)
  Locations  
docs/.gitignore
docs/content/docs/(guides)/concepts/api-keys.mdx
docs/content/docs/(guides)/concepts/auth-providers/apple.mdx
docs/content/docs/(guides)/concepts/auth-providers/bitbucket.mdx
docs/content/docs/(guides)/concepts/auth-providers/discord.mdx
docs/content/docs/(guides)/concepts/auth-providers/facebook.mdx
docs/content/docs/(guides)/concepts/auth-providers/github.mdx
docs/content/docs/(guides)/concepts/auth-providers/gitlab.mdx
docs/content/docs/(guides)/concepts/auth-providers/google.mdx
docs/content/docs/(guides)/concepts/auth-providers/index.mdx
docs/content/docs/(guides)/concepts/auth-providers/linkedin.mdx
docs/content/docs/(guides)/concepts/auth-providers/meta.json
docs/content/docs/(guides)/concepts/auth-providers/microsoft.mdx
docs/content/docs/(guides)/concepts/auth-providers/passkey.mdx
docs/content/docs/(guides)/concepts/auth-providers/spotify.mdx
docs/content/docs/(guides)/concepts/auth-providers/twitch.mdx
docs/content/docs/(guides)/concepts/auth-providers/two-factor-auth.mdx
docs/content/docs/(guides)/concepts/auth-providers/x-twitter.mdx
docs/content/docs/(guides)/concepts/backend-integration.mdx
docs/content/docs/(guides)/concepts/custom-user-data.mdx
docs/content/docs/(guides)/concepts/emails.mdx
docs/content/docs/(guides)/concepts/jwt.mdx
docs/content/docs/(guides)/concepts/oauth.mdx
docs/content/docs/(guides)/concepts/orgs-and-teams.mdx
docs/content/docs/(guides)/concepts/permissions.mdx
docs/content/docs/(guides)/concepts/stack-app.mdx
docs/content/docs/(guides)/concepts/team-selection.mdx
docs/content/docs/(guides)/concepts/user-onboarding.mdx
docs/content/docs/(guides)/concepts/webhooks.mdx
docs/content/docs/(guides)/customization/custom-pages.mdx
docs/content/docs/(guides)/customization/custom-styles.mdx
docs/content/docs/(guides)/customization/dark-mode.mdx
docs/content/docs/(guides)/customization/internationalization.mdx
docs/content/docs/(guides)/customization/page-examples/forgot-password.mdx
docs/content/docs/(guides)/customization/page-examples/index.mdx
docs/content/docs/(guides)/customization/page-examples/meta.json
docs/content/docs/(guides)/customization/page-examples/password-reset.mdx
docs/content/docs/(guides)/customization/page-examples/sign-in.mdx
docs/content/docs/(guides)/customization/page-examples/sign-up.mdx
docs/content/docs/(guides)/faq.mdx
docs/content/docs/(guides)/getting-started/components.mdx
docs/content/docs/(guides)/getting-started/example-pages.mdx
docs/content/docs/(guides)/getting-started/production.mdx
docs/content/docs/(guides)/getting-started/setup.mdx
docs/content/docs/(guides)/getting-started/users.mdx
docs/content/docs/(guides)/meta.json
docs/content/docs/(guides)/others/cli-authentication.mdx
docs/content/docs/(guides)/others/convex.mdx
docs/content/docs/(guides)/others/self-host.mdx
docs/content/docs/(guides)/others/supabase.mdx
docs/content/docs/(guides)/overview.mdx
docs/content/docs/(guides)/rest-api/overview.mdx
docs/content/docs/components/account-settings.mdx
docs/content/docs/components/credential-sign-in.mdx
docs/content/docs/components/credential-sign-up.mdx
docs/content/docs/components/forgot-password.mdx
docs/content/docs/components/index.mdx
docs/content/docs/components/magic-link-sign-in.mdx
docs/content/docs/components/meta.json
docs/content/docs/components/oauth-button-group.mdx
docs/content/docs/components/oauth-button.mdx
docs/content/docs/components/password-reset.mdx
docs/content/docs/components/selected-team-switcher.mdx
docs/content/docs/components/sign-in.mdx
docs/content/docs/components/sign-up.mdx
docs/content/docs/components/stack-handler.mdx
docs/content/docs/components/stack-provider.mdx
docs/content/docs/components/stack-theme.mdx
docs/content/docs/components/user-button.mdx
docs/content/docs/sdk/hooks/use-stack-app.mdx
docs/content/docs/sdk/hooks/use-user.mdx
docs/content/docs/sdk/index.mdx
docs/content/docs/sdk/meta.json
docs/content/docs/sdk/objects/stack-app.mdx
docs/content/docs/sdk/overview-new.mdx
docs/content/docs/sdk/types/api-key.mdx
docs/content/docs/sdk/types/connected-account.mdx
docs/content/docs/sdk/types/contact-channel.mdx
docs/content/docs/sdk/types/email.mdx
docs/content/docs/sdk/types/project.mdx
docs/content/docs/sdk/types/team-permission.mdx
docs/content/docs/sdk/types/team-profile.mdx
docs/content/docs/sdk/types/team-user.mdx
docs/content/docs/sdk/types/team.mdx
docs/content/docs/sdk/types/user.mdx
docs/docs-platform.yml
docs/package.json
docs/scripts/generate-docs.js
docs/scripts/generate-platform-navigation.js
docs/src/app/api/search/route.ts
docs/src/components/layout/custom-search-dialog.tsx
docs/src/components/layout/root-toggle.tsx
docs/src/components/layouts/docs-layout-router.tsx
docs/src/components/layouts/docs.tsx
docs/src/components/layouts/platform-aware-header.tsx
docs/src/components/layouts/shared/section-utils.ts
docs/src/components/platform-redirect.tsx
docs/src/components/sdk/overview.tsx
docs/src/hooks/use-platform-persistence.ts
docs/src/hooks/use-platform-preference.ts
docs/src/lib/platform-utils.ts
package.json

Copy link
@vercel vercel bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Additional Comments:

docs/src/components/layouts/shared-header.tsx (lines 33-44):
The section detection regex patterns are outdated and won't match the new URL structure, causing navigation highlighting to fail.

View Details
📝 Patch Details
diff --git a/docs/src/components/layouts/shared-header.tsx b/docs/src/components/layouts/shared-header.tsx
index 082a3b56..c607ff95 100644
--- a/docs/src/components/layouts/shared-header.tsx
+++ b/docs/src/components/layouts/shared-header.tsx
@@ -31,16 +31,16 @@ type SharedHeaderProps = {
  * Helper functions to detect which section we're in
  */
 export function isInSdkSection(pathname: string): boolean {
-  // Match the actual SDK section: /docs/platform/sdk or /docs/platform/sdk/...
+  // Match the actual SDK section: /docs/sdk or /docs/sdk/...
   // This excludes docs pages that might mention SDK in other contexts
-  const match = pathname.match(/^\/docs\/[^\/]+\/sdk($|\/)/);
+  const match = pathname.match(/^\/docs\/sdk($|\/)/);
   return Boolean(match);
 }
 
 export function isInComponentsSection(pathname: string): boolean {
-  // Match the actual Components section: /docs/platform/components or /docs/platform/components/...
-  // This excludes docs pages like /docs/platform/getting-started/components
-  const match = pathname.match(/^\/docs\/[^\/]+\/components($|\/)/);
+  // Match the actual Components section: /docs/components or /docs/components/...
+  // This excludes docs pages like /docs/getting-started/components
+  const match = pathname.match(/^\/docs\/components($|\/)/);
   return Boolean(match);
 }
 

Analysis

Navigation highlighting fails for SDK and Components sections due to outdated URL regex patterns

What fails: isInSdkSection() and isInComponentsSection() functions in shared-header.tsx use regex patterns expecting /docs/[platform]/sdk and /docs/[platform]/components URLs, but actual URLs are /docs/sdk and /docs/components

How to reproduce:

# Navigate to any SDK or Components page:
# - /docs/sdk
# - /docs/components  
# - /docs/sdk/overview
# - /docs/components/stack-handler

Result: Navigation links remain unhighlighted (functions return false for all SDK/Components URLs). Users lose visual indication of current section.

Expected: Navigation links should highlight when viewing SDK or Components pages per navigation-utils.ts constants which define DOCS_SDK_PATH = '/docs/sdk' and DOCS_COMPONENTS_PATH = '/docs/components'


docs/src/components/layouts/shared-header.tsx (line 66):
The navigation link activation logic checks for a label 'Documentation' that doesn't exist, so the Guides section will never be highlighted as active.

View Details
📝 Patch Details
diff --git a/docs/src/components/layouts/shared-header.tsx b/docs/src/components/layouts/shared-header.tsx
index 082a3b56..760fba90 100644
--- a/docs/src/components/layouts/shared-header.tsx
+++ b/docs/src/components/layouts/shared-header.tsx
@@ -63,7 +63,7 @@ function isNavLinkActive(pathname: string, navLink: NavLink): boolean {
   if (navLink.label === 'API Reference' && isInApiSection(pathname)) {
     return true;
   }
-  if (navLink.label === 'Documentation' && pathname.startsWith('/docs') &&
+  if (navLink.label === 'Guides' && pathname.startsWith('/docs') &&
       !isInComponentsSection(pathname) && !isInSdkSection(pathname)) {
     return true;
   }

Analysis

Navigation link mismatch prevents Guides section highlighting

What fails: isNavLinkActive() in shared-header.tsx checks for navLink.label === 'Documentation' but the actual navigation link in navigation-utils.ts has label 'Guides', so the Guides section is never highlighted as active.

How to reproduce:

  1. Navigate to any docs page like /docs/overview or /docs/getting-started
  2. Check navigation - Guides link should be highlighted as active
  3. Observe that no navigation link is highlighted

Result: Guides navigation link never shows as active despite being on guides pages

Expected: Guides link should be highlighted when viewing /docs/* pages (excluding SDK and Components sections) per the intended navigation logic

Copy link
@vercel vercel bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Additional Comments:

docs/src/components/layouts/shared-header.tsx (lines 33-44):
The section detection functions isInSdkSection and isInComponentsSection use outdated platform-based URL patterns that won't work with the new documentation structure.

View Details
📝 Patch Details
diff --git a/docs/src/components/layouts/shared-header.tsx b/docs/src/components/layouts/shared-header.tsx
index 082a3b56..57a13b1d 100644
--- a/docs/src/components/layouts/shared-header.tsx
+++ b/docs/src/components/layouts/shared-header.tsx
@@ -31,17 +31,13 @@ type SharedHeaderProps = {
  * Helper functions to detect which section we're in
  */
 export function isInSdkSection(pathname: string): boolean {
-  // Match the actual SDK section: /docs/platform/sdk or /docs/platform/sdk/...
-  // This excludes docs pages that might mention SDK in other contexts
-  const match = pathname.match(/^\/docs\/[^\/]+\/sdk($|\/)/);
-  return Boolean(match);
+  // Match SDK section: /docs/sdk or /docs/platform/sdk (with optional platform prefix for backwards compatibility)
+  return new RegExp(`^/docs/(?:[a-z-]+/)?sdk(?:/.*)?The section detection functions `isInSdkSection` and `isInComponentsSection` use outdated platform\-based URL patterns that won\'t work with the new documentation structure\.


<details>
<summary>View Details</summary>
).test(pathname);
 }
 
 export function isInComponentsSection(pathname: string): boolean {
-  // Match the actual Components section: /docs/platform/components or /docs/platform/components/...
-  // This excludes docs pages like /docs/platform/getting-started/components
-  const match = pathname.match(/^\/docs\/[^\/]+\/components($|\/)/);
-  return Boolean(match);
+  // Match Components section: /docs/components or /docs/platform/components (with optional platform prefix for backwards compatibility)
+  return new RegExp(`^/docs/(?:[a-z-]+/)?components(?:/.*)?The section detection functions `isInSdkSection` and `isInComponentsSection` use outdated platform\-based URL patterns that won\'t work with the new documentation structure\.


<details>
<summary>View Details</summary>
).test(pathname);
 }
 
 export function isInApiSection(pathname: string): boolean {

Analysis

Navigation links for SDK and Components sections never highlight as active

What fails: Navigation links for "SDK" and "Components" in the header don't highlight as active when browsing /docs/sdk/ or /docs/components/ paths due to incorrect URL pattern matching in shared-header.tsx

How to reproduce:

  1. Navigate to /docs/sdk or /docs/sdk/hooks
  2. Navigate to /docs/components or /docs/components/sign-in
  3. Observe that the "SDK" and "Components" navigation links in the header remain inactive (no highlighting/underline)

Result: Navigation links stay inactive despite being in the correct sections, making navigation confusing

Expected: Links should highlight with active state (blue text + underline) when in their respective sections, as confirmed by the correct patterns in section-utils.ts

Root cause: Functions isInSdkSection() and isInComponentsSection() in shared-header.tsx used outdated regex patterns /^\/docs\/[^\/]+\/sdk/ expecting platform-based URLs like /docs/react/sdk, but current structure uses direct paths like /docs/sdk

Copy link
Contributor
@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 56

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (8)
docs/src/app/api/search/route.ts (1)

164-165: Fix relative path construction.

The relative path ./content/docs/ is fragile and depends on the current working directory at runtime. In production or different environments, this may not resolve correctly.

Apply this diff to use an absolute path:

-        const relativePath = url.replace('/docs/', './content/docs/') + '.mdx';
-        const fullPath = path.resolve(relativePath);
+        const contentDir = path.join(process.cwd(), 'content', 'docs');
+        const relativePath = url.replace('/docs/', '') + '.mdx';
+        const fullPath = path.join(contentDir, relativePath);
docs/src/components/layout/custom-search-dialog.tsx (1)

90-133: Fix timer ref typing to unblock the docs build.

This client component assigns the browser’s setTimeout (a number) into a ref typed as NodeJS.Timeout, triggering the Type 'number' is not assignable to type 'Timeout' compile error that’s causing pnpm run build docs to fail. Type the ref using ReturnType<typeof setTimeout> and guard against null so both browser and Node signatures are supported.

-  const searchTimeoutRef = useRef<NodeJS.Timeout>();
+  const searchTimeoutRef = useRef<ReturnType<typeof setTimeout> | null>(null);
@@
-    if (searchTimeoutRef.current) {
+    if (searchTimeoutRef.current !== null) {
       clearTimeout(searchTimeoutRef.current);
     }
@@
     return () => {
-      if (searchTimeoutRef.current) {
+      if (searchTimeoutRef.current !== null) {
         clearTimeout(searchTimeoutRef.current);
+        searchTimeoutRef.current = null;
       }
     };
docs/content/docs/(guides)/getting-started/example-pages.mdx (1)

1-456: Pipeline failure may be due to missing Tabs/TabsContent components.

The document uses <Tabs>, <TabsList>, <TabsTrigger>, and <TabsContent> components extensively throughout but doesn't import them. These components need to be available globally in the MDX context or imported explicitly.

Verify that these components are properly configured in your MDX setup:

#!/bin/bash
# Description: Check if Tabs components are globally available in MDX configuration

# Search for MDX component configuration
rg -n "Tabs|TabsContent|TabsList|TabsTrigger" --type=ts --type=tsx -g "**/mdx-components.*" -g "**/source.config.*" -C3

# Check fumadocs configuration
fd -e ts -e tsx -e js "source.config" --exec cat {}
docs/content/docs/sdk/types/connected-account.mdx (1)

1-6: Complete the ConnectedAccount documentation before merging.

This file only contains placeholder content. Publishing incomplete documentation provides no value to users and could indicate that the documentation refactoring is incomplete.

Would you like me to help draft the actual ConnectedAccount documentation content? I can generate documentation based on the typical structure for SDK type references.

docs/content/docs/sdk/types/user.mdx (1)

1573-1578: Critical syntax error: missing closing backticks.

The code block at the end of the file is missing its closing backticks (````), which will cause MDX parsing to fail and break the build. This likely explains the pipeline failure.

Apply this fix:

 <ClickableTableOfContents code={`type CurrentServerUser =
   // Inherits all functionality from CurrentUser
   & CurrentUser  //$stack-link-to:#currentuser
   // Inherits all functionality from ServerUser
-  & ServerUser;  //$stack-link-to:#serveruser`} />
+  & ServerUser;  //$stack-link-to:#serveruser`} />
+```
docs/content/docs/(guides)/getting-started/platform-codeblock-example.mdx (1)

598-614: Critical syntax error: missing closing backticks.

The markdown code block starting at "## Usage" is missing its closing backticks (```), which will cause MDX parsing to fail.

Apply this fix:

 - Adapt to light/dark theme changes
 - Persist selections as users switch between platforms and frameworks
+```
docs/content/docs/sdk/types/team.mdx (1)

1-691: Critical syntax error: missing closing backticks at end of file.

The code block at line 691 is missing its closing backticks (````), which will cause MDX parsing to fail and contribute to the build failure.

Apply this fix:

   </MethodLayout>
 </CollapsibleTypesSection>
+```
docs/content/docs/(guides)/getting-started/users.mdx (1)

1-254: Critical syntax error: missing closing backticks at end of file.

The code block at line 254 is missing its closing backticks (````), which will cause MDX parsing to fail and contribute to the build failure.

Apply this fix:

 For more examples on how to use the `User` object, check the [the SDK documentation](../sdk/types/user.mdx).
 
 ## Next steps
 
 In the next guide, we will show you how to put [your application into production](./production.mdx).
+```
🧹 Nitpick comments (33)
docs/src/app/docs/[[...slug]]/page.tsx (1)

14-25: Consider performance implications of calling source.getPages() on every redirect.

The helper function calls source.getPages() on every request to /docs without a slug. If this isn't internally cached by fumadocs, it could impact performance. Consider computing this value once at build time or memoizing the result.

You could cache the result:

+let cachedDefaultUrl: string | null | undefined;
+
 function getDefaultDocsRedirectUrl(): string | null {
+  if (cachedDefaultUrl !== undefined) {
+    return cachedDefaultUrl;
+  }
+
   const pages = source.getPages();
   // Prefer an overview page if one exists without platform prefix
   const overviewPage = pages.find(page => page.url === '/docs/overview');
   if (overviewPage) {
-    return overviewPage.url;
+    cachedDefaultUrl = overviewPage.url;
+    return cachedDefaultUrl;
   }
 
   // Fall back to the first docs page in the collection
   const firstDocsPage = pages.find(page => page.url.startsWith('/docs/'));
-  return firstDocsPage?.url ?? null;
+  cachedDefaultUrl = firstDocsPage?.url ?? null;
+  return cachedDefaultUrl;
 }
docs/src/components/layouts/docs-header-wrapper.tsx (3)

183-229: Improve key generation for recursive tree items.

Lines 205 and 218 use child.type === 'page' ? child.url : index for keys. Falling back to array index for non-page items (folders, separators) can cause React reconciliation issues when the tree structure changes.

Consider generating stable keys for all node types:

-            <MobilePageTreeItem key={child.type === 'page' ? child.url : index} item={child} />
+            <MobilePageTreeItem key={child.type === 'page' ? child.url : (child.type === 'folder' ? `folder-${child.name}-${index}` : `sep-${index}`)} item={child} />

Or extract a helper function to generate consistent keys:

function getNodeKey(node: PageTree.Node, index: number): string {
  if (node.type === 'page') return node.url;
  if (node.type === 'folder') return `folder-${node.name}-${index}`;
  return `separator-${node.name || index}`;
}

Then use: key={getNodeKey(child, index)}


231-241: Same key generation issue as MobilePageTreeItem.

Line 237 has the same fallback-to-index key pattern. Consider applying the same stable key generation strategy suggested for MobilePageTreeItem.


251-279: Memoize docsSection to prevent unnecessary recalculations.

Line 254 computes docsSection on every render. Since it only depends on pathname and is used in the sectionTree memoization (line 255), wrapping it with useMemo would prevent unnecessary re-filtering of the tree when other props change.

Apply this diff:

  const navLinks = useMemo(() => generateNavLinks(), []);
- const docsSection = resolveDocsSection(pathname);
+ const docsSection = useMemo(() => resolveDocsSection(pathname), [pathname]);
  const sectionTree = useMemo(() => (pageTree ? filterTreeForSection(pageTree, docsSection) : undefined), [pageTree, docsSection]);
docs/src/components/layouts/shared/section-utils.ts (2)

8-10: Replace RegExp constructor with literal regex.

Creating a RegExp via constructor on every call is less efficient than a literal regex. Since PLATFORM_PREFIX is a compile-time constant, compile the entire pattern once.

+const SDK_SECTION_REGEX = /^\/docs\/(?:[a-z-]+\/)?sdk(?:\/.*)?$/;
+
 export function isInSdkSection(pathname: string): boolean {
-  return new RegExp(`^/docs/${PLATFORM_PREFIX}sdk(?:/.*)?$`).test(pathname);
+  return SDK_SECTION_REGEX.test(pathname);
 }

This also addresses the static analysis ReDoS warning by eliminating runtime regex construction.


12-14: Replace RegExp constructors with literal regexes.

Same issue as isInSdkSection: use literal regexes for better performance.

+const COMPONENTS_SECTION_REGEX = /^\/docs\/(?:[a-z-]+\/)?components(?:\/.*)?$/;
+const CUSTOMIZATION_SECTION_REGEX = /^\/docs\/(?:[a-z-]+\/)?customization(?:\/.*)?$/;
+
 export function isInComponentsSection(pathname: string): boolean {
-  return new RegExp(`^/docs/${PLATFORM_PREFIX}components(?:/.*)?$`).test(pathname);
+  return COMPONENTS_SECTION_REGEX.test(pathname);
 }

 export function isInCustomizationSection(pathname: string): boolean {
-  return new RegExp(`^/docs/${PLATFORM_PREFIX}customization(?:/.*)?$`).test(pathname);
+  return CUSTOMIZATION_SECTION_REGEX.test(pathname);
 }

Also applies to: 20-22

docs/src/components/layouts/docs.tsx (1)

344-344: Consider renaming platformColor to reflect its new purpose.

The variable name platformColor is now misleading since platform-specific logic has been removed. Consider renaming to accentColor, primaryColor, or similar to better reflect that it's now a static theme color.

-const platformColor = 'rgb(59, 130, 246)';
+const accentColor = 'rgb(59, 130, 246)';

Then update all references to use the new name.

Also applies to: 444-444, 600-600

docs/.gitignore (1)

8-8: Remove the ignore rule for src/lib/platform-navigation.ts from docs/.gitignore. No file or references named “platform-navigation.ts” exist in the repo, so the entry is now stale.

docs/src/components/layouts/docs-layout-router.tsx (1)

42-43: Compute section and sectionTree lazily to skip filtering for API docs.

Move

const section = resolveDocsSection(pathname);
const sectionTree = useMemo(() => filterTreeForSection(props.tree, section), [props.tree, section]);

below the if (isInApiSection…) check (i.e. inside the non-API branches) so you don’t run filterTreeForSection when rendering the API layout.

docs/content/docs/(guides)/getting-started/production.mdx (1)

45-47: Brand casing: Gitlab → GitLab.

Align with official brand spelling.

-<TabsTrigger value="gitlab">Gitlab</TabsTrigger>
+<TabsTrigger value="gitlab">GitLab</TabsTrigger>
...
-    <TabsContent value="gitlab">
+    <TabsContent value="gitlab">
       [GitLab OAuth Setup Guide](https://docs.gitlab.com/ee/integration/oauth_provider.html)

Also applies to: 96-101

docs/src/components/mdx/simple-platform-example.mdx (1)

90-98: Trailing comment inside object literal is fine, but consider block style for consistency.

Not a blocker; consider /* Override default */ for consistency with MDX/JSX comment style.

docs/content/docs/(guides)/concepts/auth-providers/twitch.mdx (1)

17-31: Add local redirect URI example for dev.
Including a localhost redirect reduces first‑run friction.

-  5. Under **OAuth Redirect URLs**, add `https://api.stack-auth.com/api/v1/auth/oauth/callback/twitch`
+  5. Under **OAuth Redirect URLs**, add:
+     - `https://api.stack-auth.com/api/v1/auth/oauth/callback/twitch` (production)
+     - `http://localhost:3000/api/v1/auth/oauth/callback/twitch` (development; adjust port as needed)
docs/content/docs/(guides)/overview.mdx (2)

7-8: Use extensionless docs link.
Avoid .mdx in routes to prevent 404s.

-You can get started in five minutes with our [setup guide](./getting-started/setup.mdx), or jump straight into the documentation.
+You can get started in five minutes with our [setup guide](./getting-started/setup), or jump straight into the documentation.

17-34: Remove deprecated IF_PLATFORM markers.
Platform gating is gone; keep both cards visible and drop the comment noise.

-  {/* IF_PLATFORM: react-like */}
   <Card 
     title="Components"
     icon="fa-solid fa-puzzle"
     href="./components"
   >
     Use our pre-built React components, or create your own
   </Card>
-  {/* END_PLATFORM */}
-  {/* IF_PLATFORM: js-like */}
   <Card 
     title="SDK Reference"
     icon="fa-regular fa-file-lines" 
     href="./sdk"
   >
     Learn how to use Stack Auth's SDK
   </Card>
-  {/* END_PLATFORM */}
docs/content/docs/(guides)/concepts/auth-providers/spotify.mdx (1)

22-35: Add dev redirect URI for completeness.
Parity with other guides and smoother local testing.

-  5. Under **Redirect URI**, add `https://api.stack-auth.com/api/v1/auth/oauth/callback/spotify`
+  5. Under **Redirect URI**, add:
+     - `https://api.stack-auth.com/api/v1/auth/oauth/callback/spotify` (production)
+     - `http://localhost:3000/api/v1/auth/oauth/callback/spotify` (development; adjust port as needed)
docs/content/docs/(guides)/concepts/auth-providers/gitlab.mdx (1)

28-32: Self‑hosted instance field: add label/example.

Add the expected field label and an example (e.g., https://gitlab.example.com) to reduce confusion.

docs/content/docs/components/sign-in.mdx (1)

1-4: Frontmatter: full: true behavior.

Verify the docs theme respects full: true for layout; otherwise drop it to avoid layout mismatch.

docs/content/docs/(guides)/customization/page-examples/index.mdx (1)

10-15: Add direct links to the example pages for fast navigation.

Listing the child pages prevents orphaning and improves crawl/search relevance. Suggest linking to sign-in, sign-up, forgot-password, and password-reset here.

 Browse the examples to learn how to:
 
 - Create custom sign-in pages
 - Build custom sign-up forms  
 - Implement password reset flows
 - Handle forgotten password scenarios
+
+## Examples
+
+- [Sign-in](./sign-in)
+- [Sign-up](./sign-up)
+- [Forgot password](./forgot-password)
+- [Password reset](./password-reset)
docs/content/docs/sdk/types/team-profile.mdx (1)

25-37: Clarify nullability semantics for profile fields.

State whether empty strings are ever returned vs null, and note size/format constraints for profileImageUrl to reduce ambiguity for integrators.

-      The display name of the user within the team context as a `string` or `null` if no display name is set.
+      The display name of the user within the team context as a `string`, or `null` if unset.
+      Note: empty string (`""`) is not returned by the API — prefer `null` checks. Max length: 128 chars. [If different, update here.]
docs/content/docs/sdk/types/project.mdx (1)

57-76: Document config default values and server-only fields.

Add defaults and whether these flags are server-only or exposed to clients. Reduces guesswork and aligns SDK expectations.

-      <ParamField path="signUpEnabled" type="boolean">
-        Indicates if sign-up is enabled for the project.
+      <ParamField path="signUpEnabled" type="boolean" default={true}>
+        Indicates if sign-up is enabled for the project. Default: `true`.
       </ParamField>
@@
-      <ParamField path="credentialEnabled" type="boolean">
-        Specifies if credential-based authentication is enabled for the project.
+      <ParamField path="credentialEnabled" type="boolean" default={true}>
+        Specifies if credential-based authentication is enabled. Default: `true`.
       </ParamField>
@@
-      <ParamField path="magicLinkEnabled" type="boolean">
-        States whether magic link authentication is enabled for the project.
+      <ParamField path="magicLinkEnabled" type="boolean" default={false}>
+        Whether magic link authentication is enabled. Default: `false`.
       </ParamField>
@@
-      <ParamField path="clientTeamCreationEnabled" type="boolean">
-        Determines if client-side team creation is permitted within the project.
+      <ParamField path="clientTeamCreationEnabled" type="boolean" default={false}>
+        If client-side team creation is permitted. Default: `false`. Server-managed in admin UI.
       </ParamField>
@@
-      <ParamField path="clientUserDeletionEnabled" type="boolean">
-        Indicates if client-side user deletion is enabled for the project.
+      <ParamField path="clientUserDeletionEnabled" type="boolean" default={false}>
+        If client-side user deletion is enabled. Default: `false`. Server-managed in admin UI.
       </ParamField>
docs/content/docs/(guides)/concepts/auth-providers/google.mdx (1)

24-27: Add local development redirect URI and environment variable names.

Improves time-to-success and parity across environments.

-    7. Under **Authorized redirect URIs**, add `https://api.stack-auth.com/api/v1/auth/oauth/callback/google`
+    7. Under **Authorized redirect URIs**, add:
+       - Production: `https://api.stack-auth.com/api/v1/auth/oauth/callback/google`
+       - Local dev (example): `http://localhost:3000/api/v1/auth/oauth/callback/google`
@@
-    9. Save the **Client ID** and **Client Secret** that are displayed.
+    9. Save the **Client ID** and **Client Secret** that are displayed (e.g., `STACK_GOOGLE_CLIENT_ID`, `STACK_GOOGLE_CLIENT_SECRET`).
-    3. Set the **Client ID** and **Client Secret** you obtained from Google Cloud Console earlier.
+    3. Set the **Client ID** and **Client Secret** you obtained from Google Cloud Console earlier.
+    4. (Optional) Restrict scopes as needed; default `openid email profile` works for basic sign-in.
docs/content/docs/sdk/types/team-user.mdx (3)

16-19: Make platform note explicit and rearrange calls for broader applicability.

List generic API first, then framework-specific hooks, and clarify that the hook is only available in React-like environments.

-It is usually obtained by calling 
-`team.useUsers()` or {/* THIS_LINE_PLATFORM react-like */}
-`team.listUsers()` on a [`Team` object](../types/team.mdx#team).
+You can obtain users via:
+- `team.listUsers()` on a [`Team` object](../types/team.mdx#team).
+- `team.useUsers()` {/* React-only hook */} in React-like environments for subscription-driven UIs.

67-74: Unify link target style for ServerUser across page and ToC.

In ToC you use ./user#serveruser, elsewhere ../types/user.mdx#serveruser. Prefer one pattern to avoid mismatches in link resolvers.

-  & ServerUser //$stack-link-to:./user#serveruser
+  & ServerUser //$stack-link-to:../types/user#serveruser

1-12: Update broken-link check to resolve links per file directory
The current script prepends docs/content globally, so ../../components/stack-provider.mdx is flagged “missing” even though it exists at docs/content/docs/components/stack-provider.mdx. Adjust your validati 4066 on to resolve each relative link against its MDX file’s directory so that ../../components/stack-provider.mdx in docs/content/docs/sdk/... correctly maps to the actual location.

docs/content/docs/components/index.mdx (1)

118-118: Unindent the “Teams & Organizations” heading.

Four leading spaces turn this heading into a code block, so it vanishes from the document outline. Align it flush-left (matching the other headings) to get proper heading styling and navigation anchors.

-    ## Teams & Organizations
+  ## Teams & Organizations
docs/src/components/mdx/platform-config.ts (1)

2-9: Consider using ES6 Map for better type safety and adherence to coding guidelines.

The nested object structure for PlatformConfig doesn't align with the coding guideline to "prefer ES6 Map over Record when representing key–value collections." While objects work here, using Maps would provide better type safety, built-in iteration, and clearer semantics for dynamic key-value lookups.

As per coding guidelines.

Consider refactoring to:

export type PlatformConfig = Map<string, Map<string, {
  defaultFilename?: string,
  language: string,
}>>

This would require updating the initialization and helper functions, but provides better runtime guarantees and aligns with the guideline.

docs/content/docs/(guides)/getting-started/users.mdx (1)

19-19: Use JSX-style comment for consistency.

Line 19 uses a plain comment inside JSX content, which may cause parsing issues depending on the MDX version. For safety and consistency with line 35 (which uses a similar comment in a JSX context), use a JSX-style comment block.

Apply this fix:

 `user.listTeams()` functions. The created team will then inherit the permissions of that user; for example, the `team.update(...)` function can only succeed if the user is allowed to make updates to the team.
+{/* or: user.useTeams() */}
-`user.listTeams()` functions. The created team will then inherit the permissions of that user; for example, the `team.update(...)` function can only succeed if the user is allowed to make updates to the team.

Or if the comment is intended as inline documentation, keep it but ensure it's properly formatted:

-`user.useTeams()` or {/* THIS_LINE_PLATFORM react-like */}
+{/* THIS_LINE_PLATFORM react-like */}
+`user.useTeams()` or
 `user.listTeams()` functions. The created team will then inherit the permissions of that user; for example, the `team.update(...)` function can only succeed if the user is allowed to make updates to the team.
docs/src/components/mdx/platform-codeblock.tsx (5)

25-31: Avoid listener map leaks; delete empty entries.

remove*Listener leaves empty arrays in the Map; over time this grows across mounts.

Apply this diff:

 function removePlatformListener(id: string, listener: PlatformChangeListener): void {
   const list = platformListeners.get(id) ?? [];
-  platformListeners.set(
-    id,
-    list.filter((item) => item !== listener),
-  );
+  const next = list.filter((item) => item !== listener);
+  if (next.length) platformListeners.set(id, next);
+  else platformListeners.delete(id);
 }
@@
 function removeFrameworkListener(id: string, listener: FrameworkChangeListener): void {
   const list = frameworkListeners.get(id) ?? [];
-  frameworkListeners.set(
-    id,
-    list.filter((item) => item !== listener),
-  );
+  const next = list.filter((item) => item !== listener);
+  if (next.length) frameworkListeners.set(id, next);
+  else frameworkListeners.delete(id);
 }

Also applies to: 39-45


181-182: Use slice instead of deprecated substr.

Minor nit; avoid deprecated substr.

Apply this diff:

-  const [componentId] = useState(() => Math.random().toString(36).substr(2, 9));
+  const [componentId] = useState(() => Math.random().toString(36).slice(2, 11));

280-334: Guard async highlight against races; only set state if latest.

Rapid changes can set stale highlightedCode. Add a cancellation flag.

Apply this diff:

-  useEffect(() => {
+  useEffect(() => {
+    let cancelled = false;
@@
-        const sanitized = DOMPurify.sanitize(html, {
+        const sanitized = DOMPurify.sanitize(html, {
           KEEP_CONTENT: true,
         });
-        setHighlightedCode(sanitized);
+        if (!cancelled) setHighlightedCode(sanitized);
@@
-        setHighlightedCode(`<pre><code>${escapeHtml(currentCodeConfig.code)}</code></pre>`);
+        if (!cancelled) setHighlightedCode(`<pre><code>${escapeHtml(currentCodeConfig.code)}</code></pre>`);
@@
-    observer.observe(document.documentElement, {
+    observer.observe(document.documentElement, {
       attributes: true,
       attributeFilter: ['class']
     });
 
-    return () => observer.disconnect();
+    return () => {
+      cancelled = true;
+      observer.disconnect();
+    };
   }, [currentCodeConfig]);

407-411: Handle missing frameworks gracefully in label.

Avoid showing “undefined” when a platform has no frameworks.

Apply this diff:

-                <span>{currentFramework}</span>
+                <span>{currentFramework ?? 'No frameworks'}</span>

70-116: Prefer Map over plain objects for key–value collections.

selectedFrameworks/selectedVariants/globalSelectedFrameworks fit Map per guidelines; objects work but Maps avoid prototype pitfalls and ease deletion.

As per coding guidelines

Also applies to: 171-176

docs/src/components/mdx/simple-platform-codeblock.tsx (1)

56-82: Minor: consider Map for fullPlatforms to align with guidelines.

Objects are fine here, but Map would align with our Map-over-Record guidance and mirror PlatformCodeblock’s listener Maps.

As per coding guidelines

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between f5a3a99 and eb2293c.

📒 Files selected for processing (107)
  • docs/.gitignore (1 hunks)
  • docs/content/docs/(guides)/concepts/api-keys.mdx (1 hunks)
  • docs/content/docs/(guides)/concepts/auth-providers/apple.mdx (1 hunks)
  • docs/content/docs/(guides)/concepts/auth-providers/bitbucket.mdx (1 hunks)
  • docs/content/docs/(guides)/concepts/auth-providers/discord.mdx (1 hunks)
  • docs/content/docs/(guides)/concepts/auth-providers/facebook.mdx (1 hunks)
  • docs/content/docs/(guides)/concepts/auth-providers/github.mdx (1 hunks)
  • docs/content/docs/(guides)/concepts/auth-providers/gitlab.mdx (1 hunks)
  • docs/content/docs/(guides)/concepts/auth-providers/google.mdx (1 hunks)
  • docs/content/docs/(guides)/c CB5A oncepts/auth-providers/index.mdx (1 hunks)
  • docs/content/docs/(guides)/concepts/auth-providers/linkedin.mdx (1 hunks)
  • docs/content/docs/(guides)/concepts/auth-providers/meta.json (1 hunks)
  • docs/content/docs/(guides)/concepts/auth-providers/microsoft.mdx (1 hunks)
  • docs/content/docs/(guides)/concepts/auth-providers/passkey.mdx (1 hunks)
  • docs/content/docs/(guides)/concepts/auth-providers/spotify.mdx (1 hunks)
  • docs/content/docs/(guides)/concepts/auth-providers/twitch.mdx (1 hunks)
  • docs/content/docs/(guides)/concepts/auth-providers/two-factor-auth.mdx (1 hunks)
  • docs/content/docs/(guides)/concepts/auth-providers/x-twitter.mdx (1 hunks)
  • docs/content/docs/(guides)/concepts/backend-integration.mdx (1 hunks)
  • docs/content/docs/(guides)/concepts/custom-user-data.mdx (1 hunks)
  • docs/content/docs/(guides)/concepts/emails.mdx (1 hunks)
  • docs/content/docs/(guides)/concepts/jwt.mdx (1 hunks)
  • docs/content/docs/(guides)/concepts/oauth.mdx (1 hunks)
  • docs/content/docs/(guides)/concepts/orgs-and-teams.mdx (1 hunks)
  • docs/content/docs/(guides)/concepts/permissions.mdx (1 hunks)
  • docs/content/docs/(guides)/concepts/stack-app.mdx (1 hunks)
  • docs/content/docs/(guides)/concepts/team-selection.mdx (1 hunks)
  • docs/content/docs/(guides)/concepts/user-onboarding.mdx (1 hunks)
  • docs/content/docs/(guides)/concepts/webhooks.mdx (1 hunks)
  • docs/content/docs/(guides)/customization/custom-pages.mdx (1 hunks)
  • docs/content/docs/(guides)/customization/custom-styles.mdx (1 hunks)
  • docs/content/docs/(guides)/customization/dark-mode.mdx (1 hunks)
  • docs/content/docs/(guides)/customization/internationalization.mdx (1 hunks)
  • docs/content/docs/(guides)/customization/page-examples/forgot-password.mdx (1 hunks)
  • docs/content/docs/(guides)/customization/page-examples/index.mdx (1 hunks)
  • docs/content/docs/(guides)/customization/page-examples/meta.json (1 hunks)
  • docs/content/docs/(guides)/customization/page-examples/password-reset.mdx (1 hunks)
  • docs/content/docs/(guides)/customization/page-examples/sign-in.mdx (1 hunks)
  • docs/content/docs/(guides)/customization/page-examples/sign-up.mdx (1 hunks)
  • docs/content/docs/(guides)/faq.mdx (1 hunks)
  • docs/content/docs/(guides)/getting-started/components.mdx (1 hunks)
  • docs/content/docs/(guides)/getting-started/example-pages.mdx (1 hunks)
  • docs/content/docs/(guides)/getting-started/platform-codeblock-example.mdx (1 hunks)
  • docs/content/docs/(guides)/getting-started/production.mdx (1 hunks)
  • docs/content/docs/(guides)/getting-started/setup.mdx (1 hunks)
  • docs/content/docs/(guides)/getting-started/users.mdx (1 hunks)
  • docs/content/docs/(guides)/meta.json (1 hunks)
  • docs/content/docs/(guides)/others/cli-authentication.mdx (1 hunks)
  • docs/content/docs/(guides)/others/convex.mdx (1 hunks)
  • docs/content/docs/(guides)/others/self-host.mdx (1 hunks)
  • docs/content/docs/(guides)/others/supabase.mdx (1 hunks)
  • docs/content/docs/(guides)/overview.mdx (1 hunks)
  • docs/content/docs/(guides)/rest-api/overview.mdx (1 hunks)
  • docs/content/docs/components/account-settings.mdx (1 hunks)
  • docs/content/docs/components/credential-sign-in.mdx (1 hunks)
  • docs/content/docs/components/credential-sign-up.mdx (1 hunks)
  • docs/content/docs/components/forgot-password.mdx (1 hunks)
  • docs/content/docs/components/index.mdx (1 hunks)
  • docs/content/docs/components/magic-link-sign-in.mdx (1 hunks)
  • docs/content/docs/components/meta.json (1 hunks)
  • docs/content/docs/components/oauth-button-group.mdx (1 hunks)
  • docs/content/docs/components/oauth-button.mdx (1 hunks)
  • docs/content/docs/components/password-reset.mdx (1 hunks)
  • docs/content/docs/components/selected-team-switcher.mdx (1 hunks)
  • docs/content/docs/components/sign-in.mdx (1 hunks)
  • docs/content/docs/components/sign-up.mdx (1 hunks)
  • docs/content/docs/components/stack-handler.mdx (1 hunks)
  • docs/content/docs/components/stack-provider.mdx (1 hunks)
  • docs/content/docs/components/stack-theme.mdx (1 hunks)
  • docs/content/docs/components/user-button.mdx (1 hunks)
  • docs/content/docs/sdk/hooks/use-stack-app.mdx (1 hunks)
  • docs/content/docs/sdk/hooks/use-user.mdx (1 hunks)
  • docs/content/docs/sdk/index.mdx (1 hunks)
  • docs/content/docs/sdk/meta.json (1 hunks)
  • docs/content/docs/sdk/objects/stack-app.mdx (1 hunks)
  • docs/content/docs/sdk/overview-new.mdx (1 hunks)
  • docs/content/docs/sdk/types/api-key.mdx (1 hunks)
  • docs/content/docs/sdk/types/connected-account.mdx (1 hunks)
  • docs/content/docs/sdk/types/contact-channel.mdx (1 hunks)
  • docs/content/docs/sdk/types/email.mdx (1 hunks)
  • docs/content/docs/sdk/types/project.mdx (1 hunks)
  • docs/content/docs/sdk/types/team-permission.mdx (1 hunks)
  • docs/content/docs/sdk/types/team-profile.mdx (1 hunks)
  • docs/content/docs/sdk/types/team-user.mdx (1 hunks)
  • docs/content/docs/sdk/types/team.mdx (1 hunks)
  • docs/content/docs/sdk/types/user.mdx (1 hunks)
  • docs/docs-platform.yml (0 hunks)
  • docs/package.json (1 hunks)
  • docs/scripts/generate-docs.js (0 hunks)
  • docs/scripts/generate-platform-navigation.js (0 hunks)
  • docs/src/app/api/search/route.ts (2 hunks)
  • docs/src/app/docs/[[...slug]]/page.tsx (1 hunks)
  • docs/src/components/homepage/iconHover.tsx (4 hunks)
  • docs/src/components/layout/custom-search-dialog.tsx (5 hunks)
  • docs/src/components/layout/root-toggle.tsx (0 hunks)
  • docs/src/components/layouts/docs-header-wrapper.tsx (7 hunks)
  • docs/src/components/layouts/docs-layout-router.tsx (3 hunks)
  • docs/src/components/layouts/docs.tsx (13 hunks)
  • docs/src/components/layouts/platform-aware-header.tsx (0 hunks)
  • docs/src/components/layouts/shared/section-utils.ts (1 hunks)
  • docs/src/components/mdx/platform-codeblock.tsx (1 hunks)
  • docs/src/components/mdx/platform-config.ts (1 hunks)
  • docs/src/components/mdx/simple-platform-codeblock.tsx (1 hunks)
  • docs/src/components/mdx/simple-platform-example.mdx (1 hunks)
  • docs/src/components/platform-redirect.tsx (0 hunks)
  • docs/src/components/sdk/overview.tsx (1 hunks)
  • docs/src/hooks/use-platform-persistence.ts (0 hunks)
⛔ Files not processed due to max files limit (6)
  • docs/src/hooks/use-platform-preference.ts
  • docs/src/lib/docs-tree.ts
  • docs/src/lib/navigation-utils.ts
  • docs/src/lib/platform-utils.ts
  • docs/src/mdx-components.tsx
  • package.json
💤 Files with no reviewable changes (7)
  • docs/src/hooks/use-platform-persistence.ts
  • docs/src/components/platform-redirect.tsx
  • docs/docs-platform.yml
  • docs/src/components/layouts/platform-aware-header.tsx
  • docs/scripts/generate-platform-navigation.js
  • docs/scripts/generate-docs.js
  • docs/src/components/layout/root-toggle.tsx
🧰 Additional context used
📓 Path-based instructions (1)
**/*.{ts,tsx,js,jsx}

📄 CodeRabbit inference engine (AGENTS.md)

Prefer ES6 Map over Record when representing key–value collections

Files:

  • docs/src/components/mdx/platform-config.ts
  • docs/src/components/sdk/overview.tsx
  • docs/src/components/layouts/docs-header-wrapper.tsx
  • docs/src/components/mdx/simple-platform-codeblock.tsx
  • docs/src/components/layouts/docs-layout-router.tsx
  • docs/src/app/api/search/route.ts
  • docs/src/components/homepage/iconHover.tsx
  • docs/src/components/layouts/shared/section-utils.ts
  • docs/src/components/layouts/docs.tsx
  • docs/src/components/mdx/platform-codeblock.tsx
  • docs/src/app/docs/[[...slug]]/page.tsx
  • docs/src/components/layout/custom-search-dialog.tsx
🧬 Code graph analysis (7)
docs/src/components/mdx/platform-config.ts (1)
docs/src/components/mdx/simple-platform-codeblock.tsx (2)
  • PLATFORM_CONFIG (102-102)
  • DEFAULT_FRAMEWORK_PREFERENCES (102-102)
docs/src/components/layouts/docs-header-wrapper.tsx (3)
docs/src/lib/navigation-utils.ts (1)
  • generateNavLinks (14-37)
docs/src/lib/docs-tree.ts (2)
  • resolveDocsSection (7-17)
  • filterTreeForSection (19-32)
docs/src/components/layouts/shared-header.tsx (1)
  • SharedHeader (224-427)
docs/src/components/mdx/simple-platform-codeblock.tsx (2)
docs/src/components/mdx/platform-codeblock.tsx (2)
  • PlatformCodeblockProps (71-116)
  • PlatformCodeblock (118-527)
docs/src/components/mdx/platform-config.ts (2)
  • getPlatformFrameworkConfig (144-146)
  • DEFAULT_FRAMEWORK_PREFERENCES (149-159)
docs/src/components/layouts/docs-layout-router.tsx (4)
docs/src/components/layouts/docs.tsx (2)
  • DocsLayoutProps (801-813)
  • DocsLayout (815-921)
docs/src/lib/docs-tree.ts (2)
  • resolveDocsSection (7-17)
  • filterTreeForSection (19-32)
docs/src/components/layouts/shared/section-utils.ts (1)
  • isInApiSection (16-18)
docs/src/app/docs/layout.tsx (1)
  • DocsLayout (8-29)
docs/src/components/homepage/iconHover.tsx (2)
docs/src/lib/docs-tree.ts (1)
  • DocsSection (3-3)
docs/src/components/icons.tsx (2)
  • Code (340-343)
  • Zap (345-347)
docs/src/components/mdx/platform-codeblock.tsx (1)
packages/stack-shared/src/utils/promises.tsx (1)
  • runAsynchronously (343-366)
docs/src/app/docs/[[...slug]]/page.tsx (1)
docs/lib/source.ts (1)
  • source (23-30)
🪛 ast-grep (0.39.5)
docs/src/components/layouts/shared/section-utils.ts

[warning] 8-8: Regular expression constructed from variable input detected. This can lead to Regular Expression Denial of Service (ReDoS) attacks if the variable contains malicious patterns. Use libraries like 'recheck' to validate regex safety or use static patterns.
Context: new RegExp(^/docs/${PLATFORM_PREFIX}sdk(?:/.*)?$)
Note: [CWE-1333] Inefficient Regular Expression Complexity [REFERENCES]
- https://owasp.org/www-community/attacks/Regular_expression_Denial_of_Service_-_ReDoS
- https://cwe.mitre.org/data/definitions/1333.html

(regexp-from-variable)


[warning] 12-12: Regular expression constructed from variable input detected. This can lead to Regular Expression Denial of Service (ReDoS) attacks if the variable contains malicious patterns. Use libraries like 'recheck' to validate regex safety or use static patterns.
Context: new RegExp(^/docs/${PLATFORM_PREFIX}components(?:/.*)?$)
Note: [CWE-1333] Inefficient Regular Expression Complexity [REFERENCES]
- https://owasp.org/www-community/attacks/Regular_expression_Denial_of_Service_-_ReDoS
- https://cwe.mitre.org/data/definitions/1333.html

(regexp-from-variable)


[warning] 20-20: Regular expression constructed from variable input detected. This can lead to Regular Expression Denial of Service (ReDoS) attacks if the variable contains malicious patterns. Use libraries like 'recheck' to validate regex safety or use static patterns.
Context: new RegExp(^/docs/${PLATFORM_PREFIX}customization(?:/.*)?$)
Note: [CWE-1333] Inefficient Regular Expression Complexity [REFERENCES]
- https://owasp.org/www-community/attacks/Regular_expression_Denial_of_Service_-_ReDoS
- https://cwe.mitre.org/data/definitions/1333.html

(regexp-from-variable)

docs/src/components/mdx/platform-codeblock.tsx

[warning] 456-456: Usage of dangerouslySetInnerHTML detected. This bypasses React's built-in XSS protection. Always sanitize HTML content using libraries like DOMPurify before injecting it into the DOM to prevent XSS attacks.
Context: dangerouslySetInnerHTML
Note: [CWE-79] Improper Neutralization of Input During Web Page Generation [REFERENCES]
- https://reactjs.org/docs/dom-elements.html#dangerouslysetinnerhtml
- https://cwe.mitre.org/data/definitions/79.html

(react-unsafe-html-injection)

🪛 Biome (2.1.2)
docs/src/components/mdx/platform-codeblock.tsx

[error] 457-457: Avoid passing content using the dangerouslySetInnerHTML prop.

Setting content using code can expose users to cross-site scripting (XSS) attacks

(lint/security/noDangerouslySetInnerHtml)

🪛 GitHub Actions: Runs E2E API Tests
docs/content/docs/(guides)/customization/page-examples/forgot-password.mdx

[error] 1-1: Command failed: pnpm run build in docs exited with code 1.

docs/content/docs/(guides)/concepts/api-keys.mdx

[error] 1-1: Command failed: pnpm run build in docs exited with code 1.

docs/content/docs/(guides)/customization/page-examples/meta.json

[error] 1-1: Command failed: pnpm run build in docs exited with code 1.

docs/content/docs/(guides)/customization/page-examples/index.mdx

[error] 1-1: Command failed: pnpm run build in docs exited with code 1.

docs/src/components/mdx/platform-config.ts

[error] 1-1: Command failed: pnpm run build in docs exited with code 1.

docs/content/docs/sdk/index.mdx

[error] 1-1: Command failed: pnpm run build in docs exited with code 1.

docs/.gitignore

[error] 1-1: Command failed: pnpm run build in docs exited with code 1.

docs/content/docs/(guides)/concepts/auth-providers/meta.json

[error] 1-1: Command failed: pnpm run build in docs exited with code 1.

docs/content/docs/sdk/types/team-permission.mdx

[error] 1-1: Command failed: pnpm run build in docs exited with code 1.

docs/content/docs/sdk/meta.json

[error] 1-1: Command failed: pnpm run build in docs exited with code 1.

docs/content/docs/sdk/types/team.mdx

[error] 1-1: Command failed: pnpm run build in docs exited with code 1.

docs/content/docs/(guides)/concepts/auth-providers/twitch.mdx

[error] 1-1: Command failed: pnpm run build in docs exited with code 1.

docs/content/docs/components/password-reset.mdx

[error] 1-1: Command failed: pnpm run build in docs exited with code 1.

docs/content/docs/(guides)/concepts/auth-providers/google.mdx

[error] 1-1: Command failed: pnpm run build in docs exited with code 1.

docs/content/docs/(guides)/customization/custom-pages.mdx

[error] 1-1: Command failed: pnpm run build in docs exited with code 1.

docs/content/docs/sdk/overview-new.mdx

[error] 1-1: Command failed: pnpm run build in docs exited with code 1.

docs/content/docs/(guides)/concepts/custom-user-data.mdx

[error] 1-1: Command failed: pnpm run build in docs exited with code 1.

docs/content/docs/(guides)/concepts/auth-providers/facebook.mdx

[error] 1-1: Command failed: pnpm run build in docs exited with code 1.

docs/content/docs/sdk/types/connected-account.mdx

[error] 1-1: Command failed: pnpm run build in docs exited with code 1.

docs/src/components/sdk/overview.tsx

[error] 1-1: Command failed: pnpm run build in docs exited with code 1.

docs/content/docs/sdk/types/user.mdx

[error] 1-1: Command failed: pnpm run build in docs exited with code 1.

docs/content/docs/components/sign-in.mdx

[error] 1-1: Command failed: pnpm run build in docs exited with code 1.

docs/content/docs/(guides)/concepts/auth-providers/spotify.mdx

[error] 1-1: Command failed: pnpm run build in docs exited with code 1.

docs/content/docs/components/forgot-password.mdx

[error] 1-1: Command failed: pnpm run build in docs exited with code 1.

docs/content/docs/(guides)/concepts/auth-providers/bitbucket.mdx

[error] 1-1: Command failed: pnpm run build in docs exited with code 1.

docs/content/docs/components/meta.json

[error] 1-1: Command failed: pnpm run build in docs exited with code 1.

docs/content/docs/(guides)/concepts/auth-providers/apple.mdx

[error] 1-1: Command failed: pnpm run build in docs exited with code 1.

docs/content/docs/(guides)/concepts/oauth.mdx

[error] 1-1: Command failed: pnpm run build in docs exited with code 1.

docs/src/components/layouts/docs-header-wrapper.tsx

[error] 1-1: Command failed: pnpm run build in docs exited with code 1.

docs/content/docs/(guides)/concepts/permissions.mdx

[error] 1-1: Command failed: pnpm run build in docs exited with code 1.

docs/content/docs/components/account-settings.mdx

[error] 1-1: Command failed: pnpm run build in docs exited with code 1.

docs/content/docs/(guides)/concepts/team-selection.mdx

[error] 1-1: Command failed: pnpm run build in docs exited with code 1.

docs/content/docs/(guides)/concepts/jwt.mdx

[error] 1-1: Command failed: pnpm run build in docs exited with code 1.

docs/content/docs/sdk/types/email.mdx

[error] 1-1: Command failed: pnpm run build in docs exited with code 1.

docs/content/docs/sdk/types/team-profile.mdx

[error] 1-1: Command failed: pnpm run build in docs exited with code 1.

docs/content/docs/components/index.mdx

[error] 1-1: Command failed: pnpm run build in docs exited with code 1.

docs/content/docs/(guides)/concepts/auth-providers/two-factor-auth.mdx

[error] 1-1: Command failed: pnpm run build in docs exited with code 1.

docs/content/docs/(guides)/concepts/auth-providers/index.mdx

[error] 1-1: Command failed: pnpm run build in docs exited with code 1.

docs/content/docs/sdk/types/team-user.mdx

[error] 1-1: Command failed: pnpm run build in docs exited with code 1.

docs/content/docs/(guides)/concepts/webhooks.mdx

[error] 1-1: Command failed: pnpm run build in docs exited with code 1.

docs/content/docs/(guides)/meta.json

[error] 1-1: Command failed: pnpm run build in docs exited with code 1.

docs/content/docs/(guides)/getting-started/production.mdx

[error] 1-1: Command failed: pnpm run build in docs exited with code 1.

docs/src/components/mdx/simple-platform-codeblock.tsx

[error] 1-1: Command failed: pnpm run build in docs exited with code 1.

docs/content/docs/sdk/hooks/use-stack-app.mdx

[error] 1-1: Command failed: pnpm run build in docs exited with code 1.

docs/content/docs/(guides)/customization/page-examples/password-reset.mdx

[error] 1-1: Command failed: pnpm run build in docs exited with code 1.

docs/src/components/layouts/docs-layout-router.tsx

[error] 1-1: Command failed: pnpm run build in docs exited with code 1.

docs/content/docs/components/magic-link-sign-in.mdx

[error] 1-1: Command failed: pnpm run build in docs exited with code 1.

docs/package.json

[error] 1-1: Command failed: pnpm run build in docs exited with code 1.

docs/content/docs/(guides)/concepts/orgs-and-teams.mdx

[error] 1-1: Command failed: pnpm run build in docs exited with code 1.

docs/content/docs/components/credential-sign-in.mdx

[error] 1-1: Command failed: pnpm run build in docs exited with code 1.

docs/content/docs/(guides)/concepts/auth-providers/microsoft.mdx

[error] 1-1: Command failed: pnpm run build in docs exited with code 1.

docs/content/docs/sdk/types/contact-channel.mdx

[error] 1-1: Command failed: pnpm run build in docs exited with code 1.

docs/src/app/api/search/route.ts

[error] 1-1: Command failed: pnpm run build in docs exited with code 1.

docs/content/docs/components/stack-theme.mdx

[error] 1-1: Command failed: pnpm run build in docs exited with code 1.

docs/content/docs/components/credential-sign-up.mdx

[error] 1-1: Command failed: pnpm run build in docs exited with code 1.

docs/src/components/mdx/simple-platform-example.mdx

[error] 1-1: Command failed: pnpm run build in docs exited with code 1.

docs/content/docs/(guides)/concepts/auth-providers/gitlab.mdx

[error] 1-1: Command failed: pnpm run build in docs exited with code 1.

docs/content/docs/components/stack-handler.mdx

[error] 1-1: Command failed: pnpm run build in docs exited with code 1.

docs/src/components/homepage/iconHover.tsx

[error] 1-1: Command failed: pnpm run build in docs exited with code 1.

docs/content/docs/(guides)/concepts/auth-providers/discord.mdx

[error] 1-1: Command failed: pnpm run build in docs exited with code 1.

docs/content/docs/(guides)/overview.mdx

[error] 1-1: Command failed: pnpm run build in docs exited with code 1.

docs/content/docs/sdk/types/api-key.mdx

[error] 1-1: Command failed: pnpm run build in docs exited with code 1.

docs/content/docs/(guides)/customization/custom-styles.mdx

[error] 1-1: Command failed: pnpm run build in docs exited with code 1.

docs/content/docs/(guides)/concepts/auth-providers/x-twitter.mdx

[error] 1-1: Command failed: pnpm run build in docs exited with code 1.

docs/content/docs/sdk/objects/stack-app.mdx

[error] 1-1: Command failed: pnpm run build in docs exited with code 1.

docs/content/docs/components/sign-up.mdx

[error] 1-1: Command failed: pnpm run build in docs exited with code 1.

docs/src/components/layouts/shared/section-utils.ts

[error] 1-1: Command failed: pnpm run build in docs exited with code 1.

docs/src/components/layouts/docs.tsx

[error] 1-1: Command failed: pnpm run build in docs exited with code 1.

docs/content/docs/(guides)/concepts/auth-providers/github.mdx

[error] 1-1: Command failed: pnpm run build in docs exited with code 1.

docs/content/docs/components/stack-provider.mdx

[error] 1-1: Command failed: pnpm run build in docs exited with code 1.

docs/src/components/mdx/platform-codeblock.tsx

[error] 1-1: Command failed: pnpm run build in docs exited with code 1.

docs/content/docs/(guides)/getting-started/platform-codeblock-example.mdx

[error] 1-1: Command failed: pnpm run build in docs exited with code 1.

docs/content/docs/(guides)/customization/internationalization.mdx

[error] 1-1: Command failed: pnpm run build in docs exited with code 1.

docs/content/docs/components/selected-team-switcher.mdx

[error] 1-1: Command failed: pnpm run build in docs exited with code 1.

docs/content/docs/(guides)/concepts/user-onboarding.mdx

[error] 1-1: Command failed: pnpm run build in docs exited with code 1.

docs/content/docs/(guides)/concepts/backend-integration.mdx

[error] 1-1: Command failed: pnpm run build in docs exited with code 1.

docs/content/docs/(guides)/getting-started/users.mdx

[error] 1-1: Command failed: pnpm run build in docs exited with code 1.

docs/content/docs/(guides)/rest-api/overview.mdx

[error] 1-1: Command failed: pnpm run build in docs exited with code 1.

docs/content/docs/(guides)/getting-started/components.mdx

[error] 1-1: Command failed: pnpm run build in docs exited with code 1.

docs/content/docs/(guides)/concepts/emails.mdx

[error] 1-1: Command failed: pnpm run build in docs exited with code 1.

docs/content/docs/components/oauth-button.mdx

[error] 1-1: Command failed: pnpm run build in docs exited with code 1.

docs/content/docs/(guides)/getting-started/example-pages.mdx

[error] 1-1: Command failed: pnpm run build in docs exited with code 1.

docs/content/docs/(guides)/faq.mdx

[error] 1-1: Command failed: pnpm run build in docs exited with code 1.

docs/content/docs/(guides)/customization/page-examples/sign-in.mdx

[error] 1-1: Command failed: pnpm run build in docs exited with code 1.

docs/content/docs/(guides)/others/cli-authentication.mdx

[error] 1-1: Command failed: pnpm run build in docs exited with code 1.

docs/content/docs/(guides)/getting-started/setup.mdx

[error] 1-1: Command failed: pnpm run build in docs exited with code 1.

docs/content/docs/sdk/hooks/use-user.mdx

[error] 1-1: Command failed: pnpm run build in docs exited with code 1.

docs/content/docs/(guides)/others/convex.mdx

[error] 1-1: Command failed: pnpm run build in docs exited with code 1.

docs/content/docs/(guides)/concepts/stack-app.mdx

[error] 1-1: Command failed: pnpm run build in docs exited with code 1.

docs/content/docs/(guides)/concepts/auth-providers/passkey.mdx

[error] 1-1: Command failed: pnpm run build in docs exited with code 1.

docs/content/docs/(guides)/customization/dark-mode.mdx

[error] 1-1: Command failed: pnpm run build in docs exited with code 1.

docs/content/docs/components/oauth-button-group.mdx

[error] 1-1: Command failed: pnpm run build in docs exited with code 1.

docs/content/docs/(guides)/customization/page-examples/sign-up.mdx

[error] 1-1: Command failed: pnpm run build in docs exited with code 1.

docs/src/app/docs/[[...slug]]/page.tsx

[error] 1-1: Command failed: pnpm run build in docs exited with code 1.

docs/content/docs/sdk/types/project.mdx

[error] 1-1: Command failed: pnpm run build in docs exited with code 1.

docs/src/components/layout/custom-search-dialog.tsx

[error] 1-1: Command failed: pnpm run build in docs exited with code 1.

docs/content/docs/(guides)/others/supabase.mdx

[error] 1-1: Command failed: pnpm run build in docs exited with code 1.

docs/content/docs/components/user-button.mdx

[error] 1-1: Command failed: pnpm run build in docs exited with code 1.

docs/content/docs/(guides)/others/self-host.mdx

[error] 1-1: Command failed: pnpm run build in docs exited with code 1.

docs/content/docs/(guides)/concepts/auth-providers/linkedin.mdx

[error] 1-1: Command failed: pnpm run build in docs exited with code 1.

⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: Security Check

Comment on lines +20 to +21
- **Scopes**: Select at minimum the `profile` and `email` scopes
5. Click **Save application**.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

GitLab scopes are incorrect; use read_user or OIDC scopes.

There is no “profile” scope in classic GitLab OAuth. Use at minimum read_user (OAuth) or openid, profile, email (OIDC). The current text will mislead users.

Apply:

-     - **Scopes**: Select at minimum the `profile` and `email` scopes
+     - **Scopes**: Select at minimum the `read_user` scope (OAuth 2.0), or `openid`, `profile`, `email` if using OIDC
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
- **Scopes**: Select at minimum the `profile` and `email` scopes
5. Click **Save application**.
- **Scopes**: Select at minimum the `read_user` scope (OAuth 2.0), or `openid`, `profile`, `email` if using OIDC
5. Click **Save application**.
🤖 Prompt for AI Agents
In docs/content/docs/(guides)/concepts/auth-providers/gitlab.mdx around lines
20-21, the guidance listing a `profile` OAuth scope is incorrect for classic
GitLab OAuth; update the sentence to state that for classic GitLab OAuth you
must include at minimum the `read_user` scope, and alternatively note that when
using GitLab OIDC you should request `openid`, `profile`, and `email` scopes;
adjust the example and surrounding text to mention both options (classic OAuth:
read_user; OIDC: openid, profile, email) so users are not misled.

Comment on lines +10 to +49
export const sdkSections = [
{
title: "General",
items: [
{ name: "StackClientApp", href: "./objects/stack-app#stackclientapp", icon: "object" },
{ name: "StackServerApp", href: "./sdk/objects/stack-app#stackserverapp", icon: "object" },
{ name: "Project", href: "./sdk/types/project#project", icon: "type" },
]
},
{
title: "Users & user data",
items: [
{ name: "CurrentUser", href: "./sdk/types/user#currentuser", icon: "type" },
{ name: "ServerUser", href: "./sdk/types/user#serveruser", icon: "type" },
{ name: "CurrentServerUser", href: "./sdk/types/user#currentserveruser", icon: "type" },
{ name: "ContactChannel", href: "./sdk/types/contact-channel#contactchannel", icon: "type" },
{ name: "ServerContactChannel", href: "./sdk/types/contact-channel#servercontactchannel", icon: "type" },
]
},
{
title: "Teams",
items: [
{ name: "Team", href: "./sdk/types/team#team", icon: "type" },
{ name: "ServerTeam", href: "./sdk/types/team#serverteam", icon: "type" },
{ name: "TeamPermission", href: "./sdk/types/team-permission#teampermission", icon: "type" },
{ name: "ServerTeamPermission", href: "./sdk/types/team-permission#serverteampermission", icon: "type" },
{ name: "TeamUser", href: "./sdk/types/team-user#teamuser", icon: "type" },
{ name: "ServerTeamUser", href: "./sdk/types/team-user#serverteamuser", icon: "type" },
{ name: "TeamProfile", href: "./sdk/types/team-profile#teamprofile", icon: "type" },
{ name: "ServerTeamProfile", href: "./sdk/types/team-profile#serverteamprofile", icon: "type" },
]
},
{
title: "Hooks",
items: [
{ name: "useStackApp", href: "./sdk/hooks/use-stack-app", icon: "hook" },
{ name: "useUser", href: "./sdk/hooks/use-user", icon: "hook" },
]
}
];
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

Correct the relative hrefs in sdkSections
Because this file already sits under /docs/sdk/, entries like href: "./sdk/objects/stack-app#stackserverapp" resolve to /docs/sdk/sdk/objects/..., which doesn’t exist. The same duplication happens for every ./sdk/types/... and ./sdk/hooks/... entry, and it’s currently breaking pnpm run build for the docs. Please drop the extra sdk/ segment in each link (e.g. ./objects/stack-app#stackserverapp, ./types/project#project, ./hooks/use-stack-app, etc.) so the overview renders without 404s.

🤖 Prompt for AI Agents
In docs/content/docs/sdk/overview-new.mdx around lines 10 to 49, the hrefs
include a duplicated "sdk/" segment (e.g. "./sdk/objects/...",
"./sdk/types/...", "./sdk/hooks/...") which resolves to /docs/sdk/sdk/... and
causes 404s; update each href to remove the extra "sdk/" segment so they are
relative to the current /docs/sdk/ directory (e.g.
"./objects/stack-app#stackserverapp", "./types/project#project",
"./hooks/use-stack-app", etc.) ensuring all link paths point to the correct
targets.

Copy link
Contributor
@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

🧹 Nitpick comments (7)
docs/src/mdx-components.tsx (1)

16-16: Importing a Client Component into the MDX registry is fine; consider lazy import to limit bundle size.

If PlatformCodeblock is rarely used, wrapping it in a dynamic import can keep the default MDX bundle lean. I can sketch a lazy wrapper if desired.

docs/src/components/mdx/platform-codeblock.tsx (6)

183-184: Use slice, not deprecated substr, and prefer crypto.randomUUID when available.

-  const [componentId] = useState(() => Math.random().toString(36).substr(2, 9));
+  const [componentId] = useState(
+    () => (typeof crypto !== 'undefined' && 'randomUUID' in crypto)
+      ? crypto.randomUUID()
+      : Math.random().toString(36).slice(2, 11),
+  );

27-33: Listener cleanup can leak empty arrays; delete keys when empty.

Free the map entry after removing the last listener.

 function removePlatformListener(id: string, listener: PlatformChangeListener): void {
   const list = platformListeners.get(id) ?? [];
-  platformListeners.set(
-    id,
-    list.filter((item) => item !== listener),
-  );
+  const next = list.filter((item) => item !== listener);
+  if (next.length === 0) platformListeners.delete(id);
+  else platformListeners.set(id, next);
 }
 
 function removeFrameworkListener(id: string, listener: FrameworkChangeListener): void {
   const list = frameworkListeners.get(id) ?? [];
-  frameworkListeners.set(
-    id,
-    list.filter((item) => item !== listener),
-  );
+  const next = list.filter((item) => item !== listener);
+  if (next.length === 0) frameworkListeners.delete(id);
+  else frameworkListeners.set(id, next);
 }

Also applies to: 41-47


332-343: Avoid UI flicker after platform selection by updating local state immediately.

Set local state before broadcasting so the Framework view shows the correct list right away.

 const handlePlatformSelect = (platform: string) => {
-  broadcastPlatformChange(platform);
-  // Show framework selection for this platform
-  setDropdownView('framework');
+  setSelectedPlatform(platform);
+  broadcastPlatformChange(platform);
+  setDropdownView('framework'); // now shows the right frameworks
 
   // Auto-select first framework of new platform
   const newPlatformFrameworks = Object.keys(platforms[platform] ?? {});
   if (newPlatformFrameworks.length > 0) {
     const firstFramework = defaultFrameworks[platform] || newPlatformFrameworks[0];
-    broadcastFrameworkChange(platform, firstFramework);
+    setSelectedFrameworks(prev => ({ ...prev, [platform]: firstFramework }));
+    broadcastFrameworkChange(platform, firstFramework);
   }
 };

450-456: dangerouslySetInnerHTML requires sanitization or a lint suppression.

If you adopt the sanitization above, this is resolved. Otherwise, add a documented eslint/biome suppression with justification.


413-437: Add basic a11y: ARIA attributes and roles for the dropdown.

Expose state to AT and use menu semantics.

 <div className="relative" data-dropdown-id={componentId}>
   <button
     onClick={handleDropdownToggle}
+    aria-haspopup="menu"
+    aria-expanded={isDropdownOpen}
+    aria-controls={`${componentId}-menu`}
 ...
 {isDropdownOpen && (
   <div
     className="absolute right-3 z-50 min-w-[160px] rounded-lg border bg-fd-background shadow-lg"
+    id={`${componentId}-menu`}
+    role="menu"
 ...
   {dropdownView === 'platform' ? (
-    <div className="py-1">
+    <div className="py-1" role="menu">
 ...
-              {platformNames.map((platform
8B3A
) => (
+              {platformNames.map((platform) => (
                 <button
                   key={platform}
+                  role="menuitem"
 ...
-    <div className="py-1">
+    <div className="py-1" role="menu">
 ...
-              {currentFrameworks.map((framework) => (
+              {currentFrameworks.map((framework) => (
                 <button
                   key={framework}
+                  role="menuitem"

Also applies to: 461-521


13-20: Consider Map over index signatures for dynamic key–value state.

globalSelectedFrameworks and selectedFrameworks model dictionaries; Map offers clearer intent and safer key handling. Convert only if cost is low; otherwise defer.

As per coding guidelines

Also applies to: 173-175

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between eb2293c and a009f64.

📒 Files selected for processing (3)
  • docs/src/components/mdx/platform-codeblock.tsx (1 hunks)
  • docs/src/components/mdx/platform-config.ts (1 hunks)
  • docs/src/mdx-components.tsx (2 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • docs/src/components/mdx/platform-config.ts
🧰 Additional context used
📓 Path-based instructions (1)
**/*.{ts,tsx,js,jsx}

📄 CodeRabbit inference engine (AGENTS.md)

Prefer ES6 Map over Record when representing key–value collections

Files:

  • docs/src/components/mdx/platform-codeblock.tsx
  • docs/src/mdx-components.tsx
🧬 Code graph analysis (1)
docs/src/components/mdx/platform-codeblock.tsx (1)
packages/stack-shared/src/utils/promises.tsx (1)
  • runAsynchronously (343-366)
🪛 ast-grep (0.39.5)
docs/src/components/mdx/platform-codeblock.tsx

[warning] 453-453: Usage of dangerouslySetInnerHTML detected. This bypasses React's built-in XSS protection. Always sanitize HTML content using libraries like DOMPurify before injecting it into the DOM to prevent XSS attacks.
Context: dangerouslySetInnerHTML
Note: [CWE-79] Improper Neutralization of Input During Web Page Generation [REFERENCES]
- https://reactjs.org/docs/dom-elements.html#dangerouslysetinnerhtml
- https://cwe.mitre.org/data/definitions/79.html

(react-unsafe-html-injection)

🪛 Biome (2.1.2)
docs/src/components/mdx/platform-codeblock.tsx

[error] 454-454: Avoid passing content using the dangerouslySetInnerHTML prop.

Setting content using code can expose users to cross-site scripting (XSS) attacks

(lint/security/noDangerouslySetInnerHtml)

⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (6)
  • GitHub Check: restart-dev-and-test
  • GitHub Check: lint_and_build (latest)
  • GitHub Check: setup-tests
  • GitHub Check: docker
  • GitHub Check: all-good
  • GitHub Check: Security Check
🔇 Additional comments (2)
docs/src/mdx-components.tsx (1)

72-72: MDX registry addition looks good.

Registration is correct; MDX pages can now use .

docs/src/components/mdx/platform-codeblock.tsx (1)

3-3: Deep import is currently required for runAsynchronously.

runAsynchronously isn’t exposed by @stackframe/stack-shared’s public API—no re-export in src/index.ts or package.json exports—so importing from /dist is necessary until the package adds a root export.

Likely an incorrect or invalid review comment.

Comment on lines +167 to +171
// Initialize global state on first render
useState(() => {
initializeGlobalFrameworks();
});

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion | 🟠 Major

Don’t use useState for one‑time side effects.

Replace with useEffect to run initialization once.

-  // Initialize global state on first render
-  useState(() => {
-    initializeGlobalFrameworks();
-  });
+  // Initialize global state on first render
+  useEffect(() => {
+    initializeGlobalFrameworks();
+  }, []);
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
// Initialize global state on first render
useState(() => {
initializeGlobalFrameworks();
});
// Initialize global state on first render
useEffect(() => {
initializeGlobalFrameworks();
}, []);
🤖 Prompt for AI Agents
In docs/src/components/mdx/platform-codeblock.tsx around lines 167 to 171, the
code uses useState to run a one-time initialization
(initializeGlobalFrameworks()), which is incorrect for side effects; replace the
useState call with useEffect and move the initialization into useEffect(() => {
initializeGlobalFrameworks(); }, []), ensuring the effect has an empty
dependency array so it runs only once on mount.

Comment on lines +278 to +331
useEffect(() => {
if (!currentCodeConfig) return;

const updateHighlightedCode = async () => {
try {
// Detect if we're in dark mode
const isDarkMode = document.documentElement.classList.contains('dark') ||
getComputedStyle(document.documentElement).getPropertyValue('--fd-background').includes('0 0% 3.9%');

const theme = isDarkMode ? 'github-dark' : 'github-light';

const html = await codeToHtml(currentCodeConfig.code, {
lang: currentCodeConfig.language || 'typescript',
theme,
transformers: [{
pre(node) {
// Remove background styles from pre element
if (node.properties.style) {
node.properties.style = (node.properties.style as string).replace(/background[^;]*;?/g, '');
}
},
code(node) {
// Remove background styles from code element
if (node.properties.style) {
node.properties.style = (node.properties.style as string).replace(/background[^;]*;?/g, '');
}
// Add consistent styling
const existingStyle = (node.properties.style as string) || '';
node.properties.style = `${existingStyle}; line-height: 1.5; font-family: ui-monospace, 'Cascadia Code', 'Source Code Pro', Menlo, Consolas, 'DejaVu Sans Mono', monospace; white-space: pre;`;
}
}]
});
setHighlightedCode(html);
} catch (error) {
console.error('Error highlighting code:', error);
setHighlightedCode(`<pre><code>${currentCodeConfig.code}</code></pre>`);
}
};

runAsynchronously(updateHighlightedCode);

// Listen for theme changes
const observer = new MutationObserver(() => {
runAsynchronously(updateHighlightedCode);
});

observer.observe(document.documentElement, {
attributes: true,
attributeFilter: ['class']
});

return () => observer.disconnect();
}, [currentCodeConfig]);

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Sanitize highlighted HTML before injection to mitigate XSS (even if content is first‑party).

Shiki’s output is generally safe, but linters flag dangerouslySetInnerHTML. Sanitizing keeps us compliant and defensive.

+import DOMPurify from 'isomorphic-dompurify';
 ...
-        const html = await codeToHtml(currentCodeConfig.code, {
+        const html = await codeToHtml(currentCodeConfig.code, {
           lang: currentCodeConfig.language || 'typescript',
           theme,
           transformers: [{
             pre(node) {
               // Remove background styles from pre element
               if (node.properties.style) {
                 node.properties.style = (node.properties.style as string).replace(/background[^;]*;?/g, '');
               }
             },
             code(node) {
               // Remove background styles from code element
               if (node.properties.style) {
                 node.properties.style = (node.properties.style as string).replace(/background[^;]*;?/g, '');
               }
               // Add consistent styling
               const existingStyle = (node.properties.style as string) || '';
               node.properties.style = `${existingStyle}; line-height: 1.5; font-family: ui-monospace, 'Cascadia Code', 'Source Code Pro', Menlo, Consolas, 'DejaVu Sans Mono', monospace; white-space: pre;`;
             }
           }]
         });
-        setHighlightedCode(html);
+        setHighlightedCode(DOMPurify.sanitize(html, { USE_PROFILES: { html: true } }));

Follow-up: add isomorphic-dompurify to the docs package dependencies.

Committable suggestion skipped: line range outside the PR's diff.

🤖 Prompt for AI Agents
In docs/src/components/mdx/platform-codeblock.tsx around lines 278-331, the
highlighted HTML returned from codeToHtml is assigned directly and later used
with dangerouslySetInnerHTML; sanitize that HTML first to mitigate XSS by adding
the isomorphic-dompurify dependency and importing a DOMPurify instance
appropriate for SSR, then replace setHighlightedCode(html) with
setHighlightedCode(DOMPurify.sanitize(html)) (optionally pass a strict
whitelist/allowed attributes config). Ensure the new dependency is added to the
docs package.json and imported at the top of the file, and keep the fallback on
error similarly sanitized before setting state.

Comment on lines +356 to +364
const handleVariantChange = (variant: 'server' | 'client') => {
setSelectedVariants(prev => ({
...prev,
[selectedPlatform]: {
...prev[selectedPlatform],
[currentFramework]: variant
}
}));
};
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Null‑safe spread to avoid edge cases when no variant object exists yet.

prev[selectedPlatform] may be undefined. Use a fallback object.

   setSelectedVariants(prev => ({
     ...prev,
     [selectedPlatform]: {
-      ...prev[selectedPlatform],
+      ...(prev[selectedPlatform] ?? {}),
       [currentFramework]: variant
     }
   }));
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
const handleVariantChange = (variant: 'server' | 'client') => {
setSelectedVariants(prev => ({
...prev,
[selectedPlatform]: {
...prev[selectedPlatform],
[currentFramework]: variant
}
}));
};
const handleVariantChange = (variant: 'server' | 'client') => {
setSelectedVariants(prev => ({
...prev,
[selectedPlatform]: {
...(prev[selectedPlatform] ?? {}),
[currentFramework]: variant
}
}));
};
🤖 Prompt for AI Agents
In docs/src/components/mdx/platform-codeblock.tsx around lines 356 to 364, the
updater uses ...prev[selectedPlatform] which can be undefined; change the update
to provide a fallback object when spreading (e.g., use prev[selectedPlatform] ||
{} or similar) so the new object safely spreads an empty object if no variants
exist yet, then set [currentFramework]: variant on that result and return the
updated state.

@madster456 madster456 changed the title [Docs][Util][Content] [Docs][Util][Content] - refactor docs to single source Oct 1, 2025
Copy link
Contributor
@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 6

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (2)
docs/src/components/mdx/dynamic-code-block-overlay.tsx (1)

144-238: Add accessibility support for keyboard and screen readers.

This overlay currently lacks ARIA roles, focus management, and screen-reader announcements.

Ensure:

  • The container uses role="dialog" and aria-modal="true", with a clear label (e.g., aria-labelledby on the header).
  • Focus is trapped inside the overlay while open and returned to the trigger on close.
  • All buttons and controls have logical tab order and tabIndex as needed.
  • Opening and closing are announced to assistive technologies (via aria-live or similar).
docs/src/components/layouts/shared-header.tsx (1)

30-41: Fix section matchers to new section-based routes; avoid “Guides” false-positives

Current regex assumes /docs/{platform}/section. With platform folders removed, “/docs/sdk” and “/docs/components” won’t match; “Guides” may be incorrectly marked active.

-export function isInSdkSection(pathname: string): boolean {
-  const match = pathname.match(/^\/docs\/[^\/]+\/sdk($|\/)/);
-  return Boolean(match);
-}
-export function isInComponentsSection(pathname: string): boolean {
-  const match = pathname.match(/^\/docs\/[^\/]+\/components($|\/)/);
-  return Boolean(match);
-}
+export function isInSdkSection(pathname: string): boolean {
+  // supports both legacy (/docs/{platform}/sdk) and new (/docs/sdk)
+  return /^\/docs\/(?:[^/]+\/)?sdk(?:$|\/)/.test(pathname);
+}
+export function isInComponentsSection(pathname: string): boolean {
+  return /^\/docs\/(?:[^/]+\/)?components(?:$|\/)/.test(pathname);
+}

Also applies to: 63-66

♻️ Duplicate comments (1)
docs/src/components/layouts/docs.tsx (1)

286-287: Avoid index as key in tree renders (same as prior review)

Use a deterministic key for non-page items to stabilize reconciliation. See earlier reviewer note.

-<PageTreeItem key={child.type === 'page' ? child.url : index} item={child} />
+<PageTreeItem key={child.type === 'page' ? child.url : `${child.type}-${typeof child.name === 'string' ? child.name : index}` } item={child} />
-<PageTreeItem key={item.type === 'page' ? item.url : index} item={item} />
+<PageTreeItem key={item.type === 'page' ? item.url : `${item.type}-${typeof item.name === 'string' ? item.name : index}` } item={item} />

Also applies to: 299-300, 321-322

🧹 Nitpick comments (14)
docs/src/components/api/auth-panel.tsx (2)

75-76: Simplify dead conditional and clarify height intent.

Line 75 has a no-op ternary (both branches return 'top-0'), which should be simplified to a constant assignment. Line 76's height calculation also uses nearly identical values ('h-screen' vs 'h-[calc(100vh)]') that behave identically in most viewport scenarios.

Apply this diff to simplify:

-  const topPosition = isHomePage && isScrolled ? 'top-0' : 'top-0';
-  const height = isHomePage && isScrolled ? 'h-screen' : 'h-[calc(100vh)]';
+  const topPosition = 'top-0';
+  const height = 'h-screen';

If the distinction between h-screen and h-[calc(100vh)] is meaningful for handling mobile browser chrome behavior, document the rationale in a comment. Otherwise, consolidate to a single value.


41-72: Consider removing unused state observation.

Given that topPosition is now constant and height has minimal variation, the isHomePage and isScrolled state tracking (and the associated MutationObserver) may no longer serve a purpose. If these states aren't used elsewhere or the height distinction isn't critical, removing this complexity would improve maintainability.

If you decide to keep the distinction, ensure the state is actually necessary. Otherwise, remove the observer setup:

-  const [isHomePage, setIsHomePage] = useState(false);
-  const [isScrolled, setIsScrolled] = useState(false);
-
-  // Detect if we're on homepage and scroll state (same as AIChatDrawer)
-  useEffect(() => {
-    const checkHomePage = () => {
-      setIsHomePage(document.body.classList.contains('home-page'));
-    };
-
-    const checkScrolled = () => {
-      setIsScrolled(document.body.classList.contains('scrolled'));
-    };
-
-    // Initial check
-    checkHomePage();
-    checkScrolled();
-
-    // Set up observers for class changes
-    const observer = new MutationObserver(() => {
-      checkHomePage();
-      checkScrolled();
-    });
-
-    observer.observe(document.body, {
-      attributes: true,
-      attributeFilter: ['class']
-    });
-
-    return () => {
-      observer.disconnect();
-    };
-  }, []);
docs/src/components/layout/toc.tsx (1)

42-73: Consider removing unused state tracking.

Since both topPosition and height now resolve to constant values regardless of isHomePage and isScrolled, the entire state tracking mechanism (including the MutationObserver) is unused and adds unnecessary runtime overhead.

If the simplified positioning is intentional, apply this diff to remove the unused code:

-  // State for tracking homepage and scroll detection (similar to AI Chat)
-  const [isHomePage, setIsHomePage] = useState(false);
-  const [isScrolled, setIsScrolled] = useState(false);
-
-  // Detect if we're on homepage and scroll state
-  useEffect(() => {
-    const checkHomePage = () => {
-      setIsHomePage(document.body.classList.contains('home-page'));
-    };
-
-    const checkScrolled = () => {
-      setIsScrolled(document.body.classList.contains('scrolled'));
-    };
-
-    // Initial check
-    checkHomePage();
-    checkScrolled();
-
-    // Set up observers for class changes
-    const observer = new MutationObserver(() => {
-      checkHomePage();
-      checkScrolled();
-    });
-
-    observer.observe(document.body, {
-      attributes: true,
-      attributeFilter: ['class']
-    });
-
-    return () => {
-      observer.disconnect();
-    };
-  }, []);
-
-  // Calculate position based on homepage and scroll state (same as AI Chat and Auth Panel)
-  const topPosition = 'top-0';
-  const height = 'h-screen';
docs/src/components/mdx/dynamic-code-block-overlay.tsx (1)

242-273: Add aria-label for better accessibility.

The trigger button looks good, but should include an aria-label attribute for screen readers, as title attributes are not consistently announced.

Apply this diff:

     <button
       onClick={onClick}
       className={cn(
         "fixed bottom-6 z-30",
         "flex items-center gap-1.5 px-3 py-2",
         "bg-fd-primary text-fd-primary-foreground",
         "rounded-full shadow-lg",
         "hover:scale-105 active:scale-95",
         "transition-all duration-200",
         "border border-fd-primary/20"
       )}
       style={{
         left: '50%',
         transform: 'translateX(-50%)'
       }}
       title="View Code Example"
+      aria-label="View Code Example"
     >
docs/src/components/layouts/api/api-sidebar.tsx (1)

68-69: Consider ES6 Map over Record for key-value collections.

Multiple locations use Record<string, ...> for runtime key-value collections:

  • Line 68: groups: Record<string, OrganizedGroup>
  • Line 85-92: accordionState: Record<string, boolean>

As per coding guidelines, prefer ES6 Map for dynamic key-value collections as it provides better type safety, avoids prototype pollution, and offers a cleaner API for runtime operations.

Example for accordion state:

-type AccordionContextType = {
-  accordionState: Record<string, boolean>,
-  setAccordionState: (key: string, isOpen: boolean) => void,
-}
+type AccordionContextType = {
+  accordionState: Map<string, boolean>,
+  setAccordionState: (key: string, isOpen: boolean) => void,
+}

 function AccordionProvider({ children }: { children: ReactNode }) {
-  const [accordionState, setAccordionStateInternal] = useState<Record<string, boolean>>({});
+  const [accordionState, setAccordionStateInternal] = useState<Map<string, boolean>>(new Map());

   const setAccordionState = (key: string, isOpen: boolean) => {
-    setAccordionStateInternal(prev => ({ ...prev, [key]: isOpen }));
+    setAccordionStateInternal(prev => new Map(prev).set(key, isOpen));
   };

Based on coding guidelines.

Also applies to: 85-92

docs/src/app/global.css (3)

33-39: Deduplicate transition rules for #nd-docs-layout and #api-main-content

Same transition declared twice; keep one to avoid override churn.

 /* Default transitions for main content */
-#nd-docs-layout {
-  transition: margin-left 300ms ease-out;
-}
-
-#api-main-content {
-  transition: margin-left 300ms ease-out;
-}
+/* (kept above at lines ~33 and ~37) */

Also applies to: 47-53


17-19: Anchor offset likely mismatched with header height on lg screens

[id]{ scroll-margin-top: 7rem } (112px) while header is h-14 (56px) on small and intended ~6.5rem (104px) on lg. Use a CSS var responsive to breakpoints to prevent awkward extra gap.

-:root {
-  --color-fd-background: #fafbfd;
-}
+:root {
+  --color-fd-background: #fafbfd;
+  --nd-header-offset: 3.5rem; /* h-14 */
+}
+.dark {
   --color-fd-background: hsl(0, 0%, 7.04%);
 }
+[id] { scroll-margin-top: var(--nd-header-offset); }
+@media (min-width: 1024px) {
+  :root { --nd-header-offset: 6.5rem; } /* matches lg header height */
+}
-
-[id] {
-  scroll-margin-top: 7rem;
-}

Also applies to: 263-266


145-196: Respect prefers-reduced-motion for heavy, infinite animations

Add a motion-reduced override to cut CPU/GPU cost and improve a11y.

 @keyframes gradient-shift { ... }
 @keyframes gradient-noise { ... }
 .chat-gradient-active::before { ... }
+@media (prefers-reduced-motion: reduce) {
+  .chat-gradient-active::before {
+    animation: none !important;
+  }
+  #nd-docs-layout, #api-main-content, .api-sidebar, body:not(.home-page) {
+    transition: none !important;
+  }
+}
docs/src/components/layouts/shared-header.tsx (3)

73-95: Make className optional on toggle components

Loosen prop typing; avoid forcing callers to pass a string.

-function AIChatToggleButton(props: { className: string }) {
+function AIChatToggleButton({ className = '' }: { className?: string }) {
 ...
-        props.className,
+        className,
 ...
-function TOCToggleButtonInner(props: { className: string }) {
+function TOCToggleButtonInner({ className = '' }: { className?: string }) {
 ...
-          : 'text-fd-muted-foreground hover:text-fd-foreground hover:bg-fd-muted/50',
-        props.className
+          : 'text-fd-muted-foreground hover:text-fd-foreground hover:bg-fd-muted/50',
+        className
 ...
-function TOCToggleButton(props: { className: string }) {
+function TOCToggleButton(props: { className?: string }) {
 ...
-function AuthToggleButton(props: { className: string }) {
+function AuthToggleButton({ className = '' }: { className?: string }) {
 ...
-          : 'text-fd-muted-foreground hover:text-fd-foreground hover:bg-fd-muted/50',
-        props.className
+          : 'text-fd-muted-foreground hover:text-fd-foreground hover:bg-fd-muted/50',
+        className

Also applies to: 101-133, 138-147, 152-183


322-345: Use stable keys for nav items (avoid array index)

Prevents reconciliation glitches when links change.

-  {navLinks.map((link, index) => {
+  {navLinks.map((link) => {
 ...
-    <Link key={index} href={link.href} ...
+    <Link key={link.href ?? link.label} href={link.href} ...
-  {navLinks.map((link, index) => {
+  {navLinks.map((link) => {
 ...
-    <Link key={index} href={link.href} ...
+    <Link key={link.href ?? link.label} href={link.href} ...

Also applies to: 366-385


293-299: Comment mismatch: Auth toggle only shows on API pages

Comment says “shows on all pages,” but component gates on isInApiSection. Update comment to avoid confusion.

-/* Auth Toggle Button - Shows on all pages like AI Chat button */
+/* Auth Toggle Button - Only on API pages */
docs/src/components/layouts/docs.tsx (3)

86-99: Use ES6 Map for accordion state (per guidelines)

Improves semantics and avoids accidental key collisions. Also aligns with repo guideline to prefer Map over Record for key–value collections.
[Based on coding guidelines]

-type AccordionContextType = {
-  accordionState: Record<string, boolean>,
-  setAccordionState: (key: string, isOpen: boolean) => void,
-};
+type AccordionContextType = {
+  accordionState: Map<string, boolean>,
+  setAccordionState: (key: string, isOpen: boolean) => void,
+};

 function AccordionProvider({ children }: { children: ReactNode }) {
-  const [accordionState, setAccordionStateInternal] = useState<Record<string, boolean>>({});
+  const [accordionState, setAccordionStateInternal] = useState<Map<string, boolean>>(
+    () => new Map<string, boolean>()
+  );

   const setAccordionState = (key: string, isOpen: boolean) => {
-    setAccordionStateInternal(prev => ({ ...prev, [key]: isOpen }));
+    setAccordionStateInternal(prev => {
+      const next = new Map(prev);
+      next.set(key, isOpen);
+      return next;
+    });
   };
 function useAccordionState(key: string, defaultValue: boolean) {
 ...
-  const isOpen = accordionState[key] ?? defaultValue;
+  const isOpen = accordionState.get(key) ?? defaultValue;

Also applies to: 106-120


344-345: Hard-coded blue; tie dot color to theme token

Use the design token to respect theming and reduce magic numbers.

-const platformColor = 'rgb(59, 130, 246)';
+const platformColor = 'hsl(var(--fd-primary))';

And where translucency is needed, prefer modern syntax:

- backgroundColor: isCurrentlyActive ? platformColor : 'rgb(100, 116, 139)',
+ backgroundColor: isCurrentlyActive ? platformColor : 'hsl(var(--fd-primary) / 0.4)',

Similarly replace ${platformColor}40 with hsl(var(--fd-primary) / 0.25), and borders with 1px solid hsl(var(--fd-primary)).

Also applies to: 445-446, 600-601


354-355: Prefer Link for navigation to preserve prefetch and accessibility

Using router.push inside buttons drops prefetch and default a11y affordances. Wrap the dot with a Link or render an anchor styled as a dot.

-<button onClick={handleNavigation} ...>
+<Link href={href} onClick={(e) => { setIsOpen?.(true); }} role="button" aria-label={`Go to ${title}`}>
   ...
-</button>
+</Link>

Also applies to: 456-457

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between a009f64 and 0591064.

📒 Files selected for processing (13)
  • docs/src/app/api/layout.tsx (1 hunks)
  • docs/src/app/docs/layout.tsx (1 hunks)
  • docs/src/app/global.css (3 hunks)
  • docs/src/components/api/auth-panel.tsx (1 hunks)
  • docs/src/components/chat/ai-chat.tsx (1 hunks)
  • docs/src/components/layout/toc.tsx (2 hunks)
  • docs/src/components/layouts/api/api-sidebar.tsx (1 hunks)
  • docs/src/components/layouts/docs-header-wrapper.tsx (7 hunks)
  • docs/src/components/layouts/docs.tsx (16 hunks)
  • docs/src/components/layouts/page.tsx (2 hunks)
  • docs/src/components/layouts/shared-header.tsx (8 hunks)
  • docs/src/components/layouts/sidebar-context.tsx (2 hunks)
  • docs/src/components/mdx/dynamic-code-block-overlay.tsx (2 hunks)
🧰 Additional context used
📓 Path-based instructions (1)
**/*.{ts,tsx,js,jsx}

📄 CodeRabbit inference engine (AGENTS.md)

Prefer ES6 Map over Record when representing key–value collections

Files:

  • docs/src/app/docs/layout.tsx
  • docs/src/components/chat/ai-chat.tsx
  • docs/src/components/layouts/sidebar-context.tsx
  • docs/src/components/layouts/api/api-sidebar.tsx
  • docs/src/components/mdx/dynamic-code-block-overlay.tsx
  • docs/src/components/layouts/shared-header.tsx
  • docs/src/components/api/auth-panel.tsx
  • docs/src/app/api/layout.tsx
  • docs/src/components/layout/toc.tsx
  • docs/src/components/layouts/docs-header-wrapper.tsx
  • docs/src/components/layouts/page.tsx
  • docs/src/components/layouts/docs.tsx
🧬 Code graph analysis (4)
docs/src/app/docs/layout.tsx (2)
docs/src/components/layouts/docs-header-wrapper.tsx (1)
  • DocsHeaderWrapper (249-276)
docs/lib/source.ts (1)
  • source (23-30)
docs/src/components/layouts/shared-header.tsx (3)
docs/src/components/layout/custom-search-toggle.tsx (1)
  • SearchInputToggle (95-150)
docs/src/components/layout/custom-search-dialog.tsx (1)
  • CustomSearchDialog (83-320)
docs/src/components/icons.tsx (2)
  • X (143-146)
  • Menu (137-141)
docs/src/app/api/layout.tsx (1)
docs/src/components/layouts/docs-header-wrapper.tsx (1)
  • DocsHeaderWrapper (249-276)
docs/src/components/layouts/docs-header-wrapper.tsx (3)
docs/src/lib/navigation-utils.ts (1)
  • generateNavLinks (14-37)
docs/src/lib/docs-tree.ts (2)
  • resolveDocsSection (7-17)
  • filterTreeForSection (19-32)
docs/src/components/layouts/shared-header.tsx (1)
  • SharedHeader (224-412)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (10)
  • GitHub Check: Vercel Agent Review
  • GitHub Check: setup-tests
  • GitHub Check: docker
  • GitHub Check: lint_and_build (latest)
  • GitHub Check: restart-dev-and-test
  • GitHub Check: build (22.x)
  • GitHub Check: all-good
  • GitHub Check: build (22.x)
  • GitHub Check: docker
  • GitHub Check: Security Check
🔇 Additional comments (14)
docs/src/components/layouts/sidebar-context.tsx (1)

115-115: LGTM: Consistent persistence for chat expansion state.

Replacing setIsChatExpanded(false) with setChatExpanded(false) ensures that the chat expansion state is correctly persisted to localStorage when the chat is closed. This aligns with the pattern used for other stateful setters in the component.

Also applies to: 156-156

docs/src/components/api/auth-panel.tsx (1)

22-22: Record usage is appropriate here despite coding guideline.

While the coding guideline prefers ES6 Map for key-value collections, using Record<string, string> for HTTP headers is the correct choice here. Headers are serialized data that integrate naturally with object spread syntax (line 179) and JSON serialization. Converting to/from Map would add unnecessary complexity.

Based on coding guidelines (noting appropriate exception).

Also applies to: 39-39

docs/src/components/mdx/dynamic-code-block-overlay.tsx (5)

1-16: LGTM!

Imports and type definitions are clean and appropriate for the component's functionality.


18-33: LGTM!

State setup is clean, and memoizing the line count calculation is a good performance optimization.


36-73: LGTM!

The responsive height calculation logic is well-thought-out with appropriate mobile/desktop breakpoints and conservative ratios to prevent overflow. The comments clearly explain the calculation strategy.


76-90: LGTM!

Window resize handling is implemented correctly with proper cleanup and SSR safety checks.


93-141: LGTM!

Syntax highlighting and clipboard functionality are well-implemented with appropriate error handling and visual feedback.

docs/src/components/layouts/api/api-sidebar.tsx (1)

3-3: LGTM! Import cleanup aligns with navigation simplification.

The removal of the ArrowLeft import and related back-navigation UI is consistent with the broader PR objective to remove platform-specific navigation elements.

docs/src/app/api/layout.tsx (1)

93-113: LGTM! Layout restructuring supports new sidebar positioning.

The flex-based layout with sticky sidebar positioning is well-structured. The height calculations (h-[calc(100vh-3.5rem)] lg:h-[calc(100vh-6.5rem)]) correctly account for the header height differences between mobile and desktop viewports.

docs/src/components/layouts/docs-header-wrapper.tsx (2)

2-3: LGTM! Clean refactor to section-based navigation.

The changes successfully replace platform-aware navigation with section-based filtering:

  • Imports the new resolveDocsSection and filterTreeForSection utilities
  • Properly memoizes derived values (navLinks, docsSection, sectionTree)
  • Updates dependency arrays correctly to include sectionTree

The section-based approach simplifies the navigation logic and aligns with the PR's objective to remove platform-specific routing.

Also applies to: 249-267


181-227: All currentPlatform prop references removed. Search across .tsx/.ts returned no matches; safe to merge.

docs/src/app/docs/layout.tsx (1)

11-19: LGTM! Layout styling adjustments align with header refactoring.

The changes simplify the layout structure:

  • mx-auto centers the content horizontally
  • Removing pt-14 eliminates duplicate top padding (likely now handled by the header component or its wrapper)

These adjustments are consistent with the broader layout and navigation simplifications across the PR.

docs/src/components/layouts/page.tsx (2)

7-26: LGTM! Import reorganization improves code organization.

The imports are reorganized without changing runtime behavior. This cleanup aligns with the broader refactoring effort across layout components.


159-161: LGTM! Additional top margin improves content spacing.

The addition of mt-6 to the content container increases vertical spacing above the page content, providing better visual separation after the breadcrumb navigation. This complements the existing bottom margin.

// Calculate position based on homepage and scroll state
const topPosition = isHomePage && isScrolled ? 'top-0' : 'top-14';
const height = isHomePage && isScrolled ? 'h-screen' : 'h-[calc(100vh-3.5rem)]';
const topPosition = isHomePage && isScrolled ? 'top-0' : 'top-0';
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Remove the no-op conditional.

The ternary operator returns 'top-0' in both branches, making the condition pointless.

Apply this diff to simplify:

-  const topPosition = isHomePage && isScrolled ? 'top-0' : 'top-0';
+  const topPosition = 'top-0';
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
const topPosition = isHomePage && isScrolled ? 'top-0' : 'top-0';
const topPosition = 'top-0';
🤖 Prompt for AI Agents
In docs/src/components/chat/ai-chat.tsx around line 179 the ternary assignment
"const topPosition = isHomePage && isScrolled ? 'top-0' : 'top-0';" is a no-op;
replace the conditional with a direct assignment "const topPosition = 'top-0';"
to simplify the code and remove the redundant condition.

const topPosition = isHomePage && isScrolled ? 'top-0' : 'top-14';
const height = isHomePage && isScrolled ? 'h-screen' : 'h-[calc(100vh-3.5rem)]';
const topPosition = isHomePage && isScrolled ? 'top-0' : 'top-0';
const height = isHomePage && isScrolled ? 'h-screen' : 'h-[calc(100vh)]';
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Simplify the height logic.

Both branches evaluate to the same effective height (100vh), making this conditional redundant. h-screen and h-[calc(100vh)] both result in 100% viewport height.

Apply this diff to simplify:

-  const height = isHomePage && isScrolled ? 'h-screen' : 'h-[calc(100vh)]';
+  const height = 'h-screen';
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
const height = isHomePage && isScrolled ? 'h-screen' : 'h-[calc(100vh)]';
const height = 'h-screen';
🤖 Prompt for AI Agents
In docs/src/components/chat/ai-chat.tsx around line 180, the conditional
assigning height is redundant because both branches produce 100vh; replace the
ternary with a single constant height value (for example 'h-screen') so the code
simply uses a single height string instead of the conditional expression.

// Calculate position based on homepage and scroll state (same as AI Chat and Auth Panel)
const topPosition = isHomePage && isScrolled ? 'top-0' : 'top-14';
const height = isHomePage && isScrolled ? 'h-screen' : 'h-[calc(100vh-3.5rem)]';
const topPosition = isHomePage && isScrolled ? 'top-0' : 'top-0';
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Dead code: condition always evaluates to the same value.

The ternary operator returns 'top-0' in both branches, making the condition isHomePage && isScrolled ineffective.

Apply this diff to simplify:

-  const topPosition = isHomePage && isScrolled ? 'top-0' : 'top-0';
+  const topPosition = 'top-0';
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
const topPosition = isHomePage && isScrolled ? 'top-0' : 'top-0';
const topPosition = 'top-0';
🤖 Prompt for AI Agents
In docs/src/components/layout/toc.tsx around line 76, the ternary const
topPosition = isHomePage && isScrolled ? 'top-0' : 'top-0' always yields
'top-0'; simplify by removing the redundant condition and set const topPosition
= 'top-0'; delete the unused variables or conditional logic if they are now
unused (isHomePage/isScrolled) or leave them if used elsewhere.

const topPosition = isHomePage && isScrolled ? 'top-0' : 'top-14';
const height = isHomePage && isScrolled ? 'h-screen' : 'h-[calc(100vh-3.5rem)]';
const topPosition = isHomePage && isScrolled ? 'top-0' : 'top-0';
const height = isHomePage && isScrolled ? 'h-screen' : 'h-[calc(100vh)]';
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Dead code: both branches evaluate to full viewport height.

Both 'h-screen' (Tailwind's height: 100vh) and 'h-[calc(100vh)]' (also 100vh) result in the same height. The condition is ineffective.

Apply this diff to simplify:

-  const height = isHomePage && isScrolled ? 'h-screen' : 'h-[calc(100vh)]';
+  const height = 'h-screen';
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
const height = isHomePage && isScrolled ? 'h-screen' : 'h-[calc(100vh)]';
const height = 'h-screen';
🤖 Prompt for AI Agents
In docs/src/components/layout/toc.tsx around line 77, the conditional assigning
const height chooses between 'h-screen' and 'h-[calc(100vh)]' which both
evaluate to 100vh; remove the dead branch and simplify the assignment to a
single height value (e.g., always use 'h-screen'), updating any references
accordingly so the conditional is removed and the code is clearer.

Comment on lines +972 to 976
"hidden md:block sticky left-0 top-14 lg:top-26 z-30 transition-all duration-300 ease-out",
isMainSidebarCollapsed ? "w-16" : "w-64"
)}>
<div className="h-[calc(100vh-3.5rem)] flex flex-col">
<div className="h-[calc(100vh-3.5rem)] lg:h-[calc(100vh-6.5rem)] flex flex-col">
{/* Scrollable content area */}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

Sticky offsets: verify lg:top-26

top-26 is non-standard unless extended. Use an arbitrary value to match the header (6.5rem) for consistent sticky behavior.

-<div className={cn("hidden md:block sticky left-0 top-14 lg:top-26 z-30 transition-all duration-300 ease-out", ... )}>
+<div className={cn("hidden md:block sticky left-0 top-14 lg:top-[6.5rem] z-30 transition-all duration-300 ease-out", ... )}>

To verify:


🏁 Script executed:

#!/bin/bash
fd tailwind.config | xargs -I{} cat {} | rg -n 'extend:\s*{\s*top|spacing|zIndex'

Length of output: 161


🏁 Script executed:

#!/bin/bash
# Locate Tailwind config file
config_file=$(fd --ignore-case 'tailwind.config.*' | head -n 1)
echo "Using config file: $config_file"
# Check for custom top values under theme.extend.top
rg -nP "theme\s*:\s*{[^}]*extend\s*:\s*{[^}]*top\s*:" "$config_file" || echo "No theme.extend.top block found"
# Check for custom spacing values under theme.extend.spacing
rg -nP "theme\s*:\s*{[^}]*extend\s*:\s*{[^}]*spacing\s*:" "$config_file" || echo "No theme.extend.spacing block found"
# Check for any key named '26' in the config
rg -nP "'?26'?\s*:" "$config_file" || echo "No '26:' key defined"

Length of output: 141


Replace non-standard lg:top-26 with lg:top-[6.5rem]
lg:top-26 isn’t defined in your Tailwind config or default scale. Use the arbitrary value to match the 6.5rem header height:

- "hidden md:block sticky left-0 top-14 lg:top-26 z-30 transition-all duration-300 ease-out"
+ "hidden md:block sticky left-0 top-14 lg:top-[6.5rem] z-30 transition-all duration-300 ease-out"
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
"hidden md:block sticky left-0 top-14 lg:top-26 z-30 transition-all duration-300 ease-out",
isMainSidebarCollapsed ? "w-16" : "w-64"
)}>
<div className="h-[calc(100vh-3.5rem)] flex flex-col">
<div className="h-[calc(100vh-3.5rem)] lg:h-[calc(100vh-6.5rem)] flex flex-col">
{/* Scrollable content area */}
className={clsx(
"hidden md:block sticky left-0 top-14 lg:top-[6.5rem] z-30 transition-all duration-300 ease-out",
isMainSidebarCollapsed ? "w-16" : "w-64"
)}>
<div className="h-[calc(100vh-3.5rem)] lg:h-[calc(100vh-6.5rem)] flex flex-col">
{/* Scrollable content area */}
🤖 Prompt for AI Agents
In docs/src/components/layouts/docs.tsx around lines 972 to 976, the Tailwind
class uses the non-standard utility "lg:top-26"; replace it with the arbitrary
value "lg:top-[6.5rem]" so the large-breakpoint top offset equals the 6.5rem
header height, i.e., update the class string to remove "lg:top-26" and add
"lg:top-[6.5rem]" while keeping the other classes unchanged.

Comment on lines +263 to +266
<header className="sticky top-0 w-full h-14 lg:h-26 z-49 flex flex-col space-around bg-fd-background">

{/* First row */}
<div className="flex items-center justify-between h-14 border-b border-fd-border px-4">
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

Invalid Tailwind utilities: replace space-around, verify h-26 and z-49

  • Tailwind has justify-around, not space-around.
  • h-26 and z-49 are non-standard unless extended in tailwind.config. Prefer arbitrary values for portability.
-<header className="sticky top-0 w-full h-14 lg:h-26 z-49 flex flex-col space-around bg-fd-background">
+<header className="sticky top-0 w-full h-14 lg:h-[6.5rem] z-[49] flex flex-col justify-between bg-fd-background">

To verify availability:


🏁 Script executed:

#!/bin/bash
rg -n --type=ts --type=tsx -C1 'h-26|z-49|space-around'
fd tailwind.config | xargs -I{} cat {} | rg -n 'theme\.extend\.(height|zIndex)'

Length of output: 27


🏁 Script executed:

#!/bin/bash
echo "Searching code for 'space-around', 'h-26', 'z-49'"
rg -n -C1 'space-around|h-26|z-49' --glob '*.[tj]s*'
echo "Locating Tailwind config files"
fd 'tailwind.config.*' -t f
echo "Checking theme.extend in config"
fd 'tailwind.config.*' -t f | xargs -I{} bash -c 'echo "== {} =="; rg -n -C5 "theme\\.extend" "{}"'

Length of output: 775


Replace invalid Tailwind utilities and use arbitrary values
Tailwind doesn’t ship with space-around, h-26, or z-49, and none of your configs extend them. Swap them out for supported classes (or arbitrary values):

- <header className="sticky top-0 w-full h-14 lg:h-26 z-49 flex flex-col space-around bg-fd-background">
+ <header className="sticky top-0 w-full h-14 lg:h-[6.5rem] z-[49] flex flex-col justify-around bg-fd-background">

If you meant equal spacing between items, use justify-between; to distribute space around each item, use justify-around.

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
<header className="sticky top-0 w-full h-14 lg:h-26 z-49 flex flex-col space-around bg-fd-background">
{/* First row */}
<div className="flex items-center justify-between h-14 border-b border-fd-border px-4">
<header className="sticky top-0 w-full h-14 lg:h-[6.5rem] z-[49] flex flex-col justify-around bg-fd-background">
{/* First row */}
<div className="flex items-center justify-between h-14 border-b border-fd-border px-4">
🤖 Prompt for AI Agents
In docs/src/components/layouts/shared-header.tsx around lines 263-266, replace
invalid Tailwind utilities: change space-around to a supported utility (e.g.,
justify-around or justify-between depending on desired spacing), replace lg:h-26
with a valid size or an arbitrary value like lg:h-[6.5rem] (or use the closest
built-in h-24/h-28), and replace z-49 with a supported z-index or an arbitrary
value like z-[49] (or use z-50). Make these swaps so only valid Tailwind classes
or arbitrary bracketed values are used.

Copy link
@vercel vercel bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Additional Comments:

docs/src/components/layouts/docs/shared.tsx (line 7):
Import references deleted file root-toggle.tsx but the Option type is still used in the sidebar configuration.

View Details
📝 Patch Details
diff --git a/docs/src/components/layouts/docs/shared.tsx b/docs/src/components/layouts/docs/shared.tsx
index 38ebd14b..ece54840 100644
--- a/docs/src/components/layouts/docs/shared.tsx
+++ b/docs/src/components/layouts/docs/shared.tsx
@@ -4,7 +4,7 @@ import {
   type GetSidebarTabsOptions,
 } from 'fumadocs-ui/utils/get-sidebar-tabs';
 import type { ReactNode } from 'react';
-import type { Option } from '../../layout/root-toggle';
+
 import {
   type SidebarComponents,
   SidebarFolder,
@@ -26,7 +26,7 @@ export type SidebarOptions = {
   /**
    * Root Toggle options
    */
-  tabs?: Option[] | GetSidebarTabsOptions | false,
+  tabs?: GetSidebarTabsOptions | false,
 
   banner?: ReactNode,
   footer?: ReactNode,
@@ -79,9 +79,7 @@ export function getSidebarTabsFromOptions(
   options: SidebarOptions['tabs'],
   tree: PageTree.Root,
 ) {
-  if (Array.isArray(options)) {
-    return options;
-  } else if (typeof options === 'object') {
+  if (typeof options === 'object') {
     return getSidebarTabs(tree, options);
   } else if (options !== false) {
     return getSidebarTabs(tree);

Analysis

Import references deleted file causing TypeScript compilation failure

What fails: TypeScript compilation fails in docs/src/components/layouts/docs/shared.tsx line 7 due to import from non-existent '../../layout/root-toggle' file

How to reproduce:

cd docs && pnpm exec tsc --noEmit

Result: Compilation error: Cannot find module '../../layout/root-toggle' or its corresponding type declarations

Expected: Compilation should succeed - the Option[] type was removed along with platform-specific tabs functionality, so the import and its usage should be cleaned up


docs/src/components/layouts/shared-header.tsx (line 263):
Invalid Tailwind CSS class lg:h-26 - Tailwind doesn't have a height utility for 26 units.

View Details
📝 Patch Details
diff --git a/docs/src/components/layouts/shared-header.tsx b/docs/src/components/layouts/shared-header.tsx
index 387c1e82..96b2f84c 100644
--- a/docs/src/components/layouts/shared-header.tsx
+++ b/docs/src/components/layouts/shared-header.tsx
@@ -260,7 +260,7 @@ export function SharedHeader({
 
   return (
     <>
-      <header className="sticky top-0 w-full h-14 lg:h-26 z-49 flex flex-col space-around bg-fd-background">
+      <header className="sticky top-0 w-full h-14 lg:h-28 z-49 flex flex-col space-around bg-fd-background">
 
         {/* First row */}
         <div className="flex items-center justify-between h-14 border-b border-fd-border px-4">

Analysis

Invalid Tailwind CSS class lg:h-26 in SharedHeader component

What fails: SharedHeader component in docs/src/components/layouts/shared-header.tsx uses invalid Tailwind class lg:h-26 on line 263, which doesn't exist in the standard spacing scale

How to reproduce:

# Check Tailwind's standard spacing scale
node -e "console.log([0, 0.5, 1, 1.5, 2, 2.5, 3, 3.5, 4, 5, 6, 7, 8, 9, 10, 11, 12, 14, 16, 20, 24, 28, 32, 36, 40, 44, 48, 52, 56, 60, 64, 72, 80, 96])"

Result: Class h-26 is not in the standard spacing scale (jumps from h-24 to h-28), causing the height property to be ignored

Expected: Use valid Tailwind class lg:h-28 (112px/7rem) for the two-row header layout per Tailwind height utilities

Copy link
@vercel vercel bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Additional Comments:

docs/src/components/layouts/shared-header.tsx (lines 30-42):
The header contains duplicate function definitions that use outdated URL patterns, causing incorrect section detection for SDK and Components navigation.

View Details
📝 Patch Details
diff --git a/docs/src/components/layouts/shared-header.tsx b/docs/src/components/layouts/shared-header.tsx
index 387c1e82..ad815761 100644
--- a/docs/src/components/layouts/shared-header.tsx
+++ b/docs/src/components/layouts/shared-header.tsx
@@ -10,6 +10,7 @@ import type { ReactNode } from 'react';
 import { useEffect, useState } from 'react';
 import { cn } from '../../lib/cn';
 import { useSidebar } from './sidebar-context';
+import { isInApiSection, isInComponentsSection, isInSdkSection } from './shared/section-utils';
 
 type SharedHeaderProps = {
   /** Navigation links to display */
@@ -24,26 +25,7 @@ type SharedHeaderProps = {
   sidebarContent?: ReactNode,
 }
 
-/**
- * Helper functions to detect which section we're in
- */
-export function isInSdkSection(pathname: string): boolean {
-  // Match the actual SDK section: /docs/platform/sdk or /docs/platform/sdk/...
-  // This excludes docs pages that might mention SDK in other contexts
-  const match = pathname.match(/^\/docs\/[^\/]+\/sdk($|\/)/);
-  return Boolean(match);
-}
 
-export function isInComponentsSection(pathname: string): boolean {
-  // Match the actual Components section: /docs/platform/components or /docs/platform/components/...
-  // This excludes docs pages like /docs/platform/getting-started/components
-  const match = pathname.match(/^\/docs\/[^\/]+\/components($|\/)/);
-  return Boolean(match);
-}
-
-export function isInApiSection(pathname: string): boolean {
-  return pathname.startsWith('/api');
-}
 
 /**
  * Determines if a navigation link should be highlighted as active

Analysis

Duplicate section detection functions cause incorrect navigation active states

What fails: SharedHeader navigation shows "Guides" as active when on /docs/sdk and /docs/components pages instead of highlighting the correct SDK/Components tabs

How to reproduce:

  1. Navigate to /docs/sdk or any SDK page like /docs/sdk/hooks
  2. Observe navigation header - "Guides" tab incorrectly shows as active instead of "SDK"
  3. Navigate to /docs/components or any components page like /docs/components/sign-in
  4. Observe navigation header - "Guides" tab incorrectly shows as active instead of "Components"

Root cause: shared-header.tsx defines duplicate isInSdkSection() and isInComponentsSection() functions with outdated regex patterns /^\/docs\/[^\/]+\/sdk($|\/)/ that expect platform-prefixed URLs like /docs/platform/sdk, but the actual documentation structure uses /docs/sdk and /docs/components directly.

Result: Functions return false for actual URLs, causing fallback logic to incorrectly activate "Guides" tab for all /docs/* paths

Expected: SDK and Components tabs should be active when browsing their respective sections, using the correct patterns from section-utils.ts that match /^\/docs\/(?:[a-z-]+\/)?sdk(?:\/.*)?$/

Copy link
@vercel vercel bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Additional Comments:

docs/src/components/layouts/shared-header.tsx (line 263):
Invalid CSS z-index value z-49 used in header component. CSS z-index classes are typically numbered in increments of 10 (z-10, z-20, z-30, z-40, z-50).

View Details
📝 Patch Details
diff --git a/docs/src/components/layouts/shared-header.tsx b/docs/src/components/layouts/shared-header.tsx
index 387c1e82..04cbefb0 100644
--- a/docs/src/components/layouts/shared-header.tsx
+++ b/docs/src/components/layouts/shared-header.tsx
@@ -260,7 +260,7 @@ export function SharedHeader({
 
   return (
     <>
-      <header className="sticky top-0 w-full h-14 lg:h-26 z-49 flex flex-col space-around bg-fd-background">
+      <header className="sticky top-0 w-full h-14 lg:h-26 z-50 flex flex-col space-around bg-fd-background">
 
         {/* First row */}
         <div className="flex items-center justify-between h-14 border-b border-fd-border px-4">

Analysis

Invalid Tailwind CSS z-index class z-49 in header component

What fails: SharedHeader component in docs/src/components/layouts/shared-header.tsx line 263 uses z-49 which is not a standard Tailwind CSS utility class

How to reproduce:

cd docs && grep -n "z-49" src/components/layouts/shared-header.tsx

Result: Shows z-49 class on line 263. Standard Tailwind CSS z-index utilities are: z-0, z-10, z-20, z-30, z-40, z-50, z-auto per official documentation

Expected: Should use z-50 (next standard value) or z-[49] (arbitrary value syntax) for proper z-index styling

Copy link
@vercel vercel bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Additional Comments:

docs/src/components/layouts/shared-header.tsx (line 263):
Invalid CSS class lg:h-26 used in header - Tailwind CSS doesn't have an h-26 utility class.

View Details
📝 Patch Details
diff --git a/docs/src/components/layouts/shared-header.tsx b/docs/src/components/layouts/shared-header.tsx
index 387c1e82..96b2f84c 100644
--- a/docs/src/components/layouts/shared-header.tsx
+++ b/docs/src/components/layouts/shared-header.tsx
@@ -260,7 +260,7 @@ export function SharedHeader({
 
   return (
     <>
-      <header className="sticky top-0 w-full h-14 lg:h-26 z-49 flex flex-col space-around bg-fd-background">
+      <header className="sticky top-0 w-full h-14 lg:h-28 z-49 flex flex-col space-around bg-fd-background">
 
         {/* First row */}
         <div className="flex items-center justify-between h-14 border-b border-fd-border px-4">

Analysis

Invalid Tailwind CSS class lg:h-26 in SharedHeader component

What fails: SharedHeader component in docs/src/components/layouts/shared-header.tsx line 263 uses lg:h-26 which is not a valid Tailwind CSS utility class

How to reproduce:

# The class is present in the header component:
grep -n "lg:h-26" docs/src/components/layouts/shared-header.tsx

Result: Class lg:h-26 found at line 263 but Tailwind CSS default spacing scale jumps from h-24 (6rem) to h-28 (7rem), with no h-26 (6.5rem) utility available

Expected: Should use a valid Tailwind height class like lg:h-24 or lg:h-28, or implement a custom height utility if 6.5rem is specifically needed per Tailwind CSS height documentation

Copy link
@vercel vercel bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Additional Comments:

docs/src/components/layouts/docs/shared.tsx (line 7):
Import references deleted file causing compilation error - the Option type is imported from root-toggle.tsx which was deleted.

View Details
📝 Patch Details
diff --git a/docs/src/components/layouts/docs/shared.tsx b/docs/src/components/layouts/docs/shared.tsx
index 38ebd14b..ece54840 100644
--- a/docs/src/components/layouts/docs/shared.tsx
+++ b/docs/src/components/layouts/docs/shared.tsx
@@ -4,7 +4,7 @@ import {
   type GetSidebarTabsOptions,
 } from 'fumadocs-ui/utils/get-sidebar-tabs';
 import type { ReactNode } from 'react';
-import type { Option } from '../../layout/root-toggle';
+
 import {
   type SidebarComponents,
   SidebarFolder,
@@ -26,7 +26,7 @@ export type SidebarOptions = {
   /**
    * Root Toggle options
    */
-  tabs?: Option[] | GetSidebarTabsOptions | false,
+  tabs?: GetSidebarTabsOptions | false,
 
   banner?: ReactNode,
   footer?: ReactNode,
@@ -79,9 +79,7 @@ export function getSidebarTabsFromOptions(
   options: SidebarOptions['tabs'],
   tree: PageTree.Root,
 ) {
-  if (Array.isArray(options)) {
-    return options;
-  } else if (typeof options === 'object') {
+  if (typeof options === 'object') {
     return getSidebarTabs(tree, options);
   } else if (options !== false) {
     return getSidebarTabs(tree);

Analysis

Import references deleted file causing TypeScript compilation error

What fails: shared.tsx imports Option type from ../../layout/root-toggle but the file was deleted, causing TypeScript compilation error TS2307

How to reproduce:

cd docs && pnpm exec tsc --noEmit --skipLibCheck

Result:

src/components/layouts/docs/shared.tsx(7,29): error TS2307: Cannot find module '../../layout/root-toggle' or its corresponding type declarations.

Expected: Should compile without errors since tabs functionality was removed and all current usages set tabs: false

Fix: Removed dead Option type import and cleaned up related code since all current tab usages are false throughout the codebase per fumadocs sidebar tabs documentation

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants
0