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

ignis-cms

v0.1.0

Published

Ein leichtgewichtiges, git-basiertes CMS als npm-Package für Next.js App Router Projekte.

Readme

ignis-cms

Ein leichtgewichtiges, git-basiertes CMS als npm-Package für Next.js App Router Projekte.

Das Package liest YAML-Dateien aus einem /content-Verzeichnis, generiert automatisch eine CMS-Oberfläche unter /admin, und schreibt Änderungen per GitHub API direkt ins Repository zurück.

Kernprinzipien

  • Git ist die Datenbank. Alle Inhalte leben als YAML-Dateien im Repo. Versionierung und Rollback kommen gratis über Git.
  • Zero Config. Package installieren, 4 Dateien anlegen, Env-Vars setzen — fertig. Kein Setup-Wizard, keine Config-Datei.
  • Schema-Ableitung. Feldtypen werden automatisch aus dem YAML-Wert ermittelt. Kein separates Schema nötig.
  • GitHub API statt lokalem Filesystem. Funktioniert auf Vercel und allen serverlosen Hosts ohne Einschränkungen.

Installation

npm install ignis-cms

Setup (4 Dateien + Env-Vars)

1. Admin-UI

CmsPage muss im Layout leben, damit der Zustand bei der Navigation erhalten bleibt.

// app/admin/layout.tsx
import { CmsPage } from "ignis-cms/ui";

export default function AdminLayout() {
  return <CmsPage />;
}
// app/admin/[[...path]]/page.tsx
export default function AdminPage() {
  return null; // Layout übernimmt alles
}

2. API-Route

// app/api/cms/[...action]/route.ts
export const runtime = "nodejs";
export { GET, POST, PUT, DELETE, PATCH } from "ignis-cms/api";

3. Auth-Route

// app/api/auth/[...nextauth]/route.ts
import { cmsAuthHandler } from "ignis-cms/api";
export { cmsAuthHandler as GET, cmsAuthHandler as POST };

4. Next.js Konfiguration

// next.config.ts
const nextConfig = {
  transpilePackages: ["ignis-cms"],
};
export default nextConfig;

5. Umgebungsvariablen

# .env.local

# NextAuth (Pflicht)
NEXTAUTH_URL=http://localhost:3001
NEXTAUTH_SECRET=<zufälliger-geheimer-string>

# GitHub API — content reads and writes (required)
# Create a fine-grained token at https://github.com/settings/tokens
# Required permissions: Contents (read & write), Metadata (read)
GITHUB_TOKEN=<fine-grained-personal-access-token>
GITHUB_OWNER=<org-oder-username>
GITHUB_REPO=<repo-name>
GITHUB_BRANCH=main

# In a monorepo, set to the path of the Next.js app (e.g. "apps/demo")
# Leave empty if the app is at the repo root
GITHUB_APP_BASE_PATH=          # Leer wenn App im Repo-Root; z. B. "apps/demo" im Monorepo
GITHUB_COMMITTER_NAME=ignis CMS
[email protected]

# MailerSend — password reset emails (optional)
# Get your API key at https://app.mailersend.com/api-tokens
MAILERSEND_API_KEY=
MAILERSEND_FROM_EMAIL=
MAILERSEND_FROM_NAME=

# AI YAML-Assistent — optional (OpenRouter)
OPENROUTER_API_KEY=

GitHub Token Berechtigungen: Contents (Read & Write), Metadata (Read).


Erster Start — Auto-Init

Beim ersten Aufruf des CMS (kein /content-Ordner im Repo) wird automatisch ein Grundgerüst angelegt:

content/
  settings.yaml     ← Globale Einstellungen (Firmenname, SEO, Header, Footer)
  _assets.yaml      ← Asset-Index (wird automatisch verwaltet)
  pages/
    home.yaml       ← Starter-Seite

Kein manuelles Anlegen nötig — einfach aufrufen und loslegen.


Benutzer verwalten

