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

@adviser/qsf

v1.1.3

Published

QUIC Stream File Format

Readme

@adviser/qsf

QUIC Stream File Format — a multiplexed streaming container format for binary streams.

Inspired by QUIC variable-length integer framing, qsf lets you pack multiple independent binary streams into a single file, each with its own composable filter pipeline (content addressing, compression, encryption). The format is designed for streaming-first access: a reader does not need to buffer the whole file to start consuming streams.


Concepts

| Term | Description | | ------------------- | ------------------------------------------------------------------------------------------------------------------ | | Stream | One logical byte sequence written with QsfWriter and read back as StreamFileBegin + StreamFileEnd | | Filter | A transform applied during encode/decode: CIDFilter, ZStrFilter, EncryptFilter | | Manifest | JSON records (stream.config, stream.result) embedded between stream frames, carrying filter config and results | | StreamFileBegin | Reader event: stream metadata + live ReadableStream + decode(keyStore) helper | | StreamFileEnd | Reader event: CID, byte range, and per-filter result summaries (filterResult) |


Install

pnpm add @adviser/qsf

Write

import { QsfWriter, CIDFilter, ZStrFilter, EncryptFilter, keyFingerprint } from "@adviser/qsf";
import { uint8array2stream } from "@adviser/cement";

const key = await crypto.subtle.generateKey({ name: "AES-GCM", length: 256 }, true, ["encrypt", "decrypt"]);
const keyId = await keyFingerprint(key);

const writer = new QsfWriter();
const chunks: Uint8Array[] = [];
const sink = new WritableStream<Uint8Array>({
  write(c) {
    chunks.push(c);
  },
});

const results = await writer.write(
  [
    {
      stream: uint8array2stream(myDocumentBytes),
      filters: [new CIDFilter(), new ZStrFilter(), new EncryptFilter(key, keyId)],
    },
    {
      stream: uint8array2stream(myMetaBytes),
      filters: [new CIDFilter(), new ZStrFilter()],
    },
  ],
  sink,
);

// results[0].cid — content address of the first stream (pre-compression, pre-encryption)

Filters are applied left-to-right during encoding and right-to-left during decoding.


Read

import { QsfReader, isStreamFileBegin, isStreamFileEnd, streamIdOf } from "@adviser/qsf";
import { uint8array2stream, stream2uint8array } from "@adviser/cement";

const keyStore = async (keyId: string): Promise<CryptoKey | undefined> => myKeys.get(keyId);

const reader = QsfReader(uint8array2stream(fileBytes)).getReader();
while (true) {
  const { done, value } = await reader.read();
  if (done) break;

  if (isStreamFileBegin(value)) {
    // value.filters — filter config from the manifest
    // value.stream  — raw (encoded) ReadableStream
    // value.decode(keyStore) — decoded ReadableStream (decompressed, decrypted, CID-verified)
    const bytes = await stream2uint8array(value.decode(keyStore));
  }

  if (isStreamFileEnd(value)) {
    // value.cid           — content address
    // value.filterResult  — [{ filterName, result }] per filter
    console.log(value.cid, value.filterResult);
  }
}

Use streamIdOf(evt) to correlate a StreamFileBegin with its StreamFileEnd.


Filters

| Filter | Encode | Decode | result() | | --------------- | --------------------------------------- | --------------------- | ------------------- | | CIDFilter | SHA2-256 CID over raw bytes | Verifies CID on flush | { cid: string } | | ZStrFilter | CompressionStream (deflate/gzip) | DecompressionStream | { codec: string } | | EncryptFilter | AES-GCM per-chunk (fresh IV each chunk) | AES-GCM per-chunk | { keyId: string } |

CIDCollector

Group streams under a combined CID (e.g. data + metadata form one logical record):

import { CIDCollector, CIDFilter } from "@adviser/qsf";

const col = new CIDCollector();
await writer.write(
  [
    { stream: dataStream, filters: [col.filter(), new ZStrFilter()], combineId: "rec-1" },
    { stream: metaStream, filters: [col.filter()], combineId: "rec-1" },
  ],
  sink,
);

const fileName = await col.result(); // combined CID of both streams

Injectable JSON codec

By default QsfWriter and QsfReader use JSON.stringify / JSON.parse with TextEncoder / TextDecoder for manifest records. To plug in a custom codec (e.g. from @adviser/cement's SuperThis):

const writer = new QsfWriter({
  ende: {
    encode: (v) => sthis.ende.json.encodeToUint8(v),
    decode: <T>(buf: Uint8Array) => sthis.ende.json.decodeUint8<T>(buf).Ok(),
  },
});

File format overview

┌─ MANIFEST_ENTRY  stream.config  (streamId, filters)
├─ STREAM_HEADER   streamId
├─ STREAM_DATA     streamId, payload   ← one frame per encoded chunk
├─ STREAM_TRAILER  streamId, {cid}
└─ MANIFEST_ENTRY  stream.result  (streamId, cid, offset, length, filterResult)
   … repeated for each logical stream …

Each frame header uses QUIC-style variable-length integers (1/2/4/8 bytes) for type, streamId, and length.


License

AFL-2.0