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

@rmdes/indiekit-endpoint-blogroll

v1.0.23

Published

Blogroll endpoint for Indiekit. Aggregates blog feeds from OPML, JSON feeds, or manual entry.

Readme

Blogroll Endpoint for Indiekit

An Indiekit plugin that provides a comprehensive blogroll management system with feed aggregation, admin UI, and public API.

Features

  • Multiple Source Types: Import blogs from OPML files/URLs, Microsub subscriptions, or add manually
  • Background Feed Fetching: Automatically syncs blogs and caches recent items
  • Microsub Integration: Mirror your Microsub subscriptions as a blogroll (zero duplication)
  • Admin UI: Manage sources, blogs, and view recent activity
  • Public JSON API: Read-only endpoints for frontend integration
  • OPML Export: Export your blogroll as OPML (all or by category)
  • Feed Discovery: Auto-discover feeds from website URLs
  • Item Retention: Automatic cleanup of old items (encourages fresh content discovery)

Installation

npm install @rmdes/indiekit-endpoint-blogroll

Configuration

Add to your indiekit.config.js:

import BlogrollEndpoint from "@rmdes/indiekit-endpoint-blogroll";

export default {
  plugins: [
    new BlogrollEndpoint({
      mountPath: "/blogrollapi",    // Admin UI and API base path
      syncInterval: 3600000,         // 1 hour (in milliseconds)
      maxItemsPerBlog: 50,           // Items to fetch per blog
      maxItemAge: 7,                 // Days - older items auto-deleted
      fetchTimeout: 15000            // 15 seconds per feed fetch
    })
  ]
};

Requirements

  • Indiekit: >=1.0.0-beta.25
  • MongoDB: Required for data storage
  • Optional: @rmdes/indiekit-endpoint-microsub for Microsub integration

Usage

Admin UI

Navigate to /blogrollapi in your Indiekit instance to access:

  • Dashboard: View sync status, blog counts, recent activity
  • Sources: Manage OPML and Microsub sources
  • Blogs: Add/edit/delete individual blogs, refresh feeds
  • Manual Sync: Trigger immediate sync or clear and resync

Source Types

  1. OPML URL: Point to a public OPML file (e.g., your feed reader's export)
  2. OPML File: Paste OPML XML directly into the form
  3. Microsub: Import subscriptions from your Microsub channels
  4. Manual: Add individual blog feeds one at a time

Public API

All API endpoints return JSON (except OPML export which returns XML).

List Blogs

GET /blogrollapi/api/blogs?category=Tech&limit=100&offset=0

Get Blog with Recent Items

GET /blogrollapi/api/blogs/:id

List Items Across All Blogs

GET /blogrollapi/api/items?blog=<id>&category=Tech&limit=50&offset=0

List Categories

GET /blogrollapi/api/categories

Sync Status

GET /blogrollapi/api/status

Export OPML

GET /blogrollapi/api/opml                  (all blogs)
GET /blogrollapi/api/opml/:category        (specific category)

Example Response

GET /blogrollapi/api/blogs

{
  "items": [
    {
      "id": "507f1f77bcf86cd799439011",
      "title": "Example Blog",
      "description": "A great blog about tech",
      "feedUrl": "https://example.com/feed",
      "siteUrl": "https://example.com",
      "feedType": "rss",
      "category": "Tech",
      "tags": ["programming", "web"],
      "photo": "https://example.com/icon.png",
      "status": "active",
      "itemCount": 25,
      "pinned": false,
      "lastFetchAt": "2026-02-13T10:30:00.000Z"
    }
  ],
  "total": 42,
  "hasMore": true
}

GET /blogrollapi/api/items

{
  "items": [
    {
      "id": "507f1f77bcf86cd799439011",
      "url": "https://example.com/post/hello",
      "title": "Hello World",
      "summary": "My first blog post...",
      "published": "2026-02-13T10:00:00.000Z",
      "isFuture": false,
      "author": { "name": "Jane Doe" },
      "photo": ["https://example.com/image.jpg"],
      "categories": ["announcement"],
      "blog": {
        "id": "507f1f77bcf86cd799439011",
        "title": "Example Blog",
        "siteUrl": "https://example.com",
        "category": "Tech",
        "photo": "https://example.com/icon.png"
      }
    }
  ],
  "hasMore": false
}

Microsub Integration

If you have @rmdes/indiekit-endpoint-microsub installed, the blogroll can mirror your subscriptions:

  1. Create a Microsub source in the admin UI
  2. Select specific channels or sync all channels
  3. Add a category prefix (optional) to distinguish Microsub blogs
  4. Blogs and items are referenced, not duplicated

Benefits:

  • Zero data duplication - items are served directly from Microsub
  • Automatic orphan cleanup when feeds are unsubscribed
  • Webhook support for real-time updates

Background Sync

The plugin automatically syncs in the background:

  1. Initial Sync: Runs 15 seconds after server startup
  2. Periodic Sync: Runs every syncInterval milliseconds (default 1 hour)
  3. What it Does:
    • Syncs enabled sources (OPML/Microsub)
    • Fetches new items from active blogs
    • Deletes items older than maxItemAge days
    • Updates sync statistics

Manual Sync:

  • Trigger from the dashboard
  • Use POST /blogrollapi/sync (protected endpoint)
  • Use POST /blogrollapi/clear-resync to clear and resync all

Feed Discovery

The plugin includes auto-discovery for finding feeds from website URLs:

// In the admin UI, when adding a blog, paste a website URL
// The plugin will:
// 1. Check <link rel="alternate"> tags in HTML
// 2. Try common feed paths (/feed, /rss, /atom.xml, etc.)
// 3. Suggest discovered feeds

Item Retention

By default, items older than 7 days are automatically deleted during sync. This encourages discovery of fresh content rather than archiving everything.

To Change Retention:

new BlogrollEndpoint({
  maxItemAge: 30  // Keep items for 30 days instead
})

Blog Status

  • active: Blog is working, fetching items normally
  • error: Last fetch failed (see lastError for details)
  • deleted: Soft-deleted, won't be recreated by sync

Navigation

The plugin adds itself to Indiekit's navigation:

  • Menu Item: "Blogroll" (requires database)
  • Shortcut: Bookmark icon in admin dashboard

Security

  • Protected Routes: Admin UI and management endpoints require authentication
  • Public Routes: Read-only API endpoints are publicly accessible
  • XSS Prevention: Feed content is sanitized with sanitize-html
  • Feed Discovery: Protected to prevent abuse (requires authentication)

Supported Feed Formats

  • RSS 2.0
  • Atom 1.0
  • JSON Feed 1.0

Contributing

Report issues at: https://github.com/rmdes/indiekit-endpoint-blogroll/issues

License

MIT