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

compresjon

v2.0.0

Published

Cold storage for large idle JSON values.

Downloads

61

Readme

CompreSJON

npm

compresjon is a tiny utility for keeping large JSON-compatible values compressed while they are idle.

It is meant for long-running Node.js workers that occasionally need a large in-memory cache, but do not need that cache inflated all the time.

See benchmarks for the current size and lifecycle tradeoffs.

Use Cases

CompreSJON is useful when JSON is large, expensive to rebuild, and idle more often than it is read. See use cases for examples where that tradeoff tends to pay off.

Install

npm install compresjon

CompreSJON is published as ESM and CommonJS:

import CompreSJON from "compresjon";
const { default: CompreSJON } = require("compresjon");

Usage

import CompreSJON from "compresjon";

let cache: ReturnType<typeof buildLargeCache> | undefined = buildLargeCache();
const coldCache = new CompreSJON(cache);

// Drop your own live reference when the cache is idle.
cache = undefined;

// Later, take() clears the compressed bytes before returning the live value.
cache = coldCache.take();

read() and its backwards-compatible alias parse() keep the compressed bytes around. Use them only when you intentionally want a non-destructive read.

const coldCache = new CompreSJON({ hello: "world" });

console.log(coldCache.read()); // { hello: 'world' }
console.log(coldCache.byteLength > 0); // true

CompreSJON stores JSON-serializable values. Values that JSON would drop, rewrite, or compute through accessors, such as undefined, functions, symbols, BigInt, NaN, Infinity, sparse arrays, symbol keys, non-enumerable properties, getters/setters, custom array properties, circular structures, and non-plain objects like Map, Set, or Date, are rejected.

Stats

Use stats to inspect the current cold payload without inflating it.

const coldCache = new CompreSJON(largeCache);

console.log(coldCache.stats);
// {
//   compressedBytes: 1104586,
//   jsonBytes: 22787451,
//   ratio: 20.63,
//   savingsBytes: 21682865,
//   savingsPercent: 0.95,
//   compressionLevel: 5,
//   isEmpty: false,
// }

jsonBytes, ratio, savingsBytes, and savingsPercent are available when CompreSJON compressed the value itself or when the value was restored from a CompreSJON JSON envelope. Raw buffers do not carry that metadata.

API At A Glance

  • read() / parse() inflate without consuming the compressed bytes.
  • take() / dump() inflate and clear the compressed bytes before returning the value.
  • process(callback) inflates, lets you mutate synchronously, then recompresses.
  • processAsync(callback) does the same for async work.
  • update(value) / updateAsync(value) replace the compressed value.
  • dispose() clears the stored payload.
  • toBuffer() / fromBuffer() are for binary transport.
  • toBase64() / fromBase64() are for string transport.
  • toEnvelope() / fromEnvelope() are for JSON-safe transport with metadata.
  • toJSON() / fromJSON() are kept as the original JSON envelope names.

Process And Recompress

process() is the safest cache lifecycle for most workers: it clears the instance while you mutate the live value, then recompresses it. The previous payload is kept as a fallback so failed recompression can restore the cache.

const coldCache = new CompreSJON([{ id: 1, status: "idle" }]);

coldCache.process((items) => {
  items.push({ id: 2, status: "idle" });
});

process() only accepts synchronous callbacks. Use processAsync() for work that awaits.

Async compression is available when you do not want Brotli work on the main event-loop turn:

const coldCache = await CompreSJON.fromAsync(largeCache);

await coldCache.processAsync(async (items) => {
  await refresh(items);
});

GC Control

CompreSJON drops its own references early, but it cannot force the runtime to collect memory unless your process exposes GC.

For memory-sensitive workers, start Node with --expose-gc and pass gc: true:

node --expose-gc worker.js
const coldCache = new CompreSJON(largeCache, { gc: true });

const liveCache = coldCache.take();

Manual GC is opt-in because it can pause your worker. CompreSJON never calls globalThis.gc() just because it exists; pass gc: true when you want CompreSJON to call it after memory-releasing operations.

If globalThis.gc is not available, gc: true is a no-op. Other runtimes can use the same option when they expose globalThis.gc, or pass a custom hook.

You can also pass a hook for custom scheduling or metrics:

const coldCache = new CompreSJON(largeCache, {
  gc: (phase) => {
    console.log(`released memory after ${phase}`);
  },
});

The hook runs after take, update, and dispose.

Hook errors are ignored so metrics or cleanup code cannot break cache reads and writes.

Transport

Use toBuffer() for binary transport or toEnvelope() for a base64 JSON envelope.

const coldCache = new CompreSJON({ hello: "world" });
const bytes = coldCache.toBuffer();
const restored = CompreSJON.fromBuffer<{ hello: string }>(bytes);
const restoredFromBase64 = CompreSJON.fromBase64<{ hello: string }>(coldCache.toBase64());
const restoredFromEnvelope = CompreSJON.fromEnvelope<{ hello: string }>(coldCache.toEnvelope());

toBuffer() returns a defensive copy by default. Pass { copy: false } only when the caller owns the returned buffer and will not mutate it.

toJSON() is kept for compatibility with the published API and returns the same JSON-safe envelope as toEnvelope().

fromBase64() rejects invalid base64 immediately. fromBuffer() expects bytes produced by this version of CompreSJON; invalid Brotli or non-JSON bytes are rejected when read.

Compression Levels

import CompreSJON, { CompressionLevel } from "compresjon";

const coldCache = new CompreSJON(largeCache, {
  compressionLevel: CompressionLevel.Balanced,
});

Brotli accepts levels 0 through 11. Higher levels can be dramatically slower; Balanced is the default.