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

p1-knowledge-seo

v0.1.0

Published

Sitemap, robots.txt, and llms.txt builders for P1 Knowledge CMS sites (SEO / GEO discovery)

Readme

p1-knowledge-seo

Configurable sitemap, robots.txt, and llms.txt builders for sites powered by the P1 Knowledge CMS. Framework-agnostic core with optional Next.js App Router adapters.

| Surface | API | |---------|-----| | Public route model | createKnowledgeSeo, getPublicSeoRoutes, mergePublicSeoRoutes | | /sitemap.xml | toSitemapEntries → Next routesToNextSitemap or pure buildSitemapXml | | /robots.txt | buildRobotsRulestoNextRobots | | /llms.txt / /llms-full.txt | buildLlmsTxt, buildLlmsFullTxtllmsTextResponse | | Webhook path helper | slugAndLocaleToPath |

Zero hard runtime dependencies. Works with @p1/knowledge-client / @p1/knowledge-next via a duck-typed client, or with any listDocuments fn.

Docs: Architecture · API reference · Install & publish · Contributing · Changelog · Examples


Install

npm install p1-knowledge-seo
# or
pnpm add p1-knowledge-seo

# Adjacent checkout
pnpm add p1-knowledge-seo@file:../p1-knowledge-seo

Optional peer (only if you import the Next adapters):

pnpm add next
import { createKnowledgeSeo } from 'p1-knowledge-seo';
import { routesToNextSitemap } from 'p1-knowledge-seo/next';

Note: The npm name is unscoped p1-knowledge-seo (not @p1/knowledge-seo).


Quick start (Next.js App Router)

// lib/seo.ts
import { createKnowledgeSeo } from 'p1-knowledge-seo';
import { createClient } from '@p1/knowledge-next'; // optional

export const seo = createKnowledgeSeo({
  siteUrl: () => process.env.NEXT_PUBLIC_APP_URL!,
  client: createClient(), // or omit + pass listDocuments
  coreRoutes: [
    {
      path: '/',
      title: 'Home',
      description: 'Product overview',
      priority: 1,
      changefreq: 'daily',
    },
    {
      path: '/pricing',
      title: 'Pricing',
      description: 'Plans',
      priority: 0.8,
    },
  ],
  // Unioned with package base (login, api, sitemap.xml, _next, …)
  reservedPathSegments: ['app', 'organic'],
  onError: (err, ctx) => console.error('knowledge-seo', ctx, err),
  llms: {
    siteName: 'My Product',
    tagline: 'One-line pitch for agents',
    intro: 'What this site is and how agents should use public pages.',
    privateProductNote: 'Authenticated app routes are not for public crawl.',
    contactLinks: [
      { label: 'Support', path: '/support' },
      { label: 'Legal', path: '/legal' },
    ],
    markdownAlternatePaths: ['/'],
  },
  robots: {
    disallow: ['/admin/', '/api/', '/app/'],
    aiBots: 'default',
  },
  sitemap: { hreflang: true },
});
// app/sitemap.ts
import { routesToNextSitemap } from 'p1-knowledge-seo/next';
import { seo } from '@/lib/seo';

export const revalidate = 3600;

export default async function sitemap() {
  const routes = await seo.getPublicSeoRoutes();
  return routesToNextSitemap(routes, seo.resolveSiteUrl());
}
// app/robots.ts
import { toNextRobots } from 'p1-knowledge-seo/next';
import { seo } from '@/lib/seo';

export default function robots() {
  return toNextRobots(seo.buildRobotsRules());
}
// app/llms.txt/route.ts
import { llmsTextResponse } from 'p1-knowledge-seo/next';
import { seo } from '@/lib/seo';

export const revalidate = 3600;

export async function GET() {
  return llmsTextResponse(await seo.buildLlmsTxt());
}
// app/api/webhooks/knowledge/route.ts
import { createKnowledgeWebhookHandler } from '@p1/knowledge-next/webhook';
import { seo } from '@/lib/seo';

export const POST = createKnowledgeWebhookHandler({
  slugToPath: (slug, locale) => seo.slugAndLocaleToPath(slug, locale),
});

Without a Knowledge client, pass listDocuments + hasAuth:

createKnowledgeSeo({
  siteUrl: 'https://example.com',
  listDocuments: async (opts) => myCms.list(opts),
  hasAuth: true, // false → core routes only (skip CMS)
  // …
});

Pure XML sitemap (any framework)

const xml = await seo.buildSitemapXml();
// or for very large sites:
const docs = await seo.buildSitemapDocuments(undefined, { maxPerFile: 50_000 });

What the host app owns

  • Core public routes and reserved path segments (product areas only — base list is free)
  • Brand / product copy for llms.txt
  • robots disallow list for authenticated product paths
  • Knowledge API credentials and published content
  • Optional onError / onDrop for observability

Empty CMS credentials → sitemap/llms still work with core routes only. CMS errors fail open so discovery surfaces stay up.


Develop & validate

git pull origin main
pnpm install          # always after pull — installs tsc, vitest, biome, …
pnpm validate         # ensure-deps + build + test + typecheck + lint
pnpm pack:check       # dry-run tarball contents

| Error | Fix | |-------|-----| | tsc: command not found | pnpm install | | biome: command not found | pnpm install (Biome is a devDependency) |

Runnable demo: node examples/basic/run.mjs (after build).


Publish to npm

Full guide: docs/PUBLISH.md.

pnpm install
pnpm validate
npm publish               # unscoped public package

| | | |--|--| | Package name | p1-knowledge-seo | | Access | Public (unscoped). Never use --access restrictedEUNSCOPED |

With a version bump:

npm version patch
npm publish
git push origin main --follow-tags

Consumers (examples)

| Consumer | Install | |----------|---------| | matext-web | pnpm add p1-knowledge-seo or file:../p1-knowledge-seo | | Other apps | pnpm add p1-knowledge-seo after publish |

If using a file: path, ensure dist/ exists (pnpm build or prepare on install).


License

See LICENSE.