Benutzer werden in content/_users.yaml verwaltet. Im CMS selbst ist die Benutzerverwaltung für Admins über die Seitenleiste erreichbar.

# content/_users.yaml
users:
  - email: [email protected]
    password: "scrypt:SALT:HASH"
    role: admin
  - email: [email protected]
    password: "scrypt:SALT:HASH"
    role: editor

Passwort-Hash erzeugen:

import { hashPassword } from "ignis-cms";
console.log(hashPassword("mein-sicheres-passwort"));
// → scrypt:abc123...:def456...

Zwei Rollen:

  • admin — Neue Dokumente anlegen, löschen, Benutzer verwalten
  • editor — Nur bestehende Dokumente bearbeiten

Content-Struktur

content/
  blog/           ← Collection (Ordner = mehrere Dokumente)
    post-1.yaml
    post-2.yaml
  pages/          ← Collection
    home.yaml
    about.yaml
  settings.yaml   ← Singleton (direkt in /content, kein Ordner)
  _assets.yaml    ← Reserviert (Asset-Index, kein Content)
  _users.yaml     ← Reserviert (Benutzer, kein Content)

Dateien mit _-Prefix sind reserviert und erscheinen nicht als Content in der UI.


Schema-Ableitung

Feldtypen werden automatisch aus dem YAML-Wert ermittelt:

| YAML-Wert | Feld-Typ | UI-Komponente | |---|---|---| | "Einzeiliger Text" | text | Text Input | | mehrzeiliger String mit \| | richtext | Textarea | | "/uploads/bild.jpg" | image | Asset Picker (Bilder) | | "/uploads/doc.pdf" | file | Asset Picker (alle Typen) | | 2025-03-15 | date | Date Picker | | true / false | boolean | Toggle | | 42 / 3.14 | number | Number Input | | ["a", "b"] | list | Tag-Liste | | [{label: "X", url: "/"}] | list_objects | Verschachteltes Formular | | {title: "...", body: "..."} | group | Fieldset / Accordion |

Schema-Override (optional)

Für Select-Felder oder Validierung kann pro Collection eine _schema.yaml angelegt werden:

# content/blog/_schema.yaml
fields:
  category:
    type: select
    options:
      - tutorial
      - news
      - review

YAML-Editor

Jedes Dokument lässt sich über den YAML-Button in der Toolbar als Roh-YAML bearbeiten. Der Editor bietet:

  • Syntax-Highlighting
  • Echtzeit-Fehler- und Warnungsanzeige
  • Formatieren-Button (nur bei gültigem YAML aktiv)
  • Tab fügt 2 Leerzeichen ein

Wechsel zwischen Formular- und YAML-Modus ist verlustfrei — Änderungen werden sofort übernommen.

AI YAML-Assistent

Wenn OPENROUTER_API_KEY gesetzt ist, erscheint im YAML-Editor eine KI-Eingabezeile. Eingabe in natürlicher Sprache — das Modell (Claude 3.5 Haiku via OpenRouter) ergänzt oder verändert das YAML entsprechend.

Beispiele:

  • „Füge ein neues Feld og_image hinzu"
  • „Ändere den Titel auf Hallo Welt"
  • „Ergänze drei weitere Navigationseinträge"

Asset Library

Dateien werden nach /public/uploads/ hochgeladen (max. 10 MB). Metadaten (Titel, Alt-Text) werden automatisch in content/_assets.yaml gespeichert. Image- und File-Felder öffnen einen Asset Picker.

Erlaubte Dateitypen: JPG, PNG, GIF, WebP, SVG, AVIF, PDF, DOC, DOCX, XLS, XLSX.


Passwort-Reset per E-Mail (optional)

Wenn MAILERSEND_API_KEY gesetzt ist, erscheint auf der Login-Seite ein „Passwort vergessen"-Link. Der Reset-Link ist 1 Stunde gültig und wird über MailerSend versendet.


Tastaturkürzel

| Kürzel | Funktion | |---|---| | Cmd+S / Ctrl+S | Dokument speichern |


Git-Commits

Jede schreibende Operation erzeugt automatisch einen Git Commit via GitHub API:

| Operation | Commit Message | |---|---| | Dokument anlegen | content: create blog/post-1 | | Dokument bearbeiten | content: update blog/post-1 | | Dokument duplizieren | content: create blog/post-1-kopie | | Dokument löschen | content: delete blog/post-1 | | Asset hochladen | assets: upload hero.jpg | | Asset-Metadaten | assets: update metadata hero.jpg | | Asset löschen | assets: delete hero.jpg | | Passwort geändert | users: update account [email protected] | | Passwort zurückgesetzt | users: reset password [email protected] |


Anforderungen

  • Next.js 14+ (App Router)
  • Node.js 18+
  • GitHub Repository (Public oder Private)
  • Fine-grained GitHub Token: Contents (Read & Write), Metadata (Read)

Lizenz

MIT


ignis CMS — Migration Prompt

Diesen Prompt an eine KI übergeben, um eine bestehende Website ins ignis CMS zu migrieren.


Du migrierst eine bestehende Website ins ignis CMS. Das ignis CMS speichert alle Inhalte als YAML-Dateien in einem `/content`-Verzeichnis und schreibt sie via GitHub API ins Repository.

## Deine Aufgabe

Analysiere die Website (URL, Screenshot, HTML oder Beschreibung) und erstelle für jede Seite eine strukturierte YAML-Datei. Alle Inhalte werden 1:1 übernommen — kein Text wird verändert, gekürzt oder umformuliert.

## Dateistruktur

content/ pages/ home.yaml ← Startseite about.yaml ← Über uns leistungen.yaml ← Leistungsseite kontakt.yaml ← Kontaktseite [weitere].yaml settings.yaml ← Globale Einstellungen (Firmenname, SEO, Navigation, Footer)


Kein `globals/`-Ordner. Navigation, Footer und SEO-Defaults gehören alle in `settings.yaml`.

## settings.yaml Struktur

