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

@leofcoin/peernet

v1.2.30

Published

Peer-to-peer networking for Leofcoin and distributed applications.

Readme

peernet

Peer-to-peer networking for Leofcoin and distributed applications.

Features

  • Decentralized peer discovery and messaging
  • Pluggable request handlers
  • File and data sharing
  • Works in Node.js, browser, and Electron

Installation

npm install @leofcoin/peernet

Usage

import Peernet from '@leofcoin/peernet'

const config = {
  network: 'leofcoin:peach',
  networkVersion: 'peach',
  stars: ['wss://peach.leofcoin.org']
}

// If your identity is password-protected, prompt for password:
import passwordPrompt from '@leofcoin/peernet/src/prompts/password/node.js';
const password = await passwordPrompt();

const node = await new Peernet(config, password)
await node.start()

console.log(globalThis.peernet)

API

addRequestHandler

Register a handler for custom requests:

peernet.addRequestHandler('lastBlock', async () => {
  const height = await chainStore.get('localIndex')
  const hash = await chainStore.get('localBlock')
  const response = JSON.stringify({ height: height.toString(), hash: hash.toString() })
  return new ResponseMessage({ response })
  // or
  // return new peernet.protos['peernet-response']({ response })
})

peernet.addRequestHandler('hello', () => {
  return new ResponseMessage({ response: 'hi' })
})

peernet.addRequestHandler('version', () => {
  return new ResponseMessage({ response: { version: 1 } })
})

Password Prompt

For password-protected identities, use the provided prompt:

  • Node.js: import passwordPrompt from '@leofcoin/peernet/src/prompts/password/node.js'
  • Browser: import passwordPrompt from '@leofcoin/peernet/src/prompts/password/browser.js'
const password = await passwordPrompt();
const node = await new Peernet(config, password);

In-Memory Broadcasts: API and Usage

What is it?
The broadcast method allows you to share files or folders with peers, storing them in-memory (not persisted to disk). Data is available for direct retrieval by hash until the process restarts.

API:

// For files:
peernet.broadcast(path: string, { content: Uint8Array }): Promise<string>

// For folders:
peernet.broadcast(path: string, { links: Array<{ path: string, hash: string }> }): Promise<string>

Parameters:

  • path (string): The virtual path or identifier for the file or folder.
  • content (Uint8Array): The file data (for files).
  • links (Array): An array of { path, hash } objects (for folders).

Returns:
A Promise that resolves to a hash string, which can be used to retrieve the data.


Examples

Broadcast a file:

const hash = await peernet.broadcast('/hello.txt', {
  content: new TextEncoder().encode('Hello world!')
});

Files larger than 256 KiB are automatically split into independently hashed pieces. The returned hash identifies a manifest, so receivers can verify every piece and request only pieces they still need. Override the piece size with chunkSize:

const hash = await peernet.broadcast('/video.mp4', {
  content: videoBytes,
  chunkSize: 1024 * 1024
})

For a pausable/resumable download, use the transfer controller:

const transfer = peernet.download(hash, { pin: true })
const unsubscribe = transfer.onProgress(({ transferredBytes, totalBytes, state }) => {
  console.log(state, transferredBytes, totalBytes)
})

transfer.pause()
transfer.resume() // already completed pieces are not fetched again

const bytes = await transfer.result
unsubscribe()

peernet.cat(hash) also reassembles chunked files transparently. pin: true caches verified pieces in the local data store, allowing a later transfer instance to reuse them.

Downloads pipeline four chunks by default. Known manifest providers are reused for all chunk hashes and chunk requests rotate across those peers, allowing different pieces to arrive concurrently from different providers. Configure the queue with transferConcurrency. Chunk size adapts to payload size (256 KiB normally, 1 MiB from 32 MiB, and 4 MiB from 256 MiB); an explicit chunkSize always overrides it.

Large blocks

Blocks larger than 1 MiB are also chunked internally, without changing the public block API or the canonical block hash supplied by the chain:

await peernet.block.put(blockHash, encodedBlock)
const encodedBlockAgain = await peernet.block.get(blockHash)

const transfer = peernet.block.download(blockHash)
transfer.pause()
transfer.resume()
const bytes = await transfer.result

