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

@git-stunts/git-cas

v5.3.2

Published

Content-addressed storage backed by Git's object database, with optional encryption and pluggable codecs

Downloads

2,449

Readme

@git-stunts/git-cas

JESSIE, STOP—

Hold on. He’s turning Git into a blob store. Let him cook.

Most potent clone available on GitHub (legally).

Git, freebased: pure CAS that’ll knock your SHAs off. LFS hates this repo.

Git isn’t source control. Git is a content-addressed object database.
We use the object database.

git-cas chunks files into Git blobs (dedupe for free), optionally encrypts them, and emits a manifest + a real Git tree so you can commit/tag/ref it like any other artifact.

What you get

  • Dedupe for free Git already hashes objects. We just lean into it.
  • Chunked storage big files become stable, reusable blobs. Fixed-size or content-defined chunking (CDC).
  • Optional AES-256-GCM encryption store secrets without leaking plaintext into the ODB.
  • Multi-recipient encryption envelope model (DEK/KEK) — add/remove access without re-encrypting data.
  • Key rotation rotate keys without re-encrypting data blobs. Respond to compromise in seconds.
  • Compression gzip before encryption — smaller blobs, same round-trip.
  • Passphrase encryption derive keys from passphrases via PBKDF2 or scrypt — no raw key management.
  • Merkle manifests large files auto-split into sub-manifests for scalability.
  • Manifests a tiny explicit index of chunks + metadata (JSON/CBOR).
  • Tree output generates standard Git trees so assets snap into commits cleanly.
  • Full round-trip store, tree, and restore — get your bytes back, verified.
  • Lifecycle management readManifest, inspectAsset, collectReferencedChunks — inspect trees, plan deletions, audit storage.
  • Vault GC-safe ref-based storage. One ref (refs/cas/vault) indexes all assets by slug. No more silent data loss from git gc.
  • Interactive dashboard git cas inspect with chunk heatmap, animated progress bars, and rich manifest views.
  • Verify & JSON output git cas verify checks integrity; --json on all current human-facing commands provides convenient structured output for CI/scripting.

Use it for: binary assets, build artifacts, model weights, data packs, secret bundles, weird experiments, etc.

What's new in v5.3.1

Patch release — repeated chunk tree fix.

  • Unique chunk tree entriescreateTree() and _createMerkleTree() now emit one tree entry per unique chunk digest instead of repeating the same filename for repeated chunk occurrences.
  • Manifest remains authoritative — chunk order and multiplicity still come entirely from the manifest; restore behavior is unchanged.
  • Clean git fsck on repetitive files — repetitive content no longer yields duplicate tree filenames or duplicateEntries errors.
  • New regressions — unit and integration coverage now exercises repeated-chunk files and validates real Git tree integrity with git fsck --full.

See CHANGELOG.md for the full list of changes.

What's new in v5.3.0

M16 Capstone — audit remediation, CLI configuration, and security hardening.

  • .casrc config file — JSON config at repo root sets defaults for all CLI flags (chunk size, strategy, concurrency, codec, compression, CDC params).
  • CLI store/restore flags — all library-level options now accessible from the command line: --gzip, --strategy, --chunk-size, --concurrency, --codec, --merkle-threshold, and CDC-specific flags.
  • Passphrase-file support--vault-passphrase-file <path> on store, restore, and vault rotate (use - for stdin).
  • Memory restore guardmaxRestoreBufferSize (default 512 MiB) prevents unbounded memory allocation on encrypted/compressed restore.
  • Web Crypto encryption buffer guardmaxEncryptionBufferSize (default 512 MiB) for the one-shot AES-GCM API.
  • Orphaned blob trackingSTREAM_ERROR now includes meta.orphanedBlobs for cleanup after partial store failures.
  • KDF brute-force awarenessdecryption_failed metric + CLI rate-limiting delay on INTEGRITY_ERROR.
  • Encryption counter — vault metadata tracks encryptionCount with observability warning near GCM nonce bound.
  • Lifecycle method renameinspectAsset() / collectReferencedChunks() replace deleteAsset() / findOrphanedChunks() (old names preserved as deprecated aliases).
  • FixedChunker O(n²) fix — pre-allocated buffer replaces Buffer.concat() loop.
  • Chunk size upper bound — 100 MiB max enforced across all chunkers.
  • Constructor validationchunkSize, maxRestoreBufferSize, maxEncryptionBufferSize validated at construction time.
  • Cross-runtime portabilityError.captureStackTrace guarded, crypto adapter contracts normalized.

