# Documentation > Complete documentation for Large Language Models --- ## Document: Writing A guide to writing documentation in Zudoku using Markdown and MDX. URL: /docs/writing # Writing Get started with creating rich documentation in Zudoku using Markdown and MDX. This guide covers the essentials to help you begin documenting your project. ## Quick Start 1. **Create a markdown file** in your `pages` directory 2. **Add frontmatter** with title and metadata 3. **Configure navigation** to make it discoverable 4. **Write content** using Markdown or MDX ### Basic Document Structure ```md --- title: My Document sidebar_icon: file-text --- Your content goes here using standard Markdown syntax. ``` ## Adding to Navigation To make your documentation discoverable, add it to the navigation configuration. Documents are referenced by their file path: ```ts title="zudoku.config.ts" const config = { navigation: [ { type: "doc", file: "my-document", label: "My Document", }, ], }; ``` Learn more about configuring navigation at [Navigation → Documents](/docs/configuration/navigation#type-doc). ## File Organization Organize your documentation files in logical directories: ``` pages/ ├── getting-started/ │ ├── installation.md │ └── quick-start.md ├── guides/ │ ├── authentication.md │ └── deployment.md └── api/ └── reference.md ``` ## What's Next? Explore the detailed guides to enhance your documentation: - **[Markdown Overview](/docs/markdown/overview)** - Complete markdown syntax reference - **[Frontmatter](/docs/markdown/frontmatter)** - Document metadata and configuration - **[MDX](/docs/markdown/mdx)** - Interactive components in markdown - **[Admonitions](/docs/markdown/admonitions)** - Callouts and alerts - **[Code Blocks](/docs/markdown/code-blocks)** - Syntax highlighting and features --- ## Document: Quickstart Get started with Zudoku by creating a new Zudoku app using the `create-zudoku` tool. URL: /docs/quickstart # Quickstart Ready to build beautiful API documentation and developer portals in minutes? Zudoku's CLI tool will have you up and running with a modern, customizable site that your developers will love. ## Prerequisites - **Node.js** `22.7.0+` (or `20.19+`) - [Download here](https://nodejs.org/) - A terminal or command prompt - Your favorite code editor ## Getting Started 1. **Create your new Zudoku project:** ```bash npm create zudoku@latest ``` The CLI will walk you through setting up your project with interactive prompts. Choose from templates like API documentation, developer portals, or start from scratch. 1. **Navigate to your project:** ```bash cd your-project-name ``` 1. **Launch the development server:** ```bash npm run dev ``` 🎉 **That's it!** Your Zudoku site is now running at `http://localhost:3000`. You'll see hot reloading as you make changes, so you can iterate quickly. 1. **What's next?** - Customize your [theme and colors](./customization/colors-theme.mdx) - Add your [OpenAPI specifications](./configuration/api-reference.md) - Set up [authentication](./configuration/authentication.md) - [Deploy your site](./deployment.md) when you're ready to go live ## 🚀 Pro Tips - Use `npm run build` to create a production build - Check out our [examples](https://github.com/zuplo/zudoku/tree/main/examples) for inspiration - Join our [Discord community](https://discord.zudoku.dev) for support and tips --- ## Document: Zudoku Plugins URL: /docs/plugins # Zudoku Plugins Zudoku can be extended using plugins. --- ## Document: Deploying Zudoku URL: /docs/deployment # Deploying Zudoku Once you are happy with your Zudoku powered documentation and ready to push your docs to production you will need to deploy it to your own server, or a hosted service of your choice. ## Build locally Zudoku can produce a build of static HTML, JavaScript and CSS files that you can deploy directly to your own server. To prepare the files you need to upload to your server, you will need to use the build command. ``` npm run build ``` Once complete, you will see a new `dist` folder in the root of your project that includes the files you need to upload. --- ## Document: Custom Plugins URL: /docs/custom-plugins # Custom Plugins Zudoku is highly extensible. You can create custom plugins to add new functionality to your documentation site. This guide will show you how to create and use plugins in your Zudoku configuration. ## Plugin Types All plugins in Zudoku must implement the `ZudokuPlugin` type, which is a union of these plugin interfaces: - **CommonPlugin**: Basic plugin with initialization, head elements, and MDX component customization - **ProfileMenuPlugin**: Add custom items to the profile menu - **NavigationPlugin**: Define custom routes and sidebar items - **ApiIdentityPlugin**: Provide API identities for testing - **SearchProviderPlugin**: Implement custom search functionality - **EventConsumerPlugin**: Handle custom events You can find all available plugin interfaces in the [Zudoku source code](https://github.com/zuplo/zudoku/blob/main/packages/zudoku/src/lib/core/plugins.ts). ## Defining Plugins You can define plugins in your Zudoku configuration using objects with explicit type declarations: ### Common Plugin Example ```tsx import { ZudokuPlugin } from "zudoku"; const commonPlugin: ZudokuPlugin = { initialize: async (context) => { // Initialization logic }, getHead: () => , getMdxComponents: () => ({ // Custom MDX components }), }; const config: ZudokuConfig = { // ... other config plugins: [commonPlugin], }; ``` ### API Identity Plugin Example ```tsx import { ZudokuPlugin, ApiIdentity } from "zudoku"; const apiIdentityPlugin: ZudokuPlugin = { getIdentities: async (context) => { return [ { label: "Test User", id: "test-user", authorizeRequest: (request: Request) => { request.headers.set("Authorization", "Bearer test-token"); return request; }, }, ] as ApiIdentity[]; }, }; // In your zudoku.config.tsx const config: ZudokuConfig = { // ... other config plugins: [apiIdentityPlugin], }; ``` ## Example Implementations Here are some common plugin implementations: ### Google Tag Manager Below is a sample of adding the necessary scripts for GTM, but this could apply to any tag manager or tracking script. ```tsx import { ZudokuPlugin } from "zudoku"; const commonPlugin: ZudokuPlugin = { getHead: () => { return ( ); }, }; ``` #### Tracking `page_view` Events Zudoku is a single page application so typical `page_view` events are not captured by most analytics scripts or tag managers. Instead, you must listen to the `location` [event](./extending/events.md) with a plugin and log navigation changes in code. ```tsx import { ZudokuPlugin, ZudokuEvents } from "zudoku"; const navigationLoggerPlugin: ZudokuPlugin = { events: { location: ({ from, to }) => { if (!from) return; window.dataLayer.push({ event: "page_view", page_path: to.pathname, page_title: document.title, page_location: window.location.href, }); }, }, }; ``` If you are using TypeScript, you will also need to add the following type declaration to the file this plugin is declared ```ts declare global { interface Window { dataLayer: Record[]; } } ``` ### Navigation Plugin ```tsx import { ZudokuPlugin, RouteObject } from "zudoku"; const navigationPlugin: ZudokuPlugin = { getRoutes: (): RouteObject[] => { return [ { path: "/custom", element: , }, ]; }, getSidebar: async (path: string) => { // Return custom sidebar items return { items: [{ id: "custom", label: "Custom Page" }], }; }, }; ``` ### Dropdown Navigation Plugin ```tsx import { ZudokuPlugin, RouteObject } from "zudoku"; import { UserIcon } from "zudoku/icons"; const AccountPageNavItemPlugin: ZudokuPlugin = { getRoutes: (): RouteObject[] => { return [ { path: "/account", element: , // This is a custom page }, ]; }, getProfileMenuItems: () => { return [ { label: "Account", path: "/account", category: "middle", icon: UserIcon, }, ]; }, }; ``` ### Event Consumer Plugin ```tsx import { ZudokuPlugin } from "zudoku"; const eventConsumerPlugin: ZudokuPlugin = { events: { location: ({ from, to }) => { if (!from) { console.log(`Initial navigation to: ${to.pathname}`); } else { console.log(`Navigation from ${from.pathname} to ${to.pathname}`); } }, }, }; ``` --- ## Document: Markdown Comprehensive guide to using Markdown and MDX in Zudoku, including formatting, frontmatter, syntax highlighting, tables, lists, task lists, collapsible sections, and advanced documentation features. URL: /docs/markdown/overview # Markdown Zudoku supports [GitHub Flavored Markdown](https://docs.github.com/en/get-started/writing-on-github/getting-started-with-writing-and-formatting-on-github/basic-writing-and-formatting-syntax) (GFM) with additional features for creating rich documentation. ## Basic Formatting ### Headers Use `#` to create headers. The number of `#` symbols determines the header level: ```md # H1 Header ## H2 Header ### H3 Header #### H4 Header ##### H5 Header ###### H6 Header ``` ### Text Formatting ```mdx **Bold text** _Italic text_ ~~Strikethrough text~~ `Inline code` ``` **Bold text** _Italic text_ ~~Strikethrough text~~ `Inline code` ### Lists **Unordered lists:** ```md - Item 1 - Item 2 - Nested item - Another nested item ``` **Ordered lists:** ```md 1. First item 2. Second item 1. Nested item 2. Another nested item ```
See list examples **Unordered list:** - Item 1 - Item 2 - Nested item - Another nested item **Ordered list:** 1. First item 2. Second item 1. Nested item 2. Another nested item
### Links and Images ```md [Link text](https://example.com) ![Image alt text](image.jpg) ```
See link and image examples [Link text](https://example.com) ![Image alt text](https://images.unsplash.com/photo-1588083066783-8828e623bad7?q=75&w=400&auto=format&fit=crop)
### Tables ```md | Header 1 | Header 2 | Header 3 | | -------- | -------- | -------- | | Cell 1 | Cell 2 | Cell 3 | | Cell 4 | Cell 5 | Cell 6 | ```
See table example | Header 1 | Header 2 | Header 3 | | -------- | -------- | -------- | | Cell 1 | Cell 2 | Cell 3 | | Cell 4 | Cell 5 | Cell 6 |
### Blockquotes ```md > This is a blockquote > > It can span multiple lines ```
See blockquote example > This is a blockquote > > It can span multiple lines
## Frontmatter Frontmatter allows you to configure page metadata using YAML at the beginning of your markdown files: ```md --- title: My Page Title description: Page description for SEO navigation_icon: book category: Getting Started --- Your markdown content starts here... ``` Common frontmatter properties include `title`, `description`, `sidebar_icon`, and `category`. For a complete list of supported properties, see the [Frontmatter documentation](./frontmatter). ## MDX Support Zudoku supports [MDX](./mdx), allowing you to use JSX components within your markdown: ```mdx title=my-page.mdx import MyCustomComponent from "./MyCustomComponent"; # Regular Markdown This is regular markdown content. You can mix markdown and JSX seamlessly. ``` MDX enables you to create interactive documentation with custom React components. Learn more in the [MDX documentation](./mdx). ## Syntax Highlighting Zudoku uses [Shiki](https://shiki.style/) for syntax highlighting in code blocks: ````md ```javascript function greet(name) { console.log(`Hello, ${name}!`); } ``` ```` **Advanced features:** - Line highlighting: `{1,3-5}` - Word highlighting: `/keyword/` - Line numbers: `showLineNumbers` - Titles: `title="filename.js"` ```` ```tsx {4-5} /useState/ title="Counter.tsx" showLineNumbers import { useState } from "react"; function Counter() { const [count, setCount] = useState(0); return ; } ``` ````
See advanced features example ```tsx {4-5} /useState/ title="Counter.tsx" showLineNumbers import { useState } from "react"; function Counter() { const [count, setCount] = useState(0); return ; } ```
For complete syntax highlighting documentation, see [Code Blocks](./code-blocks). ## Additional Features Zudoku also supports: - [Admonitions](./admonitions) - Callout boxes for notes, warnings, and tips - Task lists with checkboxes - Automatic link detection ### Task Lists ```md - [x] Completed task - [ ] Incomplete task - [ ] Another task ```
See task list example - [x] Completed task - [ ] Incomplete task - [ ] Another task
### Collapsible Sections You can create collapsible content using HTML `
` and `` tags: ```html
Click to expand This content is hidden by default and can be expanded by clicking the summary. You can include any markdown content here: - Lists - **Bold text** - Code blocks - Images
```
Click to expand This content is hidden by default and can be expanded by clicking the summary. You can include any markdown content here: - Lists - **Bold text** - Code blocks - Images
--- ## Document: MDX Learn how to use MDX in Zudoku to create rich documentation pages with markdown and custom React components. URL: /docs/markdown/mdx # MDX Zudoku supports MDX files for creating rich content pages. MDX is a markdown format that allows you to include JSX components in your markdown files. ## Getting Started To use MDX in your documentation, simply create files with the `.mdx` extension instead of `.md`. These files work exactly like regular markdown files but with all MDX features unlocked - you can write normal markdown content and add JSX components whenever needed. ``` docs/ ├── my-page.md # Regular markdown ├── my-mdx-page.mdx # MDX with JSX support ``` ## Custom Components Zudoku supports the use of custom components in your MDX files. This allows you to create reusable components that can be used across multiple pages. You can create a custom component in your project and reference it in the [Zudoku Configuration](./overview.md) file. For example, create the `` component in a file called `MyCustomComponent.tsx` in the `src` directory at the root of your project. ```tsx export default function MyCustomComponent() { return
My Custom Component
; } ``` In [Zudoku Configuration](./overview.md) you will need to import the component and add it to the `customComponents` option in the configuration. ```ts title=zudoku.config.ts import MyCustomComponent from "./src/MyCustomComponent"; const config: ZudokuConfig = { // ... mdx: { components: { MyCustomComponent, }, }, // ... }; export default config; ``` --- ## Document: Frontmatter Learn how to use YAML frontmatter in Zudoku markdown files to customize page titles, descriptions, navigation, and other document properties. URL: /docs/markdown/frontmatter # Frontmatter Frontmatter is metadata written in [YAML](https://yaml.org/) format at the beginning of markdown files, enclosed between triple dashes (`---`). It allows you to configure various aspects of your pages without affecting the visible content. In Zudoku, frontmatter enables you to customize page titles, descriptions, navigation settings, and other document properties. Here are all the supported properties: ## Properties ### `title` Sets the page title that appears in the browser tab and as the document title. ```md --- title: My Page Title --- ``` ### `description` Provides a description for the page, which can be used for SEO and content summaries. ```md --- description: This page explains how to use Zudoku's markdown features. --- ``` ### `category` Assigns the page to a specific category for organizational purposes. This will be shown above the main heading of the document. ```md --- category: Getting Started --- ``` ### `navigation_label` _Deprecated (`sidebar_label`)_ Sets a custom label for the page in the sidebar navigation, allowing you to use a shorter or different title than the main page title. ```md --- title: My Very Long Documentation Page Title navigation_label: Short Title --- ``` ### `navigation_icon` _Deprecated (`sidebar_icon`)_ Specifies a [Lucide icon](https://lucide.dev/icons) to display next to the page in the sidebar navigation. ```md --- navigation_icon: compass --- ``` ### `toc` Controls whether the table of contents is displayed for the page. Set to `false` to hide the table of contents. ```md --- toc: false --- ``` ### `disable_pager` Controls whether the previous/next page navigation is displayed at the bottom of the page. Set to `true` to disable it. ```md --- disable_pager: true --- ``` ### `lastModifiedTime` The last modified timestamp for the page. This property is automatically set by Zudoku during the build process based on the Git commit history. You generally should not set this manually. If you need to override the automatically detected date, you can set it explicitly: ```md --- lastModifiedTime: 2025-11-20T10:30:00.000Z --- ``` ::if{mode=opensource} :::info For accurate last modified dates in deployment environments, ensure full Git history is available during builds. See the [Vercel deployment guide](/docs/deploy/vercel#accurate-last-modified-dates) for configuration details. ::: :: ## Complete Example Here's an example showing multiple frontmatter properties used together: ```md title=documentation.md --- title: Advanced Configuration Guide description: Learn how to configure advanced features in Zudoku category: Configuration navigation_label: Advanced Config navigation_icon: settings toc: true disable_pager: false --- This page content follows the frontmatter... ``` --- ## Document: Code Blocks Learn how to use code blocks, syntax highlighting, and advanced features like line highlighting and ANSI output in Zudoku Markdown with Shiki. URL: /docs/markdown/code-blocks # Code Blocks Zudoku supports code blocks in Markdown using the [Shiki](https://shiki.style/) syntax highlighting library. See examples for all supported languages in the [Syntax Highlighting](../components/syntax-highlight#supported-languages) section. ## Syntax Highlighting Code blocks are text blocks wrapped around by strings of 3 backticks. You may check out this reference for the specifications of MDX. ````md ```js console.log("Every repo must come with a mascot."); ``` ```` The code block above will render as: ```js console.log("Every repo must come with a mascot."); ``` :::note You can also use the [`SyntaxHighlight` component](../components/syntax-highlight) to render code blocks in TypeScript directly. ::: ## Inline Code You can highlight inline code using either: Regular backticks without language specification: ```md `console.log("Hello World")` ``` Result: `console.log("Hello World")` or with the [tailing curly colon syntax](https://shiki.matsu.io/packages/rehype#inline-code): ```md `console.log("Hello World"){:js}` ``` Result: `console.log("Hello World"){:js}` For more details, see the [Shiki Rehype documentation](https://shiki.style/packages/rehype#inline-code). You can add a title to code blocks by adding a title attribute after the backticks: ````md ```tsx title="hello.tsx" console.log("Hello, World!"); ``` ```` Result: ```tsx title="hello.tsx" console.log("Hello, World!"); ``` For a complete list of supported languages and their aliases, see the [Shiki Languages documentation](https://shiki.style/languages#bundled-languages). ## Advanced Syntax Highlighting There are multiple ways to enhance syntax highlighting: - [Line highlighting](https://shiki.style/packages/transformers#transformermetahighlight) - [Word highlighting](https://shiki.style/packages/transformers#transformermetawordhighlight) - Line numbers: `showLineNumbers` - Title: `title` Example: ```` ```tsx {4-6} /react/ title="Example.tsx" showLineNumbers import { useEffect } from "react"; function Example() { useEffect(() => { console.log("Mounted"); }, []); return
Hello
; } ``` ```` Result: ```tsx {4-6} /react/ title="Example.tsx" showLineNumbers import { useEffect } from "react"; function Example() { useEffect(() => { console.log("Mounted"); }, []); return
Hello
; } ``` ## Configuration You can configure syntax highlighting in your `zudoku.config.tsx`: :::info Changes to the syntax `highlighting` configuration require a restart of Zudoku to take effect. ::: ```tsx {5-12} title=zudoku.config.ts import { defaultLanguages, type ZudokuConfig } from "zudoku"; const config: ZudokuConfig = { // ... syntaxHighlighting: { themes: { light: "vitesse-light", dark: "vitesse-dark", }, // Extend default languages if needed languages: [...defaultLanguages, "powershell"], }, }; ``` For a complete list of available themes and languages, see the list of [Shiki themes](https://shiki.style/themes) and [Shiki languages](https://shiki.style/languages). ## Default Supported Languages By default, Zudoku supports the following languages for syntax highlighting: - HTML/CSS/XML - `html`, `css`, `xml` - JavaScript/TypeScript - `javascript`, `js`, `typescript`, `ts` - React - `jsx`, `tsx`, `react` - Markdown - `markdown`, `md`, `mdx` - Data formats - `json`, `jsonc`, `yaml`, `toml` - Shell - `bash`, `sh`, `shell`, `zsh`, `powershell` - Terminal - `terminal`, `term` - Python - `python`, `py` - Rust - `rust`, `rs` - C/C++ - `c`, `cpp` - Zig - `zig` - PHP - `php` - Ruby - `ruby`, `rb` - Swift - `swift` - Kotlin - `kotlin`, `kt` - Scala - `scala` - C# - `csharp`, `cs`, `vb` - Go - `go` - Objective-C - `objectivec`, `objc` - Dart - `dart` - Elixir - `elixir` - OCaml - `ocaml` - Common Lisp - `common-lisp` - GraphQL - `graphql`, `gql` ## ANSI Code Blocks You can use the `ansi` language to highlight terminal outputs with ANSI escape sequences. This is useful for displaying colored terminal output, styled text, and other terminal-specific formatting. ```ansi title="Terminal Output" colored foreground bold text dimmed text underlined text reversed text strikethrough text underlined + strikethrough text ``` Usage: ````md ```ansi title="Terminal Output" colored foreground bold text dimmed text underlined text reversed text strikethrough text underlined + strikethrough text ``` ```` For more details on ANSI highlighting, see the [Shiki documentation](https://shiki.style/languages#ansi). --- ## Document: Admonitions Learn how to use admonitions (callouts) in Markdown, including syntax, types, titles, and formatting tips for compatibility with Prettier. URL: /docs/markdown/admonitions # Admonitions In addition to the basic Markdown syntax, we have a special admonitions syntax by wrapping text with a set of 3 colons, followed by a label denoting its type. :::note Admonitions are also commonly referred to as "Callouts". For programmatic usage, see the [Callout component](/docs/components/callout). ::: Example: ```markdown :::note Some **content** with _Markdown_ `syntax`. Check [this `api`](#). ::: :::tip Some **content** with _Markdown_ `syntax`. Check [this `api`](#). ::: :::info Some **content** with _Markdown_ `syntax`. Check [this `api`](#). ::: :::warning Some **content** with _Markdown_ `syntax`. Check [this `api`](#). ::: :::danger Some **content** with _Markdown_ `syntax`. Check [this `api`](#). ::: ``` :::note Some **content** with _Markdown_ `syntax`. Check [this `api`](#). ::: :::tip Some **content** with _Markdown_ `syntax`. Check [this `api`](#). ::: :::info Some **content** with _Markdown_ `syntax`. Check [this `api`](#). ::: :::warning Some **content** with _Markdown_ `syntax`. Check [this `api`](#). ::: :::danger Some **content** with _Markdown_ `syntax`. Check [this `api`](#). ::: ## With title You can also add a title to the admonition by adding it after the type: ```markdown :::warning{title="Warning of the day"} The path of the righteous man is beset on all sides by the iniquities of the selfish and the tyranny of evil men. ::: ``` :::warning{title="Warning of the day"} The path of the righteous man is beset on all sides by the iniquities of the selfish and the tyranny of evil men. ::: ## Usage with Prettier If you use Prettier to format your Markdown files, Prettier might auto-format your code to invalid admonition syntax. To avoid this problem, add empty lines around the starting and ending directives. This is also why the examples we show here all have empty lines around the content. ```markdown :::note Hello world ::: :::note Hello world ::: ::: note Hello world::: ``` --- ## Document: Multiple APIs URL: /docs/guides/using-multiple-apis # Multiple APIs Zudoku supports creating documentation and API references for multiple APIs and can work with as many OpenAPI documents as you need. In order to do this you will need to modify the [Zudoku Configuration](../configuration/overview.md) file to include additional APIs. ## Configuration Using multiple APIs is a configuration setting that you can add in the [Zudoku Configuration](../configuration/overview.md) file. ### Step 1: Add your APIs First, create a new array in your configuration file that lists each API you want to include: ```typescript const apis = [ { type: "file", input: "apis/my-first-api.json", path: "/my-first-api", }, { type: "file", input: "apis/my-second-api.json", path: "/my-second-api", }, ] as const; ``` ### Step 2: Add navigation Create a navigation array for your sidebar: ```typescript const navigation = [ { type: "link", label: "My First API", to: "/my-first-api", }, { type: "link", label: "My Second API", to: "/my-second-api", }, ] as const; ``` ### Step 3: Update your config Modify your [Zudoku Configuration](../configuration/overview.md) file to include these arrays: ```typescript import type { ZudokuConfig } from "zudoku"; const config: ZudokuConfig = { navigation: [ { type: "category", label: "Overview", items: navigation, }, ], redirects: [{ from: "/", to: "/overview" }], apis, docs: { files: "/pages/**/*.{md,mdx}", }, }; export default config; ``` Make sure that: 1. The `path` in each API config matches the `href` in the navigation 2. Your OpenAPI files are placed in the correct location as specified in the `input` field 3. The `label` in navigation matches what you want to display in the sidebar You don't necessarily need to add the APIs to your sidebar, you can also put them into the top navigation or link to them from your docs. --- ## Document: Transforming Operation Examples URL: /docs/guides/transforming-examples # Transforming Operation Examples Zudoku allows you to transform operation examples in both request and response sections of your API documentation. This feature is particularly useful when you need to: - Modify example data before displaying it - Add dynamic values to examples - Format examples in a specific way - Filter or transform example content based on certain conditions ## Configuration To use this feature, you need to configure the `transformExamples` function in your `zudoku.config.tsx` file. Here's how to do it: ```tsx import type { ZudokuConfig } from "zudoku"; const config: ZudokuConfig = { // ... other config options ... defaults: { apis: { transformExamples: (options) => { // Transform the content here return options.content; }, }, }, }; ``` ## The Transform Function The `transformExamples` function receives an options object with the following properties: 1. `content`: An array of Content objects containing the example data 1. `operation`: The operation being displayed 1. `type`: Either "request" or "response" indicating which type of example is being transformed 1. `auth`: The current authentication state 1. `context`: ZudokuContext The function should return an array of Content objects with the transformed examples. ## Example Usage Here's a practical example showing how to transform examples: ```tsx const config: ZudokuConfig = { defaults: { apis: { transformExamples: ({ content, type }) => { // Example: Add a timestamp to all examples const timestamp = new Date().toISOString(); return content.map((contentItem) => ({ ...contentItem, example: { ...contentItem.example, timestamp, // You can modify other example properties here }, })); }, }, }, }; ``` ## Use Cases ### Adding Dynamic Values ```tsx transformExamples: ({ content, auth }) => { const apiKey = auth.accessToken; return content.map((contentItem) => ({ ...contentItem, example: { ...contentItem.example, headers: { ...contentItem.example.headers, Authorization: `Bearer ${apiKey}`, }, }, })); }; ``` ### Formatting Examples ```tsx transformExamples: ({ content }) => { return content.map((contentItem) => ({ ...contentItem, example: { ...contentItem.example, // Format dates in a specific way createdAt: new Date(contentItem.example.createdAt).toLocaleDateString(), // Format numbers with specific precision amount: Number(contentItem.example.amount).toFixed(2), }, })); }; ``` ### Conditional Transformation ```tsx transformExamples: ({ content, auth, type }) => { const isAuthenticated = auth.isAuthenticated; return content.map((contentItem) => ({ ...contentItem, example: isAuthenticated ? contentItem.example // Show full example for authenticated users : { ...contentItem.example, sensitiveData: undefined }, // Hide sensitive data for unauthenticated users })); }; ``` ### Using JWT Claims ```tsx transformExamples: async ({ content, auth, context }) => { const token = await context.authentication.getAccessToken(); // Decode the JWT (this is a simple example - in production you might want to use a proper JWT library) const [, payload] = token.split("."); const decodedPayload = JSON.parse(atob(payload)); return content.map((contentItem) => ({ ...contentItem, example: { ...contentItem.example, // Add user-specific data from the JWT userId: decodedPayload.sub, organizationId: decodedPayload.org_id, // You can add any other claims from the JWT role: decodedPayload.role, }, })); }; ``` ## Best Practices 1. Always return an array of Content objects, even if you're not transforming the content 2. Preserve the original content structure while making your modifications 3. Handle errors gracefully to prevent breaking the documentation 4. Consider performance implications when transforming large examples 5. Use the provided options object to access relevant information for your transformations --- ## Document: Static Files Learn how to serve and reference static files like images and PDFs in your Zudoku documentation using the public directory. URL: /docs/guides/static-files # Static Files Zudoku makes it easy to serve static files like images, PDFs, or any other assets alongside your documentation. Any files placed in the `public` directory will be served at the root path `/` during dev, and copied to the root of the dist directory as-is. Note that you should always reference `public` assets using root absolute path - for example, `public/icon.png` should be referenced in source code as `/icon.png`. ## Usage 1. Create a `public` directory in your project root if it doesn't exist already 2. Place any static files in this directory 3. Reference these files in your documentation using the root path `/` ## Example If you have the following structure: ``` your-project/ ├── public/ │ ├── images/ │ │ └── diagram.png │ └── documents/ │ └── api-spec.pdf └── ... ``` You can reference these files using markdown like this: ```md ![API Architecture](/images/diagram.png) ``` If you want users to download a file like a PDF, you can use an anchor tag like this: ```html Download API specification ``` ## Relative paths If you want to reference a file that is in the same directory as the current file, you can also use a relative path: ```md title="page.mdx" ![API Architecture](./image.png) ``` --- ## Document: /docs/guides/processors URL: /docs/guides/processors # Schema Processors Schema processors are functions that transform your OpenAPI schemas before they are used in the documentation. They are defined in your `zudoku.build.ts` file and can be used to modify schemas in various ways. :::tip For information on how to configure processors in your project, see the [Build Configuration](../configuration/build-configuration) guide. ::: ## Built-in Processors Zudoku provides several built-in processors that you can use to transform your schemas: ### `removeExtensions` Removes OpenAPI extensions (`x-` prefixed properties) from your schema: ```ts import { removeExtensions } from "zudoku/processors/removeExtensions"; import type { ZudokuBuildConfig } from "zudoku"; const buildConfig: ZudokuBuildConfig = { processors: [ // Remove all x- prefixed properties removeExtensions(), // Remove specific extensions removeExtensions({ keys: ["x-internal", "x-deprecated"], }), // Remove extensions based on a custom filter removeExtensions({ shouldRemove: (key) => key.startsWith("x-zuplo"), }), ], }; export default buildConfig; ``` ### `removeParameters` Removes parameters from your schema: ```ts import { removeParameters } from "zudoku/processors/removeParameters"; import type { ZudokuBuildConfig } from "zudoku"; const buildConfig: ZudokuBuildConfig = { processors: [ // Remove parameters by name removeParameters({ names: ["apiKey", "secret"], }), // Remove parameters by location removeParameters({ in: ["header", "query"], }), // Remove parameters based on a custom filter removeParameters({ shouldRemove: ({ parameter }) => parameter["x-internal"], }), ], }; export default buildConfig; ``` ### `removePaths` Removes paths or operations from your schema: ```ts import { removePaths } from "zudoku/processors/removePaths"; import type { ZudokuBuildConfig } from "zudoku"; const buildConfig: ZudokuBuildConfig = { processors: [ // Remove entire paths removePaths({ paths: { "/internal": true, "/admin": ["get", "post"], }, }), // Remove paths based on a custom filter removePaths({ shouldRemove: ({ path, method, operation }) => operation["x-internal"], }), ], }; export default buildConfig; ``` :::info If you are missing a processor that you think should be built-in, please don't hesitate to [open an issue on GitHub](https://github.com/zuplo/zudoku/issues/new). ::: ## Custom Processors You can also create your own processors. Here's a simple example that adds a description to all operations: ```ts import type { ZudokuBuildConfig } from "zudoku"; async function addDescriptionProcessor({ schema }) { if (!schema.paths) return schema; // Add a description to all operations Object.values(schema.paths).forEach((path) => { Object.values(path).forEach((operation) => { if (typeof operation === "object") { operation.description = "This is a public API endpoint"; } }); }); return schema; } const buildConfig: ZudokuBuildConfig = { processors: [addDescriptionProcessor], }; export default buildConfig; ``` ### Adding Server URLs ```ts import type { ZudokuBuildConfig } from "zudoku"; async function addServerUrl({ schema }) { return { ...schema, servers: [{ url: "https://api.example.com" }], }; } const buildConfig: ZudokuBuildConfig = { processors: [addServerUrl], }; export default buildConfig; ``` ## Best Practices - **Handle missing properties**: Check for the existence of properties before accessing them - **Return the schema**: Always return the transformed schema, even if no changes were made - **Use async/await**: Processors can be async functions, which is useful for more complex transformations - **Chain processors**: Processors are executed in order, so you can chain multiple transformations --- ## Document: Navigation Migration URL: /docs/guides/navigation-migration # Navigation Migration This guide explains how to migrate existing configurations that used `topNavigation`, `sidebar` and `customPages` to the new unified `navigation` configuration introduced in vNEXT. ## Overview Navigation is now configured through a single `navigation` array. Items at the root level become top navigation tabs, while nested categories automatically form the sidebar. Custom pages are added using the `custom-page` item type. ## Before and After ```tsx title="Before" const config: ZudokuConfig = { topNavigation: [ { id: "docs", label: "Docs" }, { id: "api", label: "API" }, ], sidebar: { docs: [{ type: "doc", id: "introduction" }], }, customPages: [{ path: "/playground", render: Playground, prose: false }], apis: { type: "file", input: "./openapi.json", navigationId: "api", }, }; ``` ```tsx title="After" const config: ZudokuConfig = { navigation: [ { type: "category", label: "Docs", items: ["introduction"], }, { type: "custom-page", path: "/playground", element: , }, { type: "link", to: "/api", label: "API", }, ], apis: [ { path: "/api", type: "file", input: "./openapi.json", }, ], }; ``` ## Migration steps 1. **Create a `navigation` array** Move all items from `topNavigation` and your sidebar into a new `navigation` array. 1. **Convert custom pages** Replace entries in `customPages` with `type: "custom-page"` items inside `navigation`. 1. **Update plugin configs** Replace all uses of `navigationId` with `path` in plugin options like `apis` or `catalogs`. Navigation items of type `link` should use the `to` property to reference the path of the API or catalog. 1. **Reference plugin paths in navigation** Items produced by plugins are not added automatically. Add links or categories in your `navigation` so users can access them. --- ## Document: Mermaid Diagrams URL: /docs/guides/mermaid # Mermaid Diagrams Zudoku supports rendering [Mermaid diagrams](https://mermaid.js.org/) in two ways: | Approach | Pros | Cons | | ------------------------------- | --------------------------------------------------------------------- | ----------------------------------------------------------- | | **Build-Time** (rehype-mermaid) | • Faster page loads
• No client-side JS needed
• SEO friendly | • Requires playwright
• Slower builds
• Static only | | **Client-Side** (``) | • Fast builds
• Can be dynamic
• No build dependencies | • Requires client-side JS
• Slight render delay | ## Client-Side Rendering For the [`` component](/docs/components/mermaid), install the peer dependency: ```bash npm install mermaid ``` Then use in your MDX files (no import needed): ```tsx B; A-->C;`} /> ``` Outside of MDX, import from `zudoku/mermaid`: ```tsx import { Mermaid } from "zudoku/mermaid"; ``` See the [Mermaid component documentation](/docs/components/mermaid) for full details. ## Build-Time Rendering 1. Install dependencies: ```bash npm install rehype-mermaid npm install -D playwright npx playwright install ``` 1. Add to `zudoku.build.ts`: ```tsx title="zudoku.build.ts" import rehypeMermaid from "rehype-mermaid"; export default { rehypePlugins: (plugins) => [[rehypeMermaid, { strategy: "inline-svg" }], ...plugins], }; ``` 1. Use in markdown with code blocks: ````mdx ```mermaid graph TD; A-->B; ``` ```` --- ## Document: Managing API Keys and Identities URL: /docs/guides/managing-api-keys-and-identities # Managing API Keys and Identities ## Managing API Keys in UI Zudoku comes with a Plugin to manage API keys in the UI. This plugin is build around the concept of API consumers, where each consumer can have multiple API keys. It includes functionality for creating, viewing, updating, and deleting API keys, as well as managing consumer information. :::note The most convenient way to use this plugin is to use it in Zuplo. However the plugin can be used with any other API key management system - you can use a 3rd party API key management system or build your own and still use the Zudoku UI. ::: ## Using in Zuplo To get started with a basic setup, simply enable `apiKeys` in your config. (In the default template, this is already enabled.) ```typescript title=zudoku.config.ts { // ... apiKeys: { enabled: true, } } ``` This will make the API Key UI available at `/settings/api-keys` in your Zudoku. ### Creating API Keys By default, there is no **Create API Key** Button. To get the button working you have to implement the `createKey` callback in your config. This callback is called when the user clicks the **Create API Key** button. The callback is passed the `apiKey` object that the user has entered, the `context` object, and the `auth` object. The `apiKey` object is the object that the user has entered in the Create API Key form. In this callback you can implement the logic to create a new API key. You can use the `auth` object to access the current users auth state. Most likley you want to call your API to create a new API key. ```typescript title=zudoku.config.ts const config = { // ... apiKeys: { enabled: true, createKey: async ({ apiKey, context, auth }) => { const createApiKeyRequest = new Request("https://api.example.com/v1/developer/api-key", { method: "POST", body: JSON.stringify({ apiKey, }), }); // Sign the request using current users Authentication const signedRequest = await context.signRequest(createApiKeyRequest); const response = await fetch(signedRequest); if (!response.ok) { throw new Error("Could not create API Key"); } return true; }, }, }; ``` ## Using with any API Key Management System ```typescript interface ApiKeyService { getConsumers: (context: ZudokuContext) => Promise; rollKey?: (consumerId: string, context: ZudokuContext) => Promise; deleteKey?: (consumerId: string, keyId: string, context: ZudokuContext) => Promise; updateConsumer?: ( consumer: { id: string; label?: string }, context: ZudokuContext, ) => Promise; getUsage?: (apiKeys: string[], context: ZudokuContext) => Promise; createKey?: ({ apiKey, context, auth, }: { apiKey: { description: string; expiresOn?: string }; context: ZudokuContext; auth: UseAuthReturn; }) => Promise; } interface ApiConsumer { id: string; label: string; keys: ApiKey[]; } interface ApiKey { id: string; key: string; description?: string; createdOn: string; expiresOn?: string; } ``` ### Implementing API Key Management Here's a step-by-step guide to implementing API key management: 1. First, create a service that implements the `ApiKeyService` interface: ```typescript title=zudoku.config.ts const config = { // ... apiKeys: { enabled: true, // Retrieve all API consumers and their keys getConsumers: async (context) => { // Implement fetching consumers from your storage // Each consumer can have multiple API keys return consumers; }, // Create a new API key for a consumer createKey: async ({ apiKey, context, auth }) => { const newKey: ApiKey = { id: crypto.randomUUID(), key: `key-${crypto.randomUUID()}`, description: apiKey.description, createdOn: new Date().toISOString(), expiresOn: apiKey.expiresOn, }; // Save the new key to your storage // Associate it with the current user/consumer }, // Delete an API key deleteKey: async (consumerId, keyId, context) => { // Remove the key from the consumer's keys in your storage }, // Regenerate an API key rollKey: async (consumerId, context) => { // Update the key value for the consumer while maintaining metadata }, // Update consumer information updateConsumer: async (consumer, context) => { // Update the consumer's label or other metadata }, // Get API usage statistics (optional) getUsage: async (apiKeys, context) => { // Fetch usage data for the provided API keys }, }, }; ``` --- ## Document: Environment Variables URL: /docs/guides/environment-variables # Environment Variables Zudoku is built on top of Vite and uses [their approach](https://vite.dev/guide/env-and-mode) for managing environment variables. Zudoku exposes environment variables under the `import.meta.env` object as strings automatically. To prevent accidentally leaking environment variables to the client, only variables prefixed with `ZUDOKU_PUBLIC_` are exposed to your Zudoku-processed code. :::warning{title="Security Notice"} Environment variables prefixed with `ZUDOKU_PUBLIC_` will be exposed to the client-side code and visible in the browser. Never use this prefix for sensitive information like API keys, passwords, or other secrets. ::: ## Local Env Files When developing locally, you can create a `.env` file in the root of your project and add environment-specific variables. See the [Vite documentation](https://vite.dev/guide/env-and-mode.html#env-files) for more information on supported files. Here is an example of a `.env.local` file: ```sh ZUDOKU_PUBLIC_PAGE_TITLE=My Page Title ``` You can access this variable in your application like this: ```ts const title = import.meta.env.ZUDOKU_PUBLIC_PAGE_TITLE; ``` ## Configuration Files Environment variables can also be used in your configuration files. When referencing environment variables in your configuration files, you can use `process.env` directly. ```ts import type { ZudokuConfig } from "zudoku"; const config: ZudokuConfig = { authentication: { type: "auth0", clientId: process.env.ZUDOKU_PUBLIC_AUTH_CLIENT_ID, domain: process.env.ZUDOKU_PUBLIC_AUTH_DOMAIN, }, }; ``` ## React Components If you need to access environment variables inside a custom react component, you can access them via `import.meta.env`. Public environment variables are inlined during the build process. ```tsx import React from "react"; export const MyComponent = () => { return

{import.meta.env.ZUDOKU_PUBLIC_PAGE_TITLE}

; }; ``` ## IntelliSense for TypeScript By default, Zudoku provides type definitions for `import.meta.env` in `zudoku/client.d.ts`. While you can define more custom env variables in `.env.[mode]` files, you may want to get TypeScript IntelliSense for user-defined env variables that are prefixed with `ZUDOKU_PUBLIC_`. To achieve this, you can create a `zudoku-env.d.ts` in the src directory, then augment `ImportMetaEnv` like this: ```typescript /// interface ImportMetaEnv { readonly ZUDOKU_PUBLIC_APP_TITLE: string; // more env variables... } interface ImportMeta { readonly env: ImportMetaEnv; } ``` :::warning{title="Imports will break type augmentation"} If the `ImportMetaEnv` augmentation does not work, make sure you do not have any import statements in `vite-env.d.ts`. A helpful explanation can be found on [this StackOverflow reply](https://stackoverflow.com/a/51114250). ::: --- ## Document: Custom pages URL: /docs/guides/custom-pages # Custom pages If you want to include pages in your documentation that have greater flexibility than MDX pages, it is possible to include custom pages of your own. These pages are typically built using standard React markup and can borrow from a set of prebuilt components that Zudoku already has such as buttons, links and headers. Start by creating the page you want to add. ## Setup a custom page Each custom page is a page component of its own and lives in a `src` directory at the root of your project. Let's create the `` component as an example. From the root of your project run this command: ```command touch src/MyCustomPage.tsx ``` You can now open `/src/MyCustomPage.tsx` in the editor of your choice. It will be empty. Copy and paste this code to implement the page: ```tsx import { Button, Head, Link } from "zudoku/components"; export const MyCustomPage = () => { return (
My Custom Page