```yaml
companyName: "Firmenname GmbH"

seo:
  title: "Firmenname GmbH"
  description: "Kurze Beschreibung für Google (max. 160 Zeichen)."
  keywords: "keyword1, keyword2"
  ogImage: "/uploads/og-image.jpg"

header:
  logo: "/uploads/logo.svg"
  navigation:
    - label: "Startseite"
      url: "/"
    - label: "Leistungen"
      url: "/leistungen"
    - label: "Über uns"
      url: "/ueber-uns"
    - label: "Kontakt"
      url: "/kontakt"
  cta:
    label: "Anfragen"
    url: "/kontakt"

footer:
  tagline: "Ihr Partner für..."
  links:
    - label: "Impressum"
      url: "/impressum"
    - label: "Datenschutz"
      url: "/datenschutz"
  copyright: "© 2025 Firmenname GmbH"

Sektions-Typen

Erkenne Sektionen anhand der visuellen Struktur. Typische Sektionen (beispielsweise, nicht exklusiv):

  • hero — Hauptbanner: Überschrift, Subtext, CTA-Button, Bild/Video
  • intro — Kurze Einleitung, oft zentriert
  • features — Vorteile/Leistungen als Liste von Objekten
  • about — Über-uns-Abschnitt, Bild + Text
  • team — Personen-Grid (Liste mit name, role, image)
  • testimonials — Kundenstimmen (Liste mit quote, author, company)
  • gallery — Bildergalerie (Liste von Bild-Pfaden)
  • cta — Call-to-Action-Block
  • contact — Kontaktinformationen
  • faq — Häufige Fragen (Liste mit question + answer)
  • stats — Kennzahlen (Liste mit value + label)
  • logos — Partner-Logos (Liste von Bild-Pfaden)
  • text — Reiner Textblock (für rechtliche Seiten)

Feldtypen

# Einzeilige Texte → einfache Strings
title: "Willkommen bei uns"
button_text: "Jetzt anfragen"
button_url: "/kontakt"

# Mehrzeilige Texte / Absätze → Block-Scalar mit |
body: |
  Hier steht ein längerer Text.
  Er kann über mehrere Zeilen gehen.

# Bilder → Pfad (Platzhalter wenn noch kein Upload)
image: "/uploads/hero-bild.jpg"

# Video-URLs
video_url: "https://www.youtube.com/watch?v=..."
video_url: "/uploads/hero-video.mp4"

# Booleans
visible: true

# Listen von Strings
tags:
  - "Solar"
  - "Elektro"

# Listen von Objekten (Features, Team, FAQ, etc.)
items:
  - title: "Leistung 1"
    description: "Beschreibung der Leistung."
    icon: "check"
  - title: "Leistung 2"
    description: "Weitere Leistung."
    icon: "shield"

YAML-Template pro Seite

# Seitenweite SEO (überschreibt settings.yaml Defaults)
seo:
  title: "Seitentitel | Firmenname"
  description: "Kurze Beschreibung der Seite (max. 160 Zeichen)."

hero:
  title: "Hauptüberschrift"
  subtitle: "Kurzer Satz darunter"
  body: |
    Optionaler längerer Text.
  image: "/uploads/hero.jpg"
  button:
    text: "Jetzt kontaktieren"
    href: "/kontakt"

intro:
  title: "Wer wir sind"
  body: |
    Fließtext der Einleitung.

features:
  title: "Unsere Leistungen"
  items:
    - title: "Leistung 1"
      description: "Beschreibung."
      icon: "zap"
    - title: "Leistung 2"
      description: "Beschreibung."
      icon: "shield"

ctaSection:
  title: "Bereit loszulegen?"
  body: "Kontaktieren Sie uns noch heute."
  button:
    text: "Jetzt kontaktieren"
    href: "/kontakt"

Bilder

Mit Tool-Zugriff (empfohlen)

# Bild herunterladen und hochladen
curl -L "https://quell-website.de/images/hero.jpg" -o /tmp/hero.jpg
curl -X POST "http://localhost:3001/api/cms/upload" \
  -H "Cookie: <session-cookie>" \
  -F "file=@/tmp/hero.jpg;filename=hero.jpg"
# Antwort: { "ok": true, "path": "/uploads/hero.jpg", "asset": { ... } }
  1. Website analysieren → alle Bild-URLs sammeln
  2. Für jedes Bild: herunterladen → hochladen → zurückgegebenen Pfad im YAML verwenden
  3. YouTube/Vimeo: URL direkt als String (kein Download)
  4. Selbst gehostete Videos: herunterladen → hochladen wie Bilder

Dateinamen: Englisch, kebab-case (hero-solar-panel.jpg, team-max-mueller.jpg).

Ohne Tool-Zugriff

  • Platzhalter eintragen: /uploads/beschreibender-name.jpg
  • Am Ende Liste aller Platzhalter für manuellen Upload ausgeben

Wichtige Regeln

  1. Kein Inhalt weglassen — Jeder Text, jedes Bild, jede Information übernehmen
  2. Keine Texte verändern — 1:1, kein Umformulieren, kein Kürzen
  3. Kein globals/-Ordner — Navigation, Footer und Default SEO gehören in settings.yaml
  4. Sinnvolle Sektions-Benennung — Nicht alle Felder flach auf oberster Ebene
  5. Wiederholende Inhalte → immer als items-Liste mit Objekten
  6. Konsistente Feldnamen über alle Seiten: immer title, nie abwechselnd headline/heading

Ausgabe

Mit Tool-Zugriff

  1. Bilder herunterladen und hochladen
  2. YAML-Dateien direkt in content/ schreiben
  3. Kurze Zusammenfassung: Seiten migriert, Bilder hochgeladen

Ohne Tool-Zugriff

Pro Seite:

  1. Dateipfad als Kommentar: # content/pages/home.yaml
  2. Vollständiger YAML-Inhalt
  3. Am Ende: Liste aller Bild-Platzhalter

Reihenfolge: settings.yaml → Startseite → weitere Seiten