Skip to content

Latest commit

 

History

1 Commit

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

@stratapkg/chronicle

Audit log extension for Prisma — records before/after state of every mutation with actor metadata, reason, and custom fields. Driver-agnostic: store logs in SQLite, PostgreSQL, or plain NDJSON files.

Installation

bun add @stratapkg/chronicle

Pick a driver:

Import Requires
@stratapkg/chronicle/sqlite bun:sqlite or better-sqlite3
@stratapkg/chronicle/postgres any Prisma adapter (logs to same DB)
@stratapkg/chronicle/file nothing (NDJSON files)

Setup

import { PrismaClient } from './generated/client'
import { withChronicle } from '@stratapkg/chronicle'
import { SqliteDriver } from '@stratapkg/chronicle/sqlite'
import { Database } from 'bun:sqlite'

const auditDb = new Database('audit.db')

const prisma = new PrismaClient({ adapter })
  .$extends(withChronicle({
    driver: new SqliteDriver(auditDb),
    models: ['User', 'Order', 'Payment'],
  }))

Usage

Basic — logs automatically

await prisma.user.update({
  where: { id: 1 },
  data: { role: 'admin' },
})

Audit record:

{
  "model": "User",
  "recordId": "1",
  "action": "UPDATE",
  "before": { "role": "user", "name": "Alice" },
  "after":  { "role": "admin", "name": "Alice" },
  "actor": null,
  "timestamp": "2025-06-01T12:00:00Z"
}

With metadata

await prisma.user.update({
  where: { id: 1 },
  data: { role: 'admin' },
  chronicle: {
    actor: currentUserId,
    reason: 'promoted via request #123',
    meta: { ip: '192.168.1.1', userAgent: req.headers['user-agent'] },
  },
})

The chronicle field is typed and available on all mutating operations — create, update, upsert, delete, createMany, updateMany, deleteMany.

Query log

// all changes to a record
const history = await prisma.$chronicle.findMany({
  model: 'User',
  recordId: '1',
})

// all changes by actor
const byActor = await prisma.$chronicle.findMany({
  actor: currentUserId,
  from: new Date('2025-01-01'),
})

What gets logged

Operation before after
create null new record
update old record new record
upsert old record or null new record
delete old record null
updateMany — summary with count
deleteMany — summary with count

before snapshot is fetched automatically before the mutation via findUnique. Can be disabled per-model for performance:

withChronicle({
  driver,
  models: {
    User:    { trackBefore: true },
    Session: { trackBefore: false }, // high-frequency, skip before snapshot
  },
})

Custom driver

interface ChronicleDriver {
  log(entry: AuditEntry): Promise<void>
  query(filter: AuditFilter): Promise<AuditEntry[]>
}

Requirements

  • Prisma >= 7.0
  • Any Prisma adapter

License

MIT

About

Audit log extension for Prisma — before/after snapshots and actor metadata

Topics

Resources

Contributing

Stars

1 star

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages