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

@ccatto/nest-pages

v1.0.1

Published

Catto Pages - NestJS module for admin-authored nested content pages (a page CMS): tree, path resolution, drag-reorder, draft/publish

Readme

@ccatto/nest-pages

A page CMS for NestJS apps — admin-authored, nested content pages (docs, guides, knowledge bases) that render from your DB, with the site nav generated from the page tree. Keyed by a generic namespace / slug / parentId, so any app can host one or more page trees without a bespoke schema.

Mirrors @ccatto/nest-comments: you inject your app's Prisma and add the Page model to your own schema.prisma. Admin mutations reuse @ccatto/nest-auth guards — no reinvented auth. Pairs with the frontend @ccatto/react-pages.

Admin-authored content — no profanity/moderation here. Pages are written by platform admins; user-generated content (comments) lives in @ccatto/nest-comments. Do still sanitize the Markdown body when rendering (the frontend does this) to guard against stored XSS.

Install

yarn add @ccatto/nest-pages

Peers: @nestjs/common/core/graphql (>=12), class-validator, class-transformer, reflect-metadata, @ccatto/nest-auth (its GqlAuthGuard + PlatformAdminGuard guard the admin operations).

Setup

1. Add the Prisma model (documented, app-added)

enum PageStatus { DRAFT PUBLISHED }

model Page {
  id          String     @id @default(cuid())
  namespace   String     // scopes a tree, e.g. "pickle_talk"
  slug        String     // path segment, unique among siblings
  parentId    String?    // nesting; null = top level
  title       String
  body        String     // Markdown (rendered sanitized by the frontend)
  excerpt     String?
  icon        String?
  status      PageStatus @default(DRAFT)
  order       Int        @default(0)   // sibling order (drag-reorder)
  updatedById String?
  createdAt   DateTime   @default(now())
  updatedAt   DateTime   @updatedAt

  @@unique([namespace, parentId, slug])
  @@index([namespace, status])
  @@map("page")
}

2. Register the module

CattoAuthModule (from @ccatto/nest-auth) must also be registered.

import { CattoPagesModule } from '@ccatto/nest-pages';
import { PrismaService } from './prisma/prisma.service';

@Module({
  imports: [CattoPagesModule.forRoot({ prismaToken: PrismaService })],
})
export class AppModule {}

forRoot options: prismaToken (required), pageModel ('page'), slugify (default provided), deleteWithChildren ('reject' default, or 'cascade').

GraphQL API

| Operation | Auth | Notes | | --- | --- | --- | | pageTree(namespace) | public | nested tree, PUBLISHED only, ordered — powers the nav | | pageByPath(namespace, path) | public | one page for rendering (PUBLISHED); path = "a/b/c" slug chain | | pagesForAdmin(namespace) | admin | full tree incl. drafts + bodies (the editor loads from this) | | createPage(input) | admin | auto-slugifies title when slug omitted | | updatePage(id, input) | admin | slug only changes when explicitly provided | | deletePage(id) | admin | reject (default) or cascade when it has children | | reorderPages(parentId, orderedIds) | admin | persists sibling order | | movePage(id, newParentId) | admin | re-parent (lands at end of the group) |

Admin = @ccatto/nest-auth's PlatformAdminGuard. Public reads never return drafts, so there's no optional-auth complexity — admins preview drafts via pagesForAdmin. Every node carries a computed path (the full slug chain).

Comments by page (with @ccatto/nest-comments)

Attach comments to a page with a stable key — use the page id (survives renames/moves):

entityType: `${namespace}_page`   // e.g. "pickle_talk_page"
entityKey:  page.id

License

MIT