A library that handling audit trail like git. Using Elasticsearch (allow using custom client later) to store audit-trail data.
yarn add git-like-audit-trail
import auditTrail from "git-like-audit-trail"
// content of below 3 function depends on database type
const databaseAddOneRowFunction = async ({
data,
auditTrail = true,
parentTrail
}) => {
...
}
const databaseDeleteOneRowFunction = async ({
data,
auditTrail = true,
parentTrail
}) => {
...
}
const databaseUpdateOneRowFunction = async ({
data,
changedObj,
addChangedObj,
deleteChangedObj,
revert = true,
auditTrail = true,
parentTrail
}) => {
...
}
const _auditTrail = new auditTrail({
DBType: "elasticsearch", // default
host: "http://localhost:9200", //default
ESinfo: { //default
indexName: "audit-trail",
},
databaseAddOneRowFunction,
databaseDeleteOneRowFunction,
databaseUpdateOneRowFunction,
// databaseCustomActionFunction, // custom action function
})
- createData: Create audit trail data
- appendCommitMap: Append commitHash (obtained after createData) into CommitMap
- query: Query git tree structure
- queryD3: Query git tree structure in D3 hierarchy
- queryByCommitHash: Query commit info by commitHash
- batchQueryByCommitHash: Query commit info by commitHashArray
- revertCommit: Revert commit like git
- cherryPick: Cherry Pick like git
- checkout: checkout to other commit/branch
await
need to execute in async function
const trail = await _auditTrail.createData({
categoryId: "testTable", // target table name
userId: "awcjack", // user id
dataId: "1", // changes target data id
name: "1", // extra info
before: {}, // data before change
after: {
id: "1",
name: "test1"
}, // data after change
parent, // parent commit id (for large trail that change multiple data)
action: "CREATE", // "CREATE" || "UPDATE" || "DELETE" (allow extra action type but have to handled in databaseCustomActionFunction)
ignore: [], // ignore in diff
...otherArgs // other args that want to log into this audit trail
})
console.log(trail)
/*
{
categoryId: "testTable",
userId: "awcjack",
dataId: "1",
name: "1",
parent,
action: "CREATE",
...otherArgs,
change: "{\"added\":{\"id\":{\"after\":\"1\"},\"name\":{\"after\":\"test\"}},\"deleted\":{},\"updated\":{}}",
time: 1613749903586,
parentTrail: "04353794-da94-468d-abd9-1080426007a4",
commitHash: "834cb604b1ce6ae0eb77b8a52aab60d913e4ede2
}
// commitHash work as index
*/
const { commitHash } = trail // trail object from createData
const commitMap = _auditTrail.appendCommitMap({
currentCommitMap: "{}", // existing commit map ("{}" for init)
currentCommitHash: "", // current commit hash in category
newCommitHash: commitHash //new commit hash from createData
})
console.log(commitMap)
/*
"{^0_834cb604b1ce6ae0eb77b8a52aab60d913e4ede2:834cb604b1ce6ae0eb77b8a52aab60d913e4ede2}"
// string type for storing into db
*/
const tree = _auditTrail.query({
commitHashMap: "{}", // existing commit map
commitHash: "", // query from hash (user current commit)
before: 5, // include 5 commit (level) before
after: 5,// include 5 commit (level) after
onlyCurrentBranch: false, //only reveal current branch
getCommitInfo: false // query commit info
})
console.log(tree)
/*
[{"834cb604b1ce6ae0eb77b8a52aab60d913e4ede2":{"3e4c25f224e435372b9c1f92bc050fd3a9840d91":{},"34fc46d4e871605dcf1f3519f5f4ee0124dac4ed":{}}}]
// removed commit info prevent too long
*/
const tree = _auditTrail.queryD3({
commitHashMap: "{}", // existing commit map
commitHash: "", // query from hash (user current commit)
before: 5, // include 5 commit (level) before
after: 5,// include 5 commit (level) after
onlyCurrentBranch: false, //only reveal current branch
getCommitInfo: false, // query commit info
ignore: [], // ignore array of commit info object (delete from object)
format, // commit info format, "test" (commit info parse to key: value pair and concat with \n), "object" (commit info)
})
console.log(tree)
/*
[{"children":[{"children":{"name":"da498b3a30a06db903cc25cfac07517e3e08216c", "info": {...}, "currentCommit": true})],"name":"2a599a5d724d659b8ebb6565a626de40d52db10a","info":{"categoryId":"testTable","userId":"awcjack","dataId":"1","name":"test","action":"CREATE","change":"{\"added\":{\"id\":{\"after\":\"1\"},\"name\":{\"after\":\"test\"}},\"deleted\":{},\"updated\":{}}","time":1614433429834,"parentTrail":"b343ac62-7807-4d68-8518-f4d18e59e781","commitHash":"2a599a5d724d659b8ebb6565a626de40d52db10a"}}]
*/
const commit = _auditTrail.queryByCommitHash({
commitHash: "b11b50b366f8477e8e9f5dea5344fc42eac63b06",
})
console.log(commit)
/*
{
"categoryId": "testTable",
"userId": "awcjack",
"dataId": "3",
"name": "test3",
"action": "CREATE",
"ignore": [],
"change": "{\"added\":{\"id\":{\"after\":\"3\"},\"name\":{\"after\":\"test3\"}},\"deleted\":{},\"updated\":{}}",
"time": 1613815197218,
"parentTrail": "9aaf9a1c-7ccc-453a-9d3f-bd70a5e49c58",
"commitHash": "b11b50b366f8477e8e9f5dea5344fc42eac63b06"
}
*/
const commits = _auditTrail.batchQueryByCommitHash({
commitHashArray: ["b11b50b366f8477e8e9f5dea5344fc42eac63b06"],
})
console.log(commits)
/*
[{
"categoryId": "testTable",
"userId": "awcjack",
"dataId": "3",
"name": "test3",
"action": "CREATE",
"ignore": [],
"change": "{\"added\":{\"id\":{\"after\":\"3\"},\"name\":{\"after\":\"test3\"}},\"deleted\":{},\"updated\":{}}",
"time": 1613815197218,
"parentTrail": "9aaf9a1c-7ccc-453a-9d3f-bd70a5e49c58",
"commitHash": "b11b50b366f8477e8e9f5dea5344fc42eac63b06"
}]
*/
const result = await _auditTrail.revertCommit({
commitHash: req.params.hash,
})
console.log(result)
/*
{
"added": {
"error": false,
"content": {
"id": "1",
"name": "test"
},
"commitHash": "834cb604b1ce6ae0eb77b8a52aab60d913e4ede2"
}
}
*/
const result = await _auditTrail.cherryPick({
commitHash: req.params.hash,
})
console.log(result)
/*
{
"added": {
"error": false,
"content": {
"id": "1",
"name": "test"
},
"commitHash": "834cb604b1ce6ae0eb77b8a52aab60d913e4ede2"
}
}
*/
const result = await _auditTrail.checkout({
commitHashMap: commitHashMap.commitMap,
currentCommit: currentCommit.commitHash,
commitHash: req.params.hash,
})
console.log(result)
/*
[{"deleted":{"error":false,"content":{"id":"23","name":"test23"}}}]
*/
- verify tree structure & logic
handle checkout- handle merge (may or may not implement)
- custom client
provide frontend demo- handle batch CUD in demo