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

dignity.js

v0.3.0

Published

P2P object API for decentralized JavaScript applications

Downloads

690

Readme

dignity.js

REST-like P2P object API for decentralized JavaScript applications.

dignity.js lets many browsers synchronize shared objects with ownership rules and built-in anti-abuse + privacy controls.

Highlights

  • REST-like API over P2P replication: create, read, list, update, remove
  • Owner authorization model by default (only creator can update/delete)
  • Security defaults enabled:
    • message signing (Ed25519)
    • broadcast encryption (shared password)
    • direct encryption (recipient public key)
    • Sloth VDF proof-of-work per message
    • default powSteps: 22 (calibrated on this machine to about 1000ms)
    • automatic peer ban on invalid signature/PoW (48h default)
  • Team/subapp scoped broadcast passwords (broadcastScope + broadcastPasswords)
  • Browser-first: published npm package includes IIFE, ESM, and CJS builds

Install

npm install dignity.js

Quick Start

const {
  DignityP2P,
  InMemoryNetworkHub,
  InMemoryNetworkAdapter
} = require('dignity.js');

const hub = new InMemoryNetworkHub();

const alice = new DignityP2P({
  nodeId: 'alice',
  networkAdapter: new InMemoryNetworkAdapter(hub),
  security: {
    appPassword: 'shared-out-of-band-password',
    powSteps: 22
  }
});

const bob = new DignityP2P({
  nodeId: 'bob',
  networkAdapter: new InMemoryNetworkAdapter(hub),
  security: {
    appPassword: 'shared-out-of-band-password',
    powSteps: 22
  }
});

await alice.start();
await bob.start();

await alice.joinDiscovery('main', {
  metadata: { nickname: 'alice' }
});
await bob.joinDiscovery('main', {
  metadata: { nickname: 'bob' }
});

const visiblePeers = alice.listPeers('main', { includeSelf: false });
console.log('Peers in main room:', visiblePeers.map((peer) => peer.peerId));

await alice.create('notes', { title: 'hello decentralized world' }, {
  id: 'note-1',
  broadcastScope: 'main'
});
console.log(bob.read('notes', 'note-1'));

await alice.leaveDiscovery('main');
await bob.leaveDiscovery('main');

Team / Subapp Scoped Passwords

Use a different broadcast password per cooperative team, room, or sub-application namespace.

const node = new DignityP2P({
  nodeId: 'player-1',
  networkAdapter,
  security: {
    appPassword: 'fallback-password',
    broadcastPasswords: {
      'coop:red': 'red-team-secret',
      'coop:blue': 'blue-team-secret'
    },
    powSteps: 22,
    banDurationMs: 48 * 60 * 60 * 1000
  }
});

await node.create('matches', { mode: 'coop' }, {
  id: 'm-1',
  broadcastScope: 'coop:red'
});

Peers with a different password for coop:red cannot decrypt that broadcast traffic.

Room / Team Discovery

Use scoped discovery to find active peers in a room (for example main, team:red, raid-42).

await node.joinDiscovery('team:red', {
  metadata: { nickname: 'alice' },
  heartbeatIntervalMs: 15000,
  ttlMs: 45000
});

const peers = node.listPeers('team:red', { includeSelf: false });
await node.leaveDiscovery('team:red');

Direct Secure Messaging

alice.registerPeerPublicKey('bob', bob.getPublicKey());
bob.registerPeerPublicKey('alice', alice.getPublicKey());

await alice.sendDirectMessage('bob', 'dm', { text: 'private payload' });

Browser Usage

The published npm package includes pre-built bundles (IIFE, ESM, CJS) generated at publish time. The dist/ folder is not checked into the repository.

<script src="https://unpkg.com/dignity.js/dist/dignity.min.js"></script>
<script>
  const { DignityP2P } = DignityJS;
</script>

Security Model

dignity.js provides two encryption modes:

  • Direct mode (targetId set): true end-to-end encryption using X25519 key exchange between sender and recipient. Only the intended recipient can decrypt.
  • Broadcast mode (no targetId): symmetric encryption using a shared password. All peers that know the password can decrypt all broadcast traffic in that scope. This is a group shared-secret cipher, not end-to-end encryption.

Broadcast encryption uses PBKDF2-SHA256 (default 100,000 iterations) with a random salt per message to derive the symmetric key. This protects against offline brute-force of weak passwords. The iteration count is configurable via kdfIterations.

Messages from peers running older versions that used the legacy single-hash KDF are still accepted and decrypted automatically (backward compatible).

Important: if the broadcast password leaks, all past captured traffic for that scope is retroactively decryptable. For sensitive data, use direct mode with per-peer public keys.

Signaling Servers

Default signaling URLs include PeerJS-compatible public endpoints:

  • wss://peerjs.92k.de/peerjs?key=peerjs
  • wss://0.peerjs.com/peerjs?key=peerjs

You can also deploy your own server with peerjs-server and point createDefaultSignalingPool (or WebSocketSignalingProvider) to your own wss://.../peerjs?key=... URL.

Compatibility note:

  • dignity.js now includes a dedicated PeerJSSignalingProvider backed by the official peerjs client for PeerJS protocol compatibility.
  • In non-WebRTC runtimes (for example Node test runners), it automatically falls back to WebSocket transport checks for connectivity testing.

Development

npm test
npm run build
npm run docs:serve
npm run example:tictactoe
npm run example:chess
npm run test:pow-calibrate

Docs and Examples

  • Docs site source: docs/index.html
  • API metadata: docs/openapi-like.json
  • Minimal demos:
    • examples/decentralized-tictactoe.js
    • examples/decentralized-chess-lite.js

Publish

npm publish --access public

The prepublishOnly script runs tests and build automatically.

License

Apache 2.0 — see LICENSE.