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 🙏

© 2025 – Pkg Stats / Ryan Hefner

@nextlevels/crud

v0.0.2

Published

**CRUD Factory Package** - Generiere komplette CRUD-Operationen in wenigen Zeilen! 🚀

Readme

@nextlevels/crud

CRUD Factory Package - Generiere komplette CRUD-Operationen in wenigen Zeilen! 🚀

Features

Auto-generierte tRPC Router mit allen CRUD-Operationen ✅ Auto-generierte DataTable Columns mit Actions ✅ Auto-generierte List Pages mit Pagination & Sorting ✅ Type-Safe - Vollständige TypeScript-Unterstützung ✅ DRY - Kein duplizierter Code mehr! ✅ Flexible - Einfach anzupassen und zu erweitern


Quick Start

1. Entity Config erstellen

import { Role } from "@prisma/client";
import mySchema from "@/schema/my-schema";

const entityConfig = {
  name: "myEntity",
  schema: mySchema,
  permissions: [Role.ADMIN, Role.SUPERADMIN],
  labels: {
    singular: "Mein Entity",
    plural: "Meine Entities",
    description: "Verwalte alle Entities",
  },
};

2. Router erstellen (1 Zeile!)

import { createEntityRouter } from "@nextlevels/crud/router";
import {
  createTRPCRouter,
  protectedProcedure,
  publicProcedure,
} from "@/server/api/trpc";

export const myEntityRouter = createTRPCRouter(
  createEntityRouter(entityConfig, { publicProcedure, protectedProcedure })
);

Das war's! Du hast jetzt:

  • fetchAll - Alle Entities abrufen (public)
  • fetchPaginated - Paginierte Liste (protected)
  • fetchById - Einzelnes Entity (protected)
  • create - Neues Entity erstellen (protected)
  • update - Entity bearbeiten (protected)
  • delete - Entity löschen (protected)

3. Columns erstellen

import { createEntityColumns } from "@nextlevels/crud/columns";

export function getColumns({ isLoading, onSuccess } = {}) {
  const deleteMutation = api.myEntity.delete;

  return createEntityColumns({
    entityName: "myEntity",
    singularLabel: "Mein Entity",
    basePath: "/admin/my-entities",
    deleteMutation,
    isLoading,
    onSuccess,
    columns: [
      { key: "name", label: "Name", sortable: true },
      {
        key: "status",
        label: "Status",
        render: (value) => (value ? "Aktiv" : "Inaktiv"),
      },
    ],
  });
}

4. List Page erstellen

import { createListPage } from "@nextlevels/crud/pages";

const MyEntityListPage = createListPage({
  pluralLabel: "Meine Entities",
  singularLabel: "Mein Entity",
  description: "Verwalte alle Entities hier.",
  basePath: "/admin/my-entities",
  useQuery: api.myEntity.fetchPaginated.useQuery,
  columns: getColumns(),
});

export default MyEntityListPage;

API Reference

createEntityRouter(config, builder)

Erstellt einen vollständigen tRPC Router mit CRUD-Operationen.

Parameter:

  • config: EntityConfig - Entity-Konfiguration
  • builder: { publicProcedure, protectedProcedure } - tRPC Builder

Returns: Router mit folgenden Endpoints:

  • fetchAll(input?) - Alle Entities (limit, where)
  • fetchPaginated(input) - Paginierte Liste
  • fetchById(input) - Einzelnes Entity
  • create(input) - Neues Entity
  • update(input) - Entity bearbeiten
  • delete(input) - Entity löschen

createEntityColumns(options)

Erstellt DataTable Columns mit Actions.

Parameter:

  • entityName: string - Entity-Name
  • singularLabel: string - Singular-Label
  • basePath: string - Basis-Pfad (z.B. /admin/videos)
  • columns: ColumnConfig[] - Column-Definitionen
  • deleteMutation - tRPC Delete Mutation
  • isLoading?: boolean - Loading-State
  • onSuccess?: () => void - Success-Callback
  • displayField?: string - Feld für Delete-Bestätigung (default: "name")

ColumnConfig:

{
  key: string;              // Feld-Name
  label: string;            // Column-Header
  sortable?: boolean;       // Sortierbar? (default: true)
  render?: (value) => any;  // Custom Renderer
  accessor?: (item) => any; // Custom Accessor
}

createListPage(options)

Erstellt eine List-Page Component.

Parameter:

  • pluralLabel: string - Plural-Label
  • singularLabel: string - Singular-Label
  • description?: string - Beschreibung
  • basePath: string - Basis-Pfad
  • useQuery - tRPC Query Hook
  • columns: ColumnDef[] - Table Columns
  • initialPageSize?: number - Initiale Page-Size (default: 10)

Vergleich: Vorher vs. Nachher

Router

Vorher: 237 Zeilen Code pro Entity Nachher: ~15 Zeilen Code

// Vorher: video.ts (237 Zeilen)
export const videoRouter = createTRPCRouter({
  fetchAll: publicProcedure.input(...).query(async ({ ctx, input }) => {
    // 25 Zeilen
  }),
  fetchPaginated: protectedProcedure.input(...).query(async ({ input, ctx }) => {
    // 50 Zeilen
  }),
  // ... +160 Zeilen mehr
});

// Nachher: video-new.ts (15 Zeilen)
const videoConfig = { ... };
export const videoRouter = createTRPCRouter(
  createEntityRouter(videoConfig, { publicProcedure, protectedProcedure })
);

Columns

Vorher: 148 Zeilen Code pro Entity Nachher: ~20 Zeilen Code

List Page

Vorher: 73 Zeilen Code pro Entity Nachher: ~15 Zeilen Code


Advanced Usage

Custom Permissions Check

const config = {
  name: "myEntity",
  schema: mySchema,
  permissions: [Role.ADMIN, Role.SUPERADMIN],
  // ...
};

Custom Default Sort

const config = {
  name: "myEntity",
  schema: mySchema,
  defaultSort: {
    field: "createdAt",
    order: "desc",
  },
  // ...
};

Custom Prisma Model Name

const config = {
  name: "tire",
  prismaModel: "Tire", // Falls anders als Entity-Name
  // ...
};

Custom Column Renderer

columns: [
  {
    key: "status",
    label: "Status",
    render: (value) => (
      <Badge variant={value ? "success" : "destructive"}>
        {value ? "Aktiv" : "Inaktiv"}
      </Badge>
    ),
  },
];

Migration Guide

So migrierst du bestehende Entities:

  1. Router migrieren:

    • Alte Router-Datei kopieren
    • Entity Config erstellen
    • createEntityRouter verwenden
    • Alte Datei löschen
  2. Columns migrieren:

    • Bestehende Columns analysieren
    • ColumnConfig Array erstellen
    • createEntityColumns verwenden
  3. Pages migrieren:

    • createListPage verwenden
    • Columns importieren
    • Alte Page-Datei löschen

Next Steps

  • [ ] Erstelle Generator-CLI für neue Entities
  • [ ] Füge Form-Page Factory hinzu
  • [ ] Erweitere um Bulk-Actions
  • [ ] Füge Export-Funktionen hinzu

License

Private Package - Part of CMS Template Monorepo