or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

docs

change-observation.mdcore-operations.mdindex.mdjson-pointer-utilities.mdvalidation.md
tile.json

change-observation.mddocs/

Change Observation

Duplex functionality for observing JavaScript objects and automatically generating JSON patches when changes are detected. This enables reactive programming patterns and efficient change tracking.

Capabilities

Observe Object Changes

Starts observing an object or array for changes and automatically generates patches.

/**
 * Observes changes made to an object, which can then be retrieved using generate
 * @param obj Object or array to observe for changes
 * @param callback Optional callback function called when changes are detected
 * @returns Observer object with patches array and unobserve method
 */
function observe<T>(
  obj: Object | Array<T>,
  callback?: (patches: Operation[]) => void
): Observer<T>;

Usage Examples:

import { observe } from "fast-json-patch";

// Basic observation
const data = { name: "Alice", age: 25 };
const observer = observe(data);

// Make changes
data.name = "Bob";
data.age = 26;

// Generate patches manually
const patches = generate(observer);
console.log(patches);
// [
//   { op: "replace", path: "/name", value: "Bob" },
//   { op: "replace", path: "/age", value: 26 }
// ]

// Stop observing
observer.unobserve();

// With callback for automatic patch generation
const liveData = { counter: 0 };
const liveObserver = observe(liveData, (patches) => {
  console.log("Changes detected:", patches);
  // Could send patches to server, store in history, etc.
});

liveData.counter++; // Automatically triggers callback with patches

Stop Observing

Stops observing an object and cleans up event listeners.

/**
 * Detach an observer from an object
 * @param root The root object being observed
 * @param observer The observer to detach
 */  
function unobserve<T>(root: T, observer: Observer<T>): void;

Usage Examples:

import { observe, unobserve } from "fast-json-patch";

const obj = { status: "active" };
const observer = observe(obj);

// Later, stop observing
unobserve(obj, observer);
// Or use the observer's built-in method
observer.unobserve();

Generate Patches

Generates an array of patches from an observer, capturing all changes since the last generation.

/**
 * Generate an array of patches from an observer
 * @param observer The observer to generate patches from
 * @param invertible Whether to generate invertible patches (with test operations)
 * @returns Array of patch operations describing the changes
 */
function generate<T>(
  observer: Observer<Object>,
  invertible?: boolean
): Operation[];

Usage Examples:

import { observe, generate } from "fast-json-patch";

const document = { users: ["Alice"] };
const observer = observe(document);

// Make changes
document.users.push("Bob");
document.users[0] = "Alice Smith";

// Generate regular patches
const patches = generate(observer);
console.log(patches);
// [
//   { op: "replace", path: "/users/0", value: "Alice Smith" },
//   { op: "add", path: "/users/1", value: "Bob" }
// ]

// Generate invertible patches (with test operations)
document.users.push("Charlie");
const invertiblePatches = generate(observer, true);
console.log(invertiblePatches);
// [
//   { op: "test", path: "/users/2", value: undefined },
//   { op: "add", path: "/users/2", value: "Charlie" }
// ]

Compare Documents

Compares two objects and generates patches representing the differences.

/**
 * Create an array of patches from the differences in two objects
 * @param tree1 The original object
 * @param tree2 The target object  
 * @param invertible Whether to generate invertible patches (with test operations)
 * @returns Array of patch operations to transform tree1 into tree2
 */
function compare(
  tree1: Object | Array<any>,
  tree2: Object | Array<any>,
  invertible?: boolean
): Operation[];

Usage Examples:

import { compare } from "fast-json-patch";

const original = {
  name: "John",
  age: 30,
  hobbies: ["reading", "gaming"]
};

const updated = {
  name: "John Smith", 
  age: 31,
  hobbies: ["reading", "swimming"],
  email: "john@example.com"
};

// Generate patches to transform original into updated
const patches = compare(original, updated);
console.log(patches);
// [
//   { op: "replace", path: "/name", value: "John Smith" },
//   { op: "replace", path: "/age", value: 31 },
//   { op: "replace", path: "/hobbies/1", value: "swimming" },
//   { op: "add", path: "/email", value: "john@example.com" }
// ]

// Generate invertible patches
const invertiblePatches = compare(original, updated, true);
// Includes test operations to verify the original state

Observer Interface

The observer object returned by the observe function:

interface Observer<T> {
  /** The observed object */
  object: T;
  /** Array of accumulated patches since last generation */
  patches: Operation[];
  /** Function to stop observing and clean up */
  unobserve: () => void;
  /** Optional callback function for automatic patch generation */
  callback: (patches: Operation[]) => void;
}

Browser Integration

In browser environments, the observer automatically sets up event listeners for user interactions:

  • mouseup, mousedown - Mouse interactions
  • keyup, keydown - Keyboard interactions
  • change - Form element changes

These listeners trigger automatic patch generation through a debounced mechanism, making the observer perfect for tracking user-driven changes in web applications.

Performance Considerations

  • Lazy Evaluation: Patches are only generated when generate() is called or when changes are detected
  • Efficient Cloning: Uses optimized JSON.parse/stringify for deep cloning
  • Debounced Updates: Browser event listeners are debounced to prevent excessive patch generation
  • Memory Management: Observers should be properly cleaned up using unobserve() to prevent memory leaks

Common Use Cases

  1. State Management: Track changes in application state
  2. Real-time Sync: Generate patches to synchronize data across clients
  3. Undo/Redo: Create change history for user interfaces
  4. Form Validation: Monitor form field changes
  5. API Optimization: Send only changed data instead of full documents
  6. Change Auditing: Log all modifications to objects for compliance

The duplex observation system provides a powerful foundation for reactive programming patterns while maintaining compatibility with the JSON Patch standard.