A crypto shredding implementation for Emmett, enabling selective encryption of event streams for GDPR compliance and data protection.
👉 View Complete Documentation →
This package provides crypto shredding capabilities for Emmett event stores:
- Selective Encryption - Encrypt only sensitive streams based on policies
- Key Management - Automatic key generation, rotation, and lifecycle management
- Crypto Shredding - Destroy encryption keys to make data permanently unrecoverable (GDPR compliance)
- Multiple Algorithms - Support for AES-GCM, AES-CBC, and AES-CTR with runtime detection
- Policy-Based - Define encryption policies by stream type and partition
- Database Agnostic - Works with any database through storage adapters
npm install @wataruoguchi/emmett-crypto-shredding @event-driven-io/emmettCreate the encryption keys and policies tables in your database. See the complete documentation for the SQL schema.
The crypto event store wraps your existing event store. Create it at the module level and use it with DeciderCommandHandler:
Without Crypto (e.g., Cart Module):
// example/src/modules/cart/cart.module.ts
import { getKyselyEventStore } from "@wataruoguchi/emmett-event-store-kysely";
export function createCartModule({ db, logger }: Dependencies) {
const eventStore = getKyselyEventStore({ db, logger });
const eventHandler = cartEventHandler({ eventStore, getContext });
// ... rest of module setup
}With Crypto (e.g., Generator Module):
// example/src/modules/generator/generator.module.ts
import { getKyselyEventStore } from "@wataruoguchi/emmett-event-store-kysely";
import { createCryptoEventStore, createWebCryptoProvider, type CryptoContext } from "@wataruoguchi/emmett-crypto-shredding";
import { createPolicyResolver, createKeyManagement } from "@wataruoguchi/emmett-crypto-shredding-kysely";
export function createGeneratorModule({ db, logger }: Dependencies) {
// Wrap the base event store with crypto
const eventStore = createCryptoEventStore(
getKyselyEventStore({ db, logger }), // Base store
{
policy: createPolicyResolver(db, logger),
keys: createKeyManagement(db),
crypto: createWebCryptoProvider(),
buildAAD: ({ partition, streamId }: CryptoContext) =>
new TextEncoder().encode(`${partition}:${streamId}`),
logger,
},
);
const eventHandler = generatorEventHandler({ eventStore, getContext });
// ... rest of module setup (identical to cart module)
}That's it! The crypto event store is a drop-in replacement. Your event handlers, command handlers, and all other code remain exactly the same. Encryption/decryption happens transparently based on policies—no changes needed to your domain logic.
Set up which streams should be encrypted:
import { createPolicies } from "@wataruoguchi/emmett-crypto-shredding-kysely";
await createPolicies(db, [
{
policyId: "tenant-123-generator",
partition: "tenant-123",
streamTypeClass: "generator",
encryptionAlgorithm: "AES-GCM",
keyRotationIntervalDays: 180,
keyScope: "stream",
},
]);Destroy encryption keys to make data permanently unrecoverable:
// Destroy all keys for a partition - makes data permanently unrecoverable
await keyManagement.destroyPartitionKeys("tenant-123");- Complete Documentation
- Kysely Adapters - PostgreSQL implementation
- Example Application
- Node.js 20+ (for Web Crypto API support)
- TypeScript 5.8+
- Emmett 0.38+
MIT