@supatent/supatent-docs
v0.6.0
Published
Static-first docs framework for Next.js using Supatent content.
Readme
@supatent/supatent-docs
Static-first docs framework for Next.js using Supatent content.
Install
npm i @supatent/supatent-docsMinimal setup
// 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()),
},
});// 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";// app/page.tsx
export { DocsHomePage as default } from "@supatent/supatent-docs/next";// 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:
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.
// 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 assetspublic/.supatent-docs/ai/{locale}/{index|all}.jsonstatic AI outputs
By default, /docs/{locale}/ai/{index|all} is served from static AI artifacts.
To force dynamic AI handlers instead:
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 indist/*. - 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:
{
"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 }
]
}{
"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 }
]
}{
"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 }
]
}// 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:
