Skip to content

stratapkg/chronicle

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

1 Commit
 
 
 
 
 
 
 
 
 
 
 
 
 
 

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

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors