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

@powforge/vote

v0.1.0

Published

DoI-weighted community voting for Nostr. Every vote is weighted by the voter's depth-of-identity score, so a sock puppet farm with 1000 fresh accounts cannot outvote one real long-tenured identity. Sybil-resistant polling with no central registry.

Readme

@powforge/vote

npm version license

Every public poll is gameable by 1000 sock puppets. Discord polls, Snapshot governance, content ranking on any open feed — one operator with a thousand fresh accounts can outvote a real community 1000-to-1. Centralized identity verification (KYC, captcha, phone) makes it slightly harder while leaking who you are.

@powforge/vote makes the vote weight a function of the voter's depth-of-identity score. A voter with years of accumulated social activity, real Lightning zaps, and inbound vouches from other deep identities counts a lot. A voter whose account was created last week and whose only history is twelve copy-paste replies counts close to zero — even if a thousand of them show up.

No central registry. No KYC. Anyone can read the score formula and re-derive a voter's weight from their public Nostr history.

Install

npm install @powforge/vote

Quick start

const { createProposal, castVote, getWeightedResult } = require('@powforge/vote');
const { generateSecretKey } = require('nostr-tools/pure');

const proposerSk = generateSecretKey();
const voterSk = generateSecretKey();
const relays = ['wss://relay.powforge.dev'];

// 1. Proposer creates a poll. Returns a NIP-33 coordinate and a signed event.
const { proposalId, event: proposalEvent } = createProposal({
  title: 'Should we ship feature X?',
  options: ['ship now', 'wait one cycle', 'kill it'],
  expiryUnixSec: Math.floor(Date.now() / 1000) + 86400,
  secretKey: proposerSk,
});
// Publish proposalEvent to your relays however you normally would.

// 2. A voter casts. Pass `relays` and the signed vote will be published.
await castVote({
  proposalId,
  optionIndex: 0,
  secretKey: voterSk,
  relays,
});

// 3. Later, anyone can compute the DoI-weighted result.
const { winner, runnerUp, tally } = await getWeightedResult(proposalId, relays);
console.log(winner.option, 'wins with weight', winner.weightedCount);
console.log('Raw 1p1v counts:', tally.tallies.map((t) => `${t.option}=${t.rawCount}`));

API

createProposal({ title, options, expiryUnixSec, secretKey?, proposerPubkey?, dTag? })

Builds a NIP-33 parameterized replaceable event (kind: 30078). With secretKey it returns a signed event ready to publish. Without, you supply proposerPubkey and get an unsigned template (useful for NIP-07 browser signers — you sign in the browser).

Returns { proposalId, dTag, coordinate, event }. proposalId and coordinate are the same kind:pubkey:dTag string — pass it everywhere else.

castVote({ proposalId, optionIndex, secretKey?, voterPubkey?, comment?, relays?, publishTimeout? })

Builds a kind: 1 reply note carrying an a-tag pointing at the proposal and an option tag with the chosen index. If relays is passed and the event is signed, also publishes it and returns publish acks per relay.

Returns { event, published? }.

tallyVotes(proposalId, relays, opts?)

Fetches votes from relays, looks up each unique voter's DoI score (via @powforge/identity), and returns both raw 1p1v counts and DoI-weighted counts.

{
  proposalId,
  options,
  tallies: [
    { index: 0, option: 'ship now', rawCount: 1, weightedCount: 200 },
    { index: 1, option: 'wait',     rawCount: 5, weightedCount: 25 },
  ],
  totalRaw: 6,
  totalWeighted: 225,
  voters: [{ pubkey, optionIndex, weight }, ...],
  ignored: [],  // any voter whose score lookup failed
}

One vote per voter, latest wins. A voter who casts at t=10 for option A and at t=20 for option B counts only as a vote for B. They can change their mind until the deadline.

Late votes are ignored. Votes whose created_at exceeds the proposal's expires_at (or the override opts.expiryUnixSec) are dropped.

getWeightedResult(proposalId, relays, opts?)

One-shot helper. Returns { tally, winner, runnerUp, tied }.

tied is true when the top two options have the same non-zero weighted count, OR when no votes have been cast.

Why DoI-weighted?

A voter's depth-of-identity score is the sum of irreversible work they've done across four dimensions of public Nostr history:

| Dimension | Hard-to-fake signal | |-----------|---------------------| | Social | Bidirectional engagement with deep peers (not broadcast follower-count) | | Access | NIP-13 proof-of-work bits accumulated across all events | | Vouch | Inbound vouches from other deep identities, sqrt-diluted by voucher reach | | Economic | Lightning zaps from many distinct funded wallets |

A fresh sock puppet has none of these. Faking them is non-cheap: zaps cost real sats; vouches require coaxing real deep identities to vouch you; PoW costs CPU; bidirectional social ties require humans on the other end who actually engage.

Read the score formula and the audit trail at powforge.dev/explorer.

Adversary handling

  • 1000 sock puppets → each contributes near-zero weight; their combined weight stays a tiny fraction of one real long-tenured voter's.
  • Voter changes mind → only their latest pre-deadline vote counts.
  • Late vote → ignored entirely.
  • Voter has never used Nostr → counts in raw 1p1v but contributes zero weight.
  • Relay drops the proposal event → tally falls back to vote-only counts for option indices it sees.

Composition

@powforge/vote is a pure helper. It doesn't run a server, doesn't store state, doesn't mint keys. It assumes a Nostr stack you already have and a relay (or several) you already trust.

For richer demos, score lookup pricing, or a paywalled tally service, see powforge.dev.

License

MIT.