Welcome to MyCustomPage

); }; ``` ## Configuration In the [Zudoku Configuration](../configuration/overview.md) you will need to do the following: ### Change Your Config Extension In order to embed `jsx`/`tsx` components into your Zudoku config, you will need to change your file extension from `ts` to `tsx` (or `js` to `jsx` if not using TypeScript). ```fs zudoku.config.ts -> zudoku.config.tsx ``` ### Import Your Module Import the `` component that you created. ```typescript import { MyCustomPage } from "./src/MyCustomPage"; ``` ### Add a navigation entry Add a `custom-page` item to the `navigation` configuration. Each page you want to add to the site must be its own object. The `path` key can be set to whatever you like. This will appear as part of the URL in the address bar of the browser. The `element` key references the name of the custom page component that you want to load. ```typescript { // ... navigation: [ { type: "custom-page", path: "/a-custom-page", element: , }, ] // ... } ``` This configuration will allow Zudoku to load the contents of the `` component when a user clicks on a link that points to `/a-custom-page`. ## Troubleshooting ### Updating Your `tsconfig.json` Your `include` property in `tsconfig.json` should automatically be updated to reflect the new custom pages, but in case it isn't, it should look like this: ```json { ... "include": ["src", "zudoku.config.tsx", "src/MyCustomPage.tsx"] } ``` --- ## Document: Events URL: /docs/extending/events # Events Zudoku provides an events system that allows plugins to react to various application events. This system enables you to build dynamic features that respond to user interactions and application state changes. ## Available Events Currently, Zudoku supports the following events: ### location ```typescript type LocationEvent = (e: { from?: Location; to: Location }) => void; ``` Emitted when the user navigates to a different route. Provides both the previous (`from`) and current (`to`) [Location objects](https://api.reactrouter.com/v7/interfaces/react_router.Location.html) from react-router. Note that the `from` location will be undefined on the initial page load. ## Consuming Events in Plugins To consume events in your plugin, you can implement the events property in your plugin. This is useful for performing actions like sending analytics events or anything else that's not directly related to the UI. ```typescript import { ZudokuPlugin, ZudokuEvents } from "zudoku"; const navigationLoggerPlugin: ZudokuPlugin = { events: { location: ({ from, to }) => { if (!from) { console.log(`Initial navigation to: ${to.pathname}`); } else { console.log(`User navigated from: ${from.pathname} to: ${to.pathname}`); } }, }, }; ``` ### Example in Zudoku Config In your `zudoku.config.ts`, you can define the events like this: ```typescript export default { plugins: [ { events: { location: ({ from, to }) => { if (!from) return; // E.g. send an analytics event sendAnalyticsEvent({ from: from.pathname, to: to.pathname, }); }, }, }, ], }; ``` ## Using Events in Components Zudoku provides a convenient `useEvent` hook to subscribe to events in your React components. The hook can be used in three different ways: ### 1. Getting the Latest Event Data If you just want to access the latest event data without a callback: ```typescript import { useEvent } from "zudoku/hooks"; function MyComponent() { const locationEvent = useEvent("location"); return
Current path: {locationEvent?.to.pathname}
; } ``` ### 2. Using Event Data in a Component If you want to transform the event data, return a value from the callback: ```typescript import { useEvent } from "zudoku/hooks"; function MyComponent() { const pathname = useEvent("location", ({ to }) => to.pathname); return
Current path: {pathname}
; } ``` ### 3. Using a Callback for Side Effects If you just want to perform side effects when the event occurs: ```typescript import { useEvent } from "zudoku/hooks"; function MyComponent() { useEvent("location", ({ from, to }) => { if (from) { console.log(`Navigation: ${from.pathname} → ${to.pathname}`); } // No return value needed for side effects }); return
My Component
; } ``` The `useEvent` hook automatically handles subscription and cleanup in the React lifecycle, making it easy to work with events in your components. --- ## Document: Vercel URL: /docs/deploy/vercel # Vercel [Vercel](https://vercel.com) offers multiple ways to deploy to its service, including via GitHub, and their CLI. You can read more about them in their [Deployments Overview](https://vercel.com/docs/deployments/overview). ## Prerequisites To deploy to Vercel you will need: - A Vercel account (free) - A GitHub account (if deploying via GitHub) - The Vercel CLI Deploying your Zudoku powered documentation using the Vercel CLI is what we will cover in this guide. ## Install the CLI To get started you need to install the CLI: ```command npm i -g vercel ``` ## Setup a new project Next, set up a new Vercel project in the root of your docs: ```command vercel ``` This command will set up everything that is needed to deploy your documentation to Vercel. It will ask some specific questions including the project name and where the code is located. You can answer however you like for these. When you get to this step: ```ansi No framework detected. Default Project Settings: - Build Command: `npm run vercel-build` or `npm run build` - Development Command: None - Install Command: `yarn install`, `pnpm install`, `npm install`, or `bun install` - Output Directory: `public` if it exists, or `.` ? Want to modify these settings? (y/N) ``` Answer _Yes_ and select to modify the Output Directory. By default Vercel looks for a directory named `public`, but the Zudoku build will be found in `dist`. Set the output directory like this: ```ansi ? What's your Output Directory? dist ``` After this is complete, your site will build and Vercel will respond with the URL for you to test it. :::tip{title="Clean URLs"} You will almost certainly want to enable clean URLs for your site. This will remove the `.html` extension from your URLs. You can do this by adding a `cleanUrls` property to your `vercel.json` file. See the [Vercel Configuration](https://vercel.com/docs/projects/project-configuration#cleanurls) for more information. ::: :::caution{title="Redirects"} If you have redirects configured in your Zuplo configuration, you will need to also add those to your `vercel.json` file. See the [Vercel Configuration](https://vercel.com/docs/projects/project-configuration#redirects) for more information. This is a current limitation. See [#115](https://github.com/zuplo/zudoku/issues/151). ::: ## Accurate Last Modified Dates If you have enabled the [`showLastModified`](/docs/configuration/docs#showlastmodified) option, Zudoku automatically tracks the last modified date of your documentation pages using Git history. However, Vercel performs shallow clones by default (only fetching the last 10 commits), which can result in inaccurate "Last Modified" dates for pages that haven't been updated recently. To ensure accurate last modified dates, add the `VERCEL_DEEP_CLONE` environment variable to your Vercel project: 1. Go to your project settings in Vercel 2. Navigate to "Environment Variables" 3. Add a new variable: `VERCEL_DEEP_CLONE=true` 4. Save and redeploy your site This will enable full Git history during builds, ensuring all pages show their correct last modified dates. The impact on build time is minimal (typically 5-20 seconds on the first build), and subsequent builds benefit from caching. --- ## Document: GitHub Pages URL: /docs/deploy/github-pages # GitHub Pages [GitHub Pages](https://pages.github.com/) is a great way to publish your documentation, especially if you are using GitHub for source control. ## Prerequisites To publish your site to GitHub Pages you will need: - A GitHub account ## Deploying to GitHub Pages Use the [GitHub Actions Workflow](https://docs.github.com/en/pages/getting-started-with-github-pages/configuring-a-publishing-source-for-your-github-pages-site#publishing-with-a-custom-github-actions-workflow). You might need to configure the `basePath` in your zudoku.config.ts depending on how your site is hosted. For instance, if your site is available at username.github.io/your-repo/ you would set the `basePath` to `/your-repo`. ```typescript import type { ZudokuConfig } from "zudoku"; const config: ZudokuConfig = { basePath: "/your-repo", //... }; ``` ## Accurate Last Modified Dates If you have enabled the [`showLastModified`](/docs/configuration/docs#showlastmodified) option, Zudoku automatically tracks the last modified date of your documentation pages using Git history. However, GitHub Actions performs shallow clones by default, which can result in inaccurate "Last Modified" dates for pages that haven't been updated recently. To ensure accurate last modified dates, configure the `actions/checkout` step to fetch the full history: ```yaml - uses: actions/checkout@v4 with: fetch-depth: 0 # Fetch all history for all branches and tags ``` For more details, see the [actions/checkout documentation](https://github.com/actions/checkout#fetch-all-history-for-all-tags-and-branches). --- ## Document: Upload/FTP URL: /docs/deploy/direct-upload # Upload/FTP Zudoku can produce a build of static HTML, JavaScript and CSS files that you can deploy directly to your own server. ## Build locally To prepare the files you need to upload to your server, you will need to use the build command. ``` npm run build ``` Once complete, you will see a new `dist` folder in the root of your project that includes the files you need to upload. --- ## Document: Cloudflare Pages URL: /docs/deploy/cloudflare-pages # Cloudflare Pages [Pages](https://developers.cloudflare.com/pages) is a low configuration way of publishing your documentation. ## Prerequisites To publish your site to Cloudflare Pages you will need: - A Cloudflare account Optionally, you may also need: - A GitHub or GitLab account (optional) ## Deploying to Pages Cloudflare offers three different ways to create Pages sites. 1. Using the [Cloudflare CLI](https://developers.cloudflare.com/pages/get-started/c3/) 2. Directly uploading the files using [drag and drop](https://developers.cloudflare.com/pages/get-started/direct-upload/#drag-and-drop), or their [Wrangler CLI](https://developers.cloudflare.com/pages/get-started/direct-upload/#wrangler-cli) 3. Integration with [GitHub or GitLab](https://developers.cloudflare.com/pages/get-started/git-integration/) It's up to you which approach you choose but the fastest approach is to use the Wrangler CLI. ## Deploy using Wrangler Wrangler makes light work of deploying to Cloudflare Pages, but first you need to get your files in order. Build the static version of your documentation site by running: ```command npm run build ``` This will generate a new folder called `dist` that contains all the files that you need to deploy. Next, if you don't already have one, create a new Pages project: ```command npx wrangler pages project create ``` Finally, deploy the files to the new project: ```command npx wrangler pages deploy ./dist ``` Within a few seconds the site will be live and viewable at `.pages.dev`. ## Accurate Last Modified Dates If you have enabled the [`showLastModified`](/docs/configuration/docs#showlastmodified) option, Zudoku automatically tracks the last modified date of your documentation pages using Git history. However, Cloudflare Pages performs shallow clones by default, which can result in inaccurate "Last Modified" dates for pages that haven't been updated recently. To ensure accurate last modified dates when using Git integration with Cloudflare Pages, modify your build command to fetch the full history before building: ```bash git fetch --unshallow && npm run build ``` This command converts the shallow clone to a full clone before running your build, ensuring all pages show their correct last modified dates. --- ## Document: Font & Typography Learn how to customize fonts and typography in Zudoku using predefined Google Fonts, custom font URLs, or local fonts for sans, serif, and monospace text. URL: /docs/customization/fonts # Font & Typography Zudoku allows you to customize fonts for text (`sans`), serif content (`serif`), and code (`mono`). You can use predefined Google Fonts, external sources, or local fonts. ## Predefined Google Fonts The easiest way to use fonts is with predefined Google Fonts. Simply specify the font name as a string: ```ts title=zudoku.config.ts const config = { theme: { fonts: { sans: "Inter", serif: "Merriweather", mono: "JetBrains Mono", }, }, }; ``` ### Available Google Fonts The following fonts are available as predefined options: **Sans Serif:** Inter, Roboto, Open Sans, Poppins, Montserrat, Outfit, Plus Jakarta Sans, DM Sans, IBM Plex Sans, Geist, Oxanium, Space Grotesk **Serif:** Architects Daughter, Merriweather, Playfair Display, Lora, Source Serif Pro, Libre Baskerville **Monospace:** JetBrains Mono, Fira Code, Source Code Pro, IBM Plex Mono, Roboto Mono, Space Mono, Geist Mono ## Custom Font URLs For more control or to use fonts not in the predefined list, you can specify a custom font URL: ```ts title=zudoku.config.ts const config = { theme: { fonts: { sans: { url: "https://fonts.googleapis.com/css2?family=Roboto:wght@400;700&display=swap", fontFamily: "Roboto, sans-serif", }, mono: { url: "https://fonts.googleapis.com/css2?family=Roboto+Mono:wght@400;700&display=swap", fontFamily: "Roboto Mono, monospace", }, }, }, }; ``` ## Local Fonts To use local fonts, add them to the `public` folder and create a `fonts.css` file: ```css @font-face { font-family: "CustomFont"; font-style: normal; font-weight: 400; src: url("/custom-font-400.woff2") format("woff2"); } ``` Then reference the local CSS file: ```ts title=zudoku.config.ts const config = { theme: { fonts: { sans: { url: "/fonts.css", fontFamily: "CustomFont, sans-serif", }, }, }, }; ``` ## Mixed Configuration You can mix predefined fonts with custom fonts: ```ts title=zudoku.config.ts const config = { theme: { fonts: { sans: "Inter", // Predefined Google Font serif: { // Custom font url: "/custom-serif.css", fontFamily: "CustomSerif, serif", }, mono: "Fira Code", // Predefined Google Font }, }, }; ``` --- ## Document: Colors & Theme Customize your Zudoku site's colors and theme with flexible options, including light/dark modes, custom CSS, and shadcn registry integration. URL: /docs/customization/colors-theme # Colors & Theme Zudoku provides flexible theming options allowing you to customize colors, import themes from [shadcn registries](https://ui.shadcn.com/docs/registry), and add custom CSS. You can create cohesive light and dark mode experiences that match your brand. :::tip Try out the interactive [Theme Playground](/docs/theme-playground) to experiment with colors and see real-time previews of your theme changes. ::: The theme system is built on [shadcn/ui theming](https://ui.shadcn.com/docs/theming) and [Tailwind v4](https://tailwindcss.com), giving us a great foundation to build upon: - **CSS variables** match `shadcn/ui` conventions - **Tailwind v4** CSS variable system for modern styling - **Theme editors** like [tweakcn](https://tweakcn.com/) work out of the box - **Shadcn registries** are supported ## Custom Colors You can manually define colors for both light and dark modes, either by extending the [default theme](#default-theme) or creating a completely custom theme. Colors can be specified as hex values, RGB, HSL, OKLCH, etc. - basically anything that is supported by [Tailwind CSS](https://tailwindcss.com): ```ts title=zudoku.config.ts const config = { theme: { light: { background: "#ffffff", foreground: "#020817", card: "#ffffff", cardForeground: "#020817", popover: "#ffffff", popoverForeground: "#020817", primary: "#0284c7", primaryForeground: "#ffffff", secondary: "#f1f5f9", secondaryForeground: "#020817", muted: "#f1f5f9", mutedForeground: "#64748b", accent: "#f1f5f9", accentForeground: "#020817", destructive: "#ef4444", destructiveForeground: "#ffffff", border: "#e2e8f0", input: "#e2e8f0", ring: "#0284c7", radius: "0.5rem", }, dark: { background: "#020817", foreground: "#f8fafc", card: "#020817", cardForeground: "#f8fafc", popover: "#020817", popoverForeground: "#f8fafc", primary: "#0ea5e9", primaryForeground: "#f8fafc", secondary: "#1e293b", secondaryForeground: "#f8fafc", muted: "#1e293b", mutedForeground: "#94a3b8", accent: "#1e293b", accentForeground: "#f8fafc", destructive: "#ef4444", destructiveForeground: "#f8fafc", border: "#1e293b", input: "#1e293b", ring: "#0ea5e9", radius: "0.5rem", }, }, }; ``` ## Available Theme Variables | Variable | Description | | ----------------------- | ------------------------------------- | | `background` | Main background color | | `foreground` | Main text color | | `card` | Card background color | | `cardForeground` | Card text color | | `popover` | Popover background color | | `popoverForeground` | Popover text color | | `primary` | Primary action color | | `primaryForeground` | Text color on primary backgrounds | | `secondary` | Secondary action color | | `secondaryForeground` | Text color on secondary backgrounds | | `muted` | Muted/subtle background color | | `mutedForeground` | Text color for muted elements | | `accent` | Accent color for highlights | | `accentForeground` | Text color on accent backgrounds | | `destructive` | Color for destructive actions | | `destructiveForeground` | Text color on destructive backgrounds | | `border` | Border color | | `input` | Input field border color | | `ring` | Focus ring color | | `radius` | Border radius value | :::note While shadcn/ui defines additional theme variables, Zudoku currently uses only these core variables. ::: ## shadcn Registry Integration The easiest way to customize your theme is by using a Shadcn registry theme. For example you can use the great [tweakcn](https://tweakcn.com/) visual theme editor. ### Using tweakcn Themes 1. Visit [tweakcn.com](https://tweakcn.com/) to select a preset or customize your theme visually ![](./tweakcn0.webp) ![](./tweakcn1.webp) 1. Copy the registry URL from the "Copy" section ![](./tweakcn2.webp) 1. Add it to your configuration: ```ts title=zudoku.config.ts const config = { theme: { registryUrl: "https://tweakcn.com/r/themes/northern-lights.json", }, }; ``` 1. The theme will then be automatically imported with all color variables, fonts, and styling configured for you 🚀 ![](./tweakcn3.webp) You can still override specific values if needed: ```ts title=zudoku.config.ts const config = { theme: { registryUrl: "https://tweakcn.com/api/registry/theme/xyz123", // Override specific colors light: { primary: "#0066cc", }, dark: { primary: "#3399ff", }, }, }; ``` Alternatively, you can copy the CSS code and paste it into your `customCss` configuration: ```ts title=zudoku.config.ts const config = { theme: { customCss: ` /* Copied CSS code */ `, }, }; ``` ## Custom CSS For advanced styling, you can add custom CSS either as a string or structured object: :::note Changes to `customCss` require restarting the development server to take effect. ::: ### CSS String ```ts title=zudoku.config.ts const config = { theme: { customCss: ` .custom { background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); } `, }, }; ``` ### CSS Object ```ts title=zudoku.config.ts const config = { theme: { customCss: { ".custom": { background: "linear-gradient(135deg, #667eea 0%, #764ba2 100%)", }, }, }, }; ``` ## Default Theme Zudoku comes with a built-in default theme based on [shadcn/ui zinc base colors](https://ui.shadcn.com/docs/theming#zinc). If you want to start completely from scratch without any default styling, you can disable the default theme: ```ts title=zudoku.config.ts const config = { theme: { noDefaultTheme: true, // Your custom theme configuration }, }; ``` When `noDefaultTheme` is set to `true`, no default colors or styling will be applied, giving you complete control over your theme. Changing this requires to restart the development server. ## Complete Example Here's a comprehensive example combining multiple theming approaches: ```ts title=zudoku.config.ts const config = { theme: { // Import base theme from registry registryUrl: "https://tweakcn.com/api/registry/theme/modern-blue", // Override specific colors light: { primary: "#0066cc", accent: "#f0f9ff", }, dark: { primary: "#3399ff", accent: "#0c1b2e", }, // Custom fonts fonts: { sans: "Inter", mono: "JetBrains Mono", }, // Additional custom styling customCss: { ".hero-section": { background: "var(--primary)", color: "var(--primary-foreground)", padding: "2rem", "border-radius": "var(--radius)", }, }, }, }; ``` This configuration imports a base theme, customizes colors for both light and dark modes, sets fonts, and adds custom component styling. --- ## Document: Vite Config URL: /docs/configuration/vite-config # Vite Config Zudoku is built on top of [Vite](https://vite.dev/) and can be customized using a [Vite configuration file](https://vite.dev/config/) if advanced functionality is required. Not all configurations are supported in Zudoku, but common tasks like adding plugins will generally work as expected. Simply create a `vite.config.ts` file in the root of your project and set the configuration options as needed. Zudoku will automatically pick up the configuration file and will use it to augment the built-in configuration. You can find an [example project](https://github.com/zuplo/zudoku/tree/main/examples/with-vite-config) on GitHub that demonstrates how to use a custom Vite configuration with Zudoku. --- ## Document: Slots Learn how to use slots to inject custom content into predefined locations throughout your Zudoku site. URL: /docs/configuration/slots # Slots Slots provide a powerful way to inject custom content into predefined locations throughout Zudoku. They allow you to extend the default layout and functionality without modifying the core components. ## Configuration You can define slots in your `zudoku.config.tsx` file using the `slots` property: ```tsx import type { ZudokuConfig } from "zudoku"; import { Button } from "zudoku/ui/Button.js"; const config: ZudokuConfig = { // ... other config slots: { "head-navigation-end": () => ( ), "footer-before":
Custom footer content
, }, }; export default config; ``` ## Slot Types Slots accept either: - **React components/elements**: JSX elements - **Function components**: Functions that return JSX elements and receive routing props ```tsx slots: { // JSX element "footer-after": , // Function with access to routing props "head-navigation-end": ({ navigate, location, searchParams }) => ( ), } ``` Functions receive an object with routing properties: - `location` - Current route location - `navigate` - Navigation function - `searchParams` - URL search parameters - `setSearchParams` - Function to update search parameters - `params` - Route parameters ## Type Safety Zudoku provides full TypeScript support for slot names. All predefined slot names will show up with autocomplete when you type them in your configuration. ## Advanced Usage For more advanced slot usage, including programmatic slot management, dynamic content, and adding custom slot names, see the [Slot Component](/docs/components/slot) documentation. ## Examples ### Adding Social Links to Header ```tsx slots: { "head-navigation-end": () => ( ), } ``` ### Dynamic Content with Routing ```tsx slots: { "top-navigation-side": ({ location, navigate }) => (
), } ``` --- ## Document: /docs/configuration/site Customize your Zudoku site's branding, logo, banner, and layout options with detailed configuration examples and guidance. URL: /docs/configuration/site # Branding & Layout We offer you to customize the main aspects of your Zudoku site's appearance and behavior. ## Branding **Title**, **logo** can be configured in under the `site` property: ```tsx title=zudoku.config.tsx const config = { site: { title: "My API Documentation", logo: { src: { light: "/path/to/light-logo.png", dark: "/path/to/dark-logo.png", }, alt: "Company Logo", href: "/", }, // Other options... }, }; ``` ### Available Options #### Title Set the title of your site next to the logo in the header: ```tsx title=zudoku.config.tsx { site: { title: "My API Documentation", } } ``` #### Logo Configure the site's logo with different versions for light and dark themes: ```tsx title=zudoku.config.tsx { site: { logo: { src: { light: "/light-logo.png", dark: "/dark-logo.png" }, alt: "Company Logo", width: "120px" // optional width } } } ``` #### Colors & Theme We allow you to fully customize all colors, borders, etc - read more about it in [Colors & Themes](/docs/customization/colors-theme) ## Layout ### Banner Add a banner message to the top of the page: ```tsx title=zudoku.config.tsx { site: { banner: { message: "Welcome to our beta documentation!", color: "info", // "note" | "tip" | "info" | "caution" | "danger" or custom dismissible: true } } } ``` ### Footer The footer configuration has its own dedicated section. See the [Footer Configuration](./footer) for details. ## Complete Example Here's a comprehensive example showing all available page configuration options: ```tsx title=zudoku.config.tsx { site: { title: "My API Documentation", logo: { src: { light: "/images/logo-light.svg", dark: "/images/logo-dark.svg" }, alt: "Company Logo", width: "100px", }, banner: { message: "Welcome to our documentation!", color: "info", dismissible: true }, } } ``` --- ## Document: /docs/configuration/sentry URL: /docs/configuration/sentry # Sentry Sentry is a popular error tracking tool that helps you monitor and fix crashes in real time. It provides you with detailed error reports, so you can quickly identify and resolve issues before they affect your users. ## Enable Sentry 1. To enable it you have to first install the optional dependency `@sentry/react`. ```bash npm install --save @sentry/react ``` 2. And then set the `SENTRY_DSN` environment variable in your Zudoku project. ```bash SENTRY_DSN=https://your-sentry-dsn ``` ## Release management However this does not handle release management for you. For that you can [create a custom `vite.config.ts`](./vite-config) and use the `@sentry/vite-plugin` plugin. ```ts import { sentryVitePlugin } from "@sentry/vite-plugin"; import { defineConfig } from "vite"; export default defineConfig({ plugins: [ sentryVitePlugin({ authToken: "your-token", org: "your-org", project: "your-project", }), ], }); ``` --- ## Document: Search Learn how to configure and customize search functionality in Zudoku, including setup instructions for Pagefind and Inkeep providers, result transformation, and ranking options. URL: /docs/configuration/search # Search Zudoku offers search functionality that enhances user experience by enabling content discovery across your site. When configured, a search bar will appear in the header, allowing users to quickly find relevant information on any page. We currently support two search providers: - [Pagefind](https://pagefind.app/) - [Inkeep](https://inkeep.com/) ## Pagefind [Pagefind](https://pagefind.app/) is a lightweight, static search library that can be used to add search to your Zudoku site without any external services. To enable pagefind search, configure the `search` option in your configuration: ```typescript { search: { type: "pagefind", // Optional: Maximum number of sub results per page maxSubResults: 3, // Optional: Configure search result ranking (defaults shown below) ranking: { termFrequency: 0.8, pageLength: 0.6, termSimilarity: 1.2, termSaturation: 1.2, }, } } ``` ### Transforming/Filtering Search Results You can transform or filter search results using the `transformResults` option. This function receives the search result along with the current auth state and context, allowing you to: - Filter results based on user permissions - Modify result content - Add custom results The type of `result` is the same as [the type returned by Pagefind's search API](https://github.com/Pagefind/pagefind/blob/03552d041d9533b09563f6c50466b25d394ece64/pagefind_web_js/types/index.d.ts#L123-L160). ```typescript { search: { type: "pagefind", transformResults: ({ result, auth, context }) => { // Return false to filter out the result if (!auth.isAuthenticated) return false; // Return true or undefined to keep the original result if (result.url.includes("/private/")) return true; // Return a modified result return { ...result, title: `${result.title} (${context.meta.title})` }; } } } ``` For more information about how Pagefind's ranking system works and how to customize it for your content, see the [Pagefind ranking documentation](https://pagefind.app/docs/ranking/). ## Inkeep [Inkeep](https://inkeep.com/) is an AI-powered search and chat platform that can index your documentation and provide intelligent search capabilities to your users. ### Setting up Inkeep Integration Before you can use Inkeep search in your Zudoku site, you need to set up an Inkeep integration and have your site indexed. Here's how to get started: #### 1. Create an Inkeep Account 1. Go to [Inkeep](https://inkeep.com/) and sign up for an account 2. Navigate to the [Inkeep Portal](https://portal.inkeep.com/) #### 2. Set up Site Indexing 1. In the Inkeep Portal, create a new project or integration 2. Configure your site URL so Inkeep can crawl and index your documentation 3. Ensure your Zudoku site is deployed and publicly accessible for indexing 4. Wait for Inkeep to crawl and index your site content (this may take some time) #### 3. Get Your Integration Credentials To add Inkeep search to your site you will need to copy some variables from your [Inkeep account setting](https://portal.inkeep.com/): - API Key - Integration ID - Organization ID #### 4. Configure Zudoku Once you have your credentials and your site is indexed, you can configure the `search` option in your [Zudoku Configuration](./overview.md): ```typescript { // ... search: { type: "inkeep", apiKey: "", integrationId: "", organizationId: "", primaryBrandColor: "#26D6FF", organizationDisplayName: "Your Organization Name", } // ... } ``` --- ## Document: Protected Routes Learn how to protect specific routes in your documentation using authentication, including simple array patterns and advanced authorization logic with custom callback functions. URL: /docs/configuration/protected-routes # Protected Routes You can protect specific routes in your documentation by adding the `protectedRoutes` property to your [Zudoku configuration](./overview.md). This property supports two formats: a simple array of path patterns, or an advanced object format with custom authorization logic. ## Array Format The simplest way to protect routes is to provide an array of path patterns. Users must be authenticated to access these routes. ```typescript title="zudoku.config.ts" { // ... protectedRoutes: [ "/admin/*", // Protect all routes under /admin "/settings", // Protect the settings page "/api/*", // Protect all API-related routes "/private/:id" // Protect dynamic routes with parameters ], // ... } ``` ## Advanced Object Format For more complex authorization logic, you can provide a record mapping route patterns to custom callback functions: ```typescript title="zudoku.config.ts" { // ... protectedRoutes: { // Only allow authenticated users with admin role "/admin/*": ({ auth, context }) => auth.isAuthenticated && auth.user?.role === "admin", // Check if user has enterprise access "/api/enterprise/*": ({ auth, context }) => auth.isAuthenticated && auth.user?.subscription === "enterprise", // Allow access to beta features based on user attributes "/beta/*": ({ auth, context }) => auth.isAuthenticated && auth.user?.betaAccess === true, }, // ... } ``` The callback function receives an object with: - `auth`: The current authentication state including `isAuthenticated`, `user` data, and more - `context`: The Zudoku context providing access to configuration and utilities The callback must return a boolean indicating whether the user should have access to the route. ## Path Patterns The path patterns follow the same syntax as [React Router](https://reactrouter.com): - `:param` matches a URL segment up to the next `/`, `?`, or `#` - `*` matches zero or more characters up to the next `/`, `?`, or `#` - `/*` matches all characters after the pattern For example: - `/users/:id` matches `/users/123` or `/users/abc` - `/docs/*` matches `/docs/getting-started` or `/docs/api/reference` - `/settings` matches only the exact path `/settings` After logging in, users will be automatically redirected back to the protected route they were trying to access. ## Next Steps - Learn about [authentication providers](./authentication.md#authentication-providers) supported by Zudoku - Configure [user data](./authentication.md#user-data) display --- ## Document: Configuration File Learn how to configure your Zudoku documentation site using the configuration file. Covers file formats, options, examples, and best practices. URL: /docs/configuration/overview # Configuration File Zudoku uses a single file for configuration. It controls the structure, metadata, style, plugins, and routing for your documentation. You can find the file in the root directory of your project. It will start with `zudoku.config`. The file can be in either JavaScript or TypeScript format and use a `.js`, `.mjs`, `.jsx`, `.ts`, or `.tsx` file extension: - `zudoku.config.ts` - `zudoku.config.tsx` - `zudoku.config.js` - `zudoku.config.jsx` - `zudoku.config.mjs` When you create a project, a default configuration file is generated for you. This file is a good starting point and can be customized to suit your needs. :::note{title="Security Consideration"} The Zudoku configuration file runs on both client and server at runtime. Avoid including secrets directly in your config as they may be exposed to the client. ::: ## Example Below is an example of the default Zudoku configuration. You can edit this configuration to suit your own needs. ```ts title=zudoku.config.ts import type { ZudokuConfig } from "zudoku"; const config: ZudokuConfig = { navigation: [ { type: "category", label: "Documentation", items: ["introduction", "example"], }, { type: "link", to: "api", label: "API Reference" }, ], redirects: [{ from: "/", to: "/docs/introduction" }], apis: { type: "file", input: "./apis/openapi.yaml", path: "/api", }, docs: { files: "/pages/**/*.{md,mdx}", }, }; export default config; ``` ## Configuration options ### `apis` There are multiple options for referencing your OpenAPI document. The example below uses a URL to an OpenAPI document, but you can also use a local file path. For full details on the options available, see the [API Reference](./api-reference.md). ```ts { // ... "apis": { "type": "url", "input": "https://rickandmorty.zuplo.io/openapi.json", "path": "/api" } // ... } ``` ### `site` Controls global page attributes across the site, including logos and the site title. **Example:** ```ts { // ... "site": { "title": "Our Documentation", "logo": { "src": { "light": "/logos/zudoku-light.svg", "dark": "/logos/zudoku-dark.svg" }, "width": "99px" } } // ... } ``` ### `navigation` Defines navigation for both the top bar and the sidebar. Items can be categories, links or custom pages. ```ts { // ... "navigation": [ { "type": "category", "label": "Docs", "items": ["introduction"] }, { "type": "link", "to": "api", "label": "API Reference" } ] // ... } ``` ### `theme` Allows you to control the dark and light themes that persist across each MDX page, and the API reference. You can customize your theme as much as you want using [ShadCDN UI theme variables](https://ui.shadcn.com/docs/theming#list-of-variables). In the example below only the `primary` and `primaryForeground` variables are used but you can add any additional variables from ShadCDN UI that you would like to change. **Tip**: Use the [ShadCDN UI Theme Generator](https://zippystarter.com/tools/shadcn-ui-theme-generator) to create a great looking theme based off your primary color. **Example:** ```ts { // ... "theme": { "light": { "primary": "316 100% 50%", "primaryForeground": "360 100% 100%" }, "dark": { "primary": "316 100% 50%", "primaryForeground": "360 100% 100%" } } // ... } ``` ### `metadata` Controls the site metadata for your documentation. All possible options are outlined in the example below. **Example:** ```ts { // ... "metadata": { "title": "Example Website Title", "description": "This is an example description for the website.", "logo": "https://example.com/logo.png", "favicon": "https://example.com/favicon.ico", "generator": "Website Generator 1.0", "applicationName": "Example App", "referrer": "no-referrer", "keywords": ["example", "website", "metadata", "SEO"], "authors": ["John Doe", "Jane Smith"], "creator": "John Doe", "publisher": "Example Publisher Inc." } // ... } ``` ### `docs` Configures where your non API reference documentation can be found in your folder structure. The default is shown in the example below and you don't need to change it unless you want a different structure in place, or to have it match an existing structure that you already have. **Example:** ```ts { // ... "docs": { "files": "/pages/**/*.{md,mdx}" } // ... } ``` ### `sitemap` Controls the sitemap for your documentation. All possible options are outlined in the example below. ```ts { // ... "sitemap": { // The base url for your site // Required "siteUrl": "https://example.com", // The change frequency for the pages // Defaults to daily "changefreq": "daily", // The priority for the pages // Defaults to 0.7 "priority": 0.7, // The output directory for the sitemap // Defaults to undefined "outDir": "sitemaps/", // Whether to include the last modified date // Defaults to true "autoLastmod": true, // The pages to exclude from the sitemap // Can also be a function that returns an array of paths // () => Promise "exclude": ["/404", "/private/page"] } // ... } ``` ### `redirects` Implements any page redirects you want to use. This gives you control over the resource names in the URL. **Example:** ```ts { // ... "redirects": [ { "from": "/", "to": "/documentation/introduction" }, { "from": "/documentation", "to": "/documentation/introduction" } ] // ... } ``` ### `port` The port on which the development server will run. Defaults to `3000`. This option can also be passed to the CLI as `--port' (which takes precedence). ```ts { "port": 9001 } ``` If the port is already in use, the next available port will be used. ### `basePath` Sets the base path for your documentation site. This is useful when you want to host your documentation under a specific path. ```ts { basePath: "/docs", // A page defined as `/intro` would result in: https://example.com/docs/intro } ``` ### `canonicalUrlOrigin` Sets the canonical [origin URL](https://developer.mozilla.org/en-US/docs/Web/API/URL/origin) for your documentation site. This is used for SEO purposes and helps search engines understand the preferred version of a page. ```ts { basePath: '/docs', canonicalUrlOrigin: "https://example.com", // visiting the page `/intro` would result in: // https://example.com/docs/intro } ``` This is the resulting HTML that will be added to the `` of your pages: ```html ``` ### `cdnUrl` Configures the CDN URL for your documentation site's assets. You can provide either a string for a single CDN URL or an object to specify different URLs for base and media assets. ```ts // Single CDN URL { cdnUrl: "https://cdn.example.com" } // Separate URLs for base and media assets { cdnUrl: { base: "https://cdn.example.com", media: "https://media.example.com" } } ``` ### `https` Enables HTTPS for the dev server. `key` and `cert` are required and `ca` is optional. ```ts { "https": { "key": "/path/to/key.pem", "cert": "/path/to/cert.pem", "ca": "/path/to/ca.pem" } } ``` ### `enableStatusPages` Enables static generation of status pages for your site. This results in several files (404.html, 500.html, etc.) being generated in the `dist` directory. This is useful as many hosting providers will serve these files automatically when a user visits a non-existent page or encounters an error. This option is enabled by default, but you can disable it if you don't need these pages. ```ts { enableStatusPages: false; } ``` ## Multiple Files The configuration file is a standard JavaScript or TypeScript file, so you can split it into multiple files if you prefer. This can be useful if you have a large configuration or want to keep your code organized. For example, if you wanted to move your navigation configuration to a separate file, you could create a new file called `navigation.ts` and export the navigation configuration from there. ```ts // navigation.ts import type { Navigation } from "zudoku"; export const navigation: Navigation = [ { type: "category", label: "Documentation", items: ["example", "other-example"], }, ]; ``` Then you can import the navigation configuration into your main configuration file. ```ts title=zudoku.config.ts // zudoku.config.ts import type { ZudokuConfig } from "zudoku"; import { navigation } from "./navigation"; const config = { // ... navigation, // ... }; export default config; ``` --- ## Document: Navigation Learn how to configure the navigation in Zudoku, including links, categories, documents, and custom pages. Understand the structure of the navigation array and how to use icons, labels, and paths. URL: /docs/configuration/navigation # Navigation import { Book, Code, FileText } from "zudoku/icons"; Zudoku uses a single `navigation` array to control both the top navigation tabs and the sidebar. Items at the root of this array appear as tabs, and nested items build the sidebar tree. Navigation entries can be links, document references, categories or custom pages. ## Basic configuration The navigation is defined using the `navigation` array in the Zudoku config file. Each item can be one of several types. At the simplest level you may only have links and categories. ```json { "navigation": [ { "type": "category", "label": "Documentation", "icon": "book", "items": [ { "type": "doc", "file": "documentation/introduction", "label": "Introduction", "icon": "file-text" }, { "type": "doc", "file": "documentation/getting-started", "path": "/docs/quick-start", "label": "Quick Start" } ] }, { "type": "link", "to": "/api", "label": "API Reference", "icon": "code", "description": "Complete API documentation", "badge": { "label": "v2.0", "color": "blue" }, "display": "always" } ] } ``` ## Navigation Items Navigation items can be of these types: `category`, `doc`, `link`, or `custom-page`. - `link`: A direct link to a page or external URL. - `category`: A group of links that can be expanded or collapsed. - `doc`: A reference to a document by it's file path: `file`. - `custom-pages`: A custom page that is made of a React component, see [Custom Pages](../guides/custom-pages.md) ### `type: link` `link` is the most basic item, it directly links to a path or URL. Use this for external resources or standalone pages. ```json { "type": "link", "label": "Support", "to": "/my/api" // or: https://example.com/my-external-link } ```
**TypeScript type declaration** ```ts type NavigationLink = { type: "link"; to: string; label: string; icon?: string; // Lucide icon name description?: string; badge?: { label: string; color: "green" | "blue" | "yellow" | "red" | "purple" | "indigo" | "gray" | "outline"; }; display?: "auth" | "anon" | "always" | "hide"; target?: "_self" | "_blank"; }; ```
### `type: category` The `category` type groups related items under a collapsible section. The `label` is the displayed text, and the `items` array contains `id`s of documents, links, or other categories. ```json { "type": "category", "label": "Getting Started", "collapsible": true, // optional "collapsed": false, // optional "items": [ { "type": "link", "label": "Support", "to": "https://support.example.com" } ] } ```
**TypeScript type declaration** ```ts type NavigationCategory = { type: "category"; icon?: string; // Lucide icon name items: Array; label: string; collapsible?: boolean; collapsed?: boolean; link?: string | { type: "doc"; file: string; label?: string }; display?: "auth" | "anon" | "always" | "hide"; }; ```
### `type: doc` Doc is used to reference markdown files. The `label` is the text that will be displayed, and the `file` is the file path associated with a markdown file. ```json { "type": "doc", "label": "Overview", "file": "docs/overview" } ```
**TypeScript type declaration** ```ts type NavigationDoc = { type: "doc"; file: string; path?: string; icon?: string; label?: string; badge?: { label: string; color: "green" | "blue" | "yellow" | "red" | "purple" | "indigo" | "gray" | "outline"; }; display?: "auth" | "anon" | "always" | "hide"; }; ```
#### Using shorthands Documents can be referenced as strings (using their file path), which is equivalent to `{ "type": "doc", "file": "path" }`: ```json { "navigation": [ { "type": "category", "label": "Documentation", "icon": "book", "items": [ "documentation/introduction", "documentation/getting-started", "documentation/installation" ] }, { "type": "link", "to": "/api", "label": "API Reference", "icon": "code" } ] } ``` This is much more concise when you don't need custom labels, icons, or other properties for individual documents. Learn more in the [Markdown documentation](/docs/markdown/overview) #### Custom paths The `path` property allows you to customize the URL path for a document. By default, Zudoku uses the file path to generate the URL, but you can override this behavior by specifying a custom path. ### `type: custom-page` Custom pages allow you to create standalone pages that are not tied to a Markdown document. This is useful for creating landing pages, dashboards, or any other custom content. ```tsx { type: "custom-page", path: "/a-custom-page", element: , display: "always" } ```
**TypeScript type declaration** ```ts type NavigationCustomPage = { type: "custom-page"; path: string; label?: string; element: any; icon?: string; // Lucide icon name badge?: { label: string; color: "green" | "blue" | "yellow" | "red" | "purple" | "indigo" | "gray" | "outline"; invert?: boolean; }; display?: "auth" | "anon" | "always" | "hide"; }; ```
## Display Control All navigation items support a `display` property that controls when the item should be visible: - `"always"` (default): Always visible - `"auth"`: Only visible when user is authenticated - `"anon"`: Only visible when user is not authenticated - `"hide"`: Never visible (useful for temporarily hiding items) ```json { "type": "link", "label": "Admin Panel", "to": "/admin", "display": "auth" } ``` ## Badges Navigation items can display badges with labels and colors. Badges support an optional `invert` property for styling: ```json { "type": "doc", "file": "api/v2", "badge": { "label": "Beta", "color": "yellow" } } ``` ## Icons Icons can be added to categories and documents by specifying an `icon` property. The value should be the name of a [Lucide icon](https://lucide.dev/icons) (e.g., `book` , `code` , `file-text` ). ```json { "type": "category", "label": "Getting Started", "icon": "book" } ``` They can also be set on individual documents in their front matter: ```md --- title: My Document sidebar_icon: book --- ``` ## Title & Labels All navigation items can have a `label` property that determines the displayed text. For `doc` items, the `label` is optional; if omitted, Zudoku uses the document's `title` from its front matter or the first `#` header. To override the navigation label without changing the document's `title`, use the `sidebar_label` property in the front matter: ```md --- title: My Long Title sidebar_label: Short Title --- ``` In this example, the document's title remains "My Long Title," but the sidebar displays "Short Title." --- ## Document: LLM-Friendly Documentation Export URL: /docs/configuration/llms # LLM-Friendly Documentation Export Zudoku can generate LLM-friendly versions of your documentation following the [llms.txt](https://llmstxt.org/) specification. During build, you can optionally generate: - **`.md` files** - Individual pages with frontmatter removed (via `publishMarkdown`) - **`llms.txt`** - Summary with links to all pages - **`llms-full.txt`** - Complete documentation in one file All options are disabled by default. ## Configuration LLM features are configured through the `docs` section in your config: ```tsx title="zudoku.config.tsx" export default { docs: { files: "pages/**/*.{md,mdx}", // Your markdown files publishMarkdown: true, // Generate .md files llms: { llmsTxt: true, // Generate llms.txt llmsTxtFull: true, // Generate llms-full.txt includeProtected: false, // Exclude protected routes }, }, }; ``` All options are disabled by default. :::tip When enabled, markdown files are generated during build and deleted after creating the `llms.txt` files unless `publishMarkdown: true` is set (see [`publishMarkdown` docs](/docs/configuration/docs#publishmarkdown)). ::: ### `llmsTxt` **Type:** `boolean` **Default:** `false` Generates an `llms.txt` file with links to all documentation pages: ```markdown title="llms.txt" # Documentation - [Quickstart](/docs/quickstart.md): Get started with Zudoku - [Writing](/docs/writing.md): A guide to writing documentation ``` ### `llmsTxtFull` **Type:** `boolean` **Default:** `false` Generates `llms-full.txt` containing the complete content of all pages. ### `includeProtected` **Type:** `boolean` **Default:** `false` By default, protected routes are excluded. Set to `true` to include them in the generated files. ## Output Generated files are available in the output directory after build: ```text dist/ ├── llms.txt # Generated if llmsTxt: true ├── llms-full.txt # Generated if llmsTxtFull: true └── docs/ ├── quickstart.md # Generated if publishMarkdown: true ├── writing.md └── ... ``` **Important:** Individual `.md` files are only kept in the final build if `publishMarkdown: true`. If only `llmsTxt` or `llmsTxtFull` is enabled, the `.md` files are generated temporarily during the build but deleted after the `llms.txt` files are created. Redirect pages, error pages (400, 404, 500), and protected routes (unless `includeProtected: true`) are automatically excluded from all generated files. --- ## Document: /docs/configuration/footer Learn how to configure the footer in Zudoku, including columns, social links, copyright notice, and logo. Customize the footer's position and content with slots. URL: /docs/configuration/footer # Footer Configuration The footer is a customizable component that appears at the bottom of every page in your Zudoku site. You can configure various aspects of the footer including its position, columns, social links, copyright notice, and logo. ## Basic Configuration The footer is configured in your `zudoku.config.tsx` file under the `page.footer` property: ```tsx const config: ZudokuConfig = { site: { footer: { // Footer configuration goes here position: "center", copyright: `© ${new Date().getFullYear()} YourCompany LLC. All rights reserved.`, // Other options... }, }, // Other configuration... }; ``` ## Position You can control the horizontal alignment of the footer content using the `position` property: ```tsx footer: { position: "center"; // default // or position: "start"; // or position: "end"; } ``` This affects how the content in the footer's main row is positioned horizontally. ## Columns The footer can include multiple columns of links, each with its own title: ```tsx footer: { columns: [ { title: "Product", position: "center", // position in grid, optional: start, center, end links: [ { label: "Features", href: "/features" }, { label: "Pricing", href: "/pricing" }, { label: "Documentation", href: "/docs" }, { label: "GitHub", href: "https://github.com/org/repo" }, // Auto-detected as external ], }, { title: "Company", links: [ { label: "About", href: "/about" }, { label: "Blog", href: "/blog" }, { label: "Contact", href: "/contact" }, ], }, ]; } ``` Each column can have its own positioning with the `position` property, which can be `"start"`, `"center"`, or `"end"`. This controls how the column is positioned within the footer grid. ## Social Media Links You can add social media links to your footer: ```tsx footer: { social: [ { icon: "github", href: "https://github.com/yourusername", }, { icon: "twitter", href: "https://twitter.com/yourhandle", label: "Follow us", // optional label text }, ]; } ``` The `icon` property currently can be one of the following values:
- `"reddit"` - `"discord"` - `"github"` - `"x"` (Twitter) - `"linkedin"` - `"facebook"` - `"instagram"` - `"youtube"` - `"tiktok"` - `"twitch"` - `"pinterest"` - `"snapchat"` - `"whatsapp"` - `"telegram"`
Or you can provide a custom React component. ## Copyright Notice Add a copyright notice with the `copyright` property: ```tsx footer: { copyright: `© ${new Date().getFullYear()} YourCompany LLC. All rights reserved.`; } ``` ## Logo You can add a logo to your footer: ```tsx footer: { logo: { src: { light: "/path/to/light-logo.png", dark: "/path/to/dark-logo.png" }, alt: "Company Logo", width: "120px" // optional width } } ``` ## Customizing with Slot Zudoku provides `footer-before` and `footer-after` slots that allow you to insert custom content before or after the main footer columns: ```tsx // In your zudoku.config.tsx slots: { "footer-before": () => (

Custom pre-footer content

This appears before the columns

), "footer-after": () => (

Additional footer content

) } ``` ## Complete Example Here's a complete example showing all footer options: ```tsx footer: { position: "center", columns: [ { title: "Product", position: "start", links: [ { label: "Features", href: "/features" }, { label: "Pricing", href: "/pricing" }, { label: "Documentation", href: "/docs" } ] }, { title: "Resources", position: "center", links: [ { label: "Blog", href: "/blog" }, { label: "Support", href: "/support" }, { label: "GitHub", href: "https://github.com/yourusername" } // Auto-detected as external ] } ], social: [ { icon: "github", href: "https://github.com/yourusername" }, { icon: "linkedin", href: "https://linkedin.com/company/yourcompany", label: "LinkedIn" } ], copyright: `© ${new Date().getFullYear()} YourCompany LLC. All rights reserved.`, logo: { src: { light: "/images/logo-light.svg", dark: "/images/logo-dark.svg" }, alt: "Company Logo", width: "100px" } } ``` --- ## Document: Documentation URL: /docs/configuration/docs # Documentation Zudoku uses a file-based routing system for documentation pages, similar to many modern frameworks. This page explains how routing works and how to customize it. ## File Based Routing By default, Zudoku automatically creates routes for all Markdown and MDX files based on their file path. Files are served at URLs that match their file structure, minus the file extension. ### Basic Examples ```text title="File tree" pages/ ├── introduction.md → /introduction ├── quickstart.mdx → /quickstart ├── guides/ │ ├── getting-started.md → /guides/getting-started │ └── advanced.md → /guides/advanced └── api/ └── reference.md → /api/reference ``` ### File Extensions Both `.md` and `.mdx` files are supported: - `.md` files support standard Markdown with frontmatter - `.mdx` files support JSX components within Markdown The file extension is automatically removed from the URL. ## Custom Paths You can override the default file-based routing by specifying custom paths in your navigation configuration. When a file has a custom path, it will only be accessible at that custom path, not at its original file-based path. ### Navigation Configuration ```tsx {5-6,13-14} title="zudoku.config.tsx" showLineNumbers export default { navigation: [ { type: "doc", file: "guides/getting-started.md", path: "start-here", // Custom path label: "Start Here", }, { type: "category", label: "Advanced", link: { file: "guides/advanced.md", path: "advanced-guide", // Custom path for category link }, items: [ // ... other items ], }, ], }; ``` In this example: - `guides/getting-started.md` is accessible at `/start-here` (not `/guides/getting-started`) - `guides/advanced.md` is accessible at `/advanced-guide` (not `/guides/advanced`) ## Configuration Options Configure docs routing and behavior through the `docs` section in your config: ```tsx title="zudoku.config.tsx" export default { docs: { files: ["/pages/**/*.{md,mdx}"], defaultOptions: { toc: true, disablePager: false, showLastModified: true, suggestEdit: { url: "https://github.com/your-org/your-repo/edit/main/docs", text: "Edit this page", }, }, }, }; ``` ### `files` **Type:** `string | string[]` **Default:** `"/pages/**/*.{md,mdx}"` Glob patterns that specify which files to include as documentation pages. You can provide a single pattern or an array of patterns. ```tsx title="zudoku.config.tsx" // Single pattern docs: { files: "/content/**/*.md"; } // Multiple patterns docs: { files: ["/pages/**/*.{md,mdx}", "/guides/**/*.md", "/tutorials/**/*.mdx"]; } ``` ### `defaultOptions` Default options applied to all documentation pages. These can be overridden on individual pages using frontmatter. #### `toc` **Type:** `boolean` **Default:** `true` Whether to show the table of contents (TOC) by default. ```tsx title="zudoku.config.tsx" docs: { defaultOptions: { toc: false; // Hide TOC by default } } ``` #### `disablePager` **Type:** `boolean` **Default:** `false` Whether to disable the previous/next page navigation by default. ```tsx title="zudoku.config.tsx" docs: { defaultOptions: { disablePager: true; // Disable pager by default } } ``` #### `showLastModified` **Type:** `boolean` **Default:** `false` Whether to show the last modified date by default. ```tsx title="zudoku.config.tsx" docs: { defaultOptions: { showLastModified: true; // Show last modified date } } ``` #### `suggestEdit` **Type:** `{ url: string; text?: string }` **Default:** `undefined` Configuration for the "Edit this page" link. ```tsx title="zudoku.config.tsx" docs: { defaultOptions: { suggestEdit: { url: "https://github.com/your-org/your-repo/edit/main/docs", text: "Edit this page on GitHub" // Optional custom text } } } ``` The `url` should be a template where the file path will be appended. For example, if your docs are in a `docs/pages/` directory, the URL might be `https://github.com/your-org/your-repo/edit/main/docs/pages`. #### `copyPage` **Type:** `boolean` **Default:** `undefined` Whether to show a copy button in the page header that allows users to copy the page markdown. This feature requires `publishMarkdown` to be enabled (see below). ```tsx title="zudoku.config.tsx" docs: { defaultOptions: { copyPage: true; // Enable copy button for all pages } } ``` The copy button provides: - A primary "Copy page" action that copies the markdown to clipboard - A dropdown with additional options: - Copy link to page - Open markdown file (requires `publishMarkdown: true`) - Open in Claude - Open in ChatGPT > **Note:** The copy button requires `publishMarkdown: true` to be set in your docs config. If > `copyPage` is enabled but `publishMarkdown` is not, a warning will be displayed. ### `publishMarkdown` **Type:** `boolean` **Default:** `false` When enabled, generates `.md` files for each documentation page during build. Pages can then be accessed at their URL path with the `.md` extension appended (e.g., `/docs/quickstart.md`). ```tsx title="zudoku.config.tsx" docs: { publishMarkdown: true, } ``` The generated markdown files: - Have frontmatter removed for cleaner content - Are accessible at `{page-url}.md` in both development and production - Are required for the `copyPage` button functionality - Are used by LLM features (see [llms.txt configuration](/docs/configuration/llms) for more details) ### `llms` **Type:** `object` **Default:** `undefined` Configuration for generating LLM-friendly documentation files. See the [llms.txt configuration](/docs/configuration/llms) page for complete documentation. ```tsx title="zudoku.config.tsx" docs: { llms: { llmsTxt: true, // Generate llms.txt summary file llmsTxtFull: true, // Generate llms-full.txt with complete content includeProtected: false } } ``` ## Overriding Defaults You can override [default options](#defaultoptions) on individual pages using frontmatter: ```markdown --- toc: false disablePager: true showLastModified: false --- # My Page This page has custom options that override the defaults. ``` ## Route Resolution Zudoku resolves routes in the following order: 1. **Custom paths from navigation** - If a file has a custom path defined in navigation, it's served at that path 2. **File-based paths** - All other files are served at their file-based paths ## Best Practices 1. **Use descriptive file names** - File names become part of the URL, so make them clear and SEO-friendly 2. **Organize with folders** - Use folder structure to group related content 3. **Custom paths for better UX** - Use custom paths for important pages that need memorable URLs (sometimes also called slugs) 4. **Consistent naming** - Use consistent naming conventions for files and folders --- ## Document: /docs/configuration/build-configuration URL: /docs/configuration/build-configuration # Build Configuration The `zudoku.build.ts` file allows you to configure build-time settings and processors for your Zudoku project. This file is executed during the build process and can be used to transform your API schemas before they are used in the documentation. :::tip{title="Security Note"} Unlike `zudoku.config.ts` which runs in both client and server environments, `zudoku.build.ts` runs exclusively in Node.js during build time. This means: - Sensitive operations (like API calls, file system access) can safely be performed - No build-time code or data is included in the final client bundle - Environment variables and secrets can be safely accessed - No browser-specific APIs are available ::: ## File Location Create a file named `zudoku.build.ts` in the root of your project: ```bash your-project/ ├── zudoku.config.ts ├── zudoku.build.ts # <-- Add this file └── ... ``` ## Basic Configuration Here's a basic example of a build configuration file: ```ts import type { ZudokuBuildConfig } from "zudoku"; const buildConfig: ZudokuBuildConfig = { processors: [ async ({ schema }) => { // Transform your schema here return schema; }, ], remarkPlugins: [], rehypePlugins: [], }; export default buildConfig; ``` ## Configuration Options ### `processors` An array of functions that transform your API schemas. Each processor receives: - `file`: The path to the schema file - `schema`: The OpenAPI schema object - `dereference`: A function to dereference the schema Processors are executed in order, and each processor receives the output of the previous one. :::tip For detailed information about processors and available built-in processors, see the [Schema Processors](../guides/processors) guide. ::: Here's a simple example that adds a description to all operations: ```ts async function addDescriptionProcessor({ schema }) { if (!schema.paths) return schema; // Add a description to all operations Object.values(schema.paths).forEach((path) => { Object.values(path).forEach((operation) => { if (typeof operation === "object" && operation) { operation.description = "This is a public API endpoint"; } }); }); return schema; } export default { processors: [addDescriptionProcessor], }; ``` ### `remarkPlugins` An array of [Remark](https://github.com/remarkjs/remark) plugins to transform Markdown content. These plugins run before the content is converted to HTML. ```ts import remarkContributors from "remark-contributors"; export default { remarkPlugins: [remarkContributors], }; ``` ### `rehypePlugins` An array of [Rehype](https://github.com/rehypejs/rehype) plugins to transform HTML content. These plugins run after Markdown is converted to HTML. ```ts import rehypeKatex from "rehype-katex"; export default { rehypePlugins: [rehypeKatex], }; ``` ### `prerender` Configuration for the prerendering process that generates static HTML pages during build time. - `workers`: Number of parallel workers to use for prerendering. Defaults to 80% of available CPU cores. ```ts import os from "node:os"; export default { prerender: { workers: 4, // Fixed number of workers }, }; // Or use a percentage of available CPU cores export default { prerender: { workers: Math.floor(os.cpus().length * 0.75), // Use 75% of available cores }, }; ``` --- ## Document: Overview URL: /docs/configuration/authentication # Overview If you use a managed authentication service, such as Auth0, Clerk, or OpenID, you can implement this into your site and allow users to browse and interact with your documentation and API reference in a logged in state. ## Configuration To implement the authentication option for your site, add the `authentication` property to the [Zudoku Configuration](./overview.md) file. The configuration is slightly different depending on the authentication provider you use. ## Authentication Providers Zudoku supports Clerk, Auth0, Supabase, Azure B2C, and any OpenID provider that supports the OpenID Connect protocol. Not seeing your authentication provider? [Let us know](https://github.com/zuplo/zudoku/issues) ### Auth0 For Auth0, you will need the `clientId` associated with the domain you are using. You can find this in the Auth0 dashboard under [Application Settings](https://auth0.com/docs/get-started/applications/application-settings). ```typescript { // ... authentication: { type: "auth0", domain: "yourdomain.us.auth0.com", clientId: "", scopes: ["openid", "profile", "email", "custom_scope"], }, // ... } ``` To setup Auth0, create a Single Page Application (SPA) application in the Auth0 dashboard. Set the following options: - Callback URL to `https://your-site.com/oauth/callback`. - For development environments only, we recommend configuring your app to allow the a wildcard callback like `https://*.zuplo.app/oauth/callback` to allow for testing each environment. - For local development, set the callback url to `http://localhost:3000/oauth/callback`. - Add your site hostname (your-site.com) to the list of allowed CORS origins. ### Clerk For Clerk you will need the publishable key for your application. You can find this in the Clerk dashboard on the [API Keys](https://dashboard.clerk.com/last-active?path=api-keys) page. ```typescript { // ... authentication: { type: "clerk", clerkPubKey: "", // Optional. See: https://clerk.com/docs/backend-requests/jwt-templates jwtTemplateName: "dev-portal", }, // ... } ``` ### OpenID For authentication services that support OpenID, you will need to supply an `clientId` and `issuer`. ```typescript { // ... authentication: { type: "openid", clientId: "", issuer: "", scopes: ["openid", "profile", "email", "custom_scope"] // Optional custom scopes }, // ... } ``` When configuring your OpenID provider, you will need to set the following: - Callback or Redirect URI to `https://your-site.com/oauth/callback`. - If your provider supports wildcard callback urls, we recommend configuring your development identity provider to allow a wildcard callback like `https://*.zuplo.site/oauth/callback` to allow for testing each environment. - For local development set the callback url to `http://localhost:3000/oauth/callback`. - Add your site hostname (your-site.com) to the list of allowed CORS origins. By default, the scopes "openid", "profile", and "email" are requested. You can customize these by providing your own array of scopes. ### Supabase To use Supabase as your authentication provider, supply your project's URL, API key, and the OAuth provider to use. ```typescript title="zudoku.config.ts" { // ... authentication: { type: "supabase", provider: "github", supabaseUrl: "https://your-project.supabase.co", supabaseKey: "", redirectToAfterSignUp: "/", redirectToAfterSignIn: "/", redirectToAfterSignOut: "/", }, // ... } ``` The `provider` option can be any of Supabase Auth's supported providers, such as `apple`, `azure`, `bitbucket`, `discord`, `facebook`, `figma`, `github`, `gitlab`, `google`, `kakao`, `keycloak`, `linkedin`, `linkedin_oidc`, `notion`, `slack`, `slack_oidc`, `spotify`, `twitch`, `twitter`, `workos`, `zoom`, or `fly`. ### Azure B2C For Azure B2C authentication, you will need to provide your Azure B2C tenant name, client ID, and policy name. ```typescript title="zudoku.config.ts" { // ... authentication: { type: "azureb2c", clientId: "", tenantName: "", policyName: "", issuer: "", scopes: ["openid", "profile", "email", "custom_scope"] }, // ... } ``` When configuring your Azure B2C application, you will need to set the following: - Redirect URI to `https://your-site.com/oauth/callback` - For local development, set the redirect URI to `http://localhost:3000/oauth/callback` - Add your site hostname (your-site.com) to the list of allowed CORS origins - Configure the appropriate user flows (policies) in your Azure B2C tenant By default, the scopes "openid", "profile", and "email" are requested. You can customize these by providing your own array of scopes. ## User Data After the user authenticates, the user profile is loaded via the provider's [User Info endpoint](https://openid.net/specs/openid-connect-core-1_0.html#UserInfo). The following fields are used to display the user profile: - `name` - The user's full name - `email` - The user's email address - `picture` - The user's profile picture URL - `email_verified` - Whether the user's email address has been verified If the provider does not return a field, it will be left blank. ## Protected Routes Once authentication is configured, you can protect specific routes in your documentation to require users to be authenticated or meet custom authorization requirements. ```typescript title="zudoku.config.ts" { // ... protectedRoutes: [ "/admin/*", // Protect all routes under /admin "/settings", // Protect the settings page "/api/*", // Protect all API-related routes ], // ... } ``` See the [Protected Routes](./protected-routes.md) documentation for detailed information on configuring route protection with simple patterns or advanced authorization logic. --- ## Document: Supabase Setup Learn how to set up Supabase authentication for Zudoku, leveraging Supabase's built-in auth providers for secure documentation access. URL: /docs/configuration/authentication-supabase # Supabase Setup Supabase is an open-source Firebase alternative that provides authentication, database, and storage services. This guide shows you how to integrate Supabase authentication with your Zudoku documentation site. ## Prerequisites You'll need a Supabase project. If you don't have one, [create a free Supabase project](https://supabase.com/dashboard) to get started. ## Setup Steps 1. **Configure Authentication Provider** In your [Supabase Dashboard](https://supabase.com/dashboard): - Navigate to **Authentication** → **Providers** - Enable your preferred authentication provider (GitHub, Google, Azure, etc.) - Configure the provider settings: - **Redirect URL**: `https://your-project.supabase.co/auth/v1/callback` - Copy any required credentials (Client ID, Client Secret) from the provider 2. **Get Your Project Credentials** From your Supabase project dashboard: - Go to **Settings** → **Data API** - Copy your **Project URL** (looks like `https://your-project.supabase.co`) - Go to **Settings** → **API Keys** - Copy your **anon public** API key 3. **Configure Zudoku** Add the Supabase configuration to your [Zudoku configuration file](./overview.md): ```ts title="zudoku.config.ts" export default { // ... other configuration authentication: { type: "supabase", providers: ["github"], // one or more providers supabaseUrl: "https://your-project.supabase.co", supabaseKey: "", }, // ... other configuration }; ``` You can configure multiple providers: ```ts title="zudoku.config.ts" export default { // ... other configuration authentication: { type: "supabase", providers: ["github", "google", "azure"], supabaseUrl: "https://your-project.supabase.co", supabaseKey: "", }, // ... other configuration }; ``` 4. **Install Supabase Dependencies** Add `@supabase/supabase-js` to your project dependencies: ```bash npm install @supabase/supabase-js @supabase/auth-ui-shared @supabase/auth-ui-react ``` ## Supported Providers Supabase supports numerous authentication providers. Use any of these values in the `providers` array: - `apple` - Sign in with Apple - `azure` - Microsoft Azure AD - `bitbucket` - Bitbucket - `discord` - Discord - `facebook` - Facebook - `figma` - Figma - `github` - GitHub - `gitlab` - GitLab - `google` - Google - `kakao` - Kakao - `keycloak` - Keycloak - `linkedin` / `linkedin_oidc` - LinkedIn - `notion` - Notion - `slack` / `slack_oidc` - Slack - `spotify` - Spotify - `twitch` - Twitch - `twitter` - Twitter/X - `workos` - WorkOS - `zoom` - Zoom - `fly` - Fly.io :::info Email/password authentication does not need to be specified as a provider because it is enabled by default in Supabase. To disable email/password authentication and only use OAuth providers, set `onlyThirdPartyProviders: true` in your configuration. ::: ## Configuration Options All available configuration options for Supabase authentication: ```ts title="zudoku.config.ts" authentication: { type: "supabase", // Provider configuration (required) // Array of one or more OAuth providers to enable providers: ["google", "github"], // Supabase credentials (required) supabaseUrl: "https://your-project.supabase.co", supabaseKey: "", // Optional: Custom base path for auth routes (default: "/") basePath: "/docs", // Optional: Disable email/password authentication, only use OAuth providers onlyThirdPartyProviders: true, // Optional: Redirect URLs after authentication events redirectToAfterSignUp: "/welcome", redirectToAfterSignIn: "/dashboard", redirectToAfterSignOut: "/", } ``` ### Authentication Routes The Supabase authentication provider automatically creates the following routes: - `/signin` - Sign in page with configured providers - `/signup` - Sign up page with configured providers - `/signout` - Sign out endpoint If you configure a custom `basePath`, these routes will be prefixed with that path (e.g., `/docs/signin`). ## Advanced Configuration ### User Profile Data Zudoku automatically extracts the following user information from Supabase authentication: - `sub` - User ID from Supabase - `email` - User's email address - `name` - User's full name (from `user_metadata.full_name` or `user_metadata.name`) - `emailVerified` - Whether the email has been confirmed - `pictureUrl` - User's avatar URL (from `user_metadata.avatar_url`) ### Additional User Metadata To store and access additional user information beyond what's provided by Supabase authentication: 1. Create a `profiles` table in your Supabase database 2. Set up a database trigger to create profile records on user signup 3. Use the Supabase client to query this data in your application Example profile table structure: ```sql CREATE TABLE profiles ( id UUID REFERENCES auth.users ON DELETE CASCADE, username TEXT UNIQUE, bio TEXT, created_at TIMESTAMPTZ DEFAULT NOW(), PRIMARY KEY (id) ); -- Create trigger to automatically create profile on user signup CREATE OR REPLACE FUNCTION public.handle_new_user() RETURNS TRIGGER AS $$ BEGIN INSERT INTO public.profiles (id) VALUES (new.id); RETURN new; END; $$ LANGUAGE plpgsql SECURITY DEFINER; CREATE TRIGGER on_auth_user_created AFTER INSERT ON auth.users FOR EACH ROW EXECUTE PROCEDURE public.handle_new_user(); ``` ## Troubleshooting ### Common Issues 1. **"At least one provider must be provided" Error**: You must configure the `providers` option in your authentication configuration with at least one authentication provider in the array. 2. **Invalid API Key**: Ensure you're using the `anon public` key, not the `service_role` key from your Supabase project settings. 3. **Provider Not Working**: Verify the provider is enabled in your Supabase dashboard and properly configured with the correct redirect URLs. 4. **Redirect URLs**: For local development, update your redirect URLs in both Supabase and the OAuth provider to include `http://localhost:3000`. 5. **CORS Errors**: Check that your site's domain is properly configured in Supabase's allowed URLs under **Authentication** → **URL Configuration**. 6. **Authentication Not Working**: Make sure you have installed all required dependencies: `@supabase/supabase-js`, `@supabase/auth-ui-react`, and `@supabase/auth-ui-shared`. ## Next Steps - Explore [Supabase Auth documentation](https://supabase.com/docs/guides/auth) for advanced features - Learn about [protecting routes](./authentication.md#protected-routes) in your documentation --- ## Document: PingFederate Setup Learn how to set up PingFederate authentication for Zudoku using OpenID Connect for enterprise-grade single sign-on. URL: /docs/configuration/authentication-pingfederate # PingFederate Setup PingFederate is an enterprise federation server that enables secure single sign-on (SSO) and API security for organizations. This guide walks you through integrating PingFederate with Zudoku using OpenID Connect. ## Prerequisites - Access to a PingFederate server (version 9.0 or later recommended) - Administrative access to configure OAuth clients in PingFederate - Your PingFederate server's base URL ## Setup Steps 1. **Create an OAuth Client in PingFederate** In the PingFederate administrative console: - Navigate to **Applications** → **OAuth** → **Clients** - Click **Add Client** - Configure the client: - **Client ID**: Choose a unique identifier (e.g., `zudoku-docs`) - **Client Authentication**: Select **None (Public Client)** - **Grant Types**: Enable **Authorization Code** and **Refresh Token** - **Redirect URIs**: - Production: `https://your-site.com/oauth/callback` - Preview (wildcard): `https://*.your-domain.com/oauth/callback` - Local Development: `http://localhost:3000/oauth/callback` 2. **Configure OpenID Connect Settings** Still in the OAuth client configuration: - Enable **OpenID Connect** - Configure scopes: - Enable `openid`, `profile`, and `email` (minimum required) - Add any custom scopes your organization requires - **ID Token Signing Algorithm**: RS256 (recommended) - **Access Token Manager**: Select or create an appropriate token manager - Save the configuration 3. **Configure Zudoku** Add the PingFederate configuration to your [Zudoku configuration file](./overview.md): ```typescript // zudoku.config.ts export default { // ... other configuration authentication: { type: "openid", clientId: "zudoku-docs", // Your OAuth client ID issuer: "https://pingfederate.your-domain.com", // Your PingFederate base URL scopes: ["openid", "profile", "email"], // Optional: add custom scopes }, // ... other configuration }; ``` ## Configuration Options ### Custom Scopes If your organization uses custom scopes for authorization, include them in the configuration: ```typescript authentication: { type: "openid", clientId: "zudoku-docs", issuer: "https://pingfederate.your-domain.com", scopes: ["openid", "profile", "email", "groups", "roles", "api:read"], } ``` ## Advanced Configuration ### CORS Configuration Configure CORS in PingFederate for your documentation site: 1. Navigate to **System** → **Server Configuration** → **Cross-Origin Resource Sharing** 2. Add your site's domain to the allowed origins: - `https://your-site.com` - `http://localhost:3000` (for local development) ### Attribute Mapping PingFederate can map user attributes from various sources. Ensure these standard claims are mapped: 1. Go to **OAuth** → **Access Token Management** → **Your Token Manager** 2. Configure attribute mappings: - `sub` → User's unique identifier - `name` → User's display name - `email` → User's email address - `picture` → User's profile picture URL (if available) ## Troubleshooting ### Common Issues 1. **Discovery Endpoint Not Found**: Ensure your issuer URL is correct and accessible. The OpenID Connect discovery endpoint should be available at `https://your-pingfederate-server/.well-known/openid-configuration`. 2. **Invalid Client Configuration**: Verify that the client ID matches exactly and that the redirect URIs are properly configured in PingFederate. 3. **CORS Errors**: Check that your site's domain is added to PingFederate's CORS configuration. 4. **Missing User Attributes**: Ensure attribute mappings are configured in your Access Token Manager. 5. **Token Validation Errors**: Verify that your PingFederate server's certificates are valid and that clock synchronization is accurate. ## Security Considerations - Always use HTTPS for production deployments - Regularly rotate signing certificates in PingFederate - Configure appropriate session timeouts - Review and audit OAuth client configurations periodically ## Next Steps - Review [PingFederate documentation](https://docs.pingidentity.com/pingfederate/) for advanced features - Learn about [protecting routes](./authentication.md#protected-routes) in your documentation - Configure group-based access control using PingFederate claims --- ## Document: Firebase Setup Learn how to set up Firebase Authentication for Zudoku, leveraging Google's secure authentication infrastructure with multiple sign-in providers. URL: /docs/configuration/authentication-firebase # Firebase Setup Firebase Authentication provides a comprehensive identity solution from Google, supporting email/password authentication and federated identity providers like Google, Facebook, Twitter, and more. This guide shows you how to integrate Firebase Authentication with your Zudoku documentation site. ## Prerequisites - A Google account to access Firebase Console - A Firebase project (free tier available) - Basic knowledge of Firebase configuration ## Setup Firebase 1. Go to the [Firebase Console](https://console.firebase.google.com/): 2. Click **Create a project** (or select an existing project) 3. Make sure authentication is enabled. Choose your preferred authentication providers. 4. Configure Authorized Domains, add your domains where the authentication will be used. 5. **Get Your Firebase Configuration** - Go to **Project settings** - Scroll to **Your apps** section - Click **Add app** → **Web** if you haven't already - Register your app with a nickname - Copy the Firebase configuration object ## Configure Zudoku Add the Firebase configuration to your [Zudoku configuration file](./overview.md): ```typescript title="zudoku.config.ts" export default { authentication: { type: "firebase", // Replace these with your Firebase project configuration // Get these values from Firebase Console > Project Settings apiKey: "", authDomain: "your-domain.firebaseapp.com", projectId: "your-project-id", appId: "1:296819355813:web:91d29f11cac6f073595d4c", // Optional fields storageBucket: "your-project.firebasestorage.app", messagingSenderId: "296819355813", measurementId: "G-12W6TTNR75", // Optional: specify which providers to show in the sign-in UI // Available providers: "google", "github", "facebook", "twitter", // "microsoft", "apple", "yahoo", "password", "phone" // If not specified, all enabled providers in Firebase will be available providers: ["google", "github", "password"], // Optional: configure redirect URLs after authentication redirectToAfterSignIn: "/docs", redirectToAfterSignUp: "/getting-started", redirectToAfterSignOut: "/", }, }; ``` --- ## Document: Clerk Setup Learn how to set up Clerk authentication for Zudoku, providing a seamless authentication experience with modern UI components and extensive customization options. URL: /docs/configuration/authentication-clerk # Clerk Setup Clerk is a modern authentication platform that provides beautiful, customizable UI components and a developer-friendly experience. This guide walks you through integrating Clerk authentication with your Zudoku documentation site. ## Prerequisites If you don't have a Clerk account, you can sign up for a [free Clerk account](https://clerk.com/) that provides 10,000 monthly active users. ## Setup Steps 1. **Create a Clerk Application** In the [Clerk Dashboard](https://dashboard.clerk.com/): - Click **Create Application** - Enter your application name - Select your preferred authentication methods (email, social providers, etc.) - Click **Create Application** 2. **Create a Clerk JWT Template** You need to create a JWT Template so your JWTs include name, email and email_verified information. - Navigate to **JWT templates** in the [Clerk Dashboard](https://dashboard.clerk.com/) - Create a new template by clicking **Add new template** - Pick a name for the template - Add the following claims ```json { "name": "{{user.full_name}}", "email": "{{user.primary_email_address}}", "email_verified": "{{user.email_verified}}" } ``` - Save 3. **Configure Zudoku** Get your publishable key from the Clerk dashboard: - Navigate to **API Keys** in your Clerk dashboard - Copy the **Publishable key** Use the JWT template name defined in the previous section Add the Clerk configuration to your [Zudoku configuration file](./overview.md): ```typescript // zudoku.config.ts export default { // ... other configuration authentication: { type: "clerk", clerkPubKey: "", jwtTemplateName: "", }, // ... other configuration }; ``` 4. **Configure Redirect URLs (Optional)** If you need custom redirect behavior, configure the allowed redirect URLs in Clerk: - Go to **Paths** in your Clerk dashboard - Add your production, preview, and local development URLs to the allowed redirect URLs - Common patterns: - Production: `https://your-site.com/oauth/callback` - Preview (wildcard): `https://*.your-domain.com/oauth/callback` - Local Development: `http://localhost:3000/oauth/callback` 5. **Install Clerk Dependencies** Add `@clerk/clerk-js` to your project dependencies: ```bash npm install @clerk/clerk-js ``` ## Troubleshooting ### Common Issues 1. **Invalid Publishable Key**: Ensure you're using the publishable key (starts with `pk_`) and not the secret key. 2. **Authentication Not Working**: Verify that your Clerk application is active and not in development mode when deploying to production. 3. **Redirect Issues**: Check that your domain is added to the allowed redirect URLs in Clerk if using custom redirects. 4. **ReferenceError: can't access lexical declaration 'xxx' before initialization**: Make sure you have installed Clerk to your project. ## Next Steps - Explore [Clerk's documentation](https://clerk.com/docs) for advanced features - Learn about [protecting routes](./authentication.md#protected-routes) in your documentation - Configure [user roles and permissions](https://clerk.com/docs/organizations/roles-permissions) in Clerk --- ## Document: Azure AD Setup Learn how to set up Azure Active Directory (Microsoft Entra ID) authentication for Zudoku, enabling secure single sign-on for your organization. URL: /docs/configuration/authentication-azure-ad # Azure AD Setup Azure Active Directory (now Microsoft Entra ID) provides enterprise-grade authentication and authorization for organizations using Microsoft's cloud identity platform. This guide shows you how to integrate Azure AD with your Zudoku documentation site. ## Prerequisites - An Azure subscription with Azure Active Directory - Administrative access to register applications in Azure AD - Your Azure AD tenant ID ## Setup Steps 1. **Register an Application in Azure AD** In the [Azure Portal](https://portal.azure.com): - Navigate to **Azure Active Directory** → **App registrations** - Click **New registration** - Configure your application: - **Name**: Enter a descriptive name (e.g., "Zudoku Documentation") - **Supported account types**: Choose based on your needs: - Single tenant (your organization only) - Multitenant (any Azure AD directory) - Multitenant + personal Microsoft accounts - **Redirect URI**: - Platform: **Single-page application (SPA)** - URI: `https://your-site.com/oauth/callback` - Click **Register** 2. **Configure Authentication Settings** In your newly registered application: - Go to **Authentication** in the left menu - Under **Single-page application**, add redirect URIs: - Production: `https://your-site.com/oauth/callback` - Preview (wildcard): `https://*.your-domain.com/oauth/callback` - Local Development: `http://localhost:3000/oauth/callback` - Under **Implicit grant and hybrid flows**: - Enable **ID tokens** - Enable **Access tokens** - Configure **Supported account types** if needed - Save your changes 3. **Configure API Permissions (Optional)** If you need specific permissions: - Go to **API permissions** - Click **Add a permission** - Select **Microsoft Graph** → **Delegated permissions** - Add permissions like `User.Read`, `email`, `profile`, `openid` - Grant admin consent if required by your organization 4. **Configure Zudoku** Get your application details from the Azure Portal: - Go to **Overview** page of your app registration - Copy the **Application (client) ID** - Copy the **Directory (tenant) ID** Add the configuration to your [Zudoku configuration file](./overview.md): ```typescript // zudoku.config.ts export default { // ... other configuration authentication: { type: "openid", clientId: "", issuer: "https://login.microsoftonline.com//v2.0", scopes: ["openid", "profile", "email"], // Optional: customize scopes }, // ... other configuration }; ``` 5. **Install Azure AD Dependencies** Add `@azure/msal-browser` to your project dependencies: ```bash npm install @azure/msal-browser ``` ## Configuration Options ### Single Tenant vs Multitenant For single tenant (organization-only access): ```typescript authentication: { type: "openid", clientId: "", issuer: "https://login.microsoftonline.com//v2.0", scopes: ["openid", "profile", "email"], } ``` For multitenant (any Azure AD organization): ```typescript authentication: { type: "openid", clientId: "", issuer: "https://login.microsoftonline.com/common/v2.0", scopes: ["openid", "profile", "email"], } ``` ### Custom Scopes and Permissions Request additional Microsoft Graph API scopes: ```typescript authentication: { type: "openid", clientId: "", issuer: "https://login.microsoftonline.com//v2.0", scopes: [ "openid", "profile", "email", "User.Read", "GroupMember.Read.All" // For group-based access control ], } ``` ### Protected Routes Protect specific documentation routes using the `protectedRoutes` configuration: ```typescript { // ... other configuration authentication: { type: "openid", // ... Azure AD config }, protectedRoutes: [ "/api/*", // Protect all API documentation "/internal/*", // Protect internal documentation "/admin/*" // Protect admin sections ], } ``` ## Advanced Configuration ### Conditional Access Policies Azure AD supports conditional access policies that can: - Require multi-factor authentication - Restrict access by location - Enforce device compliance - Control session lifetime Configure these in Azure AD Portal under **Security** → **Conditional Access**. ### App Roles and Groups To implement role-based access control: 1. In your app registration, go to **App roles** 2. Create custom roles (e.g., "Documentation.Read", "Documentation.Admin") 3. Assign roles to users or groups in **Enterprise applications** 4. Access role claims in your application ### B2B Guest Access To allow external partners access: 1. Enable B2B collaboration in Azure AD 2. Configure external collaboration settings 3. Invite guest users to your directory 4. Grant appropriate permissions to your application ## User Data Azure AD provides rich user profile data through OpenID Connect: - `name` - User's display name - `email` - User's email address - `picture` - Profile picture URL (when available) - `email_verified` - Email verification status - `preferred_username` - User's UPN (User Principal Name) - Additional claims based on your API permissions ## Troubleshooting ### Common Issues 1. **Invalid Client Error**: Ensure the client ID is correct and the application is properly registered. 2. **Redirect URI Mismatch**: The redirect URI must exactly match one configured in Azure AD, including protocol and path. 3. **Tenant Access Issues**: For single-tenant apps, ensure users are from the correct tenant. For multi-tenant, verify the issuer URL uses "common" or "organizations". 4. **Missing User Information**: Check that required API permissions are granted and admin consent is provided if needed. 5. **Token Validation Errors**: Ensure your issuer URL is correct and includes the `/v2.0` endpoint for the Microsoft identity platform. 6. **Authentication Not Working**: Make sure you have installed `@azure/msal-browser` to your project. ## Security Best Practices - Use single-tenant configuration unless multi-tenant is specifically required - Implement conditional access policies for sensitive documentation - Regularly review and audit app permissions - Monitor sign-in logs in Azure AD for suspicious activity - Use app roles for fine-grained access control ## Next Steps - Explore [Microsoft identity platform documentation](https://docs.microsoft.com/en-us/azure/active-directory/develop/) - Learn about [protecting routes](./authentication.md#protected-routes) in your documentation - Implement [app roles](https://docs.microsoft.com/en-us/azure/active-directory/develop/howto-add-app-roles-in-azure-ad-apps) for advanced authorization --- ## Document: Auth0 Setup Learn how to set up Auth0 authentication for Zudoku, including application configuration and integration steps for secure API documentation access. URL: /docs/configuration/authentication-auth0 # Auth0 Setup Auth0 is a flexible authentication and authorization platform that integrates seamlessly with Zudoku. This guide walks you through setting up Auth0 authentication for your documentation site. ## Prerequisites If you don't have an Auth0 account, you can sign up for a [free Auth0 account](https://auth0.com/signup) that provides 7,000 monthly active users. ## Setup Steps 1. **Create Auth0 Application** [Create a new Auth0 application](https://auth0.com/docs/get-started/auth0-overview/create-applications) in the Auth0 dashboard: - Select type **Single Page Web Applications** - Give your application a descriptive name 2. **Configure Auth0 Application** In your Auth0 application settings, configure the following: **Application URLs:** - **Allowed Callback URLs**: - Production: `https://your-site.com/oauth/callback` - Preview (wildcard): `https://*.your-domain.com/oauth/callback` - Local Development: `http://localhost:3000/oauth/callback` - **Allowed Logout URLs**: Same as callback URLs above - **Allowed Web Origins**: - Production: `https://your-site.com` - Preview (wildcard): `https://*.your-domain.com` - Local development: `http://localhost:3000` **Refresh Token Rotation:** - **Allow Refresh Token Rotation**: Enabled - **Rotation Overlap Period**: 0 seconds (recommended) Keep the default **Refresh Token Expiration** settings unless you have specific requirements. 3. Create an Auth0 API: - Navigate to the [APIs section](https://manage.auth0.com/#/apis) in the Auth0 dashboard - Click **Create API** - Set a name (e.g., "Zudoku API") and an identifier (e.g., `https://your-domain.com/api`) - Choose **RS256** as the signing algorithm - Save the API :::warning This step is important. If you skip creating an API, Zudoku will not be able to validate the tokens issued by Auth0, leading to authentication failures. ::: 4. **Configure Zudoku** Add the Auth0 configuration to your [Zudoku configuration file](./overview.md): ```typescript // zudoku.config.ts export default { // ... other configuration authentication: { type: "auth0", domain: "your-domain.us.auth0.com", clientId: "", audience: "https://your-domain.com/api", // Your Auth0 API identifier }, // ... other configuration }; ``` Where: - **domain**: Your Auth0 domain (found in your application's Basic Information) - **clientId**: The Client ID from your Auth0 application settings - **audience**: The identifier of the Auth0 API you created (e.g., `https://your-domain.com/api`) ## Advanced Configuration ### Custom Scopes If you need additional scopes for your API access, you can specify them in the configuration: ```typescript authentication: { type: "auth0", domain: "your-domain.us.auth0.com", clientId: "", scopes: ["openid", "profile", "email", "read:api", "write:api"], } ``` ### Customizing the Prompt Parameter By default, Zudoku sets `prompt="login"` in the Auth0 authorization request, which forces users to re-enter their credentials even if they have a valid session. You can customize this behavior using the `options.prompt` configuration: ```typescript authentication: { type: "auth0", domain: "your-domain.us.auth0.com", clientId: "", audience: "https://your-domain.com/api", options: { prompt: "", // Omit the prompt parameter to allow silent authentication }, } ``` Valid values for the `prompt` parameter include: - `"login"` - Force users to re-enter their credentials even if they have a valid session (default) - `"consent"` - Force users to consent to authorization even if they previously consented - `"select_account"` - Force users to select an account (useful for multi-account scenarios) - `"none"` - No prompt is shown; silent authentication only - `""` (empty string) - Omit the prompt parameter, allowing Auth0 to handle authentication based on session state When the prompt parameter is omitted (empty string), Auth0 will: - Silently authenticate the user if they have a valid session - Redirect to the login page if no valid session exists ## Troubleshooting ### Common Issues 1. **Callback URL Mismatch**: Ensure your callback URLs in Auth0 exactly match your site's URL, including the `/oauth/callback` path. 2. **CORS Errors**: Add your site's domain to the Allowed Web Origins in Auth0. 3. **Authentication Loop**: Check that your Auth0 domain includes the protocol (`https://`) but no trailing slash. 4. **Token Validation Errors**: Ensure the audience in your Zudoku configuration matches the identifier of the Auth0 API you created. ## Next Steps - Learn about [protecting routes](./authentication.md#protected-routes) in your documentation - Explore other [authentication providers](./authentication.md#authentication-providers) supported by Zudoku - Configure [user permissions](./authentication.md#user-data) based on Auth0 roles --- ## Document: API Reference Learn how to configure the `apis` setting in Zudoku to generate API reference documentation from OpenAPI files, including file and URL references, versioning, customization options, and OpenAPI extensions. URL: /docs/configuration/api-reference # API Reference The `apis` configuration setting in the [Zudoku Configuration](./overview.md) file allows you to specify the OpenAPI document that you want to use to generate your API reference documentation. There are multiple ways to reference an API file in the configuration including using a URL or a local file path. The OpenAPI document can be in either JSON or YAML format. ## File Reference You can reference a local OpenAPI document by setting the `type` to `file` and providing the path to the file. ```ts title=zudoku.config.ts const config = { // ... apis: { type: "file", input: "./openapi.json", // Supports JSON and YAML files (ex. openapi.yaml) path: "/api", }, // ... }; ``` ## URL Reference :::danger{title="Recommendation"} We strongly recommend using `type: "file"` for your OpenAPI schemas. When using URL based references, all schema processing occurs at runtime in the browser. This can cause noticeable performance issues with large OpenAPI documents and some features may not be fully supported due to the added complexity of runtime processing. ::: If your OpenAPI document is accessible elsewhere via URL you can use this configuration, changing the `input` value to the URL of your own OpenAPI document (you can use the Rick & Morty API document if you want to test and play around): ```ts title=zudoku.config.ts const config = { // ... apis: { type: "url", input: "https://rickandmorty.zuplo.io/openapi.json", path: "/api", }, // ... }; ``` :::caution{title="CORS Policy"} If you are using a URL to reference your OpenAPI document, you may need to ensure that the server hosting the document has the correct CORS policy in place to allow the Zudoku site to access it. ::: ## Versioning ### File-based Versioning When using `type: "file"`, you can provide an array of file paths to create versioned API documentation. Version metadata is automatically extracted from each OpenAPI schema at build time: ```ts title=zudoku.config.ts const config = { apis: { type: "file", input: [ // Order of the array determines the order of the versions "./openapi-v2.json", "./openapi-v1.json", ], path: "/api", }, }; ``` ### URL-based Versioning When using `type: "url"`, you can provide an array of version configurations. Since URL-based schemas cannot be processed at build time, you must explicitly specify the version identifier and optional label: ```ts title=zudoku.config.ts const config = { apis: { type: "url", input: [ { path: "v2", label: "Version 2.0", input: "https://api.example.com/openapi-v2.json", }, { path: "v1", label: "Version 1.0", input: "https://api.example.com/openapi-v1.json", }, ], path: "/api", }, }; ``` Each URL version object requires: - `path`: Version identifier used in the URL path (e.g., `/api/v2`) - `input`: URL to the OpenAPI document - `label`: Optional display name for the version selector (defaults to `path` if not provided) ## Options The `options` field allows you to customize the API reference behavior: ```ts title=zudoku.config.ts const config = { apis: { type: "file", input: "./openapi.json", path: "/api", options: { examplesLanguage: "shell", // Default language for code examples disablePlayground: false, // Disable the interactive API playground disableSidecar: false, // Disable the sidecar completely showVersionSelect: "if-available", // Control version selector visibility expandAllTags: true, // Control initial expanded state of tag categories schemaDownload: { enabled: true }, // Enable schema download button }, }, }; ``` Available options: - `examplesLanguage`: Set default language for code examples - `disablePlayground`: Disable the interactive API playground globally - `showVersionSelect`: Control version selector visibility - `"if-available"`: Show version selector only when multiple versions exist (default) - `"always"`: Always show version selector (disabled if only one version) - `"hide"`: Never show version selector - `expandAllTags`: Control initial expanded state of tag categories (default: `true`) - `schemaDownload`: Enable schema download functionality with `{ enabled: boolean }`. When enabled, displays a button allowing users to download the OpenAPI schema, copy it to clipboard, open in a new tab, or use it with AI tools like Claude and ChatGPT. ## Default Options Instead of setting options for each API individually, you can use `defaults.apis` to set global defaults that apply to all APIs: ```ts title=zudoku.config.ts const config = { defaults: { apis: { examplesLanguage: "shell", // Default language for code examples disablePlayground: false, // Disable the interactive API playground showVersionSelect: "if-available", // Control version selector visibility expandAllTags: false, // Control initial expanded state of tag categories schemaDownload: { enabled: true }, // Enable schema download button }, }, apis: { type: "file", input: "./openapi.json", path: "/api", }, }; ``` Individual API options will override these defaults when specified. ## Extensions Zudoku supports OpenAPI extensions (properties starting with `x-`) to customize behavior at different levels of your API documentation. ### Operations - `x-zudoku-playground-enabled`: Control playground visibility for an operation (default: `true`) - `x-explorer-enabled`: Alias for `x-zudoku-playground-enabled` for compatibility Example: ```json { "paths": { "/users": { "get": { "summary": "Get users", "x-zudoku-playground-enabled": false // Disable playground for this operation } } } } ``` ### Tags Extensions that can be applied to tag categories: - `x-zudoku-collapsed`: Control initial collapsed state of a tag category (default: `true`) - `x-zudoku-collapsible`: Control if a tag category can be collapsed (default: `true`) Example: ```json { "tags": [ { "name": "Users", "x-zudoku-collapsed": false } ] } ``` ### Tag Groups Use `x-tagGroups` at the root of your OpenAPI document to group tags together in the navigation: ```yaml x-tagGroups: - name: Shipment tags: - Packages - Parcels - Letters ``` ## Metadata Your API reference page metadata is sourced directly from your OpenAPI spec. The [`info`](https://spec.openapis.org/oas/v3.1.0#info-object) object is used set the corresponding tags in the page's `head`. | Metadata Property | OpenAPI Property | Comment | | ----------------- | ---------------- | ---------------------------------------------------------------------------------------------------------------------------------------------- | | title | `info.title` | If `metadata.title` is set as a template string (ex. `%s - My Company`) it will be used | | description | `info.summary` | `info.summary` is preferred as it is shorter and plaintext-only, but Zudoku will fall back to the `info.description` if no summary is provided | --- ## Document: API Catalog URL: /docs/configuration/api-catalog # API Catalog If you're dealing with multiple APIs and multiple OpenAPI files, the API Catalog comes in handy. It creates an overview of all your APIs and lets you organize them into categories and tags. ## Enable API Catalog The first step to enable the API Catalog, you need to add a `catalogs` object to your Zudoku configuration file. ```js title=zudoku.config.ts const config = { // ... catalogs: { path: "/catalog", label: "API Catalog", }, // ... }; ``` You can then add your APIs to the catalog by adding the `categories` property to your API configuration. ```js title=zudoku.config.ts const config = { // ... apis: [ // ... { type: "file", input: "./operational.json", path: "/api-operational", categories: [{ label: "General", tags: ["Operational"] }], }, { type: "file", input: "./enduser.json", path: "/api-enduser", categories: [{ label: "General", tags: ["End-User"] }], }, { type: "file", input: "./openapi.json", path: "/api-auth", categories: [{ label: "Other", tags: ["Authentication"] }], }, // ... ], // ... }; ``` ## Advanced Configuration ### Select APIs to show in the catalog You can select which APIs are shown in the catalog by using the `items` property. The `items` property is an array of navigation IDs of the APIs you want to show in the catalog. ```js title=zudoku.config.ts const config = { // ... catalogs: { path: "/catalog", label: "API Catalog", // Only show the operational API in the catalog items: ["api-operational"], }, apis: [ // ... { type: "file", input: "./operational.json", path: "/api-operational", categories: [{ label: "General", tags: ["Operational"] }], }, { type: "file", input: "./enduser.json", path: "/api-enduser", categories: [{ label: "General", tags: ["End-User"] }], }, ], // ... }; ``` ### Filtering catalog items You can filter which APIs are shown in the catalog by using the `filterItems` property. The function receives the items and context as arguments. ```js title=zudoku.config.ts const config = { // ... catalogs: { path: "/catalog", label: "API Catalog", filterItems: (items, { auth: AuthState }) => { return items.filter((items) => items.tags.includes(auth)); }, }, // ... }; ``` --- ## Document: Authentication Providers & API Identities URL: /docs/concepts/auth-provider-api-identities # Authentication Providers & API Identities When building an API documentation portal, you often need to provide a way for users to authenticate their API requests. This typically involves managing API keys and different authentication identities. However, implementing a secure and user-friendly system for API key management can be complex and time-consuming. Zudoku provides a powerful solution to this problem through its API Keys and Identities system. ## Authentication Providers and API Identities :::tip **Authentication providers** allow your users to sign in to your documentation portal. **API Identities** allow your users to authenticate their API requests. ::: Before diving into API Identities, it's important to understand that Zudoku separates user authentication from API authentication. Authentication providers handle how users sign in to your documentation portal, while API Identities manage how these users interact with your APIs. Authentication providers (like Auth0 or custom JWT) handle: - User authentication for the documentation portal - Session management - User authorization and access control This separation allows you to: - Use different authentication methods for your portal and APIs - Manage API access independently of user authentication - Support multiple API authentication schemes simultaneously [Learn more about authentication providers](../configuration/authentication) ## Understanding API Identities API Identities in Zudoku represent different authentication contexts that can be used to make API requests. These could be different environments (production, staging), different authentication methods (API key, JWT), or different service accounts. ### The API Identity Interface ```typescript interface ApiIdentity { id: string; label: string; authorizeRequest: (request: Request) => Promise | Request; } interface ApiIdentityPlugin { getIdentities: () => Promise | ApiIdentity[]; } ``` Each API Identity consists of: - `id`: A unique identifier for the identity - `label`: A human-readable name shown in the UI - `authorizeRequest`: A function that modifies requests to include the necessary authentication ## Implementing API Identities In this example, we'll use Auth0 as our authentication provider and implement an API Identity for a demo API. :::note This example shows how to implement API Identities in Zudoku. If you're using Zuplo and you are using the built-in API Key management system, you don't need to implement this yourself. Zuplo will handle API Identities for you. ::: To add API Identities to your Zudoku configuration, you need to implement the `ApiIdentityPlugin` interface. Here's an example: ```typescript import { createApiIdentityPlugin } from "zudoku/plugins"; export default { authentication: { type: "auth0", domain: "my-domain.auth0.com", clientId: "my-client-id", }, plugins: [ createApiIdentityPlugin({ getIdentities: async (context) => [ { id: "api-key-one", label: "My API Key", authorizeRequest: (request) => { // We get the access token from the // authentication provider (Auth0) and add it to the request headers return context.authentication?.signRequest(request); }, }, ], }), ], }; ``` When implemented, this identity will appear in the Zudoku playground. --- ## Document: Typography URL: /docs/components/typography # Typography import { Typography } from "zudoku/components"; The Typography component applies consistent prose styling to text content using [Tailwind's typography plugin](https://github.com/tailwindlabs/tailwindcss-typography). It automatically formats headings, paragraphs, lists, and other text elements with appropriate spacing, ## Import ```tsx import { Typography } from "zudoku/components"; ``` font sizes, and styling that adapts to both light and dark themes. This component is particularly useful when rendering markdown content or when you need consistent text formatting across your documentation. ## Props ```ts type TypographyProps = { children: React.ReactNode; className?: string; }; ``` ## Usage Wrap any content that needs prose formatting with the Typography component. It will automatically style headings, paragraphs, lists, and other text elements: ```tsx import { Typography } from "zudoku/components";

Hello World

This is a paragraph

  • Item 1
  • Item 2
  • Item 3
; ``` ## Example

Hello World

This is a paragraph

  • Item 1
  • Item 2
  • Item 3
--- ## Document: Tooltip URL: /docs/components/tooltip # Tooltip import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger, TooltipArrow, } from "zudoku/ui/Tooltip"; import { Button } from "zudoku/ui/Button"; A tooltip component built on Radix UI primitives for displaying helpful information on hover or focus. ## Import ```tsx import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger, TooltipArrow, } from "zudoku/ui/Tooltip"; ``` ## Components The Tooltip component consists of several sub-components: - `TooltipProvider` - Provides context for tooltip behavior - `Tooltip` - The main container (root) - `TooltipTrigger` - Element that triggers the tooltip - `TooltipContent` - The tooltip content container - `TooltipArrow` - Optional arrow pointing to the trigger ## Basic Usage

Add to library

```tsx

Add to library

``` ## With Arrow

Add to library

```tsx

Add to library

``` ## Different Sides

Top tooltip

Right tooltip

Bottom tooltip

Left tooltip

```tsx

Top tooltip

Right tooltip

Bottom tooltip

Left tooltip

``` ## Global Provider For multiple tooltips, wrap your app with `TooltipProvider`: ```tsx function App() { return {/* Your app content with tooltips */}; } ``` ## Features - **Keyboard Navigation**: Accessible via keyboard focus - **Positioning**: Smart positioning to stay within viewport - **Delay Control**: Configurable show/hide delays - **Animation**: Smooth enter/exit animations - **Accessibility**: Full screen reader and keyboard support --- ## Document: Textarea URL: /docs/components/textarea # Textarea import { Textarea } from "zudoku/ui/Textarea"; import { Label } from "zudoku/ui/Label"; A multiline text input component for forms and user input. ## Import ```tsx import { Textarea } from "zudoku/ui/Textarea"; ``` ## Basic Usage