npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@next-library/core

v1.0.38

Published

Core functionality for Next.js documentation framework

Readme

@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 or build your own.

Documentation hub (start here)

Extended guides live in the monorepo docs/. Prefer them over long README drift:

| Topic | Guide | |--------|--------| | End-to-end setup | Getting started | | library.config.ts | Configuration | | CLI vs runtime | Architecture | | Docs repo layout | Content repository | | Export index | API reference |

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

pnpm add @next-library/core

Quick start

1. Config

// 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

{
  "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

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.
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.

Configuration

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

See Configuration 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.

Utilities (tree-first)

Pass the same contentTree you use in pages.

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

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

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

SEO

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

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

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.

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)

'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:

// 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

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

API reference

See ./docs/api.md for a structured export index.

Contributing

See CONTRIBUTING.md.

License

MIT