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/identity

v0.7.2

Published

Depth-of-Identity SDK for Nostr. Measures accumulated irreversible work across four dimensions of irreversible work (social, access, vouch, economic). Try it live at powforge.dev/explorer.

Readme

@powforge/identity

npm version license tests

Try it live: powforge.dev/explorer — connect your Nostr profile with NIP-07, see your depth score, rank your peers, and look up any npub. Self-lookup is free and runs client-side.

Agent-payable signed scores: POST https://identity.powforge.dev/l402/identity-score returns a schnorr-signed score JSON for 2 sats via Lightning HTTP 402.

Depth-of-Identity SDK for Nostr. Measures accumulated irreversible work across four dimensions of irreversible work (social, access, vouch, economic) to produce a single identity weight score.

Not human vs bot. Invested vs uninvested. It is about measuring intentions.

Install

npm install @powforge/identity

Quick Start

const { getIdentityDepth } = require('@powforge/identity');

const report = await getIdentityDepth(pubkey, {
  relays: ['wss://relay.powforge.dev'],
});

console.log(report.weight);      // total identity depth score
console.log(report.dimensions);  // breakdown by dimension

What It Measures

Four dimensions of identity depth:

| Dimension | What It Scores | Event Kinds | |-----------|---------------|-------------| | Social | Notes published, reactions given, unique peers interacted with | kind:1, kind:7 | | Access | NIP-13 proof-of-work accumulated across all events | nonce tags | | Vouch | Inbound vouches from other identities, weighted by voucher depth with sqrt dilution | kind:33335 | | Economic | Lightning zaps received and sent, scored on unique senders/recipients | kind:9735, kind:9734 |

v0.7.0 retired the cyberspace-spatial dimension. Kind:3333 movement events are grind-cheap and Sybil-trivial; the dimension was marketing, not measurement. scoreSpatial remains exported for backwards compatibility. Pass dimensions: ['spatial', 'social', 'access', 'vouch', 'economic'] to opt back in; expect a one-time console.warn per process.

API

getIdentityDepth(pubkey, options?)

Returns a full identity report for a hex pubkey.

Options:

| Option | Default | Description | |--------|---------|-------------| | relays | ['ws://localhost:3088'] | Array of relay WebSocket URLs to query | | timeout | 5000 | Query timeout per relay in ms | | dimensions | ['social', 'access', 'vouch', 'economic'] | Which dimensions to score. v0.7.0 retired 'spatial' from the default. Add it back explicitly to opt into the deprecated cyberspace-spatial read; a one-time console.warn will fire. |

Returns:

{
  "pubkey": "93da4435...",
  "totalEvents": 3,
  "weight": 24,
  "activeDimensions": 2,
  "dimensionMultiplier": 1.2,
  "dimensions": {
    "social": { "notes": 0, "reactions": 0, "uniquePeers": 0, "score": 0 },
    "access": { "totalEvents": 3, "totalPowBits": 0, "maxDifficulty": 0, "score": 3 },
    "vouch": { "inboundVouches": 0, "uniqueVouchers": 0, "totalWeight": 0, "score": 0 },
    "economic": { "inboundZaps": 0, "outboundZaps": 0, "uniqueSenders": 0, "score": 0 }
  },
  "firstActivity": "2026-04-12T17:25:47.000Z",
  "lastActivity": "2026-04-13T21:01:16.000Z",
  "relaysQueried": 1
}

queryRelay(relayUrl, filters, timeout?)

Low-level function to query a single relay for events matching NIP-01 filters.

How Scoring Works

Each dimension uses log2 scaling to prevent grinding attacks. You can't just spam events to inflate your score -- each additional unit of work yields diminishing returns, just like real proof-of-work.

  • Social: log2(notes+1) * 3 + log2(reactions+1) + log2(bidirectionalPeers+1) * 15 + log2(unidirectionalPeers+1) * 5
  • Access: totalPowBits * 2 + log2(powEvents+1) (PoW bits are already exponential, so they stay linear)
  • Vouch: log2(totalWeight+1) * 3 + log2(uniqueVouchers+1) * 20 (sqrt dilution prevents vouch farming)
  • Economic: log2(genuineSenders+1) * 12 + log2(genuineRecipients+1) * 8 + log2(satsReceived+1) + log2(satsSent+1) * 2

A dimension multiplier rewards spreading across dimensions: having depth in 2 dimensions gives 1.2x, 3 gives 1.4x, all 4 gives 1.6x. One-trick ponies get no bonus.

The total weight is the sum of all dimension scores times the multiplier. Higher weight means more accumulated, irreversible work.

Why Not Just Check Follower Count?

Follower counts are trivially faked. This SDK measures things that cost real resources to produce: computation (PoW), time (event history), Lightning payments (sats), and social commitment (vouches backed by depth). Every dimension requires irreversible expenditure to increase.

Chaintip Freshness (beta)

Starting in 0.7.0-beta.1, the SDK ships an optional Bitcoin chain-tip anchor you can attach to a signed DoI score. The field is experimental, opt-in, and backwards-compatible. Scores without it still verify exactly as before.

What it adds: { height, hash, observed_at } under the signer's payload, where height and hash come from the current Bitcoin tip and observed_at is the ISO-8601 time of the fetch. Honest claim: block height plus hash as a freshness anchor, verifiable against any public Bitcoin node. This is not SPV, not a Merkle proof, and not a timestamp service. It tells a consumer "this score was measured after block N" — nothing more.

How to opt in

const { getChaintip, signWithChaintip } = require('@powforge/identity');

// Fetch the current tip directly.
const tip = await getChaintip();
// => { height: 946252, hash: '00000000...', observed_at: '2026-04-23T...' }

// Or wrap any signer to fold the tip into the signed payload.
const { payload, signature } = await signWithChaintip(
  scorePayload,
  (p) => mySigner(p),
  { includeChaintip: true },
);

On the hosted oracle, pass ?chaintip=1 on any score endpoint:

curl -s -X POST 'https://identity.powforge.dev/l402/identity-score?chaintip=1' \
  -H 'Content-Type: application/json' \
  -d '{"pubkey":"<64-hex>"}'

Limitations

  • Data source: mempool.space public API. Subject to their rate limits and uptime. If mempool.space is down, the score still ships, and the envelope carries bitcoin_tip_error instead of bitcoin_tip so callers can retry.
  • Cache window: 60 seconds in-process. Two calls within a minute get the same tip, which is fine because Bitcoin blocks land every 10 minutes on average.
  • No chain verification: we forward what mempool.space reports. A consumer who wants higher assurance should cross-check the returned hash against any Bitcoin node they already trust.

Upgrade path

When self-hosted Bitcoin RPC credentials are wired up, the mempool.space fetch swaps for a direct bitcoind JSON-RPC getblockchaininfo call. The public SDK surface does not change. See the TODO(bitcoind-rpc) marker in src/chaintip.js for the exact hook point.

License

MIT