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

@pagenary/publisher

v2026.6.0

Published

Multi-tenant static publishing component for Pagenary platform.

Downloads

1,445

Readme

Pagenary Publisher

Where documentation takes shape.

@pagenary/publisher is the static site generator behind Pagenary — it turns one shared template catalog into many branded, tenant-specific documentation sites. Zero runtime dependencies, hash-based routing, full-text search, and a Git-aware build pipeline. Install it as a dev dependency and drive it with the pagenary CLI.

npm install --save-dev @pagenary/publisher   # add Pagenary to your project
npx pagenary build:tenants my-docs           # build your docs tenant
npx pagenary serve                           # serve on http://localhost:5173

npm version npm downloads Docs License: AGPL v3 Node Version

Docs Site · Quick Start · Features · Tenant Workflow · Documentation


What It Is

The publisher takes a catalog of shared section templates plus per-tenant content and configuration and produces a self-contained documentation bundle for each tenant. Each bundle is a static single-page app — hash-based routing (#/page-id), no server-side rendering, no runtime dependencies — that you build once and host anywhere that serves files. Tenants share the template catalog but keep isolated content, branding, navigation, and domains, so one repository can publish a dozen distinct sites.


Quick Start

Install the package and drive it with the pagenary CLI — no clone required. New here? Follow the Getting Started guide.

npm install --save-dev @pagenary/publisher

npx pagenary build:tenants my-docs   # build your tenant (see Tenant Registry below)
npx pagenary serve                   # preview on http://localhost:5173

Commands: build, build:tenants [id], tenants:list, serve (run npx pagenary --help). The package also ships a compiled reference site under site/ — the Pagenary docs, built by Pagenary itself.

Building from source (contributors / modifying Pagenary):

npm install
npm run dev         # build + serve with watch mode
npm run build       # build default bundle to dist/

Features

Content Authoring

  • Markdown — write in .md files with full CommonMark support
  • HTML — direct markup control with .html files
  • JavaScript Modules — dynamic content with .js files returning { html, afterRender? }
  • Nested Directories — organize content in subdirectories (content/guides/setup.md)

Rich Content

  • Mermaid Diagrams — flowcharts, sequence diagrams, state machines, and more
  • Syntax Highlighting — Prism.js with 10+ language support
  • Markdown Tables — full table syntax with alignment support
  • HTML Components — spec tables, layer stacks, box diagrams, cards
  • Internal Links — auto-resolved #section-id links in Markdown

External Links

  • Navigation Links — add external URLs directly in the manifest with a url property
  • Smart Link Handling — external links open in a new tab with security headers (rel="noopener noreferrer")
  • Visual Indicators — a subtle ↗ icon marks external destinations
  • CTA Styling — button-like external-cta class for prominent external links

Navigation & Search

  • Command PaletteCtrl/Cmd+K or / opens a global finder
  • Full-Text Search — searches all content, not just titles
  • Manifest-Driven Nav — declarative navigation structure
  • Keyboard Navigation — arrow keys, Enter to select

Theming & Branding

  • Custom ColorsaccentColor and surfaceColor per tenant
  • Brand Identity — logo text, tagline, copyright
  • Typography — IBM Plex Sans/Mono defaults, customizable

SEO (built in)

  • Absolute URLs — declare a domain (or seo.siteUrl) and the sitemap, canonical, og:url, and robots URLs become fully-qualified
  • Static snapshots — crawler-friendly /pages/<id>.html for every section, self-canonical (the SPA hash route isn't crawlable)
  • sitemap.xml, robots.txt, llms.txt — generated automatically
  • JSON-LD + Open GraphTechArticle/BreadcrumbList per page, optional Organization data, and og:image/twitter:image via seo.ogImage

Export & Sharing

  • Export Options — Current Page or Entire Site
  • Branded Exports — tenant logo, brand name, and tagline in the export header
  • Document Export — one-click HTML export with a table of contents, print-optimized for PDF

Tenant Content Workflow

Directory Structure

my-tenant/
├── config.json           # Branding, theme, and SEO settings
├── manifest.json         # Navigation structure (optional)
├── content/              # Content files
│   ├── welcome.md        # Root-level content
│   ├── guides/           # Nested directory
│   │   ├── _manifest.json  # Section manifest
│   │   ├── getting-started.md
│   │   └── advanced.md
│   └── api/
│       ├── _manifest.json
│       └── reference.md
└── overrides/            # Post-build file replacements (optional)

Content Types

Markdown (.md)

# Getting Started

Welcome to the docs. Here's a code example:

\`\`\`javascript
console.log('Hello, Pagenary!');
\`\`\`

And a Mermaid diagram:

\`\`\`mermaid
graph LR
    A[Start] --> B[Build]
    B --> C[Deploy]
\`\`\`

HTML (.html)

<section class="section doc">
  <h1>Custom HTML Section</h1>
  <table class="spec-table">
    <tr><th>Feature</th><th>Status</th></tr>
    <tr><td>Search</td><td>Ready</td></tr>
  </table>
</section>

JavaScript (.js)

export async function load() {
  const data = await fetch('/api/metrics.json').then(r => r.json());
  return {
    html: `<section><h1>Metrics: ${data.count}</h1></section>`,
    afterRender(container) {
      // DOM manipulation after render
    }
  };
}

Manifest Configuration

Root manifest.json (optional — auto-generated from content/ if omitted):

[
  { "id": "welcome", "title": "Welcome", "file": "welcome.md" },
  {
    "id": "guides",
    "title": "Guides",
    "subsections": [
      { "id": "guides/getting-started", "title": "Getting Started", "file": "guides/getting-started.md" },
      { "id": "guides/advanced", "title": "Advanced Usage", "file": "guides/advanced.md" }
    ]
  }
]

Section _manifest.json (in content subdirectories):

{
  "title": "API Reference",
  "sections": [
    { "id": "overview", "title": "Overview", "file": "overview.md" },
    { "id": "endpoints", "title": "Endpoints", "file": "endpoints.md" }
  ]
}

External links in the manifest (use url instead of file):

[
  { "id": "welcome", "title": "Welcome", "file": "welcome.md" },
  { "title": "Support Portal", "url": "https://support.example.com" }
]

Branding & SEO Configuration

config.json:

{
  "title": "My Documentation",
  "description": "Comprehensive guide to our platform",
  "brandMark": "ACME",
  "brandSub": "Docs",
  "tagline": "Build better, faster",
  "copyright": "ACME Corp",
  "accentColor": "#6366F1",
  "surfaceColor": "#F7FAFC",
  "domain": "docs.acme.com",
  "seo": {
    "siteUrl": "https://docs.acme.com",
    "ogImage": "/assets/og-card.png",
    "structuredData": { "organizationName": "ACME Corporation" }
  }
}

| Property | Description | Default | |----------|-------------|---------| | title | Browser tab title | "Documentation" | | description | Meta description for SEO | - | | brandMark | Primary brand text (bold) | "DOCS" | | brandSub | Secondary brand text (light) | "TOOLKIT" | | tagline | Subtitle under brand | - | | copyright | Footer copyright text | - | | accentColor | Links, buttons, highlights | #111111 | | surfaceColor | Background color (hex) | #ffffff | | domain | Canonical domain; also the SEO base URL when seo.siteUrl is unset | - | | seo | SEO block — see Tenant Configuration | - |


Build Commands

With the package installed (the default):

npx pagenary build                    # build the default bundle to dist/
npx pagenary build:tenants            # build all enabled tenants
npx pagenary build:tenants my-tenant  # build a specific tenant
npx pagenary tenants:list             # list configured tenants
npx pagenary serve                    # serve dist/ on localhost:5173

From source (clone — adds dev/utility scripts):

npm run build:incremental my-tenant  # git-aware incremental rebuild
npm run dev                          # build + serve with watch
npm run lint:content                 # check trailing whitespace/tabs
npm run check:seo                    # verify SEO metadata
npm run check                        # run all checks
npm test                             # run test suite

Tenant Registry

Register tenants in a tenants.json at your project root (validated by the bundled tenants.schema.json):

{
  "tenants": [
    {
      "id": "my-docs",
      "source": { "type": "local", "path": "./docs" },
      "strictLinks": true
    },
    {
      "id": "client-portal",
      "source": { "type": "git", "url": "https://github.com/org/client-docs.git", "ref": "main" },
      "domains": ["docs.client.com"]
    }
  ]
}

Source types:

  • Local: { "type": "local", "path": "./relative/or/abs/path" }
  • Git: { "type": "git", "url": "https://…", "ref": "main", "path": "subdir" }

Per-tenant options include enabled (default true), strictLinks (default true — fail the build on broken internal links), and domains (for the multi-tenant Caddy router). See Tenant Configuration.


Docker Caddy Workflow

For multi-tenant domain testing:

# Add to /etc/hosts:
# 127.0.0.1 my-docs.local client-portal.local

npm run build:tenants   # build tenants
npm run caddy:up        # start Caddy
# Visit http://my-docs.local or http://client-portal.local

npm run caddy:logs      # tail logs
npm run caddy:reload    # reload config without restart
npm run caddy:restart   # full restart
npm run caddy:down      # stop container

Use a non-privileged port: DOCS_TOOLKIT_PORT=5173 npm run caddy:up


Repository Layout

apps/publisher/
├── src/
│   ├── index.html          # SPA shell
│   ├── app.js              # Router and core logic
│   ├── styles.css          # All styling
│   ├── manifest.js         # Default navigation
│   ├── seo.js              # Runtime meta tag management
│   ├── mermaid-init.js     # Diagram rendering
│   ├── syntax-highlight.js # Code highlighting
│   └── lib/                # search, router, export
├── scripts/
│   ├── build.js            # Core build script
│   ├── build-tenants.js    # Multi-tenant builder
│   ├── serve.js            # Dev server
│   └── lib/seo-generator.js # Sitemap, robots, snapshots, JSON-LD
├── tenants/                # Built-in example tenants
├── docs/                   # Documentation
└── Caddyfile, docker-compose.yml  # Multi-tenant routing

Documentation

The full documentation site is published at docs.pagenary.com — built by this publisher from the source below. Read it online, or browse the source:


License

GNU Affero General Public License v3.0 — strong copyleft. You may use, modify, and distribute Pagenary, but if you run a modified version to provide a network service, you must make the modified source available to its users. See LICENSE.


Back to Top

Made with care by Joseph Magly