What's new in v5.2.3

Internal refactoring — no breaking API changes. The facade, CasService, and crypto adapters were restructured for better separation of concerns:

  • Consistent async sha256()NodeCryptoAdapter.sha256() now returns Promise<string> like Bun and Web adapters, fixing a Liskov Substitution violation.
  • KeyResolver extracted — ~170 lines of key resolution logic (DEK wrap/unwrap, passphrase derivation, envelope recipients) moved from CasService (1085 → 909 lines) into a dedicated KeyResolver service.
  • Facade decomposedcreateCryptoAdapter, resolveChunker, FileIOHelper, rotateVaultPassphrase, and buildKdfMetadata extracted from the monolithic index.js into focused modules.
  • Barrel re-exports — 10 re-export-only modules converted to export { default as X } from '...' form.

See CHANGELOG.md for the full list of changes.

What's new in v5.2.1

Bug fix: rotateVaultPassphrase now honours kdfOptions.algorithm — previously the --algorithm flag was silently ignored, always reusing the old KDF algorithm. CLI flag tables in docs/API.md are now split per command with --cwd documented.

See CHANGELOG.md for the full list of changes.

What's new in v5.2.0

Key rotation without re-encrypting data — Rotate a recipient's key by re-wrapping the DEK. Data blobs are never touched. Respond to key compromise in seconds, not hours.

// Rotate a single recipient's key
const rotated = await cas.rotateKey({
  manifest, oldKey: aliceOldKey, newKey: aliceNewKey, label: 'alice',
});

// Rotate the vault passphrase (all entries, atomic commit)
const { commitOid, rotatedSlugs, skippedSlugs } = await cas.rotateVaultPassphrase({
  oldPassphrase: 'old-secret', newPassphrase: 'new-secret',
});
# Rotate a recipient key
git cas rotate --slug prod-secrets --old-key-file old.key --new-key-file new.key

# Rotate vault passphrase
git cas vault rotate --old-passphrase old-secret --new-passphrase new-secret

See CHANGELOG.md for the full list of changes.

What's new in v5.1.0

Multi-recipient envelope encryption — Each file is encrypted with a random DEK; recipient KEKs wrap the DEK. Add or remove team members without re-encrypting data.

// API: store for multiple recipients
const manifest = await cas.storeFile({
  filePath: './secrets.tar.gz',
  slug: 'prod-secrets',
  recipients: [
    { label: 'alice', key: aliceKey },
    { label: 'bob', key: bobKey },
  ],
});

// Add a recipient later (no re-encryption)
const updated = await cas.addRecipient({
  manifest, existingKey: aliceKey, newRecipientKey: carolKey, label: 'carol',
});

// List / remove recipients
const labels = await cas.listRecipients({ manifest });
const trimmed = await cas.removeRecipient({ manifest, label: 'bob' });
# CLI: store with multiple recipients
git cas store ./secrets.tar.gz --slug prod-secrets \
  --recipient alice:./keys/alice.key \
  --recipient bob:./keys/bob.key --tree

# Manage recipients
git cas recipient list prod-secrets
git cas recipient add prod-secrets --label carol --key-file ./keys/carol.key --existing-key-file ./keys/alice.key
git cas recipient remove prod-secrets --label bob

See CHANGELOG.md for the full list of changes.

What's new in v5.0.0

Content-defined chunking (CDC) — Fixed-size chunking invalidates every chunk after an edit. CDC uses a buzhash rolling hash to find natural boundaries, limiting the blast radius to 1–2 chunks. Benchmarked at 98.4% chunk reuse on small edits vs 32% for fixed.

const cas = new ContentAddressableStore({
  plumbing,
  chunking: { strategy: 'cdc', targetChunkSize: 262144, minChunkSize: 65536, maxChunkSize: 1048576 },
});

