nedb-engine 2.0.5 → 2.0.30
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +140 -12
- package/nedb.darwin-x64.node +0 -0
- package/package.json +1 -1
- package/nedb.darwin-arm64.node +0 -0
- package/nedb.linux-x64-gnu.node +0 -0
- package/nedb.win32-x64-msvc.node +0 -0
package/README.md
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
# NEDB
|
|
4
4
|
|
|
5
|
-
**Hash-chained ·
|
|
5
|
+
**Content-addressed Merkle DAG · Hash-chained · Time-traveling · Bi-temporal · Causally-provable embedded database.**
|
|
6
6
|
|
|
7
7
|
Replay-protected · idempotent · relational · filterable · sortable · searchable · concurrent.
|
|
8
8
|
One Rust core → ships to **PyPI** and **npm** from a single source.
|
|
@@ -10,6 +10,8 @@ One Rust core → ships to **PyPI** and **npm** from a single source.
|
|
|
10
10
|
[](https://pypi.org/project/nedb-engine/)
|
|
11
11
|
[](https://www.npmjs.com/package/nedb-engine)
|
|
12
12
|
[](https://github.com/Eth-Interchained/nedb/actions)
|
|
13
|
+
[](https://pypi.org/project/nedb-engine-client/)
|
|
14
|
+
[](https://www.npmjs.com/package/nedb-engine-client)
|
|
13
15
|
|
|
14
16
|
**[Studio → studio.interchained.org](https://studio.interchained.org)** · **[nedb.aiassist.net](https://nedb.aiassist.net)**
|
|
15
17
|
|
|
@@ -17,6 +19,47 @@ One Rust core → ships to **PyPI** and **npm** from a single source.
|
|
|
17
19
|
|
|
18
20
|
---
|
|
19
21
|
|
|
22
|
+
## v2 — The DAG Engine (current stable: 2.0.27)
|
|
23
|
+
|
|
24
|
+
NEDB v2 replaces the append-only log (AOF) with a **content-addressed Merkle DAG**. Every document version is an immutable, BLAKE2b-verified object. Nothing is ever overwritten. As of **v2.0.27**, restarts after the first open are **O(1) warm starts** (driven by a `MANIFEST` of `seq` + Merkle head), the **cold scan is deferred** so the daemon accepts connections immediately, and a new **`GET /events` SSE endpoint** streams scan progress + per-write events live.
|
|
25
|
+
|
|
26
|
+
```bash
|
|
27
|
+
# Run the v2 DAG engine — ships inside pip install nedb-engine
|
|
28
|
+
nedbd --dag --data ./data
|
|
29
|
+
# or
|
|
30
|
+
NEDBD_DAG=1 NEDB_TMK=<32-byte-hex> nedbd --data ./data
|
|
31
|
+
|
|
32
|
+
curl http://127.0.0.1:7070/health
|
|
33
|
+
# {"ok":true,"version":"2.0.27","service":"nedbd","engine":"dag","startup_ready":true,"encrypted":true}
|
|
34
|
+
|
|
35
|
+
# Tail the live event stream (new in v2.0.27)
|
|
36
|
+
curl http://127.0.0.1:7070/events
|
|
37
|
+
# event: scan data: {"objects":730000,"of":1310703,"rate":21043,"eta_s":28}
|
|
38
|
+
# event: ready data: {"seq":1310703,"head":"b2:9c14e07a…"}
|
|
39
|
+
# event: write data: {"seq":1310704,"coll":"beliefs","head":"b2:7af3c11e…"}
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
| Property | v2 DAG | v1 AOF |
|
|
43
|
+
|---|:---:|:---:|
|
|
44
|
+
| Uncorruptable (atomic writes, hash-verified reads) | ✅ | ⚠️ |
|
|
45
|
+
| O(1) warm start via MANIFEST (no scan, no replay) | ✅ | ❌ |
|
|
46
|
+
| Deferred cold scan (socket open immediately) | ✅ | ❌ |
|
|
47
|
+
| O(1) incremental Merkle head (never recomputed) | ✅ | ❌ |
|
|
48
|
+
| Parallel writes (no global lock) | ✅ | ❌ |
|
|
49
|
+
| BLAKE2b Merkle head on every response | ✅ | ❌ |
|
|
50
|
+
| IdIndex sharded across 256 subdirectories | ✅ | ❌ |
|
|
51
|
+
| TCP_NODELAY (no 40–200 ms loopback Nagle delay) | ✅ | ❌ |
|
|
52
|
+
| `GET /events` SSE log stream | ✅ | ❌ |
|
|
53
|
+
| Tombstone deletes (history preserved) | ✅ | ✅ |
|
|
54
|
+
| Auto-migrates v1 AOF → v2 DAG on startup | ✅ | — |
|
|
55
|
+
| Same HTTP API — Vision, Studio, all clients unchanged | ✅ | ✅ |
|
|
56
|
+
|
|
57
|
+
**v1 AOF engine is still shipped and unchanged** — `nedbd` (no flag) runs v1.
|
|
58
|
+
|
|
59
|
+
**Production status:** [vision.interchained.org](https://vision.interchained.org) is live on v2.0.27 — **1,310,703 sequences** indexed in the Vision database, AES-256-GCM encrypted at rest, at block height **620,989**.
|
|
60
|
+
|
|
61
|
+
---
|
|
62
|
+
|
|
20
63
|
## What makes NEDB different
|
|
21
64
|
|
|
22
65
|
Every database stores *what*. NEDB stores *what*, *when*, *when it was true*, and *why* — all sealed in a cryptographic hash chain that proves none of it was tampered with.
|
|
@@ -173,11 +216,31 @@ db.seq(); // → BigInt
|
|
|
173
216
|
nedbd runs NEDB as a long-lived process with an HTTP/JSON API and an optional RESP2 wire protocol. Built on a **single-writer group-commit sequencer** — parallel reads, batched durable writes, one hash-chain per database, zero write-write races.
|
|
174
217
|
|
|
175
218
|
```bash
|
|
176
|
-
nedbd # :7070, data ./nedb-data
|
|
219
|
+
nedbd # :7070, data ./nedb-data (v1 AOF engine)
|
|
220
|
+
nedbd --dag --data ./data # v2 DAG engine (or NEDBD_DAG=1)
|
|
177
221
|
NEDBD_RESP2_PORT=6380 nedbd # also speak RESP2 (redis-cli compatible)
|
|
178
222
|
nedbd --log-level 2 # 0=errors 1=requests 2=deploy 3=verbose
|
|
223
|
+
|
|
224
|
+
# Live event stream (new in v2.0.27) — SSE: scan progress, ready, per-write head
|
|
225
|
+
curl http://127.0.0.1:7070/events
|
|
179
226
|
```
|
|
180
227
|
|
|
228
|
+
### Startup modes (v2.0.27)
|
|
229
|
+
|
|
230
|
+
- **Warm start** — every restart after the first open reads the `MANIFEST` file and restores `seq` + Merkle `head` in **O(1)**. No scan, no replay, independent of dataset size. Boots in milliseconds.
|
|
231
|
+
- **Cold start** — first open of an existing dataset spawns the integrity scan in a background thread *and accepts connections immediately*. Reads serve instantly from the content-addressed DAG; writes return `HTTP 503 startup in progress` until the `startup_ready` gate flips. Progress (objects, rate, ETA) streams over `GET /events`.
|
|
232
|
+
|
|
233
|
+
### Environment variables
|
|
234
|
+
|
|
235
|
+
| Variable | Default | Description |
|
|
236
|
+
|---|---|---|
|
|
237
|
+
| `NEDBD_DAG` | `0` | Set `1` to launch the v2 DAG engine (`nedbd-v2`). Same as `--dag`. |
|
|
238
|
+
| `NEDBD_HOST` | `127.0.0.1` | Bind address. **v2.0.27** defaults to loopback (was `0.0.0.0`) — security hardening fix. Set explicitly to `0.0.0.0` to expose. |
|
|
239
|
+
| `NEDBD_PORT` | `7070` | HTTP bind port. |
|
|
240
|
+
| `NEDBD_TOKEN` | unset | Optional bearer token; required on every `/v1/*` request when set. |
|
|
241
|
+
| `NEDB_TMK` | unset | 32-byte hex AES-256-GCM at-rest encryption key. |
|
|
242
|
+
| `NEDBD_DATA` | `./nedb-data` | Root directory. v2 creates `dag/`, IdIndex sharded across **256 subdirectories**, and a small `MANIFEST` file. |
|
|
243
|
+
|
|
181
244
|
```bash
|
|
182
245
|
# Create a database with seed data and relations
|
|
183
246
|
curl -X POST :7070/v1/databases -d '{
|
|
@@ -233,15 +296,37 @@ db.query('FROM policy AS OF 200 VALID AS OF "2024-02-15"')
|
|
|
233
296
|
|
|
234
297
|
---
|
|
235
298
|
|
|
236
|
-
## Performance
|
|
299
|
+
## Performance
|
|
300
|
+
|
|
301
|
+
**v2 DAG Rust server (v2.0.27, Intel iMac — 10k writes / 100k reads / 30k objects, AES-256-GCM on):**
|
|
302
|
+
|
|
303
|
+
| Operation | Throughput | p50 | p99 |
|
|
304
|
+
|---|---|---|---|
|
|
305
|
+
| Sequential writes | **418 ops/s** | 2.3 ms | 3.3 ms |
|
|
306
|
+
| Point-lookup reads | **478 ops/s** | 2.0 ms | 3.0 ms |
|
|
307
|
+
| ORDER BY queries | **489 ops/s** | 1.8 ms | 4.3 ms |
|
|
308
|
+
| Batch writes (500 ops/req) | **1,104 ops/s** | 0.9 ms | 1.2 ms |
|
|
309
|
+
| Tamper-verify (30k objects) | ~21,000 BLAKE2b/sec | — | 1.38 s total |
|
|
310
|
+
|
|
311
|
+
p99 latencies hold because of `TCP_NODELAY` on the axum listener — without it macOS loopback adds the Nagle algorithm's 40–200 ms delay on small writes.
|
|
312
|
+
|
|
313
|
+
**v1 Python server (baseline — single-threaded AOF):**
|
|
237
314
|
|
|
238
|
-
| Operation | Throughput |
|
|
315
|
+
| Operation | Throughput | p99 latency |
|
|
239
316
|
|---|---|---|
|
|
240
|
-
| PUT
|
|
241
|
-
|
|
|
242
|
-
|
|
|
243
|
-
|
|
|
244
|
-
|
|
|
317
|
+
| Sequential PUT | ~23/s | 44 ms |
|
|
318
|
+
| Concurrent PUT (16 workers) | ~92/s | 48 ms |
|
|
319
|
+
| Batch PUT (500 ops/request) | ~520 ops/s | 1.9 ms/op |
|
|
320
|
+
| Point-lookup read (NQL) | ~23/s | 44 ms |
|
|
321
|
+
| Rust napi PUT (FFI) | ~70K/s | — |
|
|
322
|
+
| Rust napi GET (FFI) | ~330K/s | — |
|
|
323
|
+
|
|
324
|
+
Reproduce with the included benchmark:
|
|
325
|
+
|
|
326
|
+
```bash
|
|
327
|
+
NEDBD_DAG=1 nedbd --data /tmp/perf &
|
|
328
|
+
python3 tests/test_dag_perf.py --n 10000 --reads 100000
|
|
329
|
+
```
|
|
245
330
|
|
|
246
331
|
---
|
|
247
332
|
|
|
@@ -271,16 +356,49 @@ Encryption: AES-256-GCM at-rest (TMK/DEK double-envelope)
|
|
|
271
356
|
|
|
272
357
|
---
|
|
273
358
|
|
|
359
|
+
## nedb-client — lightweight HTTP client
|
|
360
|
+
|
|
361
|
+
Connect to any running nedbd instance from Python or TypeScript without embedding the engine:
|
|
362
|
+
|
|
363
|
+
```bash
|
|
364
|
+
pip install nedb-engine-client # async Python
|
|
365
|
+
npm install nedb-engine-client # TypeScript / Node.js 18+
|
|
366
|
+
```
|
|
367
|
+
|
|
368
|
+
```python
|
|
369
|
+
from nedb_client import NedbClient
|
|
370
|
+
|
|
371
|
+
async with NedbClient("http://127.0.0.1:7070", db="mydb") as db:
|
|
372
|
+
await db.put("blocks", "618000", {"height": 618000})
|
|
373
|
+
rows = await db.query("FROM blocks ORDER BY height DESC LIMIT 10")
|
|
374
|
+
head = await db.head() # BLAKE2b Merkle root — changes on every write
|
|
375
|
+
ok = await db.verify() # tamper-evidence check across all objects
|
|
376
|
+
```
|
|
377
|
+
|
|
378
|
+
```typescript
|
|
379
|
+
import { NedbClient } from "nedb-engine-client";
|
|
380
|
+
const db = new NedbClient({ url: "http://127.0.0.1:7070", db: "mydb" });
|
|
381
|
+
await db.put("blocks", "618000", { height: 618000 });
|
|
382
|
+
const rows = await db.query("FROM blocks LIMIT 10");
|
|
383
|
+
```
|
|
384
|
+
|
|
385
|
+
---
|
|
386
|
+
|
|
274
387
|
## Repo layout
|
|
275
388
|
|
|
276
389
|
```
|
|
277
390
|
python/nedb/ reference engine (pure Python — always-works baseline)
|
|
278
391
|
rust/
|
|
279
|
-
nedb-core/ production Rust engine (shared by both runtimes)
|
|
392
|
+
nedb-core/ v1 production Rust engine (shared by both runtimes)
|
|
280
393
|
nedb-py/ maturin PyO3 binding → PyPI native wheels
|
|
281
394
|
nedb-node/ napi-rs binding → npm native addons
|
|
282
|
-
|
|
395
|
+
nedb-v2/ v2 DAG engine (tokio + axum + BLAKE2b DAG)
|
|
396
|
+
client/
|
|
397
|
+
python/ nedb-client — async Python HTTP client (pip install nedb-engine-client)
|
|
398
|
+
node/ nedb-client — TypeScript HTTP client (npm install nedb-client)
|
|
399
|
+
tests/ engine + concurrent + causal + bitemporal + deploy + perf benchmarks
|
|
283
400
|
examples/ resp2_python.py resp2_demo.sh
|
|
401
|
+
docs/ index.html reference.html SPEC.md
|
|
284
402
|
```
|
|
285
403
|
|
|
286
404
|
---
|
|
@@ -297,7 +415,17 @@ examples/ resp2_python.py resp2_demo.sh
|
|
|
297
415
|
- [x] SQL / Redis / MongoDB compatibility adapters
|
|
298
416
|
- [x] RESP2 wire protocol (redis-cli / redis-benchmark compatible)
|
|
299
417
|
- [x] Rust native core — napi-rs (npm) + maturin PyO3 (PyPI)
|
|
300
|
-
- [x] Self-healing
|
|
418
|
+
- [x] Self-healing AOF — auto-truncates corrupt tail on startup, never hangs
|
|
419
|
+
- [x] **v2 DAG engine** — content-addressed Merkle DAG, atomic writes, instant cold start
|
|
420
|
+
- [x] **`nedbd --dag`** — one flag switches to v2 Rust engine; v1 untouched
|
|
421
|
+
- [x] **BLAKE2b Merkle head** — tamper-evident root on every response
|
|
422
|
+
- [x] **Tombstone deletes** — history preserved in DAG, live id removed from index
|
|
423
|
+
- [x] **Auto-migration** — v1 AOF → v2 DAG on first `--dag` startup
|
|
424
|
+
- [x] **nedb-client** — async Python + TypeScript HTTP client (`pip/npm install nedb-client`)
|
|
425
|
+
- [x] **Intel Mac support** — native wheels for `aarch64` + `x86_64` Apple Darwin
|
|
426
|
+
- [ ] In-memory DAG mode — `Db::in_memory()` for zero-disk ephemeral sessions
|
|
427
|
+
- [ ] PyO3 + napi-rs bindings updated to v2 DAG API
|
|
428
|
+
- [ ] NEDB Studio DAG mode toggle
|
|
301
429
|
- [ ] Merkle inclusion proofs — prove a document existed at a specific time to a third party
|
|
302
430
|
- [ ] Git-style branching — fork database state, experiment, merge or discard
|
|
303
431
|
- [ ] Agent Memory SDK — `Memory.remember()` / `Memory.recall()` / `Memory.trace()`
|
|
Binary file
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "nedb-engine",
|
|
3
|
-
"version": "2.0.
|
|
3
|
+
"version": "2.0.30",
|
|
4
4
|
"description": "NEDB — hash-chained, time-traveling, bi-temporal embedded database with Rust native core. SQL, Redis, MongoDB adapters. Causal Write Provenance. RESP2 wire protocol.",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"types": "index.d.ts",
|
package/nedb.darwin-arm64.node
DELETED
|
Binary file
|
package/nedb.linux-x64-gnu.node
DELETED
|
Binary file
|
package/nedb.win32-x64-msvc.node
DELETED
|
Binary file
|