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

@z-torrent/utils

v0.0.13

Published

Utility functions for Z-Torrent

Downloads

1,214

Readme

@z-torrent/utils

Utility functions for Z-Torrent - a collection of helpers for BitTorrent protocol implementation.

Install

npm install @z-torrent/utils

API

IPSet

Efficient AVL-tree based data structure for storing and querying IP ranges. Supports both IPv4 and IPv6.

import { IPSet } from '@z-torrent/utils'

// Create from array of ranges
const ipSet = new IPSet([
  { start: '192.168.1.1', end: '192.168.1.100' },
  { start: '10.0.0.0', end: '10.0.0.255' },
])

// Add CIDR notation
ipSet.add('192.168.0.0/24')

// Add single IP
ipSet.add('8.8.8.8')

// Add range
ipSet.add('172.16.0.1', '172.16.0.50')

// Check if IP is in the set
ipSet.contains('192.168.1.50') // true
ipSet.contains('1.1.1.1') // false

// IPv6 support
ipSet.add('2001:db8::/32')
ipSet.contains('2001:db8::1') // true

loadIPSet

Load IP sets from a file, URL, or array. Supports plain text and gzip-compressed files.

import { loadIPSet } from '@z-torrent/utils'

// From array
const ipSet = await loadIPSet([{ start: '192.168.1.1', end: '192.168.1.100' }])

// From file
const ipSet = await loadIPSet('/path/to/blocklist.txt')

// From gzip file
const ipSet = await loadIPSet('/path/to/blocklist.txt.gz')

// From URL
const ipSet = await loadIPSet('https://example.com/blocklist.txt', {
  headers: { 'User-Agent': 'z-torrent' },
})

// Callback style
loadIPSet('/path/to/blocklist.txt', (err, ipSet) => {
  if (err) throw err
  console.log(ipSet.contains('192.168.1.1'))
})

Supported file formats:

# Comments are ignored
192.168.1.1-192.168.1.100
10.0.0.0/24
172.16.0.1

Netmask

Parse and manipulate IP network blocks (IPv4 and IPv6).

import { Netmask, ip2long, long2ip } from '@z-torrent/utils'

const block = new Netmask('192.168.1.0/24')

block.base // '192.168.1.0'
block.mask // '255.255.255.0'
block.bitmask // 24
block.hostmask // '0.0.0.255'
block.size // 256
block.first // '192.168.1.1'
block.last // '192.168.1.254'
block.broadcast // '192.168.1.255'

// Check if IP is in the block
block.contains('192.168.1.100') // true
block.contains('10.0.0.1') // false

// Iterate over all IPs
block.forEach((ip, long, index) => {
  console.log(ip)
})

// Get next block
const next = block.next()
next.toString() // '192.168.2.0/24'

// IPv6 support
const ipv6Block = new Netmask('2001:db8::/32')

// Convert IP to numeric value
const num = ip2long('192.168.1.1') // 3232235777
const ip = long2ip(3232235777) // '192.168.1.1'

string-compact

Convert between string and compact binary formats for peer addresses (used in tracker responses).

import {
  string2compact,
  compact2string,
  compact2stringMulti,
  compact2stringMulti6,
} from '@z-torrent/utils/string-compact'

// IPv4: string to compact (6 bytes)
const compact = string2compact('192.168.1.1:6881')
// Uint8Array [192, 168, 1, 1, 0x1A, 0xE1]

// Multiple addresses
const multi = string2compact(['192.168.1.1:6881', '10.0.0.1:6882'])

// Compact to string
const addr = compact2string(compact) // '192.168.1.1:6881'

// Parse multiple IPv4 addresses (6 bytes each)
const addrs = compact2stringMulti(buffer)

// Parse multiple IPv6 addresses (18 bytes each)
const addrs6 = compact2stringMulti6(buffer)

// IPv6 support (18 bytes)
const compact6 = string2compact('[2001:db8::1]:6881')
const addr6 = compact2string(compact6) // '[2001:db8::1]:6881'

addrToIPPort

Parse address string into IP and port components.

import { addrToIPPort } from '@z-torrent/utils/addr-ip-port'

const [ip, port] = addrToIPPort('192.168.1.1:6881')
// ip = '192.168.1.1', port = 6881

const [ip6, port6] = addrToIPPort('[2001:db8::1]:6881')
// ip6 = '2001:db8::1', port6 = 6881

Piece

Manage torrent piece data with block-level operations.

import { Piece } from '@z-torrent/utils/piece'

const piece = new Piece(16384) // 16KB piece

piece.length // 16384
piece.missing // 16384 (bytes not yet received)
Piece.BLOCK_LENGTH // 16384 (16KB, default block size)

// Reserve a block for downloading
const blockIndex = piece.reserve() // returns -1 if no blocks available

// Get block info
piece.chunkLength(blockIndex) // block size in bytes
piece.chunkOffset(blockIndex) // byte offset in piece

// Store received data
piece.set(blockIndex, data, peer)

// Cancel a reservation
piece.cancel(blockIndex)

// When all blocks received, flush to get complete piece
if (piece.missing === 0) {
  const completePiece = piece.flush()
}

once

Ensure a function is only called once.

import { once } from '@z-torrent/utils'

const fn = once((value) => {
  console.log('Called with:', value)
  return value * 2
})

fn(5) // logs: "Called with: 5", returns 10
fn(10) // returns 10 (no log, cached result)
fn(20) // returns 10 (cached result)

License

MIT