
Security News
Microsoft Releases Open Source Toolkit for AI Agent Runtime Security
Microsoft has released an open source toolkit for enforcing runtime security policies on AI agents as adoption accelerates faster than governance controls.
@rotorsoft/act-patch
Advanced tools
Immutable deep-merge patch utility for Act event-sourced apps. Zero dependencies, browser-safe.
npm install @rotorsoft/act-patch
# or
pnpm add @rotorsoft/act-patch
patch(original, patches) → stateImmutably deep-merges patches into original, returning a new state object.
import { patch } from "@rotorsoft/act-patch";
const state = { user: { name: "Alice", age: 30 }, theme: "dark" };
const updated = patch(state, { user: { age: 31 } });
// → { user: { name: "Alice", age: 31 }, theme: "dark" }
| Value type | Behavior |
|---|---|
| Plain objects | Deep merge recursively |
| Arrays, Dates, RegExp, Maps, Sets, TypedArrays | Replace entirely |
undefined or null | Delete the property |
| Primitives (string, number, boolean) | Replace with patch value |
// Deep merge nested objects
patch({ a: { x: 1, y: 2 } }, { a: { x: 10 } })
// → { a: { x: 10, y: 2 } }
// Replace arrays (not merged)
patch({ items: [1, 2, 3] }, { items: [4, 5] })
// → { items: [4, 5] }
// Delete properties
patch({ a: 1, b: 2, c: 3 }, { b: undefined, c: null })
// → { a: 1 }
// Add new keys
patch({ a: 1 }, { b: 2 })
// → { a: 1, b: 2 }
patch() is a pure function — it never mutates its arguments and always returns a deterministic result for the same inputs.
Unpatched subtrees are reused by reference (structural sharing), not deep-copied. This is the same approach used by Immer, Redux Toolkit, and other immutable state libraries.
const original = { unchanged: { deep: true }, patched: "old" };
const result = patch(original, { patched: "new" });
result.unchanged === original.unchanged // true — same reference
result !== original // true — new top-level object
This is safe in Act's event sourcing model because:
Readonly<S> — the type system prevents mutationpatch() call creates a new top-level object; unchanged subtrees are shared, not copiedAn empty patch short-circuits entirely and returns the original reference with zero allocation:
const result = patch(state, {});
result === state // true — no work done
import type { Patch, DeepPartial, Schema } from "@rotorsoft/act-patch";
// Schema — plain object shape
type Schema = Record<string, any>;
// Patch<T> — recursive partial for patching state
type Patch<T> = {
[K in keyof T]?: T[K] extends Schema ? Patch<T[K]> : T[K];
};
// DeepPartial<T> — recursive deep partial (alias for consumer APIs)
type DeepPartial<T> = {
[K in keyof T]?: T[K] extends Record<string, any> ? DeepPartial<T[K]> : T[K];
};
An array of operations (add, remove, replace, move, copy, test) with JSON Pointer paths.
[
{ "op": "replace", "path": "/user/name", "value": "Alice" },
{ "op": "remove", "path": "/temp" },
{ "op": "add", "path": "/items/-", "value": 42 }
]
Pros: Standardized, array-index-level operations, conditional test ops, compact for sparse changes, move/copy without data duplication.
Cons: Verbose for bulk updates (each field = separate operation), path parsing overhead, requires diff algorithm to produce patches, index-based array ops fragile under concurrency, not type-safe (paths are strings), ~5 KB+ library overhead.
A partial document recursively merged into the target. Closest to Act's approach.
{ "user": { "name": "Alice" }, "temp": null }
Pros: Simple mental model, compact for bulk updates, standardized.
Cons: Cannot set a value to null (null means delete), cannot express array-element-level changes, no conditional operations.
| Criterion | JSON Patch (6902) | Merge Patch (7396) | Act Patch |
|---|---|---|---|
| Type safety | None (paths are strings) | Partial (shape matches) | Full (Zod + Patch<T>) |
| Bundle size | ~5 KB+ | Trivial | < 1 KB |
| Apply perf | O(ops x path parse) | O(keys x depth) | O(keys x depth) |
| Delete semantics | Explicit remove op | null = delete | null/undefined = delete |
| Array handling | Index ops (fragile) | Replace only | Replace only (correct for ES) |
| Event sourcing fit | Poor (opaque ops) | Good | Best (patch = event data shape) |
Key insight: In event sourcing, each event's data is the patch. The event schema (Zod) already constrains the shape, providing compile-time and runtime validation for free. JSON Patch would add an unnecessary indirection layer — event data translated into operations, losing type safety and adding overhead.
typeof value !== "object".constructor === Object check instead of iterating types.Run with npx vitest bench libs/act-patch/test/patch.bench.ts.
All three implementations tested with equivalent operations on the same fixtures. JSON Patch and Merge Patch are inline reference implementations following their respective specs. Results on Apple M4 Max, Node 22:
| Benchmark | Act Patch | Merge Patch (7396) | JSON Patch (6902) |
|---|---|---|---|
| no-op (empty) | 21.5M ops/s | 12.5M ops/s | 2.4M ops/s |
| shallow single-key (5 keys) | 16.3M ops/s | 23.4M ops/s | 2.2M ops/s |
| deep 3-level | 3.0M ops/s | 2.6M ops/s | 957K ops/s |
| delete | 4.6M ops/s | 5.1M ops/s | 1.7M ops/s |
| array replacement | 13.0M ops/s | 12.8M ops/s | 2.9M ops/s |
| sequential 10 patches | 1.1M ops/s | 1.4M ops/s | 237K ops/s |
| wide object (100 keys) | 221K ops/s | 61K ops/s | 159K ops/s |
| large state (1000 keys, 10-key) | 20.9K ops/s | 4.0K ops/s | 7.4K ops/s |
Takeaway: Act Patch matches or beats Merge Patch on small objects and dominates on wide/large states (3.5–5.2x faster) thanks to structural sharing and the hybrid copy strategy. JSON Patch is consistently the slowest due to deep-clone + path parsing overhead.
process, Buffer, or other Node globalssideEffects: false)MIT
FAQs
Immutable deep-merge patch utility for act apps
We found that @rotorsoft/act-patch demonstrated a healthy version release cadence and project activity because the last version was released less than a year ago. It has 1 open source maintainer collaborating on the project.
Did you know?

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Security News
Microsoft has released an open source toolkit for enforcing runtime security policies on AI agents as adoption accelerates faster than governance controls.

Security News
Multiple high-impact npm maintainers confirm they have been targeted in the same social engineering campaign that compromised Axios.

Security News
Axios compromise traced to social engineering, showing how attacks on maintainers can bypass controls and expose the broader software supply chain.