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

@halleyhq/crypto-shredding

v0.1.1

Published

GDPR-safe crypto-shredding for event-sourced systems: encrypt PII per-subject, delete the key to erase, keep the audit trail intact forever.

Readme

@halleyhq/crypto-shredding

GDPR-safe erasure for event-sourced systems: encrypt PII per-subject, delete the key to erase, and keep your audit trail intact forever.

The problem

Event sourcing and GDPR's right to erasure (Article 17) are normally in direct conflict. Events are supposed to be immutable — that's the whole point of an audit trail — but "the right to be forgotten" means you sometimes have to make specific data disappear. You can't rewrite history in an append-only store without breaking the guarantee that makes it useful in the first place.

This package resolves that conflict with crypto-shredding: instead of deleting or rewriting events, each subject (a customer, a patient, a user — anything erasure requests apply to) gets its own encryption key. PII fields on events are encrypted with that key before they're ever written to your event store. To "erase" a subject, you throw away their key — not their events. The events stay exactly where they were, in full, forever. Their PII fields just become permanently unreadable.

How it works

  • Mark PII fields on a domain event with @EncryptableEvent
  • Each subject gets its own AES-256-GCM key, stored separately from the event store
  • Events are encrypted field-by-field before being persisted — your event store never sees plaintext PII
  • An erasure request deletes only the key. The event is untouched, forever
  • On replay, PII fields gracefully degrade to '[DELETED]' (strings) or null (dates) once the key is gone — every other field, timestamp, and event in the stream stays fully intact

This pattern is already running in production inside a healthcare platform, handling real erasure requests against a live event store.

Install

npm install @halleyhq/crypto-shredding

Peer dependencies: @nestjs/common and @nestjs/mongoose (encryption keys are currently stored in MongoDB via Mongoose — see Roadmap).

Usage

Mark PII fields on your event:

import { EncryptableEvent } from "@halleyhq/crypto-shredding/decorators/encryptable-event.decorator";

@EncryptableEvent({
  subjectType: "customer",
  subjectIdField: "customerId",
  piiFields: ["givenName", "familyName", "email"],
  piiDateFields: ["dateOfBirth"],
})
export class CustomerRegisteredEvent {
  constructor(
    public customerId: string,
    public givenName: string,
    public familyName: string,
    public email: string,
    public dateOfBirth: Date
  ) {}
}

Register the module:

import { CryptoShreddingModule } from "@halleyhq/crypto-shredding/crypto-shredding.module";

@Module({
  imports: [CryptoShreddingModule],
})
export class AppModule {}

Encrypt before writing, decrypt after reading:

import { CryptoShredderService } from "@halleyhq/crypto-shredding/services/crypto-shredder.service";

// write path — call before persisting the event
const encrypted = await cryptoShredder.encryptEvent(event);

// read path — call after reading the event back, or before replaying it
const decrypted = await cryptoShredder.decryptEventData(CustomerRegisteredEvent, rawData);

Erase a subject on request:

import { EncryptionKeyService } from "@halleyhq/crypto-shredding/services/encryption-key.service";

// Immediately and irreversibly destroys the key. Every historical event
// for this subject becomes cryptographically unreadable, even though the
// events themselves are never touched.
await encryptionKeyService.deleteKey("customer", customerId);

What this doesn't do

This library gives you the technical mechanism for field-level erasure in an immutable event store. It does not, on its own, make your system "GDPR compliant" — that depends on your hosting, your data processing agreements, your retention policies, and your organizational processes. Treat it as: built-in Article 17 erasure for immutable event logs, not a compliance guarantee.

Roadmap

  • Pluggable key storage (currently MongoDB-only via Mongoose; a storage-agnostic interface is under consideration)
  • Framework-agnostic core (currently assumes NestJS DI conventions)

License

MIT