{"_id":"@birtalanrobert/audit","_rev":"3-ac115b5c72baad1f8ecbb2523f7fd4f7","name":"@birtalanrobert/audit","dist-tags":{"latest":"1.0.0"},"versions":{"0.1.0":{"name":"@birtalanrobert/audit","version":"0.1.0","license":"AGPL-3.0-only","_id":"@birtalanrobert/audit@0.1.0","maintainers":[{"name":"birtalanrobert","email":"birtalanrobert@gmail.com"}],"homepage":"https://github.com/birtalanrobert/mortar#readme","bugs":{"url":"https://github.com/birtalanrobert/mortar/issues"},"dist":{"shasum":"afb72535c5359f3de3119a1391cf77d6ac71e7cd","tarball":"https://registry.npmjs.org/@birtalanrobert/audit/-/audit-0.1.0.tgz","fileCount":34,"integrity":"sha512-IW9Vgdzlg9SEDPl6ULfmq3RcrF0inN71875h0efiR7hCjq7WWDnNCaefq9McWzuKt0ybr+I1Sc2D2VK+GqqTAg==","signatures":[{"sig":"MEYCIQCdlis0CWXpcPNgr1qJMw8pkcjgoK7UVNE0ncLAzD75gQIhAPN0T39HSPKyR6Yn4uOPdu9rA4H1Xmj6mqNKvbb92DhZ","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":105971},"main":"./dist/index.js","type":"commonjs","_from":"file:birtalanrobert-audit-0.1.0.tgz","types":"./dist/index.d.ts","exports":{".":{"types":"./dist/index.d.ts","default":"./dist/index.js"},"./package.json":"./package.json"},"scripts":{"build":"tsc -p tsconfig.build.json","clean":"rm -rf dist *.tsbuildinfo","typecheck":"tsc -p tsconfig.json"},"_npmUser":{"name":"birtalanrobert","email":"birtalanrobert@gmail.com"},"_resolved":"/private/var/folders/zx/7dcyg3mn6kjfyzsymzgpx1jr0000gn/T/b362967edcc870c45d56bc39b790fe1b/birtalanrobert-audit-0.1.0.tgz","_integrity":"sha512-IW9Vgdzlg9SEDPl6ULfmq3RcrF0inN71875h0efiR7hCjq7WWDnNCaefq9McWzuKt0ybr+I1Sc2D2VK+GqqTAg==","repository":{"url":"git+https://github.com/birtalanrobert/mortar.git","type":"git","directory":"packages/audit"},"_npmVersion":"11.13.0","description":"Append-only audit log that joins the caller transaction","directories":{},"_nodeVersion":"24.16.0","dependencies":{"@birtalanrobert/context":"0.1.0","@birtalanrobert/database":"0.1.0"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"peerDependencies":{"typeorm":"^0.3.0 || ^1.0.0","@nestjs/common":"^10.0.0 || ^11.0.0"},"peerDependenciesMeta":{"@nestjs/common":{"optional":true}},"_npmOperationalInternal":{"tmp":"tmp/audit_0.1.0_1787664415573_0.2579065514576102","host":"s3://npm-registry-packages-npm-production"}},"0.2.0":{"name":"@birtalanrobert/audit","version":"0.2.0","license":"AGPL-3.0-only","_id":"@birtalanrobert/audit@0.2.0","maintainers":[{"name":"birtalanrobert","email":"birtalanrobert@gmail.com"}],"homepage":"https://github.com/birtalanrobert/mortar#readme","bugs":{"url":"https://github.com/birtalanrobert/mortar/issues"},"dist":{"shasum":"f92f2d860d462ff8b860bf147704f438a521640b","tarball":"https://registry.npmjs.org/@birtalanrobert/audit/-/audit-0.2.0.tgz","fileCount":35,"integrity":"sha512-yXnxzIn9PXHtxIfqkahsw+haQIYeJjLTeG2FpX0ryDeT4gwDWhIk9dk51gLYYiLHLMMEjOgeTfZy1+RoZllADQ==","signatures":[{"sig":"MEQCICFTlRdvIYcFkbKT52PAc3rIVXdj03naOZDV5t/BPt1NAiBd3+EgMgo7EvGgXTGw1Ziu1wRlpxAhQ2lvuIr/qa1eLg==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":108066},"main":"./dist/index.js","type":"commonjs","_from":"file:birtalanrobert-audit-0.2.0.tgz","types":"./dist/index.d.ts","exports":{".":{"types":"./dist/index.d.ts","default":"./dist/index.js"},"./package.json":"./package.json"},"scripts":{"build":"tsc -p tsconfig.build.json","clean":"rm -rf dist *.tsbuildinfo","typecheck":"tsc -p tsconfig.json"},"_npmUser":{"name":"birtalanrobert","email":"birtalanrobert@gmail.com"},"_resolved":"/private/var/folders/zx/7dcyg3mn6kjfyzsymzgpx1jr0000gn/T/c2b16498e105600465c9861d0d82743c/birtalanrobert-audit-0.2.0.tgz","_integrity":"sha512-yXnxzIn9PXHtxIfqkahsw+haQIYeJjLTeG2FpX0ryDeT4gwDWhIk9dk51gLYYiLHLMMEjOgeTfZy1+RoZllADQ==","repository":{"url":"git+https://github.com/birtalanrobert/mortar.git","type":"git","directory":"packages/audit"},"_npmVersion":"11.13.0","description":"Append-only audit log that joins the caller transaction","directories":{},"_nodeVersion":"24.16.0","dependencies":{"@birtalanrobert/context":"^0.2.0","@birtalanrobert/database":"^0.2.0"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"peerDependencies":{"typeorm":"^0.3.0 || ^1.0.0","@nestjs/common":"^10.0.0 || ^11.0.0"},"peerDependenciesMeta":{"@nestjs/common":{"optional":true}},"_npmOperationalInternal":{"tmp":"tmp/audit_0.2.0_1787732726204_0.047645298071251396","host":"s3://npm-registry-packages-npm-production"}},"1.0.0":{"name":"@birtalanrobert/audit","version":"1.0.0","description":"Append-only audit log that joins the caller transaction","license":"AGPL-3.0-only","type":"commonjs","main":"./dist/index.js","types":"./dist/index.d.ts","exports":{".":{"types":"./dist/index.d.ts","default":"./dist/index.js"},"./package.json":"./package.json"},"publishConfig":{"access":"public"},"dependencies":{"@birtalanrobert/context":"^1.0.0","@birtalanrobert/database":"^1.0.0"},"peerDependencies":{"@nestjs/common":"^10.0.0 || ^11.0.0","typeorm":"^0.3.0 || ^1.0.0"},"peerDependenciesMeta":{"@nestjs/common":{"optional":true}},"repository":{"type":"git","url":"git+https://github.com/birtalanrobert/mortar.git","directory":"packages/audit"},"scripts":{"build":"tsc -p tsconfig.build.json","clean":"rm -rf dist *.tsbuildinfo","typecheck":"tsc -p tsconfig.json"},"_id":"@birtalanrobert/audit@1.0.0","bugs":{"url":"https://github.com/birtalanrobert/mortar/issues"},"homepage":"https://github.com/birtalanrobert/mortar#readme","_integrity":"sha512-Wujkio52AvCykvIqIIPRHDeYbieUDAD43nMvQfp5qfUwSa18a7v9weZvMzfdISvwa2nj6xjcluIQuyBOrvb56g==","_resolved":"/private/var/folders/zx/7dcyg3mn6kjfyzsymzgpx1jr0000gn/T/9d1972c69ee7fe9c9cb6130803dfa289/birtalanrobert-audit-1.0.0.tgz","_from":"file:birtalanrobert-audit-1.0.0.tgz","_nodeVersion":"24.16.0","_npmVersion":"11.13.0","dist":{"integrity":"sha512-Wujkio52AvCykvIqIIPRHDeYbieUDAD43nMvQfp5qfUwSa18a7v9weZvMzfdISvwa2nj6xjcluIQuyBOrvb56g==","shasum":"50efbf6c99810e9eae1e1dc27102f735da851262","tarball":"https://registry.npmjs.org/@birtalanrobert/audit/-/audit-1.0.0.tgz","fileCount":35,"unpackedSize":111689,"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEUCIBq2ql6a9k26wvT56e3UJYd8m1V+HOrimsa7kKjcTmAKAiEAnmvr1g4485IzubuihEvcrrGgEThDUdNy5lgyadqBJuw="}]},"_npmUser":{"name":"birtalanrobert","email":"birtalanrobert@gmail.com"},"directories":{},"maintainers":[{"name":"birtalanrobert","email":"birtalanrobert@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/audit_1.0.0_1787735901022_0.38030883302672236"},"_hasShrinkwrap":false}},"time":{"created":"2026-08-25T13:26:55.419Z","modified":"2026-08-26T09:18:21.369Z","0.1.0":"2026-08-25T13:26:55.752Z","0.2.0":"2026-08-26T08:25:26.335Z","1.0.0":"2026-08-26T09:18:21.184Z"},"bugs":{"url":"https://github.com/birtalanrobert/mortar/issues"},"license":"AGPL-3.0-only","homepage":"https://github.com/birtalanrobert/mortar#readme","repository":{"type":"git","url":"git+https://github.com/birtalanrobert/mortar.git","directory":"packages/audit"},"description":"Append-only audit log that joins the caller transaction","maintainers":[{"name":"birtalanrobert","email":"birtalanrobert@gmail.com"}],"readme":"# @birtalanrobert/audit\n\nAn append-only audit trail that **joins the caller's transaction**.\n\n## Why this package exists in this form\n\n`record()` writes through the active `EntityManager` when one is open. That\nsingle property is the reason mortar adopted TypeORM at all: a package holding\nits own connection pool cannot join the caller's transaction, so a rollback\nwould leave behind an audit row for a change that never happened — a confident\nrecord of a lie, which is worse than no record.\n\n```ts\nawait runInTransaction(dataSource, async () => {\n  await bookingRepo.save(booking);\n  await audit.record({\n    action: 'booking.cancelled',\n    entityType: 'booking',\n    entityId: booking.id,\n    before,\n    after,\n  });\n});\n// Both commit, or neither does.\n```\n\n## Append-only is enforced by the database\n\nThe service exposes no update or delete for individual rows, **and** the\nmigration installs a trigger that raises on `UPDATE`. A trail that merely\nhappens not to be edited is worth less than one that cannot be — and these\nprojects use it to settle disputes about money, hours worked and who saw whose\ndata.\n\nBulk time-based purging (`purgeOlderThan`) still works, because retention is a\npolicy rather than a way to remove one inconvenient row.\n\n## Context is captured automatically\n\nTenant, actor, actor name, impersonator, request id, correlation id, address\nand user agent all come from the ambient request context. A caller writes one\nline and the entry is complete.\n\n**Impersonation records both parties** — the operator and the account they\nacted as — because \"who did this\" has two answers when support is involved.\n\n**The actor's name is denormalised** on purpose: a user who is later renamed or\ndeleted must still be identifiable, and a join to a mutable table would quietly\nrewrite history.\n\n## Only changes are stored, and secrets never are\n\n`computeChanges()` records just the fields that differ, with password, token,\nkey, PIN, card and IBAN-shaped fields replaced by `[redacted]` — the fact of\nthe change is recorded, the value is not.\n\nDates compare by instant rather than identity, so a record re-read from the\ndatabase does not register as changed.\n","readmeFilename":"README.md"}