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

@danxbot/plugin-sdk

v0.2.22

Published

SDK for building 50 Arms card-type plugins (DX-5170): the card kit's type declarations, a Vite preset that builds a plugin against the app's shared runtime and writes its manifest, and the danx-plugin CLI.

Readme

@danxbot/plugin-sdk

Build a 50 Arms card-type plugin: a small React bundle that gives a card type its own card view (CardView) and/or card-list view (CardListView), loaded into 50 Arms' own page with import().

A plugin does not bundle React, @danxbot/ui or the card features. The app serves them under fixed import specifiers through an import map, so a plugin shares the app's single React and renders the app's own components:

| Specifier | What it is | |---|---| | react, react/jsx-runtime, react-dom | The app's React | | @danxbot/ui | The app's design system | | @danxbot/card-kit@1 | The card features: data hooks, card regions (StandardCardPage, EditableTitle, ChecklistsSection, ...), CardFace, CardBoard |

The live list and each library's major version is GET /api/plugin-runtime.

Set up a plugin

package.json: depend on @danxbot/plugin-sdk and install its peers: vite, react, @types/react, @danxbot/ui and react-router (types only: the app serves the real ones; the kit's declarations import them).

vite.config.ts:

import { defineConfig } from "vite";
import { danxPlugin } from "@danxbot/plugin-sdk/vite";

export default defineConfig({ plugins: [danxPlugin()] });

tsconfig.json: add "types": ["@danxbot/plugin-sdk/card-kit"]: the kit's declarations. They are self-contained (they import only react, @danxbot/ui and react-router) and the specifier is not a package, so TypeScript reads them as ambient types.

src/index.tsx exports CardView and/or CardListView:

import { StandardCardPage, type CardViewProps } from "@danxbot/card-kit@1";

export function CardView({ card, mutation }: CardViewProps) {
  return <StandardCardPage card={card} mutation={mutation} />;
}

vite build writes the plugin to dist/: index.js (the entry), chunks/ for code splitting, index.css, source maps, and danx-plugin.json, the manifest listing every file with its size and sha256 and the runtime majors the plugin was built against.

The build refuses to bundle a copy of React, React DOM, @danxbot/ui or react-router: import only the specifiers above. For routing, use the kit's Link and useNavigate; StandardCardPage reads the plan the page was opened from out of the URL, so a view that wraps it passes only {card, mutation}.

The card kit is a contract

A runtime export of @danxbot/card-kit@1, and its parameters, is never removed or changed in place; the keys of the exported data types follow the Versioning section below. A breaking change is @danxbot/card-kit@2, served beside @1 until no approved plugin revision needs it. A plugin's manifest records the majors it was built against, and the app refuses to run a revision built for a major it no longer serves.

Publish a revision

DANXBOT_DASHBOARD_URL=https://<your dashboard> DANXBOT_API_KEY=<a key from your own account>   npx danx-plugin publish --plugin <key> --note "what changed" [--dir <project>] [--name "Display name"]

publish runs the project's own npm run build, archives the source (inside a git repo: the tracked files plus untracked ones git does not ignore; otherwise what the top-level .gitignore leaves, minus node_modules, .git and a top-level dist; a lockfile is required, so the download builds as is) and uploads both as a new revision of the plugin <key>, creating the plugin on its first publish. It prints the revision number and the Settings > Plugins link where a team admin approves it. .env* files are never archived, in or out of git. Inside git, a git failure (git missing, a dubious-ownership refusal) stops the publish with git's message; only "not a git repository" means outside git, where the top-level .gitignore is honoured (*, ?, **, anchoring and trailing /; a ! negation is refused). A blank note is refused first, before the build, the archive or any request. The dashboard validates the upload; a refusal prints its named reason.

The same flow is exported for tools as @danxbot/plugin-sdk/publish (buildPlugin, archiveSource, uploadRevision, fetchTransport): the dashboard MCP's plugin_publish tool runs it for agents.

The screenshot on a revision

An approver sees a screenshot of the plugin next to each revision. There is nothing to draw by hand: the dashboard MCP's plugin_publish tool (not danx-plugin publish, which uploads no screenshot) takes it from the plugin's own build. A headless Chromium (Playwright, resolved from your project or the MCP server's working directory) opens the dashboard's public /plugin-preview page, which imports your built CardView on the app's own React, @danxbot/ui and card kit and draws it with an invented sample card; the build is served from memory, so the revision need not be uploaded first. The capture waits until the page itself reports ready (or failed, with the reason), then saves a 1280x800 PNG as screenshot.png, which joins the revision's files and manifest.

So a plugin must export a CardView for a screenshot to exist. No browser, a dashboard that predates the page, or a plugin that fails to render all publish the revision WITHOUT a screenshot; plugin_publish answers screenshot: "none: <reason>" with the cause.

Versioning

The SDK stays 0.x until the shapes behind the card kit's data types settle: phase 1 of DX-4679 (card types as rows) changes IssueViewV2.type, and DX-5164 (designs on any card) changes the design fields. Until then the declarations may change between 0.x releases; the kit's runtime exports follow the @danxbot/card-kit@1 rule above.