Documentation

API reference

Complete reference for all 3 exported functions. Try them live in the playground.

Installation

bash
npm install audit-log-diff

deepDiff

deepDiff

deepDiff(before, after, options?): DeepDiffResult | DeepDiffWithMessages

Compare two values deeply and return audit-friendly structural diffs. Mongoose-style inputs with toObject() are unwrapped. BSON-style values with .equals() compare equal across instances. Arrays are compared by index only (no LCS).

Returns: NestedDiffNode (default) or FlatChangeWithPath[] when format is "flat". With generateMessage: true, returns { diff, messages }.

typescript
import { deepDiff } from "audit-log-diff";

const diff = deepDiff(
  { name: "Ada", profile: { age: 36 } },
  { name: "Ada", profile: { age: 37 }, role: "admin" },
);
// {
//   profile: { age: { type: "changed", before: 36, after: 37 } },
//   role: { type: "added", value: "admin" }
// }

Flat format

Good for indexing, filters, or piping into formatAuditMessages.

typescript
const flat = deepDiff(before, after, { format: "flat" });
// [
//   { path: "profile.age", type: "changed", before: 36, after: 37 },
//   { path: "role", type: "added", value: "admin" }
// ]

With messages

Paths in messages use spaced camelCase and 1-based row labels for array segments.

typescript
const { diff, messages } = deepDiff(before, after, {
  generateMessage: true,
  user: "Dheemanth Shenoy",
});
// messages e.g. ["Dheemanth changed name to Rafi", …]

Date equality

Same instant compares equal, even if references differ.

typescript
deepDiff(
  { at: new Date("2024-01-01") },
  { at: new Date("2024-01-01") }
);
// {} — same instant, no diff

Options

Configuration passed as the third argument to deepDiff.

ignoreKeys

Property names to skip on plain objects (own keys, any depth). Default [].

deepDiff(recordA, recordB, { ignoreKeys: ["updatedAt", "password"] })
format

"nested" (default) returns a tree of change nodes. "flat" returns an array of path entries.

deepDiff(before, after, { format: "flat" })
generateMessage

If true, return { diff, messages } instead of diff only. Default false.

deepDiff(before, after, { generateMessage: true, user: "Dheemanth Shenoy" })
user

Actor string for messages. The first word is used as the subject. Omit → "Someone".

{ user: "Ada Lovelace" } → subject "Ada"

Helpers

formatAuditMessages

formatAuditMessages(changes, options?): string[]

Build short English audit sentences from an existing flat diff. Paths use spaced camelCase and 1-based row labels for array segments.

Returns: string[] — one audit line per flat path

typescript
import { deepDiff, formatAuditMessages } from "audit-log-diff";

const flat = deepDiff(before, after, { format: "flat" });
const messages = formatAuditMessages(flat, { user: "Ada Lovelace" });
// ["Ada changed name to Rafi", …]

flattenDeepDiff

flattenDeepDiff(node): FlatChangeWithPath[]

Flatten a nested diff tree to path entries — same paths as deepDiff with format: "flat".

Returns: FlatChangeWithPath[]

typescript
import { deepDiff, flattenDeepDiff } from "audit-log-diff";

const nested = deepDiff(before, after);
const flat = flattenDeepDiff(nested);
// [{ path: "profile.age", type: "changed", before: 36, after: 37 }, …]

Change Types

Leaf nodes in nested diffs and entries in flat diffs.

TypeShapeDescription
added{ type: "added", value: unknown }A new field or element appeared in the after value.
removed{ type: "removed", before: unknown }A field or element existed before but is absent after.
changed{ type: "changed", before: unknown, after: unknown }A value was modified between before and after.

TypeScript Exports

With generateMessage: true, pass a literal true so TypeScript infers { diff, messages }.

typescript
import { deepDiff, flattenDeepDiff, formatAuditMessages } from "audit-log-diff";

import type {
  DeepDiffOptions,
  DeepDiffResult,
  DeepDiffWithMessages,
  NestedDiff,
  NestedDiffNode,
  NestedDiffLeaf,
  FlatChange,
  FlatChangeWithPath,
  AddedChange,
  RemovedChange,
  ChangedChange,
  DiffFormat,
} from "audit-log-diff";

Audit Log Diff

Deep-compare two values and get audit-style diffs: nested trees or flat paths, optional English log lines, Date equality by time, and per-level ignoreKeys.

© 2026 Audit Log Diff