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

@gmod/range-cache-filehandle

v1.4.0

Published

A filehandle that caches byte ranges in chunks and coalesces adjacent reads into one request

Readme

@gmod/range-cache-filehandle

NPM version Build Status

A GenericFilehandle that caches byte ranges in chunks and coalesces adjacent reads into one request.

An indexed genomics parser reads in a pattern the network is bad at: many small, adjacent, semi-random ranges, most of them near ones it just read. This layer sits under the parser and turns that into a few large requests, then serves the next query's overlapping reads from memory.

npm install @gmod/range-cache-filehandle

Usage

Drop-in for RemoteFile from generic-filehandle2:

import { RemoteFileWithRangeCache } from '@gmod/range-cache-filehandle'
import { CramFile } from '@gmod/cram'

const cram = new CramFile({
  filehandle: new RemoteFileWithRangeCache('https://example.com/file.cram'),
})

A local file or Blob can be wrapped instead. The second argument keys this file's chunks in the shared cache, so it must identify the underlying bytes:

import { CachedFilehandle } from '@gmod/range-cache-filehandle'
import { LocalFile } from 'generic-filehandle2'

const file = new CachedFilehandle(new LocalFile(path), `file://${path}`)

What it does

The picture is generated by running the cache — the range headers in it are the ones that read sent. CONTRIBUTING.md says how.

  • Serves reads from a 256 KiB chunk grid. The chunks a read is missing are grouped into contiguous runs, one request each.
  • Joins a chunk another read has in flight rather than requesting it again.
  • Reference-counts each run's readers, so a shared request is cancelled only once all of them abort. A reader passing no signal pins it for everyone.
  • Holds 1000 chunks (256 MB) per worker, swept after 15 minutes idle, 20 requests at a time per origin. clearCache() drops everything, clearCacheFor(key) drops one file, sweepIdleCache() reclaims early.
  • Clamps reads past EOF once a size is known, from Content-Range, a 416, or stat().
  • Checks a 206 against what it claims to be, so a truncated body or a proxy answering with the wrong range fails loudly instead of being cached as a file that ends early.
  • Names a cause on failure: CORS, mixed content, a server ignoring the Range header, a connection that goes 30s without answering.

Nothing is retried, and nothing puts a clock on a transfer. This layer coalesces a run of chunks into one request, so a large one is the normal case, and any duration limit would cut off a slow download rather than a broken one — fetch has no timeout of its own for the same reason. The way to stop a read is the AbortSignal you passed it, which is carried to the socket.

Requests are capped per origin rather than per process so that one unresponsive server cannot starve the others — the per-endpoint semaphore shape, since a global limit "will unnecessarily restrict requests to other endpoints as well". Per origin and not per URL, because a presigned URL rotates its signature on every read and a pool keyed on that would be new every time.

docs/dataflow.md has the diagram and walks one read through all of it.

Tuning

CHUNK_SIZE, MAX_CACHE_ENTRIES, CACHE_IDLE_TIMEOUT_MS, MAX_CONCURRENT and RESPONSE_TIMEOUT_MS are exported for reading, not setting — the cache is module-global, so a knob on one filehandle would set policy for every other one in the process. What each was measured against is in src/constants.ts and in docs/tuning.md.

Docs

  • docs/api.md — every export, and the recordSize hook a subclass with its own stat() needs
  • docs/dataflow.md — how a read flows, with the diagram
  • docs/sharing.md — one request, several readers, and whose abort cancels it
  • docs/tuning.md — the five constants, what measured them, and what changes outside a browser
  • docs/errors.md — what each failure says and why

References

The layer above

This caches bytes. Every parser that reads through it caches what it parsed out of them, on its own budget and its own idle timeout, and that cache is the one that decides whether a read reaches this layer at all:

Provenance

Extracted from JBrowse 2, where it was @jbrowse/core/util/io/RemoteFileWithRangeCache, so parsers can use it without depending on @jbrowse/core.

Replaces http-range-fetcher, the earlier inspiration. That merges the requests made in the last 100 ms; this merges the chunks a read is missing, so it needs no window to wait out and carries an AbortSignal to the socket.

License

MIT