express-activitylog
@actinode/express-activitylog logs every request (or any custom event) to your database with a fluent, readable API.
Installation
pnpm add @actinode/express-activitylognpm install @actinode/express-activitylogyarn add @actinode/express-activitylogThen install an adapter. See Adapters for full setup guides.
pnpm add @prisma/clientpnpm add mongooseQuick start
1. Set up your adapter
import { PrismaClient } from '@prisma/client'
import { prismaAdapter } from '@actinode/express-activitylog'
const prisma = new PrismaClient()
const adapter = prismaAdapter(prisma)import mongoose from 'mongoose'
import { mongooseAdapter } from '@actinode/express-activitylog'
await mongoose.connect(process.env.MONGODB_URI!)
const adapter = mongooseAdapter(mongoose)2. Register the middleware
import express from 'express'
import { activityLog } from '@actinode/express-activitylog'
const app = express()
app.use(
activityLog({
adapter,
getUserId: (req) => req.user?.id,
skip: (req) => req.method === 'GET',
}),
)Every non-GET request is now logged automatically.
3. Log manually with the fluent builder
import { activity } from '@actinode/express-activitylog'
await activity(adapter)
.by(req.user) // causer
.on(post) // subject
.withProperties({ ip: req.ip })
.log('published post')Masking sensitive data
Sensitive fields are masked before they reach your database — both in the middleware (applied to req.body) and in manual log entries (applied to .withProperties()).
TIP
Even without any mask config, common sensitive fields like password, token, and apiKey are masked automatically. See the full list.
denyList — mask specific fields, keep everything else:
activityLog({
adapter,
mask: { denyList: ['password', 'token'] },
})allowList — declare which fields are safe to log, mask everything else:
activityLog({
adapter,
mask: { allowList: ['name', 'email', 'role'] },
})For the full masking reference — deep masking, per-model config, custom replacement strings, and security best practices — see the Masking page.
Minimal working example
import express from 'express'
import { PrismaClient } from '@prisma/client'
import { prismaAdapter, activityLog, activity } from '@actinode/express-activitylog'
const prisma = new PrismaClient()
const adapter = prismaAdapter(prisma)
const app = express()
app.use(express.json())
// Auto-log every mutating request
app.use(
activityLog({
adapter,
getUserId: (req) => (req as any).user?.id,
getDescription: (req) => `${req.method} ${req.path}`,
skip: (req) => req.method === 'GET',
}),
)
app.post('/posts/:id/publish', async (req, res) => {
const post = await prisma.post.update({
where: { id: req.params.id },
data: { published: true },
})
// Manual log with full context
await activity(adapter)
.on(post)
.log('published post')
res.json(post)
})
app.listen(3000)Community & Support
- 🐛 Found a bug? Open a bug report
- 🚀 Have a feature idea? Open a feature request
- 💬 Questions? Join the community
