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

@rdub/thrds

v0.1.0

Published

Declarative thread sync for Slack, Discord, and Bluesky

Downloads

66

Readme

thrds (TypeScript)

Declarative thread sync for Slack, Discord, and Bluesky — TS impl.

The Python impl lives on the py branch (and on PyPI as thrds). See specs/typescript-port.md for the porting plan.

Status

Pre-releasecore (diff/edit/post/delete algorithm), SlackClient, and LinkedThread / syncLinked are ported and tested (39 tests). Not yet published to npm.

Install

pnpm add @rdub/thrds

Published as @rdub/thrds rather than thrds because npm blocks the unscoped name as "too similar" to the three package. The Python package on PyPI remains thrds.

Usage

Slack

import { SlackClient } from "@rdub/thrds";

const slack = new SlackClient({
  token: "xoxb-...",
  channel: "C0AQC2VKEJF",
  username: "my-bot",
  iconEmoji: ":robot_face:",
});

// Create new thread
const result = await slack.sync({ messages: ["OP", "Reply 1", "Reply 2"] });

// Update existing thread (edits changed messages, appends new, deletes extras)
await slack.sync(
  { messages: ["OP", "Reply 1", "Reply 2"] },
  { threadTs: "1775516040.743629" },
);

Generic

import { sync } from "@rdub/thrds";
import type { Thread, ThreadClient } from "@rdub/thrds";

const client: ThreadClient = /* your client */;
const result = await sync(client, { messages: ["OP", "Reply"] });
// result.actions: Action[]  (POST / EDIT / DELETE / SKIP per slot)
// result.messageIds: string[]
// result.threadId: string

Linked summary threads

Post summary bullets that link to detail messages in the same Slack thread:

import { SlackClient } from "@rdub/thrds";
import type { LinkedThread } from "@rdub/thrds";

const slack = new SlackClient({ token: "xoxb-...", channel: "C0..." });
const linked: LinkedThread = {
  summaryPrefix: "# Daily Digest",
  sections: [
    { title: "Topic A", summary: "Brief summary", body: "Full detail text..." },
    { title: "Topic B", summary: "Another summary", body: "More details..." },
  ],
};
const result = await slack.syncLinked(linked, { threadTs: /* optional */ });

Two-phase sync: posts all messages with placeholder links, then edits summaries with real permalinks once message ids are known.

Sync algorithm

Given desired messages M and existing thread messages N:

  1. Delete extras from the end (backwards — replies before OP)
  2. Edit overlapping messages where content changed (skip unchanged)
  3. Post new messages at the end

Foreign (non-editable) messages — e.g. human replies in a bot thread — are automatically skipped. The sync only operates on the bot's own messages (message.editable === false ⇒ preserved in place), leaving everyone else's untouched.

Test fixtures

tests/fixtures/sync.json is shared with the Python impl as the cross-language contract for the sync algorithm. To pull updates from the py branch:

git checkout py -- tests/fixtures/

Publishing

CI on tag ts-vX.Y.Z publishes to npm via OIDC trusted publishing — no long-lived NPM_TOKEN secret. One-time bootstrap (npm doesn't let trusted publishers be configured on a package that doesn't yet exist):

  1. Inaugural npm publish --access public --provenance from local (after npm login).
  2. On npmjs.com: package settings → Trusted Publishers → add runsascoded/thrds, workflow release.yml, environment blank.
  3. All subsequent releases via CI.