npm package: @supatent/supatent-docs
Description: Static-first docs framework for Next.js using Supatent content.
Latest version: 0.6.0

# @supatent/supatent-docs

Static-first docs framework for Next.js using Supatent content.

## Install

```bash
npm i @supatent/supatent-docs
```

## Minimal setup

```ts
// docs.config.ts
import { defineDocsConfig } from "@supatent/supatent-docs";

export const docsConfig = defineDocsConfig({
  supatent: {
    baseUrl: process.env.SUPATENT_BASE_URL || "https://app.supatent.ai",
    projectSlug: process.env.SUPATENT_PROJECT_SLUG!,
  },
  schemas: {
    settings: process.env.DOCS_SCHEMA_SETTINGS!,
    page: process.env.DOCS_SCHEMA_PAGE!,
    category: process.env.DOCS_SCHEMA_CATEGORY!,
  },
  routing: {
    basePath: process.env.DOCS_BASE_PATH || "/docs",
    defaultLocale: process.env.DOCS_DEFAULT_LOCALE || "en-US",
    locales: (process.env.DOCS_LOCALES || "en-US").split(",").map((x) => x.trim()),
  },
});
```

```ts
// app/layout.tsx
import "@supatent/supatent-docs/styles.css";

export { docsMetadata as metadata } from "@supatent/supatent-docs/next";
export { DocsRootLayout as default } from "@supatent/supatent-docs/next";
```

```ts
// app/page.tsx
export { DocsHomePage as default } from "@supatent/supatent-docs/next";
```

```ts
// app/[locale]/docs-internal/[[...slug]]/page.tsx
export {
  DocsInternalPage as default,
  generateDocsPageStaticParams as generateStaticParams,
} from "@supatent/supatent-docs/next";

export const dynamicParams = false;
```

To opt into request-time rendering instead:

```ts
import { DocsInternalPageDynamic } from "@supatent/supatent-docs/next";

export const dynamic = "force-dynamic";
export default DocsInternalPageDynamic;
```

The docs entry URL is `/docs` (or your configured `DOCS_BASE_PATH`). It redirects to the resolved locale route.

```ts
// next.config.ts
import type { NextConfig } from "next";
import { withSupatentDocs } from "@supatent/supatent-docs/next-config";

const nextConfig: NextConfig = {};
export default withSupatentDocs(nextConfig);
```

`next build` generates:
- `public/.supatent-docs/search/*` search index assets
- `public/.supatent-docs/ai/{locale}/{index|all}.json` static AI outputs

By default, `/docs/{locale}/ai/{index|all}` is served from static AI artifacts.
To force dynamic AI handlers instead:

```ts
export default withSupatentDocs(nextConfig, {
  ai: { mode: "dynamic" },
});
```

The navbar brand/logo link target is read from the docs settings singleton.
Add a `brand-href` text field to your `docs-settings` schema and set it in content when the brand should link somewhere like `/`.
If that setting is missing, the brand falls back to the locale docs home such as `/docs/en-US`.

## Bundler compatibility

- Public runtime entrypoints (`@supatent/supatent-docs/next`, `@supatent/supatent-docs/next-config`) resolve to built ESM in `dist/*`.
- This avoids Turbopack module-type failures that can occur when dependency subpaths point to raw TypeScript files.

## Required Supatent schemas

`DOCS_SCHEMA_SETTINGS`, `DOCS_SCHEMA_CATEGORY`, and `DOCS_SCHEMA_PAGE` must point to schemas that include the fields below.

Recommended schema slugs:

- `docs-settings` (`isSingleton: true`)
- `docs-category` (`isSingleton: false`)
- `docs-page` (`isSingleton: false`)

Settings schema fields:

| Field slug | Required | Type | Interface | Purpose |
|---|---|---|---|---|
| `site-title` | Yes | `text` | `textInput` | Navbar/site title |
| `logo` | No | `image` | `singleImage` | Navbar logo (left of title) |
| `brand-href` | No | `text` | `textInput` | Navbar brand/logo click target |

Category schema fields:

| Field slug | Required | Type | Interface | Purpose |
|---|---|---|---|---|
| `title` | Yes | `text` | `textInput` | Category label in nav |
| `order` | Yes | `number` | `numberInput` | Category sort order |

Page schema fields:

| Field slug | Required | Type | Interface | Purpose |
|---|---|---|---|---|
| `title` | Yes | `text` | `textInput` | Page title |
| `body` | Yes | `markdown` | `markdownEditor` | Page content |
| `category` | Yes | `text` | `textInput` | Category content slug reference |
| `order` | Yes | `number` | `numberInput` | Page sort order inside category |

Minimal schema examples:

```json
{
  "slug": "docs-settings",
  "name": "Docs Settings",
  "isSingleton": true,
  "fields": [
    { "slug": "site-title", "name": "Site Title", "type": "text", "interface": "textInput", "order": 0 },
    { "slug": "logo", "name": "Logo", "type": "image", "interface": "singleImage", "order": 1 },
    { "slug": "brand-href", "name": "Brand Href", "type": "text", "interface": "textInput", "order": 2 }
  ]
}
```

```json
{
  "slug": "docs-category",
  "name": "Docs Category",
  "isSingleton": false,
  "fields": [
    { "slug": "title", "name": "Title", "type": "text", "interface": "textInput", "order": 0 },
    { "slug": "order", "name": "Order", "type": "number", "interface": "numberInput", "order": 1 }
  ]
}
```

```json
{
  "slug": "docs-page",
  "name": "Docs Page",
  "isSingleton": false,
  "fields": [
    { "slug": "title", "name": "Title", "type": "text", "interface": "textInput", "order": 0 },
    { "slug": "body", "name": "Body", "type": "markdown", "interface": "markdownEditor", "order": 1 },
    { "slug": "category", "name": "Category", "type": "text", "interface": "textInput", "order": 2 },
    { "slug": "order", "name": "Order", "type": "number", "interface": "numberInput", "order": 3 }
  ]
}
```

```ts
// proxy.ts
import { docsProxy } from "@supatent/supatent-docs/next";

export const proxy = docsProxy;
export const config = {
  matcher: ["/((?!_next|api|favicon.ico|robots.txt|sitemap.xml).*)"],
};
```

For the full integration guide and examples, see:
- [Repo README](https://github.com/supatent/supatent-docs/blob/main/README.md)
- [Integration test shell](https://github.com/supatent/supatent-docs/tree/main/test_project)