ChunkingPort — new hexagonal port abstracts chunking strategy. FixedChunker and CdcChunker adapters ship out of the box. Bring your own chunker by extending ChunkingPort.

See CHANGELOG.md for the full list of changes.

What's new in v4.0.1

git cas verify — verify stored asset integrity from the CLI without restoring (git cas verify --slug my-asset).

--json everywhere — all commands now support --json for structured output. Pipe git cas vault list --json | jq in CI.

CryptoPort base class — shared key validation, metadata building, and KDF normalization. All three adapters (Node/Bun/Web) inherit from a single source of truth.

Centralized error handlingrunAction wrapper with CasError codes and actionable hints (e.g., "Provide --key-file or --vault-passphrase").

Vault list filteringgit cas vault list --filter "photos/*" with TTY-aware table formatting.

See CHANGELOG.md for the full list of changes.

What's new in v4.0.0

ObservabilityPortCasService no longer extends EventEmitter. A new hexagonal ObservabilityPort decouples the domain from Node's event infrastructure. Three adapters ship out of the box: SilentObserver (no-op default), EventEmitterObserver (backward-compatible event bridge), and StatsCollector (metric accumulator).

Streaming restorerestoreStream() returns an AsyncIterable<Buffer> with O(chunkSize) memory for unencrypted files. restoreFile() now writes via createWriteStream + pipeline instead of buffering.

Parallel chunk I/O — new concurrency option gates store writes and restore reads through a counting semaphore. concurrency: 4 can significantly speed up large-file operations.

See CHANGELOG.md for the full list of changes.

What's new in v3.1.0

Interactive vault dashboardgit cas inspect --slug my-asset renders a rich TUI with chunk heatmap, encryption card, and history timeline. Animated progress bars for long store/restore operations.

See CHANGELOG.md for the full list of changes.

What's new in v3.0.0

Vault — GC-safe ref-based storage under refs/cas/vault. Assets are indexed by slug and survive git gc. Full CLI: git cas vault init, list, info, remove, history. Store with --tree to vault automatically.

See CHANGELOG.md for the full list of changes.

What's new in v2.0.0

Compressioncompression: { algorithm: 'gzip' } on store(). Compression runs before encryption. Decompression on restore() is automatic.

Passphrase-based encryption — Pass passphrase instead of encryptionKey. Keys are derived via PBKDF2 (default) or scrypt. KDF parameters are stored in the manifest for deterministic re-derivation. Use deriveKey() directly for manual control.

Merkle tree manifests — When chunk count exceeds merkleThreshold (default: 1000), manifests are automatically split into sub-manifests stored as separate blobs. readManifest() transparently reconstitutes them. Full backward compatibility with v1 manifests.

See CHANGELOG.md for the full list of changes.

Install

npm install @git-stunts/git-cas
npx jsr add @git-stunts/git-cas

Usage (Node API)

import GitPlumbing from '@git-stunts/plumbing';
import ContentAddressableStore from '@git-stunts/cas';

const git = new GitPlumbing({ cwd: './assets-repo' });
const cas = new ContentAddressableStore({ plumbing: git });

// Store a file -> returns a manifest (chunk list + metadata)
const manifest = await cas.storeFile({
  filePath: './image.png',
  slug: 'my-image',
  encryptionKey: myKeyBuffer, // optional (32 bytes)
});

// Turn the manifest into a Git tree OID
const treeOid = await cas.createTree({ manifest });

// Restore later — get your bytes back, integrity-verified
await cas.restoreFile({ manifest, outputPath: './restored.png' });

// Read the manifest back from a tree OID
const m = await cas.readManifest({ treeOid });

// Lifecycle: inspect deletion impact, collect referenced chunks
const { slug, chunksOrphaned } = await cas.inspectAsset({ treeOid });
const { referenced, total } = await cas.collectReferencedChunks({ treeOids: [treeOid] });

// v2.0.0: Compressed + passphrase-encrypted store
const manifest2 = await cas.storeFile({
  filePath: './image.png',
  slug: 'my-image',
  passphrase: 'my secret passphrase',
  compression: { algorithm: 'gzip' },
});

CLI (git plugin)

