audit fixes, repo restructure, and documentation

Soundness and performance audit (17 fixes):
- See AUDIT.md for full details and @claude comments in code

Repo restructure:
- Inline json-ptr and json-patch submodules as regular directories
- Remove cbor submodule, replace serde_cbor with ciborium
- Rename patch-db/ -> core/, patch-db-macro/ -> macro/,
  patch-db-macro-internals/ -> macro-internals/, patch-db-util/ -> util/
- Purge upstream CI/CD, bench, and release cruft from json-patch
- Remove .gitmodules

Test fixes:
- Fix proptest doesnt_crash (unique file paths, proper close/cleanup)
- Add PatchDb::close() for clean teardown

Documentation:
- Add README.md, ARCHITECTURE.md, CONTRIBUTING.md, CLAUDE.md, AUDIT.md
- Add TSDocs to TypeScript client exports

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Matt Hill
2026-02-23 19:06:42 -07:00
parent 05c93290c7
commit 86b0768bbb
46 changed files with 5744 additions and 95 deletions

81
README.md Normal file
View File

@@ -0,0 +1,81 @@
# patch-db
A database that tracks state updates as [RFC 6902 JSON Patches](https://tools.ietf.org/html/rfc6902). Enables observable, event-driven state management with a Rust backend and TypeScript client.
## Overview
patch-db stores your application state as a single JSON document. Instead of opaque writes, every mutation is recorded as a JSON Patch — a sequence of add/remove/replace operations. Subscribers receive only the patches relevant to the subtree they're watching, making it efficient for UIs that need to react to fine-grained state changes.
### Key properties
- **Event-sourced** — patches are the source of truth, not snapshots
- **Observable** — subscribers watch arbitrary subtrees via JSON Pointers and receive scoped patches in real time
- **Persistent** — the Rust backend writes to disk with CBOR serialization, automatic compaction, and crash-safe backup files
- **Type-safe** — derive macros on the Rust side; generic type parameters and deep `watch$()` overloads on the TypeScript side
- **Immutable values** — the Rust side uses `imbl_value::Value` for efficient structural sharing
## Quick start
### Rust
Add to your `Cargo.toml`:
```toml
[dependencies]
patch-db = { git = "https://github.com/Start9Labs/patch-db" }
```
```rust
use patch_db::PatchDb;
use json_ptr::ROOT;
#[tokio::main]
async fn main() -> Result<(), patch_db::Error> {
let db = PatchDb::open("my.db").await?;
// Write a value
db.put(&ROOT, &serde_json::json!({ "count": 0 })).await?;
// Read it back
let dump = db.dump(&ROOT).await;
println!("revision {}: {}", dump.id, dump.value);
// Subscribe to changes
let mut watch = db.watch(ROOT.to_owned()).await;
// watch implements Stream — use it with tokio, futures, etc.
Ok(())
}
```
### TypeScript
```typescript
import { PatchDB, Dump, Update } from 'patch-db'
import { Observable } from 'rxjs'
interface AppState {
users: { [id: string]: { name: string; online: boolean } }
settings: { theme: string }
}
// source$ delivers updates from the server (WebSocket, SSE, etc.)
const source$: Observable<Update<AppState>[]> = getUpdatesFromServer()
const db = new PatchDB<AppState>(source$)
db.start()
// Watch a deeply nested path — fully type-safe
db.watch$('settings', 'theme').subscribe(theme => {
console.log('Theme changed:', theme)
})
```
## Further reading
- [ARCHITECTURE.md](ARCHITECTURE.md) — project structure, crate/package details, data flow, storage format
- [CONTRIBUTING.md](CONTRIBUTING.md) — environment setup, build commands, testing, code style
## License
MIT