The block manifest remains stored under the canonical block hash; individual chunks have their own transport hashes. Peernet verifies every chunk before reconstruction. The chain layer must still verify the reconstructed canonical block hash and perform normal consensus validation before loading it. Defaults can be configured with blockChunkThreshold and blockChunkSize in the Peernet constructor.

Broadcast a folder:

const folderHash = await peernet.broadcast('/my-folder', {
  links: [
    { path: '/hello.txt', hash: hash }
  ]
});

Retrieve data by hash (peer side):

const proto = { decoded: { hash } };
await peernet.handleData(peer, 'some-id', proto);
// The peer will receive either .data (for files) or .links (for folders)

Notes

  • If you broadcast a folder, only the links property is required; content should be omitted.
  • If you broadcast a file, only the content property is required; links should be omitted.
  • The hash returned is unique to the content or folder structure.
  • Data is lost when the process restarts.

In-Memory Broadcasts

Peernet supports in-memory data sharing for fast, temporary distribution of files or folders between peers. This feature allows you to broadcast a file (with content) or a folder (with just links), which is then available for retrieval by other peers (or yourself) until the process is restarted or the in-memory cache is cleared.

Usage Example

// Broadcast a file in-memory
const hash = await peernet.broadcast('/example', {
  content: new TextEncoder().encode('hello world')
});

// Broadcast a folder (just links) in-memory
const folderHash = await peernet.broadcast('/folder', {
  links: [
    { path: '/file1', hash: 'hash1' },
    { path: '/file2', hash: 'hash2' }
  ]
});

// Another peer can request the data by hash
// (handled internally by peernet.handleData)

Detailed Example

// 1. Broadcast a file in-memory
const hash = await peernet.broadcast('/example', {
  content: new TextEncoder().encode('Hello Peernet!')
});
console.log('Broadcasted hash:', hash);

// 2. Broadcast a folder in-memory
const folderHash = await peernet.broadcast('/folder', {
  links: [
    { path: '/file1', hash: 'hash1' },
    { path: '/file2', hash: 'hash2' }
  ]
});
console.log('Broadcasted folder hash:', folderHash);

// 3. Simulate a peer requesting the data by hash
const mockPeer = {
  connected: true,
  send: async (data, id) => {
    // Handle the received data (for demo/testing)
    const DataResponseProto = globalThis.peernet.protos['peernet-data-response'];
    const decodedProto = await new DataResponseProto(data);
    await decodedProto.decode();
    if (decodedProto.decoded.data) {
      const decodedContent = new TextDecoder().decode(decodedProto.decoded.data);
      console.log('Received content:', decodedContent);
    } else if (decodedProto.decoded.links) {
      console.log('Received folder links:', decodedProto.decoded.links);
    }
  }
};
const proto = { decoded: { hash } };
await peernet.handleData(mockPeer, 'test-id', proto);

Data Flow Diagram

[You/Peer] --(broadcast)--> [Peernet Node: In-Memory Map]
     ^                                 |
     |                                 |
     +------(handleData request)--------+
  • broadcast() stores the data in-memory and returns a hash.

  • handleData() retrieves the data by hash and sends it to the requesting peer.

  • The broadcasted data is stored in-memory and is not persisted to disk.

  • Retrieval is by hash, matching the value returned from broadcast().

  • The feature is useful for ephemeral data, rapid prototyping, or testing.

  • If the process restarts, the in-memory data is lost.

Testing

Automated tests verify that broadcasting and retrieving in-memory data works as expected, including content integrity and hash matching.

Folder Support (Files with Just Links)

Peernet supports "folders" as special file objects that contain only links to other files, without any content. This allows you to represent directory structures or collections of files.

Example: Broadcasting a Folder

const folderHash = await peernet.broadcast('/folder', {
  links: [
    { path: '/file1', hash: 'hash1' },
    { path: '/file2', hash: 'hash2' }
  ]
});

Retrieving a Folder When a folder is retrieved (e.g., via handleData), its links array will be preserved, and content will be empty or undefined.

Test Coverage Automated tests verify that broadcasting and retrieving folders works as expected, ensuring the links are preserved and content is empty or undefined.

Development

Note: You need to install jsproject

npm i -g @vandeurenglenn/project

Scripts

  • Watch:
    npm run watch
  • Build:
    npm run build
  • Test:
    npm test
  • Serve HTML Demo:
    npm run demo

License

MIT