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-conversations

v2.4.3

Published

Conversation aggregation endpoint for Indiekit. Backend enrichment service that polls Mastodon/Bluesky notifications and serves JF2-compatible data for the interactions page.

Readme

@rmdes/indiekit-endpoint-conversations

Conversation aggregation endpoint for Indiekit. Polls Mastodon, Bluesky, and ActivityPub notifications, stores interactions in MongoDB, and serves them as a JF2-compatible API — including threaded owner replies.

Features

  • Multi-platform polling — Mastodon, Bluesky, and native ActivityPub (via Fedify)
  • JF2 API — serves likes, reposts, and replies in webmention-compatible format
  • Owner reply threading — enriches API responses with the site owner's replies from the posts collection, with threading metadata
  • Webmention ingestion — accepts incoming webmentions from Bridgy or external services
  • Admin dashboard — connection status, polling stats, platform health
  • Syndication URL matching — resolves canonical post URLs from syndicated copies

Installation

npm install @rmdes/indiekit-endpoint-conversations
// indiekit.config.js
import ConversationsEndpoint from "@rmdes/indiekit-endpoint-conversations";

export default {
  plugins: [
    new ConversationsEndpoint({
      mountPath: "/conversations",
    }),
  ],
};

Environment Variables

| Variable | Required | Description | |----------|----------|-------------| | MASTODON_ACCESS_TOKEN | For Mastodon | Mastodon API access token | | MASTODON_URL or MASTODON_INSTANCE | For Mastodon | Mastodon instance URL | | BLUESKY_IDENTIFIER or BLUESKY_HANDLE | For Bluesky | Bluesky account identifier | | BLUESKY_PASSWORD | For Bluesky | Bluesky app password | | AUTHOR_NAME | Optional | Owner display name (falls back to site hostname) | | AUTHOR_AVATAR | Optional | Owner avatar URL |

ActivityPub polling is auto-detected when @rmdes/indiekit-endpoint-activitypub is installed.

API

GET /conversations/api/mentions

Returns interactions for a target URL in JF2 feed format. Compatible with the webmention.io API shape used by @chrisburnell/eleventy-cache-webmentions.

Parameters:

| Param | Type | Description | |-------|------|-------------| | target | string | Target URL to fetch interactions for | | wm-property | string | Filter by type: like-of, repost-of, in-reply-to | | per-page | number | Results per page (default: 50, max: 100) | | page | number | Page number (default: 0) |

Response:

{
  "type": "feed",
  "name": "Conversations",
  "children": [
    {
      "type": "entry",
      "wm-id": "conv-mastodon:12345",
      "wm-property": "in-reply-to",
      "wm-target": "https://example.com/posts/hello",
      "author": {
        "type": "card",
        "name": "Jane Doe",
        "url": "https://mastodon.social/@jane",
        "photo": "https://..."
      },
      "url": "https://mastodon.social/@jane/67890",
      "published": "2026-03-11T16:19:52.652Z",
      "platform": "mastodon",
      "content": {
        "html": "<p>Great post!</p>",
        "text": "Great post!"
      }
    },
    {
      "type": "entry",
      "wm-id": "owner-reply-abc123",
      "wm-property": "in-reply-to",
      "wm-target": "https://example.com/posts/hello",
      "author": {
        "type": "card",
        "name": "Site Owner",
        "url": "https://example.com",
        "photo": "https://..."
      },
      "url": "https://example.com/replies/2026/03/11/65e12",
      "published": "2026-03-11T17:00:00.000Z",
      "content": {
        "html": "<p>Thanks!</p>",
        "text": "Thanks!"
      },
      "is_owner": true,
      "parent_url": "https://mastodon.social/@jane/67890"
    }
  ]
}

Owner Reply Enrichment

When the API returns replies (wm-property: "in-reply-to"), it checks the Indiekit posts collection for owner posts whose properties.in-reply-to matches any reply's url. Matching owner posts are appended to the response with two extra fields:

| Field | Type | Description | |-------|------|-------------| | is_owner | boolean | Always true for owner replies | | parent_url | string | The URL of the interaction this reply responds to |

The frontend uses parent_url to thread the owner's reply under the correct parent interaction. See indiekit-eleventy-theme for the client-side threading implementation.

GET /conversations/api/status

Returns connection health and platform status.

POST /conversations/ingest

Accepts incoming webmentions. Body: { source, target }.

POST /conversations/poll (authenticated)

Triggers an immediate poll of all configured platforms.

Architecture

Mastodon API ──┐
Bluesky API  ──┼──> Scheduler ──> conversation_items (MongoDB)
ActivityPub  ──┘                         │
                                         v
               GET /api/mentions ──> JF2 response
                                    + owner reply enrichment
                                      (from posts collection)

Collections

| Collection | Purpose | |------------|---------| | conversation_items | Stored interactions (likes, reposts, replies) | | conversation_state | Polling state (last poll timestamps, cursors) |

Dependencies

  • @rmdes/indiekit-endpoint-activitypub — Optional. When installed, the scheduler also polls native ActivityPub interactions from the ap_interactions collection.
  • indiekit-eleventy-theme — The theme's webmentions.js consumes the /api/mentions endpoint and threads owner replies using the is_owner and parent_url fields.
  • @rmdes/indiekit-endpoint-comments — Handles native comment replies (not platform interactions). Owner replies to native comments go through the comments API, not this plugin.

License

MIT