Transparent audit tracking for object field changes in TypeScript applications. Non-intrusive proxy-based tracking that preserves original object behavior while passively collecting audit information.
- Features
- Installation
- Quick Start
- API Reference
- Examples
- Performance
- Why @snow-tzu/audit?
- Requirements
- Contributing
- License
β¨ Field-level tracking - @AuditField() decorator for selective field monitoring
π― Class-level tracking - @Auditable() decorator for comprehensive audit coverage
π« Field exclusion - @AuditIgnore() decorator to exclude sensitive fields
π Non-intrusive proxies - Preserve original object behavior and method context
π‘οΈ Type safety - Full TypeScript support with strong typing
π Change history - Retrieve all tracked changes with changes()
π Reset functionality - Clear audit history without affecting object state
β‘ Robust error handling - Never disrupts business logic execution
π Optional logging - Built-in debugging utilities
yarn add @snow-tzu/audit
# or
npm install @snow-tzu/auditimport { Audit, AuditField } from '@snow-tzu/audit';
class User {
@AuditField()
email: string = '';
name: string = ''; // Not tracked
}
const user = new User();
const audited = Audit(user);
audited.email = 'john@example.com';
audited.name = 'John Doe';
console.log(audited.changes());
// [{ field: 'email', oldValue: '', newValue: 'john@example.com' }]import { Audit, Auditable, AuditIgnore } from '@snow-tzu/audit';
@Auditable()
class Product {
id: number = 0;
name: string = '';
@AuditIgnore()
internalCode: string = ''; // Excluded from tracking
}
const product = new Product();
const audited = Audit(product);
audited.id = 123;
audited.name = 'Widget';
audited.internalCode = 'X123';
console.log(audited.changes());
// [
// { field: 'id', oldValue: 0, newValue: 123 },
// { field: 'name', oldValue: '', newValue: 'Widget' }
// ]const audited = Audit(new User());
audited.email = 'test@example.com';
console.log(audited.changes().length); // 1
audited.resetAudit?.();
console.log(audited.changes().length); // 0Wraps an object for audit tracking while preserving all original behavior.
Parameters:
target- The object to wrap with audit tracking
Returns: A wrapped object that behaves identically to the original while tracking changes
Property decorator that marks individual fields for audit tracking.
class Example {
@AuditField()
trackedField: string = '';
}Class decorator that marks all fields in a class for audit tracking.
@Auditable()
class Example {
field1: string = ''; // Tracked
field2: number = 0; // Tracked
}Property decorator that excludes specific fields from tracking when used with @Auditable().
@Auditable()
class Example {
tracked: string = '';
@AuditIgnore()
ignored: string = ''; // Not tracked
}interface AuditHandle {
changes(): ChangeRecord[];
resetAudit?(): void;
}interface ChangeRecord {
readonly field: string;
readonly oldValue: unknown;
readonly newValue: unknown;
}Enable debug logging for audit operations.
Disable audit logging.
enum LogLevel {
ERROR = 'ERROR',
WARN = 'WARN',
DEBUG = 'DEBUG'
}π NestJS + TypeORM Example - Complete audit tracking with PostgreSQL
@Auditable()
class Order {
id: number = 0;
items: string[] = [];
@AuditIgnore()
internalNotes: string = '';
calculateTotal(): number {
return this.items.length * 10;
}
}
const order = new Order();
const audited = Audit(order);
// Method calls work normally
console.log(audited.calculateTotal()); // 0
// Field changes are tracked
audited.id = 123;
audited.items = ['item1', 'item2'];
audited.internalNotes = 'secret'; // Not tracked
console.log(audited.changes());
console.log(audited.calculateTotal()); // 20
// [
// { field: 'id', oldValue: 0, newValue: 123 },
// { field: 'items', oldValue: [], newValue: ['item1', 'item2'] }
// ]@Auditable()
class BaseEntity {
id: number = 0;
createdAt: Date = new Date();
}
class User extends BaseEntity {
@AuditField()
email: string = '';
name: string = ''; // Tracked via inheritance
}
const user = new User();
const audited = Audit(user);
audited.id = 1;
audited.email = 'user@example.com';
audited.name = 'John';
console.log(audited.changes().length); // 3 changes tracked@snow-tzu/audit is designed for production use with minimal overhead:
- β‘ Fast proxy creation - Efficient object wrapping
- π Negligible field access overhead - Transparent property access
- π Efficient change detection - Smart change tracking and collapsing
- π Minimal memory footprint - ~0.2KB per tracked object
The library includes comprehensive benchmarks to measure real-world performance impact:
| Metric | Unwrapped | Wrapped | Overhead |
|---|---|---|---|
| Assignment Performance | 1.34M ops/sec | 0.59M ops/sec | +56.1% |
| Memory Usage | ~0 KB | 0.21 KB | +0.21 KB per object |
The optimized implementation provides excellent performance with minimal memory overhead.
| Feature | @snow-tzu/audit | Manual Tracking |
|---|---|---|
| Setup complexity | β Decorator-based | β Boilerplate code |
| Type safety | β Full TypeScript | |
| Non-intrusive | β Transparent proxies | β Code modification |
| Error handling | β Built-in resilience | β Manual implementation |
| Performance | β Optimized proxies |
| Feature | @snow-tzu/audit | Object.observe |
|---|---|---|
| Browser support | β All modern browsers | β Deprecated |
| Selective tracking | β Decorator-based | β All properties |
| TypeScript support | β Native | β No types |
| Change collapsing | β Smart merging | β Raw events |
- Node.js 16+ or modern browsers
- TypeScript 4.5+ (for decorator support)
experimentalDecorators: truein tsconfig.json
We welcome contributions!
MIT Β© Ganesan Arunachalam
Check out the examples directory for fully working projects:
- NestJS + TypeORM + PostgreSQL - Complete audit tracking with database transactions
Each example includes:
- π Ready-to-run setup with Docker
- π Database schema and migrations
- π Transaction-based audit logging
- π― Real-world usage patterns
- π API examples and documentation
- π Issues
- π¬ Discussions