npm package: @next-library/core
Description: Core functionality for Next.js documentation framework
Author: FAKGROUP
Latest version: 1.0.38

# @next-library/core

Core utilities for a **Next.js (App Router)** documentation site backed by markdown in a **GitHub repository**: content tree generation, page data extraction, GitHub fetch, i18n helpers, markdown processing, and SEO helpers. **No UI components** — pair with [`@next-library/theme`](../theme/README.md) or build your own.

## Documentation hub (start here)

Extended guides live in the monorepo **[`docs/`](../../docs/README.md)**. Prefer them over long README drift:

| Topic | Guide |
|--------|--------|
| End-to-end setup | [Getting started](../../docs/getting-started.md) |
| `library.config.ts` | [Configuration](../../docs/configuration.md) |
| CLI vs runtime | [Architecture](../../docs/architecture.md) |
| Docs repo layout | [Content repository](../../docs/content-repository.md) |
| Export index | [API reference](./docs/api.md) |

**Supported workflow:** run **`next-library generate`** (often from `predev` / `prebuild`) to emit **`lib/tree.ts`**. Import **`contentTree`** and call **`extractPageData(contentTree, locale, slugSegments)`**. You do **not** need `withLibrary` or a virtual **`@next-library/tree`** module.

## Features

- Multi-language content (repo layout + `i18n/`), RTL-aware helpers
- Markdown pipeline (syntax highlighting, math, diagrams — see theme for rendering)
- GitHub API integration for tree generation and raw file fetch
- SEO: metadata helpers and JSON-LD builders
- TypeScript-first

## Installation

```bash
pnpm add @next-library/core
```

## Quick start

### 1. Config

```typescript
// library.config.ts
import type { LibraryConfigInput } from '@next-library/core';

export const libraryConfig: LibraryConfigInput = {
  github: {
    user: 'org-or-user',
    repo: 'your-docs-repo',
    branch: 'main',
    token: process.env.GITHUB_TOKEN,
  },
  i18n: {
    cookieName: process.env.NEXT_PUBLIC_LOCALE_COOKIE_NAME || 'NEXT_LOCALE',
  },
  website: {
    title: 'My docs',
    description: 'Documentation',
    siteUrl: process.env.NEXT_PUBLIC_SITE_URL || 'http://localhost:3000',
    organizationName: 'My org',
    organizationLogo: '/logo.png',
  },
};
```

### 2. Generate `lib/tree.ts`

```json
{
  "scripts": {
    "predev": "node ./node_modules/@next-library/core/dist/cli/generate.cjs generate",
    "prebuild": "node ./node_modules/@next-library/core/dist/cli/generate.cjs generate"
  }
}
```

### 3. Use the tree at runtime

```typescript
import contentTree from '@/lib/tree';
import {
  extractPageData,
  isValidLocale,
  getSupportedLocales,
  createConfig,
  type Locale,
} from '@next-library/core';
import { loadDocumentationMarkdown } from '@next-library/core/server';
import { libraryConfig } from '@/library.config';

const fullConfig = createConfig(libraryConfig);
const locale = 'en' as Locale;
const slug = ['guides', 'intro'];
const pageData = extractPageData(contentTree, locale, slug);

const locales = getSupportedLocales(contentTree);

if (pageData.node?.githubPath && fullConfig.github?.user && fullConfig.github?.repo) {
  const markdown = await loadDocumentationMarkdown(pageData.node.githubPath, {
    contentDir: fullConfig.tree?.contentBodiesDir,
    github: {
      user: fullConfig.github.user,
      repo: fullConfig.github.repo,
      branch: fullConfig.github.branch || 'main',
      token: fullConfig.github.token,
      app: fullConfig.github.app,
    },
  });
}
```

Merge runtime config with **`createConfig(libraryConfig)`** so GitHub and website settings match what the CLI used to build the tree.

## How it works

### Build time (or pre-dev)

1. **`next-library generate`** loads **`library.config.ts`**, calls **`generateContentTree`**, writes **`lib/tree.ts`**, and (by default) writes **markdown bodies + `manifest.json`** under **`tree.contentBodiesDir`** (default **`.next-library/content`**, gitignored). Use **`--no-content-bodies`** to skip body output (Next will fetch from GitHub during build/runtime instead).
2. Run **`next build`** after generate so static pages read bodies from disk (fast SSG, no per-page GitHub raw fetch). In CI/Vercel, set **`NEXT_LIBRARY_CONTENT_DIR`** if bodies live outside the default path.
3. Next.js bundles **`lib/tree.ts`** like any other TypeScript module.

**Operational:** run generate with a **GitHub token or app** so contributor commits populate **`lastCommitAt`** on nodes (better metadata without extra API calls at page render).

### Runtime

1. Routes import **`contentTree`** and resolve locale (e.g. **`isValidLocale`**).
2. **`extractPageData(contentTree, locale, slug)`** returns **`PageData`**: node, sidebars, breadcrumbs, prev/next, computed flags.
3. **`loadDocumentationMarkdown`** (from **`@next-library/core/server`**) reads from the generated content directory when present, otherwise falls back to **`fetchRawFileContent`**. The **`/server`** entry uses Node **`fs`** and must not be imported from client components.

