express-activity-audit
v1.1.5
Published
Express + Sequelize activity/audit log with functional API
Maintainers
Readme
📜 express-activity-audit
A simple, flexible, and reusable Node/Express audit logging utility for Sequelize-based apps.
Features:
- Stores audit logs in an
activity_logstable - Supports afterCreate / afterUpdate Sequelize hooks
- Automatic human-readable change descriptions
- Configurable field inclusion/exclusion
- Custom field label mapping
- 📖 Includes
getActivityLogsfunction to easily fetch & paginate logs (ORM or raw SQL fallback)
🗂️ Directory Structure Example
express-activity-audit/
├── index.js
└── lib/
├── diffChanges.js
├── generateDescription.js
├── logActivity.js
└── getActivityLogs.js⚡ Installation
Local development
npm pack
# then in consuming project
npm install /path/to/express-activity-audit-1.0.0.tgzor via link:
npm link
# then in consuming project
npm link express-activity-audit🚀 How to Use in Your Project
const {
logActivity,
diffChanges,
getActivityLogs,
} = require('express-activity-audit');⚡ Example: Sequelize Hook for Employee
Employee.addHook('afterCreate', async (instance, options) => {
await logActivity({
db: instance.sequelize,
module: 'HRMS',
action: 'create',
userId: options.user_id,
meta: { created: instance.toJSON() },
});
});
Employee.addHook('afterUpdate', async (instance, options) => {
const changes = diffChanges(
instance._previousDataValues || {},
instance.toJSON()
);
await logActivity({
db: instance.sequelize,
module: 'HRMS',
action: 'update',
userId: options.user_id,
meta: changes,
});
});✅ Options for logActivity
| Option | Type | Description | Default |
| ------------- | ------ | --------------------------------------------------------- | --------------- |
| db | object | Required. Sequelize instance or connection. | - |
| tableName | string | Table name for storing logs. | activity_logs |
| module | string | Required. Which module triggered the log. | - |
| action | string | Action type (create, update, etc.). | update |
| message | string | Custom message. If omitted, auto-generated from meta. | Generated |
| userId | string | User ID who did the action. | - |
| meta | object | Changes or entity data. | - |
| ref_id | any | Optional reference ID to the related record. | null |
| ref_table | string | Optional reference table name for the related record. | null |
| excludeFields | array | Fields to remove entirely from logs. | [] |
| includeFields | array | Only include these fields (whitelist). Overrides exclude. | null |
| fieldLabels | object | Map of field -> human label. | {} |
✅ How It Works
✔️ excludeFields: remove these keys from meta before logging
✔️ includeFields: only these keys are included (overrides excludeFields)
✔️ fieldLabels: rename fields in logs for human readability
✔️ Auto-generates message like:
Ticket Status changed from "Open" to "Closed", Agent changed from "Alice" to "Bob"or
Created new record with First Name="John", Last Name="Doe"✅ Example activity_logs Schema
await queryInterface.createTable('activity_logs', {
id: { type: Sequelize.INTEGER, autoIncrement: true, primaryKey: true },
user_id: { type: Sequelize.INTEGER },
ref_id: { type: Sequelize.INTEGER },
ref_table: { type: Sequelize.STRING },
module: { type: Sequelize.STRING, allowNull: false },
action: { type: Sequelize.STRING, allowNull: false },
message: { type: Sequelize.STRING(1000), allowNull: false },
meta: { type: Sequelize.JSON },
created_at: {
type: Sequelize.DATE,
allowNull: false,
defaultValue: Sequelize.literal('CURRENT_TIMESTAMP'),
},
updated_at: {
type: Sequelize.DATE,
allowNull: false,
defaultValue: Sequelize.literal('CURRENT_TIMESTAMP'),
},
});🔍 getActivityLogs
A helper to fetch activity logs for your UI or reports. Supports filtering, pagination, search, sort — works with Sequelize ORM or raw SQL.
✅ Usage
const { getActivityLogs } = require('express-activity-audit');
const result = await getActivityLogs({
db: sequelize, // required: Sequelize instance
refId: 123, // optional: filter by related record id
refTable: 'employees', // optional: filter by related table
search: 'ticket', // optional: partial search on message
limit: 20, // default 50
offset: 0, // for pagination
orderBy: 'created_at', // default created_at
order: 'DESC', // ASC / DESC
});Returns:
{
rows: [ ...logs ],
count: 200,
page: 1
}✅ Options for getActivityLogs
| Option | Type | Description |
| -------- | ------ | ------------------------------------------------- |
| db | object | Required. Sequelize instance. |
| refId | any | Filter by ref_id |
| refTable | string | Filter by ref_table |
| search | string | Searches message (case-insensitive, LIKE match) |
| limit | number | Number of records (default: 50) |
| offset | number | Pagination offset (default: 0) |
| orderBy | string | Column to order by (default: created_at) |
| order | string | ASC or DESC (default: DESC) |
✅ How It Works Internally
If you have a model
ActivityLog, it usesfindAndCountAll.Otherwise, falls back to raw SQL with
db.query.Automatically builds
WHEREfor:ref_idref_table- partial
LIKEsearch onmessage
Returns count + page calculation.
✅ Example with Sequelize ORM
// Assuming your sequelize has models.ActivityLog
const logs = await getActivityLogs({
db: sequelize,
refTable: 'tickets',
search: 'closed',
limit: 10,
offset: 0,
});✅ Example with raw SQL fallback
If you don’t have models.ActivityLog registered, it auto-falls back:
const logs = await getActivityLogs({
db: sequelize,
refId: 45,
orderBy: 'created_at',
order: 'DESC',
});✅ Best Practices
✅ Use limit & offset for UI pagination
✅ Use search to allow filtering logs by message keywords
✅ Always wrap in try/catch to handle DB errors gracefully
❤️ Contributing
✅ Keep functions small and modular ✅ Follow semantic versioning for releases ✅ Add unit tests for your additions
