# bt-bencode

> Byte-faithful bencode codec and BitTorrent v1/v2/hybrid torrent reader

Latest version **0.1.0** (published 2026-08-10) · MIT license · 0 weekly downloads

> **Deprecated.** This package is deprecated.

## Install

```sh
npm install bt-bencode
pnpm add bt-bencode
yarn add bt-bencode
bun add bt-bencode
```

## Health

**Score 10/100 (F)** — status: deprecated.

Negative: deprecated.

## Facts

| | |
|---|---|
| Version | 0.1.0 |
| Published | 2026-08-10 |
| First published | 2026-08-10 |
| Weekly downloads | 0 |
| License | MIT |
| TypeScript types | bundled |
| Module format | ESM + CommonJS |
| Node | >=22.18 |
| Dependencies | 1 |
| Unpacked size | 65.3 KB |
| Known vulnerabilities | 0 |
| Install scripts | no |
| Maintainers | pm0u |
| Keywords | bencode, bittorrent, torrent, bep52, bep3, metainfo, infohash |

## Links

- npm: https://www.npmjs.com/package/bt-bencode
- Repository: https://github.com/pm0u/bt-bencode
- Homepage: https://github.com/pm0u/bt-bencode#readme
- Issues: https://github.com/pm0u/bt-bencode/issues
- npm.io page: https://npm.io/package/bt-bencode

## Dependencies (1)

- [@noble/hashes](https://npm.io/package/@noble/hashes.md) ^2.3.0

## Alternatives

- [flatbuffers](https://npm.io/package/flatbuffers.md) — 6.0M weekly downloads
- [jwt-simple](https://npm.io/package/jwt-simple.md) — 259.5K weekly downloads
- [@exodus/patch-broken-hermes-typed-arrays](https://npm.io/package/@exodus/patch-broken-hermes-typed-arrays.md) — 28.5K weekly downloads
- [@native-to-anchor/buffer-layout](https://npm.io/package/@native-to-anchor/buffer-layout.md) — 12.2K weekly downloads
- [binary-parser-encoder](https://npm.io/package/binary-parser-encoder.md) — 5.3K weekly downloads

## Recent versions

- 0.1.0 (latest) — 2026-08-10

## README

# bt-bencode

A bencode codec that keeps bytes as bytes, plus a reader for BitTorrent v1, v2
and hybrid torrents.

## Install

```sh
npm install bt-bencode
```

## Development

```sh
npm test        # node --test, runs .ts sources directly (Node >= 22.18)
npm run typecheck
npm run build   # emits ESM + .d.ts to dist/
```

## Layout

```
src/bencode/   byte-faithful bencode codec; knows nothing about torrents
  bdict.ts     BDict + the Bencode type
  decode.ts    encode.ts
  inspect.ts   read-only render for debugging
  brand.ts     the tag that keeps a render out of a builder
  errors.ts    DecodeError, TypeMismatchError
src/torrent/   BEP 3/12/47/52 knowledge
  schema.ts    known keys, their types and scopes
  torrent.ts   typed read-only view over a decoded torrent
  infohash.ts  hashing a dictionary you built or modified
  errors.ts    InvalidTorrentError
```

The codec layer never imports the torrent layer.

`inspect()` output is one-way: it is branded, so a debug render cannot be fed
back into `BDict.from()` at any nesting depth, and `encode()` does not accept
it. A value mangled for display cannot round trip into a file.

`Torrent` is a different thing -- a read-only *projection* over a live,
mutable `BDict`. Mutating `torrent.raw` and re-encoding is the intended way to
modify a torrent. Infohashes are computed from the source bytes, so they do not
track such mutations; use `infoHashV1(info)` / `infoHashV2(info)` to hash a
dictionary you have changed.

## Test fixtures

The fixtures in `src/__fixtures__/` are generated, not hand-authored, and
regenerating them requires only Docker:

```sh
npm run fixtures            # regenerate + verify against libtorrent
npm run fixtures:generate   # regenerate only
```

Both generation and verification run in the container defined by
`docker/Dockerfile`, so output is byte-identical across machines and nothing is
installed on the host. `scripts/make-fixtures.py` uses the Python standard
library only and is deliberately independent of this package — fixtures built
with our own encoder would inherit our own bugs and the roundtrip tests would
pass vacuously.

The source tree is synthesised from a hash keystream rather than committed, and
file sizes are chosen so each fixture exercises a distinct branch:

| File | Size | Exercises |
|---|---|---|
| `a.bin` | 96 KiB | 3 whole pieces; no padding file in the hybrid torrent |
| `b.txt` | 1 KiB | under one piece, so it is omitted from `piece layers` |
| `empty.bin` | 0 | no `pieces root` at all — the case that breaks a type requiring one |
| `sub/c.bin` | 48 KiB | 1.5 pieces, so the final piece subtree needs zero-padding |

Six fixtures are produced: `v1`, `v2` and `hybrid` over that tree, plus
`single-v1`, `single-v2` and `single-hybrid` — single-file torrents use
`info.length` instead of `info.files` and are probably the most common shape in
existence.

Verification also writes `src/__fixtures__/expected.json`, holding libtorrent's
own infohashes for every fixture. Nothing else in the repo knows what those
should be, so without an independently derived oracle an off-by-one in slicing
the `info` dictionary would go unnoticed.

Piece length is 32 KiB — two 16 KiB blocks per piece, so v2 piece subtrees have
real structure. At the 16 KiB minimum the merkle tree collapses into a flat list
and tests nothing.

Verification (`scripts/verify-fixtures.py`) checks each fixture twice against
libtorrent 2.x: parsing validates `piece layers` against each file's `pieces
root`, and a forced recheck against the real source tree validates `pieces root`
for files smaller than one piece, which have no piece layer to cross-check
against. BEP 52 does not state whether a sub-piece file's leaf count rounds to
the next power of two or to a full piece, so that reading is confirmed
empirically rather than assumed.

---
_Source: https://npm.io/package/bt-bencode · Machine-readable twin of the npm.io package page. Health data is recomputed on every publish._