```mermaid
sequenceDiagram
  participant CLI as next_library_generate
  participant GH as GitHub_API
  participant Tree as lib_tree.ts
  participant Bodies as content_bodies_dir
  participant Page as App_Route
  participant Core as extractPageData

  CLI->>GH: List and read markdown
  CLI->>Tree: Write ContentTree module
  CLI->>Bodies: Write body files plus manifest
  Page->>Tree: import contentTree
  Page->>Core: extractPageData(tree, locale, slug)
  Core-->>Page: PageData
  Page->>Bodies: loadDocumentationMarkdown
  Bodies-->>Page: markdown
```

### PageData (summary)

`extractPageData` returns navigation, sidebars, **`computed`** (`pathExists`, `isFolderView`, `lang`, fallback flags, etc.), and **`node`** (or `null`). For field-level detail, use your editor on **`PageData`** in `src/lib/content/page-data/types.ts` or see the [example app](../../example/app/).

## Configuration

Types live in **`src/lib/config/types.ts`**. At runtime, **`createConfig(libraryConfig)`** produces a merged **`LibraryConfig`**.

See **[Configuration](../../docs/configuration.md)** for **`github`**, **`website`**, **`i18n`**, env vars, and CLI config discovery.

## Content repository layout

English (or primary locale) at repo root; other locales under **`i18n/<locale>/`** mirroring paths. See **[Content repository](../../docs/content-repository.md)**.

## Utilities (tree-first)

Pass the same **`contentTree`** you use in pages.

```typescript
import contentTree from '@/lib/tree';
import {
  extractPageData,
  getSupportedLocales,
  getContentMetadataBySlug,
  generateStaticContentPaths,
  getBreadcrumbs,
  getSiblingPages,
  type Locale,
} from '@next-library/core';

const locale = 'en' as Locale;
const slug = ['api', 'reference'];

const pageData = extractPageData(contentTree, locale, slug);
const meta = getContentMetadataBySlug(contentTree, slug, locale);
const paths = generateStaticContentPaths(contentTree);
const crumbs = getBreadcrumbs(contentTree, 'api/reference', locale);
const siblings = getSiblingPages(contentTree, 'api/reference', locale);
```

### i18n

```typescript
import {
  isValidLocale,
  isLocaleEnabled,
  getTextDirection,
  getLocaleMetadata,
  isRightToLeft,
  getSupportedLocales,
} from '@next-library/core';
import contentTree from '@/lib/tree';

isValidLocale('en');
getSupportedLocales(contentTree);
getTextDirection('ar');
```

### SEO

```typescript
import {
  generatePageMetadata,
  generateArticleSchema,
  generateBreadcrumbSchema,
} from '@next-library/core';

const metadata = generatePageMetadata(
  { title: 'Page', description: '…', canonicalUrl: 'https://…', lang: 'en' },
  websiteConfig
);
```

Use **`generateAlternateLanguageUrls(contentTree, path, baseUrl)`** when wiring hreflang (see **`example/app/[locale]/docs/[[...slug]]/page.tsx`** in the monorepo).

### Static params

```typescript
import contentTree from '@/lib/tree';
import { generateStaticContentPaths } from '@next-library/core';

export async function generateStaticParams() {
  const paths = generateStaticContentPaths(contentTree);
  return paths.map((p) =>
    p.slug.length > 0 ? { locale: p.lang, slug: p.slug } : { locale: p.lang }
  );
}
```

### Markdown processing

```typescript
import { processMarkdown } from '@next-library/core';

const processed = await processMarkdown(markdownContent, {
  allowHtml: true,
  allowMath: true,
  syntaxHighlighting: true,
  sanitize: true,
  cacheEnabled: true,
});
```

### GitHub / doc markdown

Prefer **`loadDocumentationMarkdown`** so SSG uses files from **`next-library generate`** when **`tree.contentBodiesDir`** is set. **`fetchRawFileContent`** remains available for direct raw fetches.

```typescript
import { createConfig } from '@next-library/core';
import { loadDocumentationMarkdown } from '@next-library/core/server';
import { libraryConfig } from '@/library.config';

const config = createConfig(libraryConfig);
const gh = config.github;
if (gh?.user && gh?.repo) {
  await loadDocumentationMarkdown('path/in/repo.md', {
    contentDir: config.tree?.contentBodiesDir,
    github: {
      user: gh.user,
      repo: gh.repo,
      branch: gh.branch || 'main',
      token: gh.token,
      app: gh.app,
    },
  });
}
```

**Speed Insights / TTFB:** after `generate` + `build`, doc HTML should not wait on GitHub; confirm **`NEXT_LIBRARY_CONTENT_DIR`** matches your CI output if you override the default directory.

## Hooks (client only)

```typescript
'use client';
import { useLocale } from '@next-library/core/hooks';
```

## Proxy / locale routing

For Next.js **proxy** handling (locale detection / redirects), use **`handleLocaleRequest`** from the main package:

```typescript
// proxy.ts
import { handleLocaleRequest } from '@next-library/core';
import type { NextRequest } from 'next/server';

export async function proxy(request: NextRequest) {
  return handleLocaleRequest(request);
}
```

## Markdown pipeline (overview)

```
Raw Markdown → frontmatter → remark (gfm, math, …) → rehype (slug, highlight, mermaid, sanitize) → HTML + TOC
```

## TypeScript

```typescript
import type {
  LibraryConfig,
  LibraryConfigInput,
  ContentTree,
  ContentNode,
  PageData,
  Locale,
} from '@next-library/core';
```

## API reference

See **[./docs/api.md](./docs/api.md)** for a structured export index.

## Contributing

See **[CONTRIBUTING.md](../../CONTRIBUTING.md)**.

## License

MIT