git-cas installs as a Git subcommand:

# Store a file — prints manifest JSON
git cas store ./image.png --slug my-image

# Store and vault the tree OID (GC-safe)
git cas store ./image.png --slug my-image --tree

# Restore from a vault slug
git cas restore --slug my-image --out ./restored.png

# Restore from a direct tree OID
git cas restore --oid <tree-oid> --out ./restored.png

# Verify integrity without restoring
git cas verify --slug my-image

# Inspect manifest (interactive dashboard)
git cas inspect --slug my-image

# Vault management
git cas vault init
git cas vault list                        # TTY table
git cas vault list --json                 # structured JSON
git cas vault list --filter "photos/*"    # glob filter
git cas vault info my-image
git cas vault remove my-image
git cas vault history

# Multi-recipient encryption
git cas store ./secret.bin --slug shared \
  --recipient alice:./keys/alice.key \
  --recipient bob:./keys/bob.key --tree
git cas recipient list shared
git cas recipient add shared --label carol --key-file ./keys/carol.key --existing-key-file ./keys/alice.key
git cas recipient remove shared --label bob

# Key rotation (no re-encryption)
git cas rotate --slug shared --old-key-file old.key --new-key-file new.key
git cas rotate --slug shared --old-key-file old.key --new-key-file new.key --label alice

# Vault passphrase rotation
git cas vault rotate --old-passphrase old-secret --new-passphrase new-secret

# Encrypted vault round-trip (passphrase via env var or --vault-passphrase flag)
export GIT_CAS_PASSPHRASE="secret"
git cas vault init
git cas store ./secret.bin --slug vault-entry --tree
git cas restore --slug vault-entry --out ./decrypted.bin

# Compression, chunking, codec, concurrency
git cas store ./data.bin --slug my-data --tree --gzip
git cas store ./data.bin --slug my-data --tree --strategy cdc
git cas store ./data.bin --slug my-data --tree --chunk-size 65536 --concurrency 4
git cas store ./data.bin --slug my-data --tree --codec cbor

# Restore with concurrency
git cas restore --slug my-data --out ./data.bin --concurrency 4

# JSON output on any command (for CI/scripting)
git cas store ./data.bin --slug my-data --tree --json

.casrc — Project Config File

Place a .casrc JSON file at the repository root to set defaults for CLI flags. CLI flags always take precedence over .casrc values.

{
  "chunkSize": 65536,
  "strategy": "cdc",
  "concurrency": 4,
  "codec": "json",
  "compression": "gzip",
  "merkleThreshold": 500,
  "maxRestoreBufferSize": 1073741824,
  "cdc": {
    "minChunkSize": 8192,
    "targetChunkSize": 32768,
    "maxChunkSize": 131072
  }
}

Documentation

When to use git-cas (and when not to)

"I just want screenshots in my README"

Use an orphan branch. Seriously. It's 5 git commands, zero dependencies, and GitHub renders the images inline. Google "git orphan branch assets" — that's all you need. git-cas is overkill for public images and demo GIFs.

"I need encrypted secrets / large binaries / deduplicated assets in a Git repo"

That's git-cas. The orphan branch gives you none of:

| | Orphan branch | git-cas | |---|---|---| | Encryption | None — plaintext forever in history | AES-256-GCM + passphrase KDF + multi-recipient + key rotation | | Large files | Bloats git clone for everyone | Chunked, restored on demand | | Dedup | None | Chunk-level content addressing | | Integrity | Git SHA-1 | SHA-256 per chunk + GCM auth tag | | Lifecycle | git rm (still in reflog) | Vault with audit trail + git gc reclaims | | Compression | None | gzip before encryption |

"Why not Git LFS?"

Because sometimes you want the Git object database to be the store — deterministic, content-addressed, locally replicable, commit-addressable — with no external server, no LFS endpoint, and no second system to manage.

If your team uses GitHub and needs file locking + web UI previews, use LFS. If you want encrypted, self-contained, server-free binary storage that travels with git clone, use git-cas.


THIS HASH’LL KNOCK YOUR SHAs OFF! FIRST COMMIT’S FREE, MAN.


License

Apache-2.0 Copyright © 2